importjsonimportosimporttimeimporturllib.requestfromsymbolchain.CryptoTypesimportPrivateKeyfromsymbolchain.facade.NemFacadeimportNemFacadefromsymbolchain.ncimportAmountfromsymbolchain.nem.FeeCalculatorimportcalculate_transaction_feefromsymbolchain.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))RECIPIENT_ADDRESS=os.getenv('RECIPIENT_ADDRESS','TBULEAUG2CZQISUR442HWA6UAKGWIXHDABJVIPS4')MOSAIC_ID=os.getenv('MOSAIC_ID','company:token')MOSAIC_NAMESPACE,MOSAIC_NAME=MOSAIC_ID.split(':')QUANTITY=int(os.getenv('QUANTITY','100'))print(f'Sending mosaic {MOSAIC_ID}')print(f' Amount: {QUANTITY} units')facade=NemFacade('testnet')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)# Fetch the mosaic's divisibility and supplydefinition_path=f'/mosaic/definition?mosaicId={MOSAIC_ID}'print(f'Fetching mosaic definition from {definition_path}')withurllib.request.urlopen(f'{NODE_URL}{definition_path}')asresponse:definition=json.loads(response.read().decode())properties={prop['name']:prop['value']forpropindefinition['properties']}divisibility=int(properties['divisibility'])supply_path=f'/mosaic/supply?mosaicId={MOSAIC_ID}'print(f'Fetching mosaic supply from {supply_path}')withurllib.request.urlopen(f'{NODE_URL}{supply_path}')asresponse:supply=json.loads(response.read().decode())['supply']print(f' {MOSAIC_ID}: divisibility {divisibility}, supply {supply}')# Build the transactionatomic_quantity=QUANTITY*(10**divisibility)multiplier=1scaled_multiplier=multiplier*1_000_000transaction=facade.transaction_factory.create({'type':'transfer_transaction_v2','signer_public_key':signer_key_pair.public_key,'timestamp':timestamp.timestamp,'deadline':deadline.timestamp,'recipient_address':RECIPIENT_ADDRESS,'amount':scaled_multiplier,'mosaics':[{'mosaic':{'mosaic_id':{'namespace_id':{'name':MOSAIC_NAMESPACE},'name':MOSAIC_NAME},'amount':atomic_quantity}}]})# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction,{MOSAIC_ID:{'supply':supply,'divisibility':divisibility}})transaction.fee=Amount(fee)print(f' Transaction fee: {fee/1_000_000} XEM')# Sign transaction and generate final payloadsignature=facade.sign_transaction(signer_key_pair,transaction)json_payload=facade.transaction_factory.attach_signature(transaction,signature)print('Built transaction:')print(json.dumps(transaction.to_json(),indent=2))# Announce the transactionannounce_path='/transaction/announce'print(f'Announcing transaction 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']}')# Wait for confirmationif'SUCCESS'==announce_result['message']:status_path=(f'/transaction/get?hash={facade.hash_transaction(transaction)}')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']}')excepturllib.error.URLErrorase:print(e.reason)
import{PrivateKey}from'symbol-sdk';import{NemFacade,NetworkTimestamp,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));constRECIPIENT_ADDRESS=process.env.RECIPIENT_ADDRESS||'TBULEAUG2CZQISUR442HWA6UAKGWIXHDABJVIPS4';constMOSAIC_ID=process.env.MOSAIC_ID||'company:token';const[MOSAIC_NAMESPACE,MOSAIC_NAME]=MOSAIC_ID.split(':');constQUANTITY=parseInt(process.env.QUANTITY||'100',10);console.log('Sending mosaic',MOSAIC_ID);console.log(` Amount: ${QUANTITY} units`);constfacade=newNemFacade('testnet');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);// Fetch the mosaic's divisibility and supplyconstdefinitionPath=`/mosaic/definition?mosaicId=${MOSAIC_ID}`;console.log('Fetching mosaic definition from',definitionPath);constdefinitionResponse=awaitfetch(`${NODE_URL}${definitionPath}`);constdefinition=awaitdefinitionResponse.json();constproperties=Object.fromEntries(definition.properties.map(property=>[property.name,property.value]));constdivisibility=parseInt(properties.divisibility,10);constsupplyPath=`/mosaic/supply?mosaicId=${MOSAIC_ID}`;console.log('Fetching mosaic supply from',supplyPath);constsupplyResponse=awaitfetch(`${NODE_URL}${supplyPath}`);const{supply}=awaitsupplyResponse.json();console.log(` ${MOSAIC_ID}: divisibility ${divisibility},`,`supply ${supply}`);// Build the transactionconstatomicQuantity=QUANTITY*(10**divisibility);constmultiplier=1;constscaledMultiplier=multiplier*1_000_000;consttransaction=facade.transactionFactory.create({type:'transfer_transaction_v2',signerPublicKey:signerKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,recipientAddress:RECIPIENT_ADDRESS,amount:BigInt(scaledMultiplier),mosaics:[{mosaic:{mosaicId:{namespaceId:{name:MOSAIC_NAMESPACE},name:MOSAIC_NAME},amount:BigInt(atomicQuantity)}}]});// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction,{[MOSAIC_ID]:{supply:BigInt(supply),divisibility}});transaction.fee=newmodels.Amount(fee);console.log(` Transaction fee: ${Number(fee)/1_000_000} XEM`);// Sign transaction and generate final payloadconstsignature=facade.signTransaction(signerKeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built transaction:');console.dir(transaction.toJson(),{colors:true,depth:null});// Announce the transactionconstannouncePath='/transaction/announce';console.log('Announcing transaction to',announcePath);constannounceResponse=awaitfetch(`${NODE_URL}${announcePath}`,{method:'POST',headers:{'Content-Type':'application/json'},body:jsonPayload});constannounceResult=awaitannounceResponse.json();console.log(' Result:',announceResult.message);// Wait for confirmationif('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);}}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);
NEM のすべてのトランザクションには、作成時点を示す timestamp と、ネットワークが承認を試み続ける期間を示す deadline が必要です。どちらも ネットワーク時刻 で表します。
# Fetch the mosaic's divisibility and supplydefinition_path=f'/mosaic/definition?mosaicId={MOSAIC_ID}'print(f'Fetching mosaic definition from {definition_path}')withurllib.request.urlopen(f'{NODE_URL}{definition_path}')asresponse:definition=json.loads(response.read().decode())properties={prop['name']:prop['value']forpropindefinition['properties']}divisibility=int(properties['divisibility'])supply_path=f'/mosaic/supply?mosaicId={MOSAIC_ID}'print(f'Fetching mosaic supply from {supply_path}')withurllib.request.urlopen(f'{NODE_URL}{supply_path}')asresponse:supply=json.loads(response.read().decode())['supply']print(f' {MOSAIC_ID}: divisibility {divisibility}, supply {supply}')
# Build the transactionatomic_quantity=QUANTITY*(10**divisibility)multiplier=1scaled_multiplier=multiplier*1_000_000transaction=facade.transaction_factory.create({'type':'transfer_transaction_v2','signer_public_key':signer_key_pair.public_key,'timestamp':timestamp.timestamp,'deadline':deadline.timestamp,'recipient_address':RECIPIENT_ADDRESS,'amount':scaled_multiplier,'mosaics':[{'mosaic':{'mosaic_id':{'namespace_id':{'name':MOSAIC_NAMESPACE},'name':MOSAIC_NAME},'amount':atomic_quantity}}]})
// Build the transactionconstatomicQuantity=QUANTITY*(10**divisibility);constmultiplier=1;constscaledMultiplier=multiplier*1_000_000;consttransaction=facade.transactionFactory.create({type:'transfer_transaction_v2',signerPublicKey:signerKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,recipientAddress:RECIPIENT_ADDRESS,amount:BigInt(scaledMultiplier),mosaics:[{mosaic:{mosaicId:{namespaceId:{name:MOSAIC_NAMESPACE},name:MOSAIC_NAME},amount:BigInt(atomicQuantity)}}]});