importjsonimportosimporttimeimporturllib.requestfromsymbolchain.CryptoTypesimportPrivateKeyfromsymbolchain.facade.NemFacadeimportNemFacadefromsymbolchain.ncimportAmountfromsymbolchain.nem.FeeCalculatorimport(calculate_mosaic_rental_fee,calculate_transaction_fee)NODE_URL=os.getenv('NODE_URL','http://libertalia.nemtest.net:7890')print(f'Using node {NODE_URL}')# Helper function to announce a transactiondefannounce_transaction(payload,label):announce_path='/transaction/announce'print(f'Announcing {label} to {announce_path}')request=urllib.request.Request(f'{NODE_URL}{announce_path}',data=payload.encode(),headers={'Content-Type':'application/json'},method='POST')withurllib.request.urlopen(request)asannounce_response:result=json.loads(announce_response.read().decode())print(f' Result: {result["message"]}')returnresult['message']# Helper function to wait for transaction confirmationdefwait_for_confirmation(tx_hash,label):status_path=f'/transaction/get?hash={tx_hash}'print(f'Waiting for {label} confirmation from {status_path}')is_confirmed=Falsefor_inrange(120):try:withurllib.request.urlopen(f'{NODE_URL}{status_path}')asstatus_response:confirmed=json.loads(status_response.read().decode())height=confirmed['meta']['height']print(f'{label} confirmed in block {height}')is_confirmed=Truebreakexcepturllib.error.HTTPError:print(' Transaction status: pending')time.sleep(1)ifnotis_confirmed:print(f'{label} confirmation took too long.')SIGNER_PRIVATE_KEY=os.getenv('SIGNER_PRIVATE_KEY','0000000000000000000000000000000000000000000000000000000000000000')signer_key_pair=NemFacade.KeyPair(PrivateKey(SIGNER_PRIVATE_KEY))facade=NemFacade('testnet')signer_address=facade.network.public_key_to_address(signer_key_pair.public_key)print(f'Signer address: {signer_address}')try:# Build the mosaic IDnamespace_name=os.getenv('NAMESPACE','my_namespace')mosaic_name=os.getenv('MOSAIC',f'token_{int(time.time())}')mosaic_id=f'{namespace_name}:{mosaic_name}'print(f'Creating mosaic: {mosaic_id}')# Define the mosaicmosaic_definition={'owner_public_key':signer_key_pair.public_key,'id':{'namespace_id':{'name':namespace_name},'name':mosaic_name},'description':'My tutorial mosaic','properties':[{'property_':{'name':b'divisibility','value':b'2'}},{'property_':{'name':b'initialSupply','value':b'1000'}},{'property_':{'name':b'supplyMutable','value':b'true'}},{'property_':{'name':b'transferable','value':b'true'}}]}# Build the mosaic definition transactionrental_fee=calculate_mosaic_rental_fee()print(f' Mosaic creation fee: {rental_fee/1_000_000} XEM')transaction=facade.create_transaction_from_descriptor({'type':'mosaic_definition_transaction_v1','rental_fee_sink':'TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC','rental_fee':rental_fee,'mosaic_definition':mosaic_definition},signer_key_pair.public_key,0,2*60*60)# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction)transaction.fee=Amount(fee)print(f' Transaction fee: {fee/1_000_000} XEM')# Sign and generate final payloadsignature=facade.sign_transaction(signer_key_pair,transaction)json_payload=facade.transaction_factory.attach_signature(transaction,signature)print('Built mosaic definition transaction:')print(json.dumps(transaction.to_json(),indent=2))# Announce the transactionannounce_result=announce_transaction(json_payload,'mosaic definition')# Wait for confirmationif'SUCCESS'==announce_result:transaction_hash=facade.hash_transaction(transaction)print(f'Transaction hash: {transaction_hash}')wait_for_confirmation(transaction_hash,'mosaic definition')else:print(f'Transaction rejected: {announce_result}')# Retrieve the mosaicdefinition_path=f'/mosaic/definition?mosaicId={mosaic_id}'print(f'Fetching mosaic information from {definition_path}')withurllib.request.urlopen(f'{NODE_URL}{definition_path}')asresponse:mosaic_info=json.loads(response.read().decode())properties={prop['name']:prop['value']forpropinmosaic_info['properties']}print('Mosaic information:')print(f' Creator: {mosaic_info["creator"]}')print(f' Divisibility: {properties["divisibility"]}')print(f' Initial supply: {properties["initialSupply"]}')print(f' Supply mutable: {properties["supplyMutable"]}')print(f' Transferable: {properties["transferable"]}')exceptExceptionaserror:print(error)
import{PrivateKey}from'symbol-sdk';import{Address,NemFacade,calculateMosaicRentalFee,calculateTransactionFee,descriptors,models}from'symbol-sdk/nem';constNODE_URL=process.env.NODE_URL||'http://libertalia.nemtest.net:7890';console.log('Using node',NODE_URL);// Helper function to announce a transactionasyncfunctionannounceTransaction(payload,label){constannouncePath='/transaction/announce';console.log(`Announcing ${label} to ${announcePath}`);constresponse=awaitfetch(`${NODE_URL}${announcePath}`,{method:'POST',headers:{'Content-Type':'application/json'},body:payload});if(!response.ok)thrownewError(`HTTP ${response.status}`);constresult=awaitresponse.json();console.log(' Result:',result.message);returnresult.message;}// Helper function to wait for transaction confirmationasyncfunctionwaitForConfirmation(transactionHash,label){conststatusPath=`/transaction/get?hash=${transactionHash}`;console.log(`Waiting for ${label} confirmation from`,statusPath);letisConfirmed=false;for(letattempt=1;120>=attempt;++attempt){constresponse=awaitfetch(`${NODE_URL}${statusPath}`);if(!response.ok){console.log(' Transaction status: pending');awaitnewPromise(resolve=>{setTimeout(resolve,1000);});}else{constconfirmed=awaitresponse.json();console.log(`${label} confirmed in block`,confirmed.meta.height);isConfirmed=true;break;}}if(!isConfirmed)console.warn(`${label} confirmation took too long.`);}constSIGNER_PRIVATE_KEY=process.env.SIGNER_PRIVATE_KEY||'0000000000000000000000000000000000000000000000000000000000000000';constsignerKeyPair=newNemFacade.KeyPair(newPrivateKey(SIGNER_PRIVATE_KEY));constfacade=newNemFacade('testnet');constsignerAddress=facade.network.publicKeyToAddress(signerKeyPair.publicKey);console.log('Signer address:',signerAddress.toString());try{// Build the mosaic IDconstnamespaceName=process.env.NAMESPACE||'my_namespace';constmosaicName=process.env.MOSAIC||`token_${Math.floor(Date.now()/1000)}`;constmosaicId=`${namespaceName}:${mosaicName}`;console.log('Creating mosaic:',mosaicId);// Define the mosaicconstmosaicDefinition=newdescriptors.MosaicDefinitionDescriptor(signerKeyPair.publicKey,newdescriptors.MosaicIdDescriptor(newdescriptors.NamespaceIdDescriptor(namespaceName),mosaicName),'My tutorial mosaic',[['divisibility','2'],['initialSupply','1000'],['supplyMutable','true'],['transferable','true']].map(([name,value])=>newdescriptors.SizePrefixedMosaicPropertyDescriptor(newdescriptors.MosaicPropertyDescriptor(name,value))));// Build the mosaic definition transactionconstrentalFee=calculateMosaicRentalFee();console.log(' Mosaic creation fee:',`${Number(rentalFee)/1_000_000} XEM`);consttransaction=facade.createTransactionFromTypedDescriptor(newdescriptors.MosaicDefinitionTransactionV1Descriptor(mosaicDefinition,newAddress('TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC'),newmodels.Amount(rentalFee)),signerKeyPair.publicKey,0n,2*60*60);// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(' Transaction fee:',`${Number(fee)/1_000_000} XEM`);// Sign and generate final payloadconstsignature=facade.signTransaction(signerKeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built mosaic definition transaction:');console.dir(transaction.toJson(),{colors:true});// Announce the transactionconstannounceResult=awaitannounceTransaction(jsonPayload,'mosaic definition');// Wait for confirmationif('SUCCESS'===announceResult){consttransactionHash=facade.hashTransaction(transaction).toString();console.log('Transaction hash:',transactionHash);awaitwaitForConfirmation(transactionHash,'mosaic definition');}else{console.log('Transaction rejected:',announceResult);}// Retrieve the mosaicconstdefinitionPath=`/mosaic/definition?mosaicId=${mosaicId}`;console.log('Fetching mosaic information from',definitionPath);constdefinitionResponse=awaitfetch(`${NODE_URL}${definitionPath}`);constmosaicInfo=awaitdefinitionResponse.json();constproperties=Object.fromEntries(mosaicInfo.properties.map(prop=>[prop.name,prop.value]));console.log('Mosaic information:');console.log(' Creator:',mosaicInfo.creator);console.log(' Divisibility:',properties.divisibility);console.log(' Initial supply:',properties.initialSupply);console.log(' Supply mutable:',properties.supplyMutable);console.log(' Transferable:',properties.transferable);}catch(e){console.error(e.message,'| Cause:',e.cause?.code??'unknown');}
// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(' Transaction fee:',`${Number(fee)/1_000_000} XEM`);
# Sign and generate final payloadsignature=facade.sign_transaction(signer_key_pair,transaction)json_payload=facade.transaction_factory.attach_signature(transaction,signature)print('Built mosaic definition transaction:')print(json.dumps(transaction.to_json(),indent=2))# Announce the transactionannounce_result=announce_transaction(json_payload,'mosaic definition')
// Sign and generate final payloadconstsignature=facade.signTransaction(signerKeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built mosaic definition transaction:');console.dir(transaction.toJson(),{colors:true});// Announce the transactionconstannounceResult=awaitannounceTransaction(jsonPayload,'mosaic definition');
// Sign and generate final payloadfinalCryptoTypes.Signaturesignature=facade.signTransaction(signerKeyPair,transaction);finalStringpayload=NemTransactionFactory.attachSignature(transaction,signature);System.out.println("Built mosaic definition transaction:");System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(transaction.toJson()));// Announce the transactionfinalStringresult=announceTransaction(payload,"mosaic definition");
// Retrieve the mosaicfinalStringpath="/mosaic/definition?mosaicId="+mosaicId;System.out.printf("Fetching mosaic information from %s%n",path);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(nodeUrl+path)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());finalJsonNodeinfo=JSON_MAPPER.readTree(response.body());System.out.println("Mosaic information:");System.out.printf(" Creator: %s%n",info.get("creator").asText());for(finalJsonNodeitem:info.get("properties"))System.out.printf(" %s: %s%n",item.get("name").asText(),item.get("value").asText());