importjsonimportosimporttimeimporturllib.requestfromsymbolchain.CryptoTypesimportPrivateKeyfromsymbolchain.facade.NemFacadeimportNemFacadefromsymbolchain.ncimportAmountfromsymbolchain.nem.FeeCalculatorimport(calculate_mosaic_rental_fee,calculate_transaction_fee)fromsymbolchain.nem.NetworkimportNetworkTimestampNODE_URL=os.getenv('NODE_URL','http://libertalia.nemtest.net:7890')print(f'Using node {NODE_URL}')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}')namespace_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}')try:# Fetch current network timetime_path='/time-sync/network-time'print(f'Fetching current network time from {time_path}')withurllib.request.urlopen(f'{NODE_URL}{time_path}')asresponse:response_json=json.loads(response.read().decode())network_time=response_json['receiveTimeStamp']//1000print(f' Network time: {network_time} s since the nemesis block')# Derived fields from network timetimestamp=NetworkTimestamp(network_time)deadline=timestamp.add_hours(2)# Describe the levyLEVY_RECIPIENT=os.getenv('LEVY_RECIPIENT','TBULEAUG2CZQISUR442HWA6UAKGWIXHDABJVIPS4')levy={'transfer_fee_type':'absolute','recipient_address':LEVY_RECIPIENT,'mosaic_id':{'namespace_id':{'name':'nem'},'name':'xem'},'fee':1_000_000}levy_mosaic_id=levy['mosaic_id']print('Levy:')print(f' Type: {levy["transfer_fee_type"]}')print(f' Recipient: {levy["recipient_address"]}')print(f' Mosaic: {levy_mosaic_id["namespace_id"]["name"]}:'f'{levy_mosaic_id["name"]}')print(f' Fee: {levy["fee"]}')# Build the mosaic definition transactionrental_fee=calculate_mosaic_rental_fee()print(f' Mosaic creation fee: {rental_fee/1_000_000} XEM')transaction=facade.transaction_factory.create({'type':'mosaic_definition_transaction_v1','signer_public_key':signer_key_pair.public_key,'timestamp':timestamp.timestamp,'deadline':deadline.timestamp,'rental_fee_sink':'TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC','rental_fee':rental_fee,'mosaic_definition':{'owner_public_key':signer_key_pair.public_key,'id':{'namespace_id':{'name':namespace_name},'name':mosaic_name},'description':'My tutorial mosaic with a levy','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'}}],'levy':levy}})# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction)transaction.fee=Amount(fee)print(f' Transaction fee: {fee/1_000_000} XEM')# Sign, announce and wait for confirmationsignature=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_path='/transaction/announce'print(f'Announcing mosaic definition to {announce_path}')announce_request=urllib.request.Request(f'{NODE_URL}{announce_path}',data=json_payload.encode(),headers={'Content-Type':'application/json'},method='POST')withurllib.request.urlopen(announce_request)asresponse:announce_result=json.loads(response.read().decode())print(f' Result: {announce_result["message"]}')if'SUCCESS'==announce_result['message']:transaction_hash=facade.hash_transaction(transaction)status_path=f'/transaction/get?hash={transaction_hash}'print(f'Waiting for confirmation from {status_path}')is_confirmed=Falseforattemptinrange(120):try:withurllib.request.urlopen(f'{NODE_URL}{status_path}')asresponse:confirmed=json.loads(response.read().decode())height=confirmed['meta']['height']print(f'Transaction confirmed in block {height}')is_confirmed=Truebreakexcepturllib.error.HTTPError:print(' Transaction status: pending')time.sleep(1)ifnotis_confirmed:print('Confirmation took too long.')else:print(f'Transaction rejected: {announce_result["message"]}')# Retrieve the levydefinition_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())levy_info=mosaic_info['levy']levy_mosaic_id=levy_info['mosaicId']levy_type='absolute'if1==levy_info['type']else'percentile'print('Levy information:')print(f' Type: {levy_type}')print(f' Recipient: {levy_info["recipient"]}')print(f' Mosaic: 'f'{levy_mosaic_id["namespaceId"]}:{levy_mosaic_id["name"]}')print(f' Fee: {levy_info["fee"]}')excepturllib.error.URLErrorase:print(e.reason)
import{PrivateKey}from'symbol-sdk';import{NemFacade,NetworkTimestamp,calculateMosaicRentalFee,calculateTransactionFee,models}from'symbol-sdk/nem';constNODE_URL=process.env.NODE_URL||'http://libertalia.nemtest.net:7890';console.log('Using node',NODE_URL);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());constnamespaceName=process.env.NAMESPACE||'my_namespace';constmosaicName=process.env.MOSAIC||`token_${Math.floor(Date.now()/1000)}`;constmosaicId=`${namespaceName}:${mosaicName}`;console.log('Creating mosaic:',mosaicId);try{// Fetch current network timeconsttimePath='/time-sync/network-time';console.log('Fetching current network time from',timePath);consttimeResponse=awaitfetch(`${NODE_URL}${timePath}`);consttimeJSON=awaittimeResponse.json();constnetworkTime=Math.floor(timeJSON.receiveTimeStamp/1000);console.log(' Network time:',networkTime,'s since the nemesis block');// Derived fields from network timeconsttimestamp=newNetworkTimestamp(networkTime);constdeadline=timestamp.addHours(2);// Describe the levyconstLEVY_RECIPIENT=process.env.LEVY_RECIPIENT||'TBULEAUG2CZQISUR442HWA6UAKGWIXHDABJVIPS4';constlevy={transferFeeType:'absolute',recipientAddress:LEVY_RECIPIENT,mosaicId:{namespaceId:{name:'nem'},name:'xem'},fee:1_000_000};console.log('Levy:');console.log(' Type:',levy.transferFeeType);console.log(' Recipient:',levy.recipientAddress);console.log(' Mosaic:',`${levy.mosaicId.namespaceId.name}:${levy.mosaicId.name}`);console.log(' Fee:',levy.fee);// Build the mosaic definition transactionconstrentalFee=calculateMosaicRentalFee();console.log(' Mosaic creation fee:',`${Number(rentalFee)/1_000_000} XEM`);consttransaction=facade.transactionFactory.create({type:'mosaic_definition_transaction_v1',signerPublicKey:signerKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,rentalFeeSink:'TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC',rentalFee,mosaicDefinition:{ownerPublicKey:signerKeyPair.publicKey.toString(),id:{namespaceId:{name:namespaceName},name:mosaicName},description:'My tutorial mosaic with a levy',properties:[{property:{name:'divisibility',value:'2'}},{property:{name:'initialSupply',value:'1000'}},{property:{name:'supplyMutable',value:'true'}},{property:{name:'transferable',value:'true'}}],levy}});// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(' Transaction fee:',`${Number(fee)/1_000_000} XEM`);// Sign, announce and wait for confirmationconstsignature=facade.signTransaction(signerKeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built mosaic definition transaction:');console.dir(transaction.toJson(),{colors:true});constannouncePath='/transaction/announce';console.log('Announcing mosaic definition to',announcePath);constannounceResponse=awaitfetch(`${NODE_URL}${announcePath}`,{method:'POST',headers:{'Content-Type':'application/json'},body:jsonPayload});constannounceResult=awaitannounceResponse.json();console.log(' Result:',announceResult.message);if('SUCCESS'===announceResult.message){consttransactionHash=facade.hashTransaction(transaction).toString();conststatusPath=`/transaction/get?hash=${transactionHash}`;console.log('Waiting for confirmation from',statusPath);letisConfirmed=false;for(letattempt=1;120>=attempt;++attempt){constresponse=awaitfetch(`${NODE_URL}${statusPath}`);if(response.ok){constconfirmed=awaitresponse.json();console.log('Transaction confirmed in block',confirmed.meta.height);isConfirmed=true;break;}console.log(' Transaction status: pending');awaitnewPromise(resolve=>{setTimeout(resolve,1000);});}if(!isConfirmed)console.warn('Confirmation took too long.');}else{console.log('Transaction rejected:',announceResult.message);}// Retrieve the levyconstdefinitionPath=`/mosaic/definition?mosaicId=${mosaicId}`;console.log('Fetching mosaic information from',definitionPath);constdefinitionResponse=awaitfetch(`${NODE_URL}${definitionPath}`);constmosaicInfo=awaitdefinitionResponse.json();constlevyInfo=mosaicInfo.levy;constlevyMosaicId=levyInfo.mosaicId;constlevyType=1===levyInfo.type?'absolute':'percentile';console.log('Levy information:');console.log(' Type:',levyType);console.log(' Recipient:',levyInfo.recipient);console.log(' Mosaic:',`${levyMosaicId.namespaceId}:${levyMosaicId.name}`);console.log(' Fee:',levyInfo.fee);}catch(e){console.error(e.message,'| Cause:',e.cause?.code??'unknown');}
# Fetch current network timetime_path='/time-sync/network-time'print(f'Fetching current network time from {time_path}')withurllib.request.urlopen(f'{NODE_URL}{time_path}')asresponse:response_json=json.loads(response.read().decode())network_time=response_json['receiveTimeStamp']//1000print(f' Network time: {network_time} s since the nemesis block')# Derived fields from network timetimestamp=NetworkTimestamp(network_time)deadline=timestamp.add_hours(2)
// Fetch current network timeconsttimePath='/time-sync/network-time';console.log('Fetching current network time from',timePath);consttimeResponse=awaitfetch(`${NODE_URL}${timePath}`);consttimeJSON=awaittimeResponse.json();constnetworkTime=Math.floor(timeJSON.receiveTimeStamp/1000);console.log(' Network time:',networkTime,'s since the nemesis block');// Derived fields from network timeconsttimestamp=newNetworkTimestamp(networkTime);constdeadline=timestamp.addHours(2);
// Build the mosaic definition transactionconstrentalFee=calculateMosaicRentalFee();console.log(' Mosaic creation fee:',`${Number(rentalFee)/1_000_000} XEM`);consttransaction=facade.transactionFactory.create({type:'mosaic_definition_transaction_v1',signerPublicKey:signerKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,rentalFeeSink:'TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC',rentalFee,mosaicDefinition:{ownerPublicKey:signerKeyPair.publicKey.toString(),id:{namespaceId:{name:namespaceName},name:mosaicName},description:'My tutorial mosaic with a levy',properties:[{property:{name:'divisibility',value:'2'}},{property:{name:'initialSupply',value:'1000'}},{property:{name:'supplyMutable',value:'true'}},{property:{name:'transferable',value:'true'}}],levy}});// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(' Transaction fee:',`${Number(fee)/1_000_000} XEM`);
# Sign, announce and wait for confirmationsignature=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_path='/transaction/announce'print(f'Announcing mosaic definition to {announce_path}')announce_request=urllib.request.Request(f'{NODE_URL}{announce_path}',data=json_payload.encode(),headers={'Content-Type':'application/json'},method='POST')withurllib.request.urlopen(announce_request)asresponse:announce_result=json.loads(response.read().decode())print(f' Result: {announce_result["message"]}')if'SUCCESS'==announce_result['message']:transaction_hash=facade.hash_transaction(transaction)status_path=f'/transaction/get?hash={transaction_hash}'print(f'Waiting for confirmation from {status_path}')is_confirmed=Falseforattemptinrange(120):try:withurllib.request.urlopen(f'{NODE_URL}{status_path}')asresponse:confirmed=json.loads(response.read().decode())height=confirmed['meta']['height']print(f'Transaction confirmed in block {height}')is_confirmed=Truebreakexcepturllib.error.HTTPError:print(' Transaction status: pending')time.sleep(1)ifnotis_confirmed:print('Confirmation took too long.')else:print(f'Transaction rejected: {announce_result["message"]}')
// Sign, announce and wait for confirmationconstsignature=facade.signTransaction(signerKeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built mosaic definition transaction:');console.dir(transaction.toJson(),{colors:true});constannouncePath='/transaction/announce';console.log('Announcing mosaic definition to',announcePath);constannounceResponse=awaitfetch(`${NODE_URL}${announcePath}`,{method:'POST',headers:{'Content-Type':'application/json'},body:jsonPayload});constannounceResult=awaitannounceResponse.json();console.log(' Result:',announceResult.message);if('SUCCESS'===announceResult.message){consttransactionHash=facade.hashTransaction(transaction).toString();conststatusPath=`/transaction/get?hash=${transactionHash}`;console.log('Waiting for confirmation from',statusPath);letisConfirmed=false;for(letattempt=1;120>=attempt;++attempt){constresponse=awaitfetch(`${NODE_URL}${statusPath}`);if(response.ok){constconfirmed=awaitresponse.json();console.log('Transaction confirmed in block',confirmed.meta.height);isConfirmed=true;break;}console.log(' Transaction status: pending');awaitnewPromise(resolve=>{setTimeout(resolve,1000);});}if(!isConfirmed)console.warn('Confirmation took too long.');}else{console.log('Transaction rejected:',announceResult.message);}