11import json
22import os
3+ import random
34import time
45from argparse import ArgumentParser
56from multiprocessing .dummy import Pool
@@ -88,6 +89,12 @@ def do_setup(args: Any):
8889 print ("Do airdrops for non-fungible tokens..." )
8990 controller .do_airdrops_for_non_fungible_tokens ()
9091
92+ print ("Issue semi-fungible token..." )
93+ controller .issue_semi_fungible_token ("SFT" )
94+
95+ print ("Do airdrops for semi-fungible tokens..." )
96+ controller .do_airdrops_for_semi_fungible_tokens ()
97+
9198 print ("Setup done." )
9299
93100
@@ -921,6 +928,7 @@ def do_run_relayed_builtin_functions(memento: "Memento", accounts: "BunchOfAccou
921928
922929 fungible_token = memento .get_custom_currencies ()[0 ]
923930 non_fungible_token = memento .get_non_fungible_tokens ()[0 ]
931+ semi_fungible_token = memento .get_semi_fungible_tokens ()[0 ]
924932
925933 # Ownership transferred to "a".
926934 controller .do_change_contract_owner (contract = named_contracts ["y" ], new_owner = named_accounts ["a" ])
@@ -1063,19 +1071,190 @@ def do_run_relayed_builtin_functions(memento: "Memento", accounts: "BunchOfAccou
10631071 controller .send (transaction , await_processing_started = True )
10641072
10651073 # ESDTNFTAddQuantity
1066- # TODO
1074+ # https://docs.multiversx.com/tokens/nft-tokens/#add-quantity-sft-only
1075+
1076+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1077+ print (f"## ESDTNFTAddQuantity, sender={ sender } , relayer={ relayer } " )
1078+
1079+ transaction = controller .token_management_transactions_factory .create_transaction_for_adding_quantity (
1080+ sender = named_addresses [sender ],
1081+ token_identifier = semi_fungible_token ,
1082+ token_nonce = 7 ,
1083+ quantity_to_add = 42 ,
1084+ )
1085+
1086+ # Gas limit set by default (by the SDKs) seems a bit too much
1087+ transaction .gas_limit = 500_000
1088+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1089+ controller .send (transaction , await_processing_started = True )
10671090
10681091 # ESDTNFTBurn
1069- # TODO
1092+ # https://docs.multiversx.com/tokens/nft-tokens/#burn-quantity
1093+
1094+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1095+ print (f"## ESDTNFTBurn, sender={ sender } , relayer={ relayer } " )
1096+
1097+ transaction = controller .token_management_transactions_factory .create_transaction_for_burning_quantity (
1098+ sender = named_addresses [sender ],
1099+ token_identifier = semi_fungible_token ,
1100+ token_nonce = 7 ,
1101+ quantity_to_burn = 41 ,
1102+ )
1103+
1104+ # Gas limit set by default (by the SDKs) seems a bit too much
1105+ transaction .gas_limit = 500_000
1106+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1107+ controller .send (transaction , await_processing_started = True )
10701108
10711109 # ESDTNFTAddURI
1072- # TODO
1110+ # https://docs.multiversx.com/tokens/nft-tokens/#add-uris-to-nft
1111+
1112+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1113+ print (f"## ESDTNFTAddURI, sender={ sender } , relayer={ relayer } " )
1114+
1115+ controller .send (controller .create_transfer_and_execute (
1116+ sender = named_accounts [sender ],
1117+ contract = named_accounts [sender ].address ,
1118+ function = "ESDTNFTAddURI" ,
1119+ arguments = [TokenIdentifierValue (non_fungible_token ), U32Value (0x64 ), StringValue ("e" ), StringValue ("f" ), StringValue ("g" )],
1120+ gas_limit = 500_000 ,
1121+ native_amount = 0 ,
1122+ custom_amount = 0 ,
1123+ relayer = named_accounts [relayer ],
1124+ ), await_processing_started = True )
1125+
1126+ # ESDTSetNewURIs
1127+
1128+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1129+ print (f"## ESDTSetNewURIs, sender={ sender } , relayer={ relayer } " )
1130+
1131+ controller .send (controller .create_transfer_and_execute (
1132+ sender = named_accounts [sender ],
1133+ contract = named_accounts [sender ].address ,
1134+ function = "ESDTSetNewURIs" ,
1135+ arguments = [TokenIdentifierValue (non_fungible_token ), U32Value (0x65 ), StringValue ("new" )],
1136+ gas_limit = 1_000_000 ,
1137+ native_amount = 0 ,
1138+ custom_amount = 0 ,
1139+ relayer = named_accounts [relayer ],
1140+ ), await_processing_started = True )
10731141
10741142 # ESDTNFTUpdateAttributes
1075- # TODO
1143+ # https://docs.multiversx.com/tokens/nft-tokens/#change-nft-attributes
1144+
1145+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1146+ print (f"## ESDTNFTUpdateAttributes, sender={ sender } , relayer={ relayer } " )
1147+
1148+ transaction = controller .token_management_transactions_factory .create_transaction_for_updating_attributes (
1149+ sender = named_addresses [sender ],
1150+ token_identifier = non_fungible_token ,
1151+ token_nonce = 0x64 ,
1152+ attributes = b"new-attributes" ,
1153+ )
1154+
1155+ # Gas limit set by default (by the SDKs) seems a bit too much
1156+ transaction .gas_limit = 500_000
1157+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1158+ controller .send (transaction , await_processing_started = True )
1159+
1160+ # ESDTModifyRoyalties
1161+ # https://docs.multiversx.com/tokens/nft-tokens/#modify-royalties
1162+
1163+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1164+ print (f"## ESDTModifyRoyalties, sender={ sender } , relayer={ relayer } " )
1165+
1166+ transaction = controller .token_management_transactions_factory .create_transaction_for_modifying_royalties (
1167+ sender = named_addresses [sender ],
1168+ token_identifier = non_fungible_token ,
1169+ token_nonce = 0x64 ,
1170+ new_royalties = random .randint (1000 , 10_000 ),
1171+ )
1172+
1173+ # Gas limit set by default(by the SDKs) seems a bit too much
1174+ transaction .gas_limit = 3_000_000
1175+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1176+ controller .send (transaction , await_processing_started = True )
1177+
1178+ # ESDTModifyCreator
1179+ # https://docs.multiversx.com/tokens/nft-tokens/#modify-creator
1180+
1181+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1182+ print (f"## ESDTModifyCreator, sender={ sender } , relayer={ relayer } " )
1183+
1184+ transaction = controller .token_management_transactions_factory .create_transaction_for_modifying_creator (
1185+ sender = named_addresses [sender ],
1186+ token_identifier = non_fungible_token ,
1187+ token_nonce = 0x64
1188+ )
1189+
1190+ # Gas limit set by default(by the SDKs) seems a bit too much
1191+ transaction .gas_limit = 3_000_000
1192+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1193+ controller .send (transaction , await_processing_started = True )
1194+
1195+ # ESDTMetaDataUpdate
1196+ # https://docs.multiversx.com/tokens/nft-tokens/#metadata-update
1197+
1198+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1199+ print (f"## ESDTMetaDataUpdate, sender={ sender } , relayer={ relayer } " )
1200+
1201+ transaction = controller .token_management_transactions_factory .create_transaction_for_updating_metadata (
1202+ sender = named_addresses [sender ],
1203+ token_identifier = non_fungible_token ,
1204+ token_nonce = 0x64 ,
1205+ new_token_name = "new-name" ,
1206+ new_royalties = random .randint (1000 , 10_000 ),
1207+ new_hash = "abba" ,
1208+ new_attributes = b"new-attributes" ,
1209+ new_uris = ["x" , "y" ]
1210+ )
1211+
1212+ # Gas limit set by default(by the SDKs) seems a bit too much
1213+ transaction .gas_limit = 3_000_000
1214+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1215+ controller .send (transaction , await_processing_started = True )
1216+
1217+ # ESDTMetaDataRecreate
1218+ # https://docs.multiversx.com/tokens/nft-tokens/#metadata-recreate
1219+
1220+ for (sender , relayer ) in [("sponsor" , "a" ), ("sponsor" , "sponsor" )]:
1221+ print (f"## ESDTMetaDataRecreate, sender={ sender } , relayer={ relayer } " )
1222+
1223+ transaction = controller .token_management_transactions_factory .create_transaction_for_nft_metadata_recreate (
1224+ sender = named_addresses [sender ],
1225+ token_identifier = non_fungible_token ,
1226+ token_nonce = 0x64 ,
1227+ new_token_name = "new-name" ,
1228+ new_royalties = random .randint (1000 , 10_000 ),
1229+ new_hash = "abba" ,
1230+ new_attributes = b"new-attributes" ,
1231+ new_uris = ["x" , "y" ]
1232+ )
1233+
1234+ # Gas limit set by default(by the SDKs) seems a bit too much
1235+ transaction .gas_limit = 3_000_000
1236+ controller .relay_arbitrary_transaction (transaction , relayer = named_accounts [relayer ], apply_nonce = True )
1237+ controller .send (transaction , await_processing_started = True )
10761238
10771239 # MultiESDTNFTTransfer
1078- # TODO
1240+
1241+ for (sender , receiver , relayer ) in [
1242+ # Send, then receive back.
1243+ ("a" , "b" , "c" ), ("b" , "a" , "c" ),
1244+ # Send, then receive back.
1245+ ("a" , "m" , "c" ), ("m" , "a" , "n" ),
1246+ # Send, then receive back (varying relaying patterns).
1247+ ("a" , "b" , "a" ), ("b" , "a" , "a" ),
1248+ ]:
1249+ print (f"## MultiESDTNFTTransfer, sender={ sender } , receiver={ receiver } , relayer={ relayer } " )
1250+
1251+ controller .send (controller .create_transfer (
1252+ sender = named_accounts [sender ],
1253+ receiver = named_addresses [receiver ],
1254+ native_amount = 3 ,
1255+ custom_transfers = [(non_fungible_token , 1 , 1 ), (semi_fungible_token , 1 , 42 )],
1256+ relayer = named_accounts [relayer ],
1257+ ), await_completion = True )
10791258
10801259 # MigrateDataTrie
10811260
@@ -1105,12 +1284,6 @@ def do_run_relayed_builtin_functions(memento: "Memento", accounts: "BunchOfAccou
11051284 relayer = named_accounts [relayer ],
11061285 ), await_processing_started = True )
11071286
1108- # UnGuardAccount
1109- # TODO
1110-
1111- # GuardAccount
1112- # TODO
1113-
11141287
11151288class BunchOfAccounts :
11161289 def __init__ (self , configuration : Configuration , memento : "Memento" ) -> None :
@@ -1429,6 +1602,95 @@ def do_airdrops_for_non_fungible_tokens(self):
14291602 print ("Wait for the last transaction to be processed (optimization)..." )
14301603 self .await_processing_started (transactions [- 1 :])
14311604
1605+ def issue_semi_fungible_token (self , name : str ):
1606+ transaction = self .token_management_transactions_factory .create_transaction_for_issuing_semi_fungible (
1607+ sender = self .accounts .sponsor .address ,
1608+ token_name = name ,
1609+ token_ticker = name ,
1610+ can_freeze = True ,
1611+ can_wipe = True ,
1612+ can_pause = True ,
1613+ can_change_owner = True ,
1614+ can_upgrade = True ,
1615+ can_add_special_roles = True ,
1616+ can_transfer_nft_create_role = True
1617+ )
1618+
1619+ self .apply_nonce (transaction )
1620+ self .sign (transaction )
1621+ self .send (transaction )
1622+
1623+ [transaction_on_network ] = self .await_completed ([transaction ])
1624+ [issue_outcome ] = self .token_management_outcome_parser .parse_issue_semi_fungible (transaction_on_network )
1625+ token_identifier = issue_outcome .token_identifier
1626+
1627+ print (f"Semi-fungible token identifier: { token_identifier } " )
1628+
1629+ self .memento .add_semi_fungible_token (token_identifier )
1630+
1631+ # Set some roles:
1632+ transaction = self .token_management_transactions_factory .create_transaction_for_setting_special_role_on_semi_fungible_token (
1633+ sender = self .accounts .sponsor .address ,
1634+ user = self .accounts .sponsor .address ,
1635+ token_identifier = token_identifier ,
1636+ add_role_nft_create = True ,
1637+ add_role_nft_burn = True ,
1638+ add_role_nft_add_quantity = True ,
1639+ )
1640+
1641+ self .apply_nonce (transaction )
1642+ self .sign (transaction )
1643+ self .send (transaction )
1644+
1645+ [transaction_on_network ] = self .await_completed ([transaction ])
1646+ [outcome ] = self .token_management_outcome_parser .parse_set_special_role (transaction_on_network )
1647+ print ("Roles set:" , outcome .roles )
1648+
1649+ # Now create a few tokens:
1650+ create_transactions : List [Transaction ] = []
1651+
1652+ for i in range (100 ):
1653+ transaction = self .token_management_transactions_factory .create_transaction_for_creating_nft (
1654+ sender = self .accounts .sponsor .address ,
1655+ token_identifier = token_identifier ,
1656+ initial_quantity = 100_000 ,
1657+ name = f"{ name } #{ i } " ,
1658+ royalties = 1000 ,
1659+ hash = "abba" ,
1660+ attributes = bytes .fromhex ("abba" ),
1661+ uris = ["a" , "b" , "c" ]
1662+ )
1663+
1664+ self .apply_nonce (transaction )
1665+ self .sign (transaction )
1666+ create_transactions .append (transaction )
1667+
1668+ self .send_multiple (create_transactions , chunk_size = 99 , wait_between_chunks = 7 )
1669+
1670+ print ("Wait for the last transaction to be completed (optimization)..." )
1671+ self .await_completed (create_transactions [- 1 :])
1672+
1673+ def do_airdrops_for_semi_fungible_tokens (self ):
1674+ identifiers = self .memento .get_semi_fungible_tokens ()
1675+ transactions : List [Transaction ] = []
1676+
1677+ for index , user in enumerate (self .accounts .users ):
1678+ for identifier in identifiers :
1679+ transaction = self .transfer_transactions_factory .create_transaction_for_transfer (
1680+ sender = self .accounts .sponsor .address ,
1681+ receiver = user .address ,
1682+ token_transfers = [TokenTransfer (Token (identifier , index + 1 ), 100 )]
1683+ )
1684+
1685+ self .apply_nonce (transaction )
1686+ self .sign (transaction )
1687+ transactions .append (transaction )
1688+
1689+ self .send_multiple (transactions , chunk_size = 99 , wait_between_chunks = 7 )
1690+
1691+ print ("Wait for the last transaction to be processed (optimization)..." )
1692+ self .await_processing_started (transactions [- 1 :])
1693+
14321694 def do_create_contract_deployments (self ):
14331695 transactions_adder : List [Transaction ] = []
14341696 transactions_dummy : List [Transaction ] = []
@@ -2001,6 +2263,7 @@ def __init__(self, path: Path) -> None:
20012263 self ._contracts : List [SmartContract ] = []
20022264 self ._custom_currencies : List [str ] = []
20032265 self ._non_fungible_tokens : List [str ] = []
2266+ self ._semi_fungible_tokens : List [str ] = []
20042267 self ._run_transactions : List [str ] = []
20052268
20062269 def clear (self ):
@@ -2018,6 +2281,11 @@ def add_non_fungible_token(self, identifier: str):
20182281 self ._non_fungible_tokens .append (identifier )
20192282 self .save ()
20202283
2284+ def add_semi_fungible_token (self , identifier : str ):
2285+ self .load ()
2286+ self ._semi_fungible_tokens .append (identifier )
2287+ self .save ()
2288+
20212289 def get_custom_currencies (self ) -> list [str ]:
20222290 self .load ()
20232291 return self ._custom_currencies
@@ -2026,6 +2294,10 @@ def get_non_fungible_tokens(self) -> list[str]:
20262294 self .load ()
20272295 return self ._non_fungible_tokens
20282296
2297+ def get_semi_fungible_tokens (self ) -> list [str ]:
2298+ self .load ()
2299+ return self ._semi_fungible_tokens
2300+
20292301 def add_contract (self , tag : str , address : str ):
20302302 self .load ()
20312303 self ._contracts .append (SmartContract (tag , address ))
@@ -2056,6 +2328,7 @@ def load(self):
20562328 self ._contracts = [SmartContract .from_dictionary (item ) for item in contracts_raw ]
20572329 self ._custom_currencies = data .get ("customCurrencies" , [])
20582330 self ._non_fungible_tokens = data .get ("nonFungibleTokens" , [])
2331+ self ._semi_fungible_tokens = data .get ("semiFungibleTokens" , [])
20592332 self ._run_transactions = data .get ("runTransactions" , [])
20602333
20612334 def save (self ):
@@ -2065,6 +2338,7 @@ def save(self):
20652338 "contracts" : contracts_raw ,
20662339 "customCurrencies" : self ._custom_currencies ,
20672340 "nonFungibleTokens" : self ._non_fungible_tokens ,
2341+ "semiFungibleTokens" : self ._semi_fungible_tokens ,
20682342 "runTransactions" : self ._run_transactions ,
20692343 }
20702344
0 commit comments