importjsonimportosimporttimeimporturllib.requestfromsymbolchain.CryptoTypesimportPrivateKey,PublicKeyfromsymbolchain.facade.NemFacadeimportNemFacadefromsymbolchain.ncimportAmountfromsymbolchain.nem.FeeCalculatorimportcalculate_transaction_feeNODE_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.')facade=NemFacade('testnet')MULTISIG_PUBLIC_KEY=os.getenv('MULTISIG_PUBLIC_KEY','D656155B48D4E71E4C59EC6FAEB5EB4F214DE8BC3C65D5BF6A3D9931B4E5ACF2')multisig_public_key=PublicKey(MULTISIG_PUBLIC_KEY)multisig_address=facade.network.public_key_to_address(multisig_public_key)print(f'Multisig public key: {multisig_public_key}')COSIGNATORY0_PRIVATE_KEY=os.getenv('COSIGNATORY0_PRIVATE_KEY','0000000000000000000000000000000000000000000000000000000000000002')cosignatory0_key_pair=NemFacade.KeyPair(PrivateKey(COSIGNATORY0_PRIVATE_KEY))print(f'Cosignatory 0 public key: {cosignatory0_key_pair.public_key}')COSIGNATORY1_PRIVATE_KEY=os.getenv('COSIGNATORY1_PRIVATE_KEY','0000000000000000000000000000000000000000000000000000000000000003')cosignatory1_key_pair=NemFacade.KeyPair(PrivateKey(COSIGNATORY1_PRIVATE_KEY))print(f'Cosignatory 1 public key: {cosignatory1_key_pair.public_key}')try:# Build the inner transfer transactiontransfer_transaction=facade.create_transaction_from_descriptor({'type':'transfer_transaction_v2','recipient_address':multisig_address,'amount':1_000_000# 1 XEM},multisig_public_key,0,2*60*60)transfer_transaction.fee=Amount(calculate_transaction_fee(transfer_transaction))# Build the wrapper multisig transactiontransaction=facade.create_transaction_from_descriptor({'type':'multisig_transaction_v1','inner_transaction':facade.transaction_factory.to_non_verifiable_transaction(transfer_transaction)},# This is the cosignatory that initiates the transfercosignatory0_key_pair.public_key,0,2*60*60)transaction.fee=Amount(calculate_transaction_fee(transaction))# Sign and announce the multisig transactionsignature=facade.sign_transaction(cosignatory0_key_pair,transaction)json_payload=facade.transaction_factory.attach_signature(transaction,signature)print('Built multisig transaction:')print(json.dumps(transaction.to_json(),indent=2))transaction_hash=facade.hash_transaction(transaction)print(f'Transaction hash: {transaction_hash}')announce_result=announce_transaction(json_payload,'multisig transaction')# The transaction is now waiting for the second signature# Retrieve the pending transaction from the networkif'SUCCESS'==announce_result:cosignatory1_address=facade.network.public_key_to_address(cosignatory1_key_pair.public_key)unconfirmed_path=('/account/unconfirmedTransactions'f'?address={cosignatory1_address}')print(f'Fetching pending transactions from {unconfirmed_path}')withurllib.request.urlopen(f'{NODE_URL}{unconfirmed_path}')asresponse:pending=json.loads(response.read().decode())['data']# Select the pending transaction issued by the multisig accountinner_transaction_hash=next(entry['meta']['data']forentryinpendingifentry['transaction'].get('otherTrans',{}).get('signer','').upper()==str(multisig_public_key))print(f' Inner transaction hash: {inner_transaction_hash}')# Build the cosignaturecosignature=facade.create_transaction_from_descriptor({'type':'cosignature_v1',# Hash of the inner transfer transaction'other_transaction_hash':inner_transaction_hash,# Address of the multisig account'multisig_account_address':multisig_address},# This is the cosignatory providing the second signaturecosignatory1_key_pair.public_key,0,2*60*60)cosignature.fee=Amount(calculate_transaction_fee(cosignature))# Sign and announce the cosignaturecosignature_signature=facade.sign_transaction(cosignatory1_key_pair,cosignature)cosignature_payload=facade.transaction_factory.attach_signature(cosignature,cosignature_signature)print('Built cosignature:')print(json.dumps(cosignature.to_json(),indent=2))cosignature_result=announce_transaction(cosignature_payload,'cosignature')# Wait for the multisig transaction to be confirmedif'SUCCESS'==cosignature_result:wait_for_confirmation(transaction_hash,'multisig transaction')else:print(f'Transaction rejected: {cosignature_result}')else:print(f'Transaction rejected: {announce_result}')exceptExceptionaserror:print(error)
import{Hash256,PrivateKey,PublicKey}from'symbol-sdk';import{Address,NemFacade,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.`);}constfacade=newNemFacade('testnet');constMULTISIG_PUBLIC_KEY=process.env.MULTISIG_PUBLIC_KEY||('D656155B48D4E71E4C59EC6FAEB5EB4F214DE8BC3C65D5BF6A3D9931B4E5ACF2');constmultisigPublicKey=newPublicKey(MULTISIG_PUBLIC_KEY);constmultisigAddress=facade.network.publicKeyToAddress(multisigPublicKey);console.log(`Multisig public key: ${multisigPublicKey}`);constCOSIGNATORY0_PRIVATE_KEY=process.env.COSIGNATORY0_PRIVATE_KEY||('0000000000000000000000000000000000000000000000000000000000000002');constcosignatory0KeyPair=newNemFacade.KeyPair(newPrivateKey(COSIGNATORY0_PRIVATE_KEY));console.log(`Cosignatory 0 public key: ${cosignatory0KeyPair.publicKey}`);constCOSIGNATORY1_PRIVATE_KEY=process.env.COSIGNATORY1_PRIVATE_KEY||('0000000000000000000000000000000000000000000000000000000000000003');constcosignatory1KeyPair=newNemFacade.KeyPair(newPrivateKey(COSIGNATORY1_PRIVATE_KEY));console.log(`Cosignatory 1 public key: ${cosignatory1KeyPair.publicKey}`);try{// Build the inner transfer transactionconsttransferTransaction=facade.createTransactionFromTypedDescriptor(newdescriptors.TransferTransactionV2Descriptor(newAddress(multisigAddress.toString()),newmodels.Amount(1_000_000n)),// 1 XEMmultisigPublicKey,0n,2*60*60);transferTransaction.fee=newmodels.Amount(calculateTransactionFee(transferTransaction));// Build the wrapper multisig transactionconsttransaction=facade.createTransactionFromTypedDescriptor(newdescriptors.MultisigTransactionV1Descriptor(facade.transactionFactory.static.toNonVerifiableTransaction(transferTransaction)),// This is the cosignatory that initiates the transfercosignatory0KeyPair.publicKey,0n,2*60*60);transaction.fee=newmodels.Amount(calculateTransactionFee(transaction));// Sign and announce the multisig transactionconstsignature=facade.signTransaction(cosignatory0KeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built multisig transaction:');console.log(JSON.stringify(transaction.toJson(),null,2));consttransactionHash=facade.hashTransaction(transaction).toString();console.log('Transaction hash:',transactionHash);constannounceResult=awaitannounceTransaction(jsonPayload,'multisig transaction');// The transaction is now waiting for the second signature// Retrieve the pending transaction from the networkif('SUCCESS'===announceResult){constcosignatory1Address=facade.network.publicKeyToAddress(cosignatory1KeyPair.publicKey);constunconfirmedPath='/account/unconfirmedTransactions'+`?address=${cosignatory1Address}`;console.log('Fetching pending transactions from',unconfirmedPath);constunconfirmedResponse=awaitfetch(`${NODE_URL}${unconfirmedPath}`);constpending=(awaitunconfirmedResponse.json()).data;// Select the pending transaction issued by the multisig accountconstpendingEntry=pending.find(entry=>multisigPublicKey.toString()===(entry.transaction.otherTrans?.signer??'').toUpperCase());constinnerTransactionHash=pendingEntry.meta.data;console.log(' Inner transaction hash:',innerTransactionHash);// Build the cosignatureconstcosignature=facade.createTransactionFromTypedDescriptor(newdescriptors.CosignatureV1Descriptor(// Hash of the inner transfer transactionnewHash256(innerTransactionHash),// Address of the multisig accountnewAddress(multisigAddress.toString())),// This is the cosignatory providing the second signaturecosignatory1KeyPair.publicKey,0n,2*60*60);cosignature.fee=newmodels.Amount(calculateTransactionFee(cosignature));// Sign and announce the cosignatureconstcosignatureSignature=facade.signTransaction(cosignatory1KeyPair,cosignature);constcosignaturePayload=facade.transactionFactory.static.attachSignature(cosignature,cosignatureSignature);console.log('Built cosignature:');console.log(JSON.stringify(cosignature.toJson(),null,2));constcosignatureResult=awaitannounceTransaction(cosignaturePayload,'cosignature');// Wait for the multisig transaction to be confirmedif('SUCCESS'===cosignatureResult){awaitwaitForConfirmation(transactionHash,'multisig transaction');}else{console.log('Transaction rejected:',cosignatureResult);}}else{console.log('Transaction rejected:',announceResult);}}catch(e){console.error(e.message,'| Cause:',e.cause?.code??'unknown');}
//JAVA 21+//DEPS org.symbol:symbol-sdk:3.3.3importjava.io.IOException;importjava.net.URI;importjava.net.http.HttpClient;importjava.net.http.HttpRequest;importjava.net.http.HttpResponse;importjava.net.http.HttpResponse.BodyHandlers;importjava.util.List;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.symbol.sdk.CryptoTypes;importorg.symbol.sdk.facade.NemFacade;importorg.symbol.sdk.nem.Address;importorg.symbol.sdk.nem.FeeCalculator;importorg.symbol.sdk.nem.KeyPair;importorg.symbol.sdk.nem.NemTransactionFactory;importorg.symbol.sdk.nem.descriptors.CosignatureV1Descriptor;importorg.symbol.sdk.nem.descriptors.MultisigTransactionV1Descriptor;importorg.symbol.sdk.nem.descriptors.TransferTransactionV2Descriptor;importorg.symbol.sdk.nem.models.Amount;importorg.symbol.sdk.nem.models.Transaction;publicfinalclassSignMultisig{privatestaticfinalObjectMapperJSON_MAPPER=newObjectMapper();privatestaticfinalHttpClientHTTP_CLIENT=HttpClient.newHttpClient();privatefinalStringnodeUrl=System.getenv().getOrDefault("NODE_URL","http://libertalia.nemtest.net:7890");privatefinalNemFacadefacade=newNemFacade("testnet");// Helper method to announce a transactionprivateStringannounceTransaction(finalStringpayload,finalStringlabel)throwsIOException,InterruptedException{finalStringannouncePath="/transaction/announce";System.out.printf("Announcing %s to %s%n",label,announcePath);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(nodeUrl+announcePath)).header("Content-Type","application/json").POST(HttpRequest.BodyPublishers.ofString(payload)).build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());if(2!=response.statusCode()/100)thrownewIOException("HTTP "+response.statusCode());finalStringresult=JSON_MAPPER.readTree(response.body()).get("message").asText();System.out.printf(" Result: %s%n",result);returnresult;}// Helper method to wait for transaction confirmationprivatevoidwaitForConfirmation(finalStringtransactionHash,finalStringlabel)throwsIOException,InterruptedException{finalStringstatusPath=String.format("/transaction/get?hash=%s",transactionHash);System.out.printf("Waiting for %s confirmation from %s%n",label,statusPath);booleanisConfirmed=false;for(intattempt=1;120>=attempt;++attempt){finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(nodeUrl+statusPath)).GET().build();finalHttpResponse<String>response=HTTP_CLIENT.send(request,BodyHandlers.ofString());if(2!=response.statusCode()/100){System.out.println(" Transaction status: pending");Thread.sleep(1000);}else{finalJsonNodeconfirmed=JSON_MAPPER.readTree(response.body());System.out.printf("%s confirmed in block %s%n",label,confirmed.get("meta").get("height").asText());isConfirmed=true;break;}}if(!isConfirmed)System.out.printf("%s confirmation took too long.%n",label);}publicstaticvoidmain(finalString[]args){try{newSignMultisig().run();}catch(finalExceptionex){System.out.println(null==ex.getMessage()?ex.toString():ex.getMessage());}}privatevoidrun()throwsIOException,InterruptedException{System.out.printf("Using node %s%n",nodeUrl);finalStringmultisigPublicKeyString=System.getenv().getOrDefault("MULTISIG_PUBLIC_KEY","D656155B48D4E71E4C59EC6FAEB5EB4F214DE8BC3C65D5BF6A3D9931B4E5"+"ACF2");finalCryptoTypes.PublicKeymultisigPublicKey=newCryptoTypes.PublicKey(multisigPublicKeyString);finalAddressmultisigAddress=facade.network.publicKeyToAddress(multisigPublicKey);System.out.printf("Multisig public key: %s%n",multisigPublicKey);finalKeyPaircosignatory0KeyPair=newKeyPair(newCryptoTypes.PrivateKey(System.getenv().getOrDefault("COSIGNATORY0_PRIVATE_KEY","0".repeat(63)+"2")));System.out.printf("Cosignatory 0 public key: %s%n",cosignatory0KeyPair.getPublicKey());finalKeyPaircosignatory1KeyPair=newKeyPair(newCryptoTypes.PrivateKey(System.getenv().getOrDefault("COSIGNATORY1_PRIVATE_KEY","0".repeat(63)+"3")));System.out.printf("Cosignatory 1 public key: %s%n",cosignatory1KeyPair.getPublicKey());// Build the inner transfer transactionfinalTransactiontransferTransaction=facade.createTransactionFromTypedDescriptor(newTransferTransactionV2Descriptor(newAddress(multisigAddress.toString()),newAmount(1_000_000),null,List.of()),// 1 XEMmultisigPublicKey,0,2*60*60);transferTransaction.setFee(newAmount(FeeCalculator.calculateTransactionFee(transferTransaction)));// Build the wrapper multisig transactionfinalTransactiontransaction=facade.createTransactionFromTypedDescriptor(newMultisigTransactionV1Descriptor(NemTransactionFactory.toNonVerifiableTransaction(transferTransaction),List.of()),// This is the cosignatory that initiates the transfercosignatory0KeyPair.getPublicKey(),0,2*60*60);transaction.setFee(newAmount(FeeCalculator.calculateTransactionFee(transaction)));// Sign and announce the multisig transactionfinalCryptoTypes.Signaturesignature=facade.signTransaction(cosignatory0KeyPair,transaction);finalStringpayload=NemTransactionFactory.attachSignature(transaction,signature);System.out.println("Built multisig transaction:");System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(transaction.toJson()));finalStringtransactionHash=facade.hashTransaction(transaction).toString();System.out.printf("Transaction hash: %s%n",transactionHash);finalStringannounceResult=announceTransaction(payload,"multisig transaction");// The transaction is now waiting for the second signature// Retrieve the pending transaction from the networkif("SUCCESS".equals(announceResult)){finalAddresscosignatory1Address=facade.network.publicKeyToAddress(cosignatory1KeyPair.getPublicKey());finalStringpath=String.format("/account/unconfirmedTransactions?address=%s",cosignatory1Address);System.out.printf("Fetching pending transactions from %s%n",path);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(nodeUrl+path)).GET().build();finalJsonNodepending=JSON_MAPPER.readTree(HTTP_CLIENT.send(request,BodyHandlers.ofString()).body()).get("data");// Select the pending transaction issued by the multisigJsonNodependingEntry=null;for(finalJsonNodeentry:pending){finalJsonNodeotherTransaction=entry.get("transaction").get("otherTrans");if(null!=otherTransaction&&multisigPublicKeyString.equalsIgnoreCase(otherTransaction.get("signer").asText())){pendingEntry=entry;break;}}if(null==pendingEntry)thrownewIOException("Pending transaction not found");finalStringinnerTransactionHash=pendingEntry.get("meta").get("data").asText();System.out.printf(" Inner transaction hash: %s%n",innerTransactionHash);// Build the cosignaturefinalTransactioncosignature=facade.createTransactionFromTypedDescriptor(newCosignatureV1Descriptor(// Hash of the inner transfer transactionnewCryptoTypes.Hash256(innerTransactionHash),// Address of the multisig accountnewAddress(multisigAddress.toString())),// Cosignatory providing the second signaturecosignatory1KeyPair.getPublicKey(),0,2*60*60);cosignature.setFee(newAmount(FeeCalculator.calculateTransactionFee(cosignature)));// Sign and announce the cosignaturefinalCryptoTypes.SignaturecosignatureSignature=facade.signTransaction(cosignatory1KeyPair,cosignature);finalStringcosignaturePayload=NemTransactionFactory.attachSignature(cosignature,cosignatureSignature);System.out.println("Built cosignature:");System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(cosignature.toJson()));finalStringcosignatureResult=announceTransaction(cosignaturePayload,"cosignature");// Wait for the multisig transaction to be confirmedif("SUCCESS".equals(cosignatureResult))waitForConfirmation(transactionHash,"multisig transaction");elseSystem.out.printf("Transaction rejected: %s%n",cosignatureResult);}else{System.out.printf("Transaction rejected: %s%n",announceResult);}}}
MULTISIG_PUBLIC_KEY=os.getenv('MULTISIG_PUBLIC_KEY','D656155B48D4E71E4C59EC6FAEB5EB4F214DE8BC3C65D5BF6A3D9931B4E5ACF2')multisig_public_key=PublicKey(MULTISIG_PUBLIC_KEY)multisig_address=facade.network.public_key_to_address(multisig_public_key)print(f'Multisig public key: {multisig_public_key}')COSIGNATORY0_PRIVATE_KEY=os.getenv('COSIGNATORY0_PRIVATE_KEY','0000000000000000000000000000000000000000000000000000000000000002')cosignatory0_key_pair=NemFacade.KeyPair(PrivateKey(COSIGNATORY0_PRIVATE_KEY))print(f'Cosignatory 0 public key: {cosignatory0_key_pair.public_key}')COSIGNATORY1_PRIVATE_KEY=os.getenv('COSIGNATORY1_PRIVATE_KEY','0000000000000000000000000000000000000000000000000000000000000003')cosignatory1_key_pair=NemFacade.KeyPair(PrivateKey(COSIGNATORY1_PRIVATE_KEY))print(f'Cosignatory 1 public key: {cosignatory1_key_pair.public_key}')
constMULTISIG_PUBLIC_KEY=process.env.MULTISIG_PUBLIC_KEY||('D656155B48D4E71E4C59EC6FAEB5EB4F214DE8BC3C65D5BF6A3D9931B4E5ACF2');constmultisigPublicKey=newPublicKey(MULTISIG_PUBLIC_KEY);constmultisigAddress=facade.network.publicKeyToAddress(multisigPublicKey);console.log(`Multisig public key: ${multisigPublicKey}`);constCOSIGNATORY0_PRIVATE_KEY=process.env.COSIGNATORY0_PRIVATE_KEY||('0000000000000000000000000000000000000000000000000000000000000002');constcosignatory0KeyPair=newNemFacade.KeyPair(newPrivateKey(COSIGNATORY0_PRIVATE_KEY));console.log(`Cosignatory 0 public key: ${cosignatory0KeyPair.publicKey}`);constCOSIGNATORY1_PRIVATE_KEY=process.env.COSIGNATORY1_PRIVATE_KEY||('0000000000000000000000000000000000000000000000000000000000000003');constcosignatory1KeyPair=newNemFacade.KeyPair(newPrivateKey(COSIGNATORY1_PRIVATE_KEY));console.log(`Cosignatory 1 public key: ${cosignatory1KeyPair.publicKey}`);
finalStringmultisigPublicKeyString=System.getenv().getOrDefault("MULTISIG_PUBLIC_KEY","D656155B48D4E71E4C59EC6FAEB5EB4F214DE8BC3C65D5BF6A3D9931B4E5"+"ACF2");finalCryptoTypes.PublicKeymultisigPublicKey=newCryptoTypes.PublicKey(multisigPublicKeyString);finalAddressmultisigAddress=facade.network.publicKeyToAddress(multisigPublicKey);System.out.printf("Multisig public key: %s%n",multisigPublicKey);finalKeyPaircosignatory0KeyPair=newKeyPair(newCryptoTypes.PrivateKey(System.getenv().getOrDefault("COSIGNATORY0_PRIVATE_KEY","0".repeat(63)+"2")));System.out.printf("Cosignatory 0 public key: %s%n",cosignatory0KeyPair.getPublicKey());finalKeyPaircosignatory1KeyPair=newKeyPair(newCryptoTypes.PrivateKey(System.getenv().getOrDefault("COSIGNATORY1_PRIVATE_KEY","0".repeat(63)+"3")));System.out.printf("Cosignatory 1 public key: %s%n",cosignatory1KeyPair.getPublicKey());
# Build the inner transfer transactiontransfer_transaction=facade.create_transaction_from_descriptor({'type':'transfer_transaction_v2','recipient_address':multisig_address,'amount':1_000_000# 1 XEM},multisig_public_key,0,2*60*60)transfer_transaction.fee=Amount(calculate_transaction_fee(transfer_transaction))
// Build the inner transfer transactionconsttransferTransaction=facade.createTransactionFromTypedDescriptor(newdescriptors.TransferTransactionV2Descriptor(newAddress(multisigAddress.toString()),newmodels.Amount(1_000_000n)),// 1 XEMmultisigPublicKey,0n,2*60*60);transferTransaction.fee=newmodels.Amount(calculateTransactionFee(transferTransaction));
// Build the inner transfer transactionfinalTransactiontransferTransaction=facade.createTransactionFromTypedDescriptor(newTransferTransactionV2Descriptor(newAddress(multisigAddress.toString()),newAmount(1_000_000),null,List.of()),// 1 XEMmultisigPublicKey,0,2*60*60);transferTransaction.setFee(newAmount(FeeCalculator.calculateTransactionFee(transferTransaction)));
# Build the wrapper multisig transactiontransaction=facade.create_transaction_from_descriptor({'type':'multisig_transaction_v1','inner_transaction':facade.transaction_factory.to_non_verifiable_transaction(transfer_transaction)},# This is the cosignatory that initiates the transfercosignatory0_key_pair.public_key,0,2*60*60)transaction.fee=Amount(calculate_transaction_fee(transaction))
// Build the wrapper multisig transactionconsttransaction=facade.createTransactionFromTypedDescriptor(newdescriptors.MultisigTransactionV1Descriptor(facade.transactionFactory.static.toNonVerifiableTransaction(transferTransaction)),// This is the cosignatory that initiates the transfercosignatory0KeyPair.publicKey,0n,2*60*60);transaction.fee=newmodels.Amount(calculateTransactionFee(transaction));
// Build the wrapper multisig transactionfinalTransactiontransaction=facade.createTransactionFromTypedDescriptor(newMultisigTransactionV1Descriptor(NemTransactionFactory.toNonVerifiableTransaction(transferTransaction),List.of()),// This is the cosignatory that initiates the transfercosignatory0KeyPair.getPublicKey(),0,2*60*60);transaction.setFee(newAmount(FeeCalculator.calculateTransactionFee(transaction)));
# Sign and announce the multisig transactionsignature=facade.sign_transaction(cosignatory0_key_pair,transaction)json_payload=facade.transaction_factory.attach_signature(transaction,signature)print('Built multisig transaction:')print(json.dumps(transaction.to_json(),indent=2))transaction_hash=facade.hash_transaction(transaction)print(f'Transaction hash: {transaction_hash}')announce_result=announce_transaction(json_payload,'multisig transaction')# The transaction is now waiting for the second signature
// Sign and announce the multisig transactionconstsignature=facade.signTransaction(cosignatory0KeyPair,transaction);constjsonPayload=facade.transactionFactory.static.attachSignature(transaction,signature);console.log('Built multisig transaction:');console.log(JSON.stringify(transaction.toJson(),null,2));consttransactionHash=facade.hashTransaction(transaction).toString();console.log('Transaction hash:',transactionHash);constannounceResult=awaitannounceTransaction(jsonPayload,'multisig transaction');// The transaction is now waiting for the second signature
// Sign and announce the multisig transactionfinalCryptoTypes.Signaturesignature=facade.signTransaction(cosignatory0KeyPair,transaction);finalStringpayload=NemTransactionFactory.attachSignature(transaction,signature);System.out.println("Built multisig transaction:");System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(transaction.toJson()));finalStringtransactionHash=facade.hashTransaction(transaction).toString();System.out.printf("Transaction hash: %s%n",transactionHash);finalStringannounceResult=announceTransaction(payload,"multisig transaction");// The transaction is now waiting for the second signature
# Retrieve the pending transaction from the networkif'SUCCESS'==announce_result:cosignatory1_address=facade.network.public_key_to_address(cosignatory1_key_pair.public_key)unconfirmed_path=('/account/unconfirmedTransactions'f'?address={cosignatory1_address}')print(f'Fetching pending transactions from {unconfirmed_path}')withurllib.request.urlopen(f'{NODE_URL}{unconfirmed_path}')asresponse:pending=json.loads(response.read().decode())['data']# Select the pending transaction issued by the multisig accountinner_transaction_hash=next(entry['meta']['data']forentryinpendingifentry['transaction'].get('otherTrans',{}).get('signer','').upper()==str(multisig_public_key))print(f' Inner transaction hash: {inner_transaction_hash}')
// Retrieve the pending transaction from the networkif('SUCCESS'===announceResult){constcosignatory1Address=facade.network.publicKeyToAddress(cosignatory1KeyPair.publicKey);constunconfirmedPath='/account/unconfirmedTransactions'+`?address=${cosignatory1Address}`;console.log('Fetching pending transactions from',unconfirmedPath);constunconfirmedResponse=awaitfetch(`${NODE_URL}${unconfirmedPath}`);constpending=(awaitunconfirmedResponse.json()).data;// Select the pending transaction issued by the multisig accountconstpendingEntry=pending.find(entry=>multisigPublicKey.toString()===(entry.transaction.otherTrans?.signer??'').toUpperCase());constinnerTransactionHash=pendingEntry.meta.data;console.log(' Inner transaction hash:',innerTransactionHash);
// Retrieve the pending transaction from the networkif("SUCCESS".equals(announceResult)){finalAddresscosignatory1Address=facade.network.publicKeyToAddress(cosignatory1KeyPair.getPublicKey());finalStringpath=String.format("/account/unconfirmedTransactions?address=%s",cosignatory1Address);System.out.printf("Fetching pending transactions from %s%n",path);finalHttpRequestrequest=HttpRequest.newBuilder(URI.create(nodeUrl+path)).GET().build();finalJsonNodepending=JSON_MAPPER.readTree(HTTP_CLIENT.send(request,BodyHandlers.ofString()).body()).get("data");// Select the pending transaction issued by the multisigJsonNodependingEntry=null;for(finalJsonNodeentry:pending){finalJsonNodeotherTransaction=entry.get("transaction").get("otherTrans");if(null!=otherTransaction&&multisigPublicKeyString.equalsIgnoreCase(otherTransaction.get("signer").asText())){pendingEntry=entry;break;}}if(null==pendingEntry)thrownewIOException("Pending transaction not found");finalStringinnerTransactionHash=pendingEntry.get("meta").get("data").asText();System.out.printf(" Inner transaction hash: %s%n",innerTransactionHash);
# Build the cosignaturecosignature=facade.create_transaction_from_descriptor({'type':'cosignature_v1',# Hash of the inner transfer transaction'other_transaction_hash':inner_transaction_hash,# Address of the multisig account'multisig_account_address':multisig_address},# This is the cosignatory providing the second signaturecosignatory1_key_pair.public_key,0,2*60*60)cosignature.fee=Amount(calculate_transaction_fee(cosignature))
// Build the cosignatureconstcosignature=facade.createTransactionFromTypedDescriptor(newdescriptors.CosignatureV1Descriptor(// Hash of the inner transfer transactionnewHash256(innerTransactionHash),// Address of the multisig accountnewAddress(multisigAddress.toString())),// This is the cosignatory providing the second signaturecosignatory1KeyPair.publicKey,0n,2*60*60);cosignature.fee=newmodels.Amount(calculateTransactionFee(cosignature));
// Build the cosignaturefinalTransactioncosignature=facade.createTransactionFromTypedDescriptor(newCosignatureV1Descriptor(// Hash of the inner transfer transactionnewCryptoTypes.Hash256(innerTransactionHash),// Address of the multisig accountnewAddress(multisigAddress.toString())),// Cosignatory providing the second signaturecosignatory1KeyPair.getPublicKey(),0,2*60*60);cosignature.setFee(newAmount(FeeCalculator.calculateTransactionFee(cosignature)));
# Sign and announce the cosignaturecosignature_signature=facade.sign_transaction(cosignatory1_key_pair,cosignature)cosignature_payload=facade.transaction_factory.attach_signature(cosignature,cosignature_signature)print('Built cosignature:')print(json.dumps(cosignature.to_json(),indent=2))cosignature_result=announce_transaction(cosignature_payload,'cosignature')
// Sign and announce the cosignatureconstcosignatureSignature=facade.signTransaction(cosignatory1KeyPair,cosignature);constcosignaturePayload=facade.transactionFactory.static.attachSignature(cosignature,cosignatureSignature);console.log('Built cosignature:');console.log(JSON.stringify(cosignature.toJson(),null,2));constcosignatureResult=awaitannounceTransaction(cosignaturePayload,'cosignature');
// Sign and announce the cosignaturefinalCryptoTypes.SignaturecosignatureSignature=facade.signTransaction(cosignatory1KeyPair,cosignature);finalStringcosignaturePayload=NemTransactionFactory.attachSignature(cosignature,cosignatureSignature);System.out.println("Built cosignature:");System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(cosignature.toJson()));finalStringcosignatureResult=announceTransaction(cosignaturePayload,"cosignature");
# Wait for the multisig transaction to be confirmedif'SUCCESS'==cosignature_result:wait_for_confirmation(transaction_hash,'multisig transaction')else:print(f'Transaction rejected: {cosignature_result}')
// Wait for the multisig transaction to be confirmedif('SUCCESS'===cosignatureResult){awaitwaitForConfirmation(transactionHash,'multisig transaction');}else{console.log('Transaction rejected:',cosignatureResult);}
// Wait for the multisig transaction to be confirmedif("SUCCESS".equals(cosignatureResult))waitForConfirmation(transactionHash,"multisig transaction");elseSystem.out.printf("Transaction rejected: %s%n",cosignatureResult);