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}')facade=NemFacade('testnet')KEY_TEMPLATE='0'*63+'{}'# Set up the keys for the multisig account and its two cosignatoriesMULTISIG_PRIVATE_KEY=os.getenv('MULTISIG_PRIVATE_KEY',KEY_TEMPLATE.format(1))multisig_key_pair=NemFacade.KeyPair(PrivateKey(MULTISIG_PRIVATE_KEY))multisig_address=facade.network.public_key_to_address(multisig_key_pair.public_key)print(f'Multisig address: {multisig_address} 'f'(public key {multisig_key_pair.public_key})')cosignatory_key_pairs=[]foriinrange(2):COSIGNATORY_PRIVATE_KEY=os.getenv(f'COSIGNATORY{i}_PRIVATE_KEY',KEY_TEMPLATE.format(i+2))key_pair=NemFacade.KeyPair(PrivateKey(COSIGNATORY_PRIVATE_KEY))cosignatory_key_pairs.append(key_pair)addr=facade.network.public_key_to_address(key_pair.public_key)print(f'Cosignatory {i} address: 'f'{addr} (public key {key_pair.public_key})')# 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.')# Returns the cosignatory addresses of the provided multisig# account, or an empty list if the account is not multisigdefget_multisig_cosignatories(address):account_path=f'/account/get?address={address}'print(f'Getting cosignatories from {account_path}')url=f'{NODE_URL}{account_path}'withurllib.request.urlopen(url)asaccount_response:account_info=json.loads(account_response.read().decode())found_cosignatories=[cosignatory['address']forcosignatoryinaccount_info['meta']['cosignatories']]ifnotfound_cosignatories:print(' Response: No cosignatories')return[]print(f' Response: {found_cosignatories}')returnfound_cosignatories# Returns a transaction that turns a regular account into a multisigdefmultisig_enable_transaction(tx_timestamp,tx_deadline,approval_delta):# Create a multisig account modification transaction# that adds the cosignatoriesmodifications=[{'modification':{'modification_type':'add_cosignatory','cosignatory_public_key':key_pair.public_key}}forkey_pairincosignatory_key_pairs]transaction=facade.transaction_factory.create({'type':'multisig_account_modification_transaction_v2',# This is the account that will be turned into a multisig'signer_public_key':multisig_key_pair.public_key,'timestamp':tx_timestamp.timestamp,'deadline':tx_deadline.timestamp,# Change of the number of cosignatures# required to approve transactions'min_approval_delta':approval_delta,'modifications':modifications})# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction)transaction.fee=Amount(fee)print(f' Transaction fee: {fee/1_000_000} XEM')print('Enabling the multisig with the modification transaction:')print(json.dumps(transaction.to_json(),indent=2))# Sign the transaction with the multisig's keysignature=facade.sign_transaction(multisig_key_pair,transaction)facade.transaction_factory.attach_signature(transaction,signature)returntransaction# Returns a transaction that removes one cosignatory from the multisigdefmultisig_removal_transaction(tx_timestamp,tx_deadline,removed_key_pair,approval_delta):# Create a multisig account modification transaction# that removes a single cosignatoryinner_transaction=facade.transaction_factory.create({'type':'multisig_account_modification_transaction_v2',# This is the multisig account that will be modified'signer_public_key':multisig_key_pair.public_key,'timestamp':tx_timestamp.timestamp,'deadline':tx_deadline.timestamp,# Change of the number of cosignatures# required to approve transactions'min_approval_delta':approval_delta,'modifications':[{'modification':{'modification_type':'delete_cosignatory','cosignatory_public_key':removed_key_pair.public_key}}]})# Wrap the modification in a multisig transactioninner_fee=calculate_transaction_fee(inner_transaction)inner_transaction.fee=Amount(inner_fee)transaction=facade.transaction_factory.create({'type':'multisig_transaction_v1',# This is the cosignatory that initiates the removal'signer_public_key':cosignatory_key_pairs[0].public_key,'timestamp':tx_timestamp.timestamp,'deadline':tx_deadline.timestamp,'inner_transaction':facade.transaction_factory.to_non_verifiable_transaction(inner_transaction)})# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction)transaction.fee=Amount(fee)print(f' Transaction fee: {(inner_fee+fee)/1_000_000} XEM')print('Disabling the multisig with the multisig transaction:')print(json.dumps(transaction.to_json(),indent=2))# Sign the transaction with the cosignatory's keysignature=facade.sign_transaction(cosignatory_key_pairs[0],transaction)facade.transaction_factory.attach_signature(transaction,signature)returntransactiontry:# 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)# Get current state of the multisig account and decide which# operation to performcosignatories=get_multisig_cosignatories(multisig_address)iflen(cosignatories)==0:# Enable the multisigtransactions=[multisig_enable_transaction(timestamp,deadline,1)]else:# Disable the multisigtransactions=[multisig_removal_transaction(timestamp,deadline,cosignatory_key_pairs[1],0),multisig_removal_transaction(timestamp,deadline,cosignatory_key_pairs[0],-1)]# Announce each transaction and wait for confirmationforsigned_transactionintransactions:transaction_hash=facade.hash_transaction(signed_transaction)print(f'Built transaction with hash: {transaction_hash}')json_payload=facade.transaction_factory.to_json(signed_transaction)announce_result=announce_transaction(json_payload,'transaction')if'SUCCESS'!=announce_result:print('Transaction rejected')breakwait_for_confirmation(transaction_hash,'transaction')exceptExceptionase:print(e)
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);constfacade=newNemFacade('testnet');constKEY_PREFIX='0'.repeat(63);// Set up the keys for the multisig account and its two cosignatoriesconstMULTISIG_PRIVATE_KEY=process.env.MULTISIG_PRIVATE_KEY||(`${KEY_PREFIX}1`);constmultisigKeyPair=newNemFacade.KeyPair(newPrivateKey(MULTISIG_PRIVATE_KEY));constmultisigAddress=facade.network.publicKeyToAddress(multisigKeyPair.publicKey);console.log(`Multisig address: ${multisigAddress}`,`(public key ${multisigKeyPair.publicKey})`);constcosignatoryKeyPairs=[];for(leti=0;2>i;i++){constCOSIGNATORY_PRIVATE_KEY=process.env[`COSIGNATORY${i}_PRIVATE_KEY`]||(KEY_PREFIX+String(i+2));constkeyPair=newNemFacade.KeyPair(newPrivateKey(COSIGNATORY_PRIVATE_KEY));cosignatoryKeyPairs.push(keyPair);constaddr=facade.network.publicKeyToAddress(keyPair.publicKey);console.log(`Cosignatory ${i} address: ${addr}`,`(public key ${keyPair.publicKey})`);}// Helper function to announce a transactionasyncfunctionannounceTransaction(payload,label){constannouncePath='/transaction/announce';console.log(`Announcing ${label} to ${announcePath}`);constannounceResponse=awaitfetch(`${NODE_URL}${announcePath}`,{method:'POST',headers:{'Content-Type':'application/json'},body:payload});constresult=awaitannounceResponse.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){constconfirmed=awaitresponse.json();console.log(`${label} confirmed in block`,confirmed.meta.height);isConfirmed=true;break;}console.log(' Transaction status: pending');awaitnewPromise(resolve=>{setTimeout(resolve,1000);});}if(!isConfirmed)console.warn(`${label} confirmation took too long.`);}// Returns the cosignatory addresses of the provided multisig// account, or an empty list if the account is not multisigasyncfunctiongetMultisigCosignatories(address){constaccountPath=`/account/get?address=${address}`;console.log(`Getting cosignatories from ${accountPath}`);constresponse=awaitfetch(`${NODE_URL}${accountPath}`);constaccountInfo=awaitresponse.json();constfoundCosignatories=accountInfo.meta.cosignatories.map(cosignatory=>cosignatory.address);if(0===foundCosignatories.length){console.log(' Response: No cosignatories');return[];}console.log(' Response:',JSON.stringify(foundCosignatories));returnfoundCosignatories;}// Returns a transaction that turns a regular account into a multisigfunctionmultisigEnableTransaction(timestamp,deadline,approvalDelta){// Create a multisig account modification transaction// that adds the cosignatoriesconstmodifications=cosignatoryKeyPairs.map(keyPair=>({modification:{modificationType:'add_cosignatory',cosignatoryPublicKey:keyPair.publicKey.toString()}}));consttransaction=facade.transactionFactory.create({type:'multisig_account_modification_transaction_v2',// This is the account that will be turned into a multisigsignerPublicKey:multisigKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,// Change of the number of cosignatures// required to approve transactionsminApprovalDelta:approvalDelta,modifications});// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(` Transaction fee: ${Number(fee)/1_000_000} XEM`);console.log('Enabling the multisig with the modification transaction:');console.log(JSON.stringify(transaction.toJson(),null,2));// Sign the transaction with the multisig's keyconstsignature=facade.signTransaction(multisigKeyPair,transaction);facade.transactionFactory.static.attachSignature(transaction,signature);returntransaction;}// Returns a transaction that removes one cosignatory from the multisigfunctionmultisigRemovalTransaction(timestamp,deadline,removedKeyPair,approvalDelta){// Create a multisig account modification transaction// that removes a single cosignatoryconstinnerTransaction=facade.transactionFactory.create({type:'multisig_account_modification_transaction_v2',// This is the multisig account that will be modifiedsignerPublicKey:multisigKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,// Change of the number of cosignatures// required to approve transactionsminApprovalDelta:approvalDelta,modifications:[{modification:{modificationType:'delete_cosignatory',cosignatoryPublicKey:removedKeyPair.publicKey.toString()}}]});// Wrap the modification in a multisig transactionconstinnerFee=calculateTransactionFee(innerTransaction);innerTransaction.fee=newmodels.Amount(innerFee);consttransaction=facade.transactionFactory.create({type:'multisig_transaction_v1',// This is the cosignatory that initiates the removalsignerPublicKey:cosignatoryKeyPairs[0].publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,innerTransaction:facade.transactionFactory.static.toNonVerifiableTransaction(innerTransaction)});// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(' Transaction fee:',`${Number(innerFee+fee)/1_000_000} XEM`);console.log('Disabling the multisig with the multisig transaction:');console.log(JSON.stringify(transaction.toJson(),null,2));// Sign the transaction with the cosignatory's keyconstsignature=facade.signTransaction(cosignatoryKeyPairs[0],transaction);facade.transactionFactory.static.attachSignature(transaction,signature);returntransaction;}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);// Get current state of the multisig account and decide// which operation to performconstcosignatories=awaitgetMultisigCosignatories(multisigAddress);lettransactions;if(0===cosignatories.length){// Enable the multisigtransactions=[multisigEnableTransaction(timestamp,deadline,1)];}else{// Disable the multisigtransactions=[multisigRemovalTransaction(timestamp,deadline,cosignatoryKeyPairs[1],0),multisigRemovalTransaction(timestamp,deadline,cosignatoryKeyPairs[0],-1)];}// Announce each transaction and wait for confirmationfor(constsignedTransactionoftransactions){consttransactionHash=facade.hashTransaction(signedTransaction).toString();console.log('Built transaction with hash:',transactionHash);constjsonPayload=facade.transactionFactory.static.toJson(signedTransaction);constresult=awaitannounceTransaction(jsonPayload,'transaction');if('SUCCESS'!==result){console.log('Transaction rejected');break;}awaitwaitForConfirmation(transactionHash,'transaction');}}catch(e){console.error(e.message,'| Cause:',e.cause?.code??'unknown');}
KEY_TEMPLATE='0'*63+'{}'# Set up the keys for the multisig account and its two cosignatoriesMULTISIG_PRIVATE_KEY=os.getenv('MULTISIG_PRIVATE_KEY',KEY_TEMPLATE.format(1))multisig_key_pair=NemFacade.KeyPair(PrivateKey(MULTISIG_PRIVATE_KEY))multisig_address=facade.network.public_key_to_address(multisig_key_pair.public_key)print(f'Multisig address: {multisig_address} 'f'(public key {multisig_key_pair.public_key})')cosignatory_key_pairs=[]foriinrange(2):COSIGNATORY_PRIVATE_KEY=os.getenv(f'COSIGNATORY{i}_PRIVATE_KEY',KEY_TEMPLATE.format(i+2))key_pair=NemFacade.KeyPair(PrivateKey(COSIGNATORY_PRIVATE_KEY))cosignatory_key_pairs.append(key_pair)addr=facade.network.public_key_to_address(key_pair.public_key)print(f'Cosignatory {i} address: 'f'{addr} (public key {key_pair.public_key})')
constKEY_PREFIX='0'.repeat(63);// Set up the keys for the multisig account and its two cosignatoriesconstMULTISIG_PRIVATE_KEY=process.env.MULTISIG_PRIVATE_KEY||(`${KEY_PREFIX}1`);constmultisigKeyPair=newNemFacade.KeyPair(newPrivateKey(MULTISIG_PRIVATE_KEY));constmultisigAddress=facade.network.publicKeyToAddress(multisigKeyPair.publicKey);console.log(`Multisig address: ${multisigAddress}`,`(public key ${multisigKeyPair.publicKey})`);constcosignatoryKeyPairs=[];for(leti=0;2>i;i++){constCOSIGNATORY_PRIVATE_KEY=process.env[`COSIGNATORY${i}_PRIVATE_KEY`]||(KEY_PREFIX+String(i+2));constkeyPair=newNemFacade.KeyPair(newPrivateKey(COSIGNATORY_PRIVATE_KEY));cosignatoryKeyPairs.push(keyPair);constaddr=facade.network.publicKeyToAddress(keyPair.publicKey);console.log(`Cosignatory ${i} address: ${addr}`,`(public key ${keyPair.publicKey})`);}
# 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);
# Returns the cosignatory addresses of the provided multisig# account, or an empty list if the account is not multisigdefget_multisig_cosignatories(address):account_path=f'/account/get?address={address}'print(f'Getting cosignatories from {account_path}')url=f'{NODE_URL}{account_path}'withurllib.request.urlopen(url)asaccount_response:account_info=json.loads(account_response.read().decode())found_cosignatories=[cosignatory['address']forcosignatoryinaccount_info['meta']['cosignatories']]ifnotfound_cosignatories:print(' Response: No cosignatories')return[]print(f' Response: {found_cosignatories}')returnfound_cosignatories
// Returns the cosignatory addresses of the provided multisig// account, or an empty list if the account is not multisigasyncfunctiongetMultisigCosignatories(address){constaccountPath=`/account/get?address=${address}`;console.log(`Getting cosignatories from ${accountPath}`);constresponse=awaitfetch(`${NODE_URL}${accountPath}`);constaccountInfo=awaitresponse.json();constfoundCosignatories=accountInfo.meta.cosignatories.map(cosignatory=>cosignatory.address);if(0===foundCosignatories.length){console.log(' Response: No cosignatories');return[];}console.log(' Response:',JSON.stringify(foundCosignatories));returnfoundCosignatories;}
# Get current state of the multisig account and decide which# operation to performcosignatories=get_multisig_cosignatories(multisig_address)iflen(cosignatories)==0:# Enable the multisigtransactions=[multisig_enable_transaction(timestamp,deadline,1)]else:# Disable the multisigtransactions=[multisig_removal_transaction(timestamp,deadline,cosignatory_key_pairs[1],0),multisig_removal_transaction(timestamp,deadline,cosignatory_key_pairs[0],-1)]
// Get current state of the multisig account and decide// which operation to performconstcosignatories=awaitgetMultisigCosignatories(multisigAddress);lettransactions;if(0===cosignatories.length){// Enable the multisigtransactions=[multisigEnableTransaction(timestamp,deadline,1)];}else{// Disable the multisigtransactions=[multisigRemovalTransaction(timestamp,deadline,cosignatoryKeyPairs[1],0),multisigRemovalTransaction(timestamp,deadline,cosignatoryKeyPairs[0],-1)];}
# Returns a transaction that turns a regular account into a multisigdefmultisig_enable_transaction(tx_timestamp,tx_deadline,approval_delta):# Create a multisig account modification transaction# that adds the cosignatoriesmodifications=[{'modification':{'modification_type':'add_cosignatory','cosignatory_public_key':key_pair.public_key}}forkey_pairincosignatory_key_pairs]transaction=facade.transaction_factory.create({'type':'multisig_account_modification_transaction_v2',# This is the account that will be turned into a multisig'signer_public_key':multisig_key_pair.public_key,'timestamp':tx_timestamp.timestamp,'deadline':tx_deadline.timestamp,# Change of the number of cosignatures# required to approve transactions'min_approval_delta':approval_delta,'modifications':modifications})
// Returns a transaction that turns a regular account into a multisigfunctionmultisigEnableTransaction(timestamp,deadline,approvalDelta){// Create a multisig account modification transaction// that adds the cosignatoriesconstmodifications=cosignatoryKeyPairs.map(keyPair=>({modification:{modificationType:'add_cosignatory',cosignatoryPublicKey:keyPair.publicKey.toString()}}));consttransaction=facade.transactionFactory.create({type:'multisig_account_modification_transaction_v2',// This is the account that will be turned into a multisigsignerPublicKey:multisigKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,// Change of the number of cosignatures// required to approve transactionsminApprovalDelta:approvalDelta,modifications});
# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction)transaction.fee=Amount(fee)print(f' Transaction fee: {fee/1_000_000} XEM')print('Enabling the multisig with the modification transaction:')print(json.dumps(transaction.to_json(),indent=2))
// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(` Transaction fee: ${Number(fee)/1_000_000} XEM`);console.log('Enabling the multisig with the modification transaction:');console.log(JSON.stringify(transaction.toJson(),null,2));
# Sign the transaction with the multisig's keysignature=facade.sign_transaction(multisig_key_pair,transaction)facade.transaction_factory.attach_signature(transaction,signature)returntransaction
// Sign the transaction with the multisig's keyconstsignature=facade.signTransaction(multisigKeyPair,transaction);facade.transactionFactory.static.attachSignature(transaction,signature);returntransaction;
# Returns a transaction that removes one cosignatory from the multisigdefmultisig_removal_transaction(tx_timestamp,tx_deadline,removed_key_pair,approval_delta):# Create a multisig account modification transaction# that removes a single cosignatoryinner_transaction=facade.transaction_factory.create({'type':'multisig_account_modification_transaction_v2',# This is the multisig account that will be modified'signer_public_key':multisig_key_pair.public_key,'timestamp':tx_timestamp.timestamp,'deadline':tx_deadline.timestamp,# Change of the number of cosignatures# required to approve transactions'min_approval_delta':approval_delta,'modifications':[{'modification':{'modification_type':'delete_cosignatory','cosignatory_public_key':removed_key_pair.public_key}}]})
// Returns a transaction that removes one cosignatory from the multisigfunctionmultisigRemovalTransaction(timestamp,deadline,removedKeyPair,approvalDelta){// Create a multisig account modification transaction// that removes a single cosignatoryconstinnerTransaction=facade.transactionFactory.create({type:'multisig_account_modification_transaction_v2',// This is the multisig account that will be modifiedsignerPublicKey:multisigKeyPair.publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,// Change of the number of cosignatures// required to approve transactionsminApprovalDelta:approvalDelta,modifications:[{modification:{modificationType:'delete_cosignatory',cosignatoryPublicKey:removedKeyPair.publicKey.toString()}}]});
# Wrap the modification in a multisig transactioninner_fee=calculate_transaction_fee(inner_transaction)inner_transaction.fee=Amount(inner_fee)transaction=facade.transaction_factory.create({'type':'multisig_transaction_v1',# This is the cosignatory that initiates the removal'signer_public_key':cosignatory_key_pairs[0].public_key,'timestamp':tx_timestamp.timestamp,'deadline':tx_deadline.timestamp,'inner_transaction':facade.transaction_factory.to_non_verifiable_transaction(inner_transaction)})
// Wrap the modification in a multisig transactionconstinnerFee=calculateTransactionFee(innerTransaction);innerTransaction.fee=newmodels.Amount(innerFee);consttransaction=facade.transactionFactory.create({type:'multisig_transaction_v1',// This is the cosignatory that initiates the removalsignerPublicKey:cosignatoryKeyPairs[0].publicKey.toString(),timestamp:timestamp.timestamp,deadline:deadline.timestamp,innerTransaction:facade.transactionFactory.static.toNonVerifiableTransaction(innerTransaction)});
# Calculate and attach the transaction feefee=calculate_transaction_fee(transaction)transaction.fee=Amount(fee)print(f' Transaction fee: {(inner_fee+fee)/1_000_000} XEM')print('Disabling the multisig with the multisig transaction:')print(json.dumps(transaction.to_json(),indent=2))
// Calculate and attach the transaction feeconstfee=calculateTransactionFee(transaction);transaction.fee=newmodels.Amount(fee);console.log(' Transaction fee:',`${Number(innerFee+fee)/1_000_000} XEM`);console.log('Disabling the multisig with the multisig transaction:');console.log(JSON.stringify(transaction.toJson(),null,2));
# Sign the transaction with the cosignatory's keysignature=facade.sign_transaction(cosignatory_key_pairs[0],transaction)facade.transaction_factory.attach_signature(transaction,signature)returntransaction
// Sign the transaction with the cosignatory's keyconstsignature=facade.signTransaction(cosignatoryKeyPairs[0],transaction);facade.transactionFactory.static.attachSignature(transaction,signature);returntransaction;
# Announce each transaction and wait for confirmationforsigned_transactionintransactions:transaction_hash=facade.hash_transaction(signed_transaction)print(f'Built transaction with hash: {transaction_hash}')json_payload=facade.transaction_factory.to_json(signed_transaction)announce_result=announce_transaction(json_payload,'transaction')if'SUCCESS'!=announce_result:print('Transaction rejected')breakwait_for_confirmation(transaction_hash,'transaction')
// Announce each transaction and wait for confirmationfor(constsignedTransactionoftransactions){consttransactionHash=facade.hashTransaction(signedTransaction).toString();console.log('Built transaction with hash:',transactionHash);constjsonPayload=facade.transactionFactory.static.toJson(signedTransaction);constresult=awaitannounceTransaction(jsonPayload,'transaction');if('SUCCESS'!==result){console.log('Transaction rejected');break;}awaitwaitForConfirmation(transactionHash,'transaction');}