importjsonimportosimporttimeimporturllib.requestfromsymbolchain.CryptoTypesimportPrivateKeyfromsymbolchain.facade.SymbolFacadeimportSymbolFacadefromsymbolchain.scimportAmountfromsymbolchain.symbol.NetworkimportNetworkTimestampfromsymbolchain.symbol.Restrictionimportmosaic_restriction_generate_keyNODE_URL=os.environ.get('NODE_URL','https://reference.symboltest.net:3001')print(f'Using node {NODE_URL}')# Helper function to announce a transactiondefannounce_transaction(payload,label):print(f'Announcing {label} to /transactions')request=urllib.request.Request(f'{NODE_URL}/transactions',data=payload.encode(),headers={'Content-Type':'application/json'},method='PUT')withurllib.request.urlopen(request)asresponse:print(f' Response: {response.read().decode()}')# Helper function to wait for transaction confirmationdefwait_for_confirmation(transaction_hash,label):print(f'Waiting for {label} confirmation...')forattemptinrange(60):time.sleep(1)try:url=f'{NODE_URL}/transactionStatus/{transaction_hash}'withurllib.request.urlopen(url)asresponse:status=json.loads(response.read().decode())print(f' Transaction status: {status["group"]}')ifstatus['group']=='confirmed':print(f'{label} confirmed in {attempt} seconds')returnifstatus['group']=='failed':raiseException(f'{label} failed: {status["code"]}')excepturllib.error.HTTPError:print(' Transaction status: unknown')raiseException(f'{label} not confirmed after 60 seconds')# Returns a filtered list of restrictions currently applied to the mosaic# matching the given restriction keydefget_mosaic_restrictions(query,key):restrictions_path=f'/restrictions/mosaic?{query}'print(f' Getting restrictions from {restrictions_path}')res=[]try:url=f'{NODE_URL}{restrictions_path}'withurllib.request.urlopen(url)asresponse:status=json.loads(response.read().decode())data=status['data']iflen(data)>0:# Look at the first returned restrictionrlist=data[0]['mosaicRestrictionEntry']['restrictions']# Filter by keyres=[rforrinrlistifint(r['key'])==key]excepturllib.error.HTTPError:# The mosaic has no restrictions applied to this keypassprint(f' Response: {res}')returnresdefget_mosaic_global_restrictions(mosaic_id,key):returnget_mosaic_restrictions(f'mosaicId={mosaic_id:X}&entryType=1',key)defget_mosaic_address_restrictions(mosaic_id,address,key):returnget_mosaic_restrictions(f'mosaicId={mosaic_id:X}&entryType=0&targetAddress={address}',key)# Returns a transaction enabling a mosaic's global restrictiondefglobal_restriction_enable_transaction():transaction=facade.transaction_factory.create_embedded({'type':'mosaic_global_restriction_transaction_v1','signer_public_key':owner_key_pair.public_key,'mosaic_id':mosaic_id,'reference_mosaic_id':0,'restriction_key':restriction_key,'previous_restriction_type':0,'previous_restriction_value':0,'new_restriction_type':'ge','new_restriction_value':1})print(json.dumps(transaction.to_json(),indent=2))returntransaction# Returns a transaction setting an address restriction's valuedefaddress_restriction_set_value(prev_value,new_value,address):transaction=facade.transaction_factory.create_embedded({'type':'mosaic_address_restriction_transaction_v1','signer_public_key':owner_key_pair.public_key,'mosaic_id':mosaic_id,'restriction_key':restriction_key,'previous_restriction_value':prev_value,'new_restriction_value':new_value,'target_address':address})print(json.dumps(transaction.to_json(),indent=2))returntransactionfacade=SymbolFacade('testnet')OWNER_PRIVATE_KEY=os.getenv('OWNER_PRIVATE_KEY','0000000000000000000000000000000000000000000000000000000000000000')owner_key_pair=SymbolFacade.KeyPair(PrivateKey(OWNER_PRIVATE_KEY))owner_address=facade.network.public_key_to_address(owner_key_pair.public_key)print(f'Owner address: {owner_address}')target_address=os.getenv('TARGET_ADDRESS','TB6QOVCUOFRCF5QJSKPIQMLUVWGJS3KYFDETRPA')print(f'Target address: {target_address}')mosaic_id=int(os.getenv('MOSAIC_ID','6A5ACF2376E50D4A'),16)print(f'Mosaic ID: 0x{mosaic_id:08X}')restriction_name=os.getenv('RESTRICTION_NAME','security_level')restriction_key=mosaic_restriction_generate_key(restriction_name)print(f'Restriction name: "{restriction_name}"'f' (key: 0x{restriction_key:016X})')try:# Fetch current network timetime_path='/node/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())receive_timestamp=(response_json['communicationTimestamps']['receiveTimestamp'])timestamp=NetworkTimestamp(int(receive_timestamp))print(f' Network time: {timestamp.timestamp} ms since nemesis')# Fetch recommended feesfee_path='/network/fees/transaction'print(f'Fetching recommended fees from {fee_path}')withurllib.request.urlopen(f'{NODE_URL}{fee_path}')asresponse:response_json=json.loads(response.read().decode())median_mult=response_json['medianFeeMultiplier']minimum_mult=response_json['minFeeMultiplier']fee_mult=max(median_mult,minimum_mult)print(f' Fee multiplier: {fee_mult}')# Enable global restriction if requiredtransactions=[]print("Checking if the global restriction is enabled:")global_restrictions=get_mosaic_global_restrictions(mosaic_id,restriction_key)iflen(global_restrictions)==0:# Enable the global restrictionprint('+ Enabling global restriction')transactions.append(global_restriction_enable_transaction())# Enable the address restrictionprint('+ Authorizing owner account')transactions.append(address_restriction_set_value(0xFFFFFFFF_FFFFFFFF,1,owner_address))# Toggle target address restrictionprint("Checking if target account is authorized:")address_restrictions=get_mosaic_address_restrictions(mosaic_id,target_address,restriction_key)prev_value=0xFFFFFFFF_FFFFFFFFiflen(address_restrictions)>0:prev_value=int(address_restrictions[0]['value'])ifprev_value!=1:# Enable the address restrictionprint('+ Authorizing target account')transactions.append(address_restriction_set_value(prev_value,1,target_address))else:# Disable the address restrictionprint('+ Deauthorizing target account')transactions.append(address_restriction_set_value(prev_value,0,target_address))# Build an aggregate transactionprint('Bundling',len(transactions),'transaction(s) in an aggregate')transaction=facade.transaction_factory.create({'type':'aggregate_complete_transaction_v3','signer_public_key':owner_key_pair.public_key,'deadline':timestamp.add_hours(2).timestamp,'transactions_hash':facade.hash_embedded_transactions(transactions),'transactions':transactions})transaction.fee=Amount(fee_mult*transaction.size)# Sign, announce and wait for confirmationpayload=facade.transaction_factory.attach_signature(transaction,facade.sign_transaction(owner_key_pair,transaction))transaction_hash=facade.hash_transaction(transaction)announce_transaction(payload,'aggregate')wait_for_confirmation(transaction_hash,'aggregate')# Try to transfer the mosaic to the target addresstransaction=facade.transaction_factory.create({'type':'transfer_transaction_v1','signer_public_key':owner_key_pair.public_key,'deadline':timestamp.add_hours(2).timestamp,'recipient_address':target_address,'mosaics':[{'mosaic_id':mosaic_id,'amount':1}]})transaction.fee=Amount(fee_mult*transaction.size)payload=facade.transaction_factory.attach_signature(transaction,facade.sign_transaction(owner_key_pair,transaction))transaction_hash=facade.hash_transaction(transaction)print('\nAttempting transfer to the target account')announce_transaction(payload,'test transfer')wait_for_confirmation(transaction_hash,'test transfer')exceptExceptionase:print(e)
import{PrivateKey}from'symbol-sdk';import{KeyPair,mosaicRestrictionGenerateKey,SymbolTransactionFactory,models,NetworkTimestamp,SymbolFacade}from'symbol-sdk/symbol';constNODE_URL=process.env.NODE_URL||'https://reference.symboltest.net:3001';console.log('Using node',NODE_URL);// Helper function to announce a transactionasyncfunctionannounceTransaction(payload,label){console.log(`Announcing ${label} to /transactions`);constresponse=awaitfetch(`${NODE_URL}/transactions`,{method:'PUT',headers:{'Content-Type':'application/json'},body:payload});console.log(' Response:',awaitresponse.text());}// Helper function to wait for transaction confirmationasyncfunctionwaitForConfirmation(transactionHash,label){console.log(`Waiting for ${label} confirmation...`);for(letattempt=0;attempt<60;attempt++){awaitnewPromise(resolve=>setTimeout(resolve,1000));try{constresponse=awaitfetch(`${NODE_URL}/transactionStatus/${transactionHash}`);conststatus=awaitresponse.json();console.log(' Transaction status:',status.group);if(status.group==='confirmed'){console.log(`${label} confirmed in`,attempt,'seconds');return;}if(status.group==='failed'){thrownewError(`${label} failed: ${status.code}`);}}catch(e){if(e.message.includes('failed'))throwe;console.log(' Transaction status: unknown');}}thrownewError(`${label} not confirmed after 60 seconds`);}// Returns a filtered list of restrictions currently applied to the mosaic// matching the given restriction keyasyncfunctiongetMosaicRestrictions(query,key){constrestrictionsPath=`/restrictions/mosaic?${query}`;console.log(` Getting restrictions from ${restrictionsPath}`);letres=[];try{constresponse=awaitfetch(`${NODE_URL}${restrictionsPath}`);conststatus=awaitresponse.json();constdata=status.data;if(data.length>0){// Look at the first returned restrictionconstrlist=data[0].mosaicRestrictionEntry.restrictions;// Filter by keyres=rlist.filter(r=>BigInt(r.key)===key);}}catch{// The mosaic has no restrictions applied to this key}console.log(' Response:',res);returnres;}functiongetMosaicGlobalRestrictions(mosaicId,key){returngetMosaicRestrictions(`mosaicId=${mosaicId.toString(16)}&entryType=1`,key);}functiongetMosaicAddressRestrictions(mosaicId,address,key){returngetMosaicRestrictions(`mosaicId=${mosaicId.toString(16)}&entryType=0`+`&targetAddress=${address}`,key);}// Returns a transaction enabling a mosaic's global restrictionfunctionglobalRestrictionEnableTransaction(){consttransaction=facade.transactionFactory.createEmbedded({type:'mosaic_global_restriction_transaction_v1',signerPublicKey:ownerKeyPair.publicKey,mosaicId,referenceMosaicId:0n,restrictionKey,previousRestrictionType:0,previousRestrictionValue:0n,newRestrictionType:'ge',newRestrictionValue:1n});console.dir(transaction.toJson(),{colors:true,depth:null});returntransaction;}// Returns a transaction setting an address restriction's valuefunctionaddressRestrictionSetValue(prevValue,newValue,address){consttransaction=facade.transactionFactory.createEmbedded({type:'mosaic_address_restriction_transaction_v1',signerPublicKey:ownerKeyPair.publicKey,mosaicId,restrictionKey,previousRestrictionValue:prevValue,newRestrictionValue:newValue,targetAddress:address});console.dir(transaction.toJson(),{colors:true,depth:null});returntransaction;}constfacade=newSymbolFacade('testnet');constOWNER_PRIVATE_KEY=process.env.OWNER_PRIVATE_KEY||'0000000000000000000000000000000000000000000000000000000000000000';constownerKeyPair=newKeyPair(newPrivateKey(OWNER_PRIVATE_KEY));constownerAddress=facade.network.publicKeyToAddress(ownerKeyPair.publicKey);console.log(`Owner address: ${ownerAddress}`);consttargetAddress=process.env.TARGET_ADDRESS||'TB6QOVCUOFRCF5QJSKPIQMLUVWGJS3KYFDETRPA';console.log(`Target address: ${targetAddress}`);constmosaicId=BigInt('0x'+(process.env.MOSAIC_ID||'6A5ACF2376E50D4A'));console.log(`Mosaic ID: 0x${mosaicId.toString(16).toUpperCase()}`);constrestrictionName=process.env.RESTRICTION_NAME||'security_level';constrestrictionKey=mosaicRestrictionGenerateKey(restrictionName);console.log(`Restriction name: "${restrictionName}" (key: 0x${restrictionKey.toString(16).toUpperCase().padStart(16,'0')})`);try{// Fetch current network timeconsttimePath='/node/time';console.log('Fetching current network time from',timePath);consttimeResponse=awaitfetch(`${NODE_URL}${timePath}`);consttimeJSON=awaittimeResponse.json();consttimestamp=newNetworkTimestamp(timeJSON.communicationTimestamps.receiveTimestamp);console.log(' Network time:',timestamp.timestamp,'ms since nemesis');// Fetch recommended feesconstfeePath='/network/fees/transaction';console.log('Fetching recommended fees from',feePath);constfeeResponse=awaitfetch(`${NODE_URL}${feePath}`);constfeeJSON=awaitfeeResponse.json();constmedianMult=feeJSON.medianFeeMultiplier;constminimumMult=feeJSON.minFeeMultiplier;constfeeMult=Math.max(medianMult,minimumMult);console.log(' Fee multiplier:',feeMult);// Enable global restriction if requiredconsttransactions=[];console.log('Checking if the global restriction is enabled:');constglobalRestrictions=awaitgetMosaicGlobalRestrictions(mosaicId,restrictionKey);if(globalRestrictions.length===0){// Enable the global restrictionconsole.log('+ Enabling global restriction');transactions.push(globalRestrictionEnableTransaction());// Enable the address restrictionconsole.log('+ Authorizing owner account');transactions.push(addressRestrictionSetValue(0xFFFFFFFFFFFFFFFFn,1n,ownerAddress.toString()));}// Toggle target address restrictionconsole.log('Checking if target account is authorized:');constaddressRestrictions=awaitgetMosaicAddressRestrictions(mosaicId,targetAddress,restrictionKey);letprevValue=0xFFFFFFFFFFFFFFFFn;if(addressRestrictions.length>0)prevValue=BigInt(addressRestrictions[0].value);if(prevValue!==1n){// Enable the address restrictionconsole.log('+ Authorizing target account');transactions.push(addressRestrictionSetValue(prevValue,1n,targetAddress));}else{// Disable the address restrictionconsole.log('+ Deauthorizing target account');transactions.push(addressRestrictionSetValue(prevValue,0n,targetAddress));}// Build an aggregate transactionconsole.log('Bundling',transactions.length,'transaction(s) in an aggregate');constaggregate=facade.transactionFactory.create({type:'aggregate_complete_transaction_v3',signerPublicKey:ownerKeyPair.publicKey,deadline:timestamp.addHours(2).timestamp,transactionsHash:facade.static.hashEmbeddedTransactions(transactions),transactions});aggregate.fee=newmodels.Amount(feeMult*aggregate.size);// Sign, announce and wait for confirmationletpayload=SymbolTransactionFactory.attachSignature(aggregate,facade.signTransaction(ownerKeyPair,aggregate));lethash=facade.hashTransaction(aggregate).toString();awaitannounceTransaction(payload,'aggregate');awaitwaitForConfirmation(hash,'aggregate');// Try to transfer the mosaic to the target addressconsttransfer=facade.transactionFactory.create({type:'transfer_transaction_v1',signerPublicKey:ownerKeyPair.publicKey,deadline:timestamp.addHours(2).timestamp,recipientAddress:targetAddress,mosaics:[{mosaicId,amount:1n}]});transfer.fee=newmodels.Amount(feeMult*transfer.size);payload=SymbolTransactionFactory.attachSignature(transfer,facade.signTransaction(ownerKeyPair,transfer));hash=facade.hashTransaction(transfer).toString();console.log('\nAttempting transfer to the target account');awaitannounceTransaction(payload,'test transfer');awaitwaitForConfirmation(hash,'test transfer');}catch(e){console.error(e.message);}
# Fetch current network timetime_path='/node/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())receive_timestamp=(response_json['communicationTimestamps']['receiveTimestamp'])timestamp=NetworkTimestamp(int(receive_timestamp))print(f' Network time: {timestamp.timestamp} ms since nemesis')# Fetch recommended feesfee_path='/network/fees/transaction'print(f'Fetching recommended fees from {fee_path}')withurllib.request.urlopen(f'{NODE_URL}{fee_path}')asresponse:response_json=json.loads(response.read().decode())median_mult=response_json['medianFeeMultiplier']minimum_mult=response_json['minFeeMultiplier']fee_mult=max(median_mult,minimum_mult)print(f' Fee multiplier: {fee_mult}')
# Enable global restriction if requiredtransactions=[]print("Checking if the global restriction is enabled:")global_restrictions=get_mosaic_global_restrictions(mosaic_id,restriction_key)iflen(global_restrictions)==0:# Enable the global restrictionprint('+ Enabling global restriction')transactions.append(global_restriction_enable_transaction())# Enable the address restrictionprint('+ Authorizing owner account')transactions.append(address_restriction_set_value(0xFFFFFFFF_FFFFFFFF,1,owner_address))
// Enable global restriction if requiredconsttransactions=[];console.log('Checking if the global restriction is enabled:');constglobalRestrictions=awaitgetMosaicGlobalRestrictions(mosaicId,restrictionKey);if(globalRestrictions.length===0){// Enable the global restrictionconsole.log('+ Enabling global restriction');transactions.push(globalRestrictionEnableTransaction());// Enable the address restrictionconsole.log('+ Authorizing owner account');transactions.push(addressRestrictionSetValue(0xFFFFFFFFFFFFFFFFn,1n,ownerAddress.toString()));}
defget_mosaic_restrictions(query,key):restrictions_path=f'/restrictions/mosaic?{query}'print(f' Getting restrictions from {restrictions_path}')res=[]try:url=f'{NODE_URL}{restrictions_path}'withurllib.request.urlopen(url)asresponse:status=json.loads(response.read().decode())data=status['data']iflen(data)>0:# Look at the first returned restrictionrlist=data[0]['mosaicRestrictionEntry']['restrictions']# Filter by keyres=[rforrinrlistifint(r['key'])==key]excepturllib.error.HTTPError:# The mosaic has no restrictions applied to this keypassprint(f' Response: {res}')returnresdefget_mosaic_global_restrictions(mosaic_id,key):returnget_mosaic_restrictions(f'mosaicId={mosaic_id:X}&entryType=1',key)defget_mosaic_address_restrictions(mosaic_id,address,key):returnget_mosaic_restrictions(f'mosaicId={mosaic_id:X}&entryType=0&targetAddress={address}',key)
asyncfunctiongetMosaicRestrictions(query,key){constrestrictionsPath=`/restrictions/mosaic?${query}`;console.log(` Getting restrictions from ${restrictionsPath}`);letres=[];try{constresponse=awaitfetch(`${NODE_URL}${restrictionsPath}`);conststatus=awaitresponse.json();constdata=status.data;if(data.length>0){// Look at the first returned restrictionconstrlist=data[0].mosaicRestrictionEntry.restrictions;// Filter by keyres=rlist.filter(r=>BigInt(r.key)===key);}}catch{// The mosaic has no restrictions applied to this key}console.log(' Response:',res);returnres;}functiongetMosaicGlobalRestrictions(mosaicId,key){returngetMosaicRestrictions(`mosaicId=${mosaicId.toString(16)}&entryType=1`,key);}functiongetMosaicAddressRestrictions(mosaicId,address,key){returngetMosaicRestrictions(`mosaicId=${mosaicId.toString(16)}&entryType=0`+`&targetAddress=${address}`,key);}
print("Checking if target account is authorized:")address_restrictions=get_mosaic_address_restrictions(mosaic_id,target_address,restriction_key)prev_value=0xFFFFFFFF_FFFFFFFFiflen(address_restrictions)>0:prev_value=int(address_restrictions[0]['value'])ifprev_value!=1:# Enable the address restrictionprint('+ Authorizing target account')transactions.append(address_restriction_set_value(prev_value,1,target_address))else:# Disable the address restrictionprint('+ Deauthorizing target account')transactions.append(address_restriction_set_value(prev_value,0,target_address))
console.log('Checking if target account is authorized:');constaddressRestrictions=awaitgetMosaicAddressRestrictions(mosaicId,targetAddress,restrictionKey);letprevValue=0xFFFFFFFFFFFFFFFFn;if(addressRestrictions.length>0)prevValue=BigInt(addressRestrictions[0].value);if(prevValue!==1n){// Enable the address restrictionconsole.log('+ Authorizing target account');transactions.push(addressRestrictionSetValue(prevValue,1n,targetAddress));}else{// Disable the address restrictionconsole.log('+ Deauthorizing target account');transactions.push(addressRestrictionSetValue(prevValue,0n,targetAddress));}
print('Bundling',len(transactions),'transaction(s) in an aggregate')transaction=facade.transaction_factory.create({'type':'aggregate_complete_transaction_v3','signer_public_key':owner_key_pair.public_key,'deadline':timestamp.add_hours(2).timestamp,'transactions_hash':facade.hash_embedded_transactions(transactions),'transactions':transactions})transaction.fee=Amount(fee_mult*transaction.size)
console.log('Bundling',transactions.length,'transaction(s) in an aggregate');constaggregate=facade.transactionFactory.create({type:'aggregate_complete_transaction_v3',signerPublicKey:ownerKeyPair.publicKey,deadline:timestamp.addHours(2).timestamp,transactionsHash:facade.static.hashEmbeddedTransactions(transactions),transactions});aggregate.fee=newmodels.Amount(feeMult*aggregate.size);
transaction=facade.transaction_factory.create({'type':'transfer_transaction_v1','signer_public_key':owner_key_pair.public_key,'deadline':timestamp.add_hours(2).timestamp,'recipient_address':target_address,'mosaics':[{'mosaic_id':mosaic_id,'amount':1}]})transaction.fee=Amount(fee_mult*transaction.size)payload=facade.transaction_factory.attach_signature(transaction,facade.sign_transaction(owner_key_pair,transaction))transaction_hash=facade.hash_transaction(transaction)print('\nAttempting transfer to the target account')announce_transaction(payload,'test transfer')wait_for_confirmation(transaction_hash,'test transfer')
consttransfer=facade.transactionFactory.create({type:'transfer_transaction_v1',signerPublicKey:ownerKeyPair.publicKey,deadline:timestamp.addHours(2).timestamp,recipientAddress:targetAddress,mosaics:[{mosaicId,amount:1n}]});transfer.fee=newmodels.Amount(feeMult*transfer.size);payload=SymbolTransactionFactory.attachSignature(transfer,facade.signTransaction(ownerKeyPair,transfer));hash=facade.hashTransaction(transfer).toString();console.log('\nAttempting transfer to the target account');awaitannounceTransaction(payload,'test transfer');awaitwaitForConfirmation(hash,'test transfer');
Using node https://reference.symboltest.net:3001
Owner address: TCHBDENCLKEBILBPWP3JPB2XNY64OE7PYHHE32I
Target address: TB6QOVCUOFRCF5QJSKPIQMLUVWGJS3KYFDETRPA
Mosaic ID: 0x6A5ACF2376E50D4A
Restriction name: "security_level" (key: 0xE08F1643881FD0C1)
Fetching current network time from /node/time
Network time: 109528567086 ms since nemesis
Fetching recommended fees from /network/fees/transaction
Fee multiplier: 100
Checking if the global restriction is enabled:
Getting restrictions from /restrictions/mosaic?mosaicId=6A5ACF2376E50D4A&entryType=1
Response: [{'key': '16181176465467887809', 'restriction': {'referenceMosaicId': '0000000000000000', 'restrictionValue': '1', 'restrictionType': 6}}]
Checking if target account is authorized:
Getting restrictions from /restrictions/mosaic?mosaicId=6A5ACF2376E50D4A&entryType=0&targetAddress=TB6QOVCUOFRCF5QJSKPIQMLUVWGJS3KYFDETRPA
Response: [{'key': '16181176465467887809', 'value': '1'}]
+ Deauthorizing target account
{
"signer_public_key": "3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29",
"version": 1,
"network": 152,
"type": 16977,
"mosaic_id": "7663665467149847882",
"restriction_key": "16181176465467887809",
"previous_restriction_value": "1",
"new_restriction_value": "0",
"target_address": "987D075454716222F609929E883174AD8C996D5828C938BC"
}
Bundling 1 transaction(s) in an aggregate
Announcing aggregate to /transactions
Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for aggregate confirmation...
Transaction status: unconfirmed
Transaction status: unconfirmed
...
Transaction status: confirmed
aggregate confirmed in 21 seconds
Attempting transfer to the target account
Announcing test transfer to /transactions
Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for test transfer confirmation...
Transaction status: failed
test transfer failed: Failure_RestrictionMosaic_Account_Unauthorized