1
1
""" Interact with the NFT module of the app"""
2
2
import copy
3
- from typing import Dict , List
3
+ from typing import Dict , List , Union
4
4
import json
5
+ from uuid import uuid4
6
+ from eth_account .messages import encode_structured_data
5
7
6
8
import web3
7
9
from thirdweb .abi .erc20 import ERC20
8
10
from thirdweb .constants import NativeAddress , ZeroAddress
9
11
10
- from thirdweb_web3 import Web3
12
+ from web3 import Web3
13
+ from zero_ex .contract_wrappers import TxParams
11
14
12
15
from thirdweb .types .role import Role
13
16
14
- from ..abi .nft import SignatureMint721 as NFT
17
+ from ..abi .nft import SignatureMint721 as NFT , ISignatureMint721MintRequest
15
18
from ..types .nft import BatchGeneratedSignature , MintArg , MintRequestStructOutput , NewSignaturePayload , SignaturePayload
16
19
from ..types .nft import NftMetadata as NftType
17
20
from .base import BaseModule
18
- import uuid
21
+
19
22
import binascii
20
23
21
24
@@ -51,7 +54,7 @@ def mint(self, arg: MintArg) -> NftType:
51
54
:param arg: the `MintArg` object
52
55
:return: the metadata of the token
53
56
54
- Mints a new token to the signer.
57
+ Mints a new token to the signer.
55
58
- Arguments passed: Note, a class is used -> MintArg(name, description, image_uri, properties)
56
59
- Returns the `NftMetadata(name,description,image,properties,id,uri)`
57
60
"""
@@ -70,7 +73,7 @@ def mint_to(
70
73
71
74
Mints a new token to an address
72
75
- Arguments passed: `to_address` and a class -> `MintArg(name, description, image_uri, properties)`
73
- - Returns the `NftMetadata(name,description,image,properties,id,uri)`
76
+ - Returns the `NftMetadata(name,description,image,properties,id,uri)`
74
77
"""
75
78
final_properties : Dict
76
79
if arg .properties is None :
@@ -233,7 +236,7 @@ def balance_of(self, address: str) -> int:
233
236
234
237
Returns balance of the given addressss
235
238
- Use-case: Use this method if you don't want to use the connected wallet, but want to check another wallet.
236
- - Dashboard: Project ➝ NFT Module ➝ Total amount of NFT's
239
+ - Dashboard: Project ➝ NFT Module ➝ Total amount of NFT's
237
240
"""
238
241
return self .__abi_module .balance_of .call (address )
239
242
@@ -299,41 +302,46 @@ def set_restricted_transfer(self, restricted: bool = True):
299
302
)
300
303
)
301
304
302
- def __map_payload (req : SignaturePayload or NewSignaturePayload ) -> MintRequestStructOutput :
303
- return MintRequestStructOutput (
305
+ def __map_payload (self , req : Union [ SignaturePayload , NewSignaturePayload ] ) -> ISignatureMint721MintRequest :
306
+ return ISignatureMint721MintRequest (
304
307
to = req .to ,
305
308
price = req .price ,
306
309
currency = req .currency_address ,
307
- validity_end_timestamp = req .mint_end_time_epoch_seconds ,
308
- validity_start_timestamp = req .mint_start_time_epoch_seconds ,
310
+ validityEndTimestamp = req .mint_end_time_epoch_seconds ,
311
+ validityStartTimestamp = req .mint_start_time_epoch_seconds ,
309
312
uid = req .id ,
313
+ uri = req .uri
310
314
)
311
315
312
316
def __set_allowance (
313
317
self ,
314
318
value : int ,
315
- currency_address : str
319
+ currency_address : str ,
320
+ overrides : TxParams ,
316
321
):
317
322
params = self .get_transact_opts ()
318
323
if currency_address == ZeroAddress or currency_address == NativeAddress :
319
- params [ " value" ] = value
324
+ overrides . value = value
320
325
else :
321
326
erc20 = ERC20 (self .get_client (), currency_address )
322
327
owner = self .get_signer_address ()
323
328
spender = self .address
324
- allownace = erc20 .allowance (owner , spender )
325
- if allownace < value :
329
+ allowance = erc20 .allowance . call (owner , spender )
330
+ if allowance < value :
326
331
tx = erc20 .increase_allowance .build_transaction (
327
- owner , value - allownace , params )
332
+ owner , value - allowance , params )
328
333
self .execute_tx (tx )
329
334
return params
330
335
331
336
def mint_with_signature (self , req : NewSignaturePayload , signature : str ) -> int :
332
337
message = self .__map_payload (req )
333
338
overrides = self .get_transact_opts ()
334
- self .__set_allowance (req .price , req .currency_address )
335
- tx = self .__abi_module .mint_with_signature .build_transaction (
336
- message , signature , overrides )
339
+
340
+ self .__set_allowance (req .price , req .currency_address , overrides )
341
+
342
+ print ("Minting NFT with signature" , message )
343
+
344
+ tx = self .__abi_module .mint_with_signature .build_transaction (message , signature , overrides )
337
345
receipt = self .execute_tx (tx )
338
346
logs = self .__abi_module .get_mint_with_signature_event (
339
347
receipt .transactionHash .hex ())
@@ -345,59 +353,82 @@ def verify(self, mint_request: SignaturePayload, signature: str) -> bool:
345
353
return self .__abi_module .verify .call (message , signature )[0 ]
346
354
347
355
def generate_signature_batch (self , payloads : list ) -> list :
356
+ '''
357
+ Generates a batch of signatures that can be used for minting a number of NFTs
358
+
359
+ :param payloads: The payloads to generate the signature for
360
+ :return: The generated signature
361
+ '''
348
362
def resolve_id (mint_request : NewSignaturePayload ):
349
- if not mint_request .id :
363
+ if mint_request .id is None :
350
364
print ("mint_request.id is empty, generating uuid-v4" )
351
- generated_id = uuid . uuid4 ().hex
352
- return generated_id
365
+ generated_id = uuid4 ().hex
366
+ return "0x" + binascii . hexlify ( str . encode ( generated_id )). decode ()
353
367
else :
354
- return binascii .hexlify (mint_request .id ).decode ()
368
+ return "0x" + binascii .hexlify (str . encode ( mint_request .id ) ).decode ()
355
369
356
370
if not self .get_signer_address () in self .get_role_members (Role .minter ):
357
371
raise Exception ("You are not a minter" )
358
- storage = self .get_storage ()
359
372
360
- def generate_sign (payload : NewSignaturePayload ):
373
+ def generate_signature (payload : NewSignaturePayload ) -> BatchGeneratedSignature :
361
374
resolved_id = resolve_id (payload )
362
- uri = storage .upload (payload .metadata , self .address , self .get_signer_address ())
375
+
376
+ uri = self .upload_metadata (payload .metadata )
363
377
payload .id = resolved_id
364
378
payload .uri = uri
365
379
chain_id = self .get_client ().eth .chain_id
366
380
message = self .__map_payload (payload )
367
381
message ["uri" ] = uri
368
382
message ["uid" ] = resolved_id
369
- return BatchGeneratedSignature (payload = payload ,
370
- signature = self .get_client ().eth .sign_typed_data (
371
- {
372
- "name" : "SignatureMint721" ,
373
- "version" : "1" ,
374
- "chainId" : chain_id ,
375
- "verifyingContract" : self .address ,
376
- },
377
- {
378
- "MintRequest" : [
379
- {"name" : "to" ,
380
- "type" : "address" },
381
- {"name" : "uri" ,
382
- "type" : "string" },
383
- {"name" : "price" ,
384
- type : "uint256" },
385
- {"name" : "currency" ,
386
- type : "address" },
387
- {"name" : "validityStartTimestamp" ,
388
- type : "uint128" },
389
- {"name" : "validityEndTimestamp" ,
390
- type : "uint128" },
391
- {"name" : "uid" ,
392
- type : "bytes32" },
393
- ]
394
- },
395
- message
396
- )
397
- )
398
- return [generate_sign (payload ) for payload in payloads ]
383
+
384
+ print ("message" , message )
385
+ encode_message = {
386
+ ** message ,
387
+ "uid" : str (message ['uid' ].encode ('utf-8' ))
388
+ }
389
+ encoded_message = encode_structured_data (text = json .dumps ({
390
+ "types" : {
391
+ "MintRequest" : [
392
+ {"name" : "to" , "type" : "address" },
393
+ {"name" : "uri" , "type" : "string" },
394
+ {"name" : "price" , "type" : "uint256" },
395
+ {"name" : "currency" , "type" : "address" },
396
+ {"name" : "validityStartTimestamp" , "type" : "uint128" },
397
+ {"name" : "validityEndTimestamp" , "type" : "uint128" },
398
+ {"name" : "uid" , "type" : "string" },
399
+ ],
400
+ "EIP712Domain" : [
401
+ {"name" : "name" , "type" : "string" },
402
+ {"name" : "version" , "type" : "string" },
403
+ {"name" : "chainId" , "type" : "uint256" },
404
+ {"name" : "verifyingContract" , "type" : "address" }
405
+ ]
406
+ },
407
+ "primaryType" : "MintRequest" ,
408
+ "domain" : {
409
+ "name" : "SignatureMint721" ,
410
+ "version" : "1" ,
411
+ "chainId" : chain_id ,
412
+ "verifyingContract" : self .address
413
+ },
414
+ "message" : encode_message
415
+ }))
416
+ print ("encoded_message =" , encoded_message )
417
+ return BatchGeneratedSignature (
418
+ payload = payload ,
419
+ signature = self .get_client ().eth .account .sign_message (
420
+ encoded_message ,
421
+ self .get_private_key ()
422
+ ).signature .hex ())
423
+ return [generate_signature (payload ) for payload in payloads ]
399
424
400
425
def generate_signature (self , mint_request : NewSignaturePayload ):
426
+ '''
427
+ Generates a signature that can be used for minting an NFT
428
+
429
+ :param mint_request: The payload to generate the signature for
430
+ :return: The generated signature
431
+ '''
401
432
return self .generate_signature_batch ([mint_request ])[0 ]
402
433
403
434
def get_with_owner (self , token_id : int ):
0 commit comments