Python SDK: A Beginners Guide to NEM Transactions

Following on from my previous post about writing Symbol transactions in Python I have a short post showing how NEM transactions can be sent using the Python SDK. I haven’t covered all transaction types but this should give an idea of how to get started. As usual, these examples all use testnet and therefore I have included Alice’s private key (never share your own!).

Note: This was written a while ago – if there are any issues then let me know 😊

Transfer transaction

Simple transfers, with and without messages can also be sent on the NEM network using the Python SDK. In this example, Alice sends a transfer of 1 XEM to Bob with a plain message. It uses transfer_transaction_v1 meaning that the mosaic sent is set to nem.xem by default, only the amount field needs to be specified to transfer funds.

Transaction

Code

from symbolchain.nem.KeyPair import KeyPair
from symbolchain.facade.NemFacade import NemFacade
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.nem.Network import NetworkTimestamp
from binascii import unhexlify, hexlify
import requests
import datetime
import json


facade = NemFacade('testnet')

# Replace with your private key
alicePrivateKey = PrivateKey(unhexlify('9A243BD88D1F3EA4B46264EF0505EFE102A46E58E4EC100407DA5F5AAD08BC0A'))

# Replace with the recipient address
bobAddress = 'TBNEN3NVDMKRDVMLIVDVAS4SLZMJRIBWFWOCERZV'

# Replace with node URL and connection port
node_url = 'http://95.216.73.245:7890'

# Set URLs for obtaining network time and to post transactions to
post_string = node_url + '/transaction/announce'
time_string = node_url + '/time-sync/network-time'

# Obtain network time
networkTimeRequest = requests.get(time_string)
# Convert from milliseconds to seconds
networkTime = NetworkTimestamp(int(networkTimeRequest.json()['sendTimeStamp'] / 1000))
# Set the deadline to 1 hour in the future
deadline = networkTime.add_hours(1).timestamp


aliceKeypair = NemFacade.KeyPair(alicePrivateKey)
alicePubkey = aliceKeypair.public_key
aliceAddress = facade.network.public_key_to_address(alicePubkey)

# Create a transfer transaction
transfer = facade.transaction_factory.create({
    'type': 'transfer_transaction_v1',
    'signer_public_key': alicePubkey,
		'recipient_address': bobAddress, # Send to Bob
    'deadline': deadline,
    'message': {
    			'message_type': 'plain', # Plain message type
    			'message': 'Hello Bob! Here is 1 XEM - transfer tx v1!' #message
    			},
	'amount': 1000000, # Send 1 XEM
	'fee': 200000, # Add a 0.2 XEM fee
	'timestamp': networkTime.timestamp # Add network time stamp
})

# Sign the transaction and attach the signature
signature = facade.sign_transaction(aliceKeypair, transfer)
tx = facade.transaction_factory.attach_signature(transfer, signature)

# Announce the transaction to the network
r = requests.post(post_string, json=json.loads(tx))
print(f"Status Code: {r.status_code}, Response: {r.json()}")

Transfer transaction (v2)

Using transfer_transaction_v2 we can set custom mosaic(s) to send in the transaction. In this example, Alice sends 1 nem.xem and 1 test1.testmosaic to Bob with an associated message.

Transaction

Code

from symbolchain.nem.KeyPair import KeyPair
from symbolchain.facade.NemFacade import NemFacade
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.nem.Network import NetworkTimestamp
from binascii import unhexlify, hexlify
import requests
import datetime
import json

facade = NemFacade('testnet')

# Replace with your private key
alicePrivateKey = PrivateKey(unhexlify('9A243BD88D1F3EA4B46264EF0505EFE102A46E58E4EC100407DA5F5AAD08BC0A'))

# Replace with the recipient address
bobAddress = 'TBNEN3NVDMKRDVMLIVDVAS4SLZMJRIBWFWOCERZV'

# Replace with node URL and connection port
node_url = 'http://95.216.73.245:7890'

# Set URLs for obtaining network time and to post transactions to
post_string = node_url + '/transaction/announce'
time_string = node_url + '/time-sync/network-time'

# Obtain network time
networkTimeRequest = requests.get(time_string)
# Convert from milliseconds to seconds
networkTime = NetworkTimestamp(int(networkTimeRequest.json()['sendTimeStamp'] / 1000))
# Set the deadline to 1 hour in the future
deadline = networkTime.add_hours(1).timestamp

aliceKeypair = NemFacade.KeyPair(alicePrivateKey)
alicePubkey = aliceKeypair.public_key
aliceAddress = facade.network.public_key_to_address(alicePubkey)

# Create a transfer transaction. version 2
transfer = facade.transaction_factory.create({
    'type': 'transfer_transaction_v2',
    'signer_public_key': alicePubkey,
		'recipient_address': bobAddress, # Bob's address
		'deadline': deadline,
    'message': {
    			'message_type': 'plain', # Plain message
    			'message': 'Hello Bob! Here is 1 XEM and 1 testmosaic! - transfer tx v2'
    			},
		# Set mosaics to send
		'mosaics': [{'mosaic':
					# Send 1 XEM
					{'mosaic_id': {'namespace_id': {'name': b'nem'}, 'name': b'xem'},
					'amount': 1000000}
				},
				# Send 10 "testmosaic" mosaics linked to the namespace "test1"
				{'mosaic':
					{'mosaic_id': {'namespace_id': {'name': b'test1'}, 'name': b'testmosaic'},
					'amount': 1}
				}
			],
	'fee': 200000, # Add a 0.2 XEM fee
	'timestamp': networkTime.timestamp # Add network timestamp
})

# Sign the transaction and attach signature
signature = facade.sign_transaction(aliceKeypair, transfer)
tx = facade.transaction_factory.attach_signature(transfer, signature)

# Announce the transaction to the network
r = requests.post(post_string, json=json.loads(tx))
print(f"Status Code: {r.status_code}, Response: {r.json()}")

Namespace definition

NEM namespaces can be rented for a set time period of 1 year for the cost of 100 XEM and can be renewed before expiry. In the transaction below Alice registers a new namespace “newnamespace” and sends the rental fee to the namespace sink address for testnet TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35.

Code

from symbolchain.nem.KeyPair import KeyPair
from symbolchain.facade.NemFacade import NemFacade
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.nem.Network import NetworkTimestamp
from binascii import unhexlify, hexlify
import requests
import datetime
import json


facade = NemFacade('testnet')

# Replace with your private key
alicePrivateKey = PrivateKey(unhexlify('9A243BD88D1F3EA4B46264EF0505EFE102A46E58E4EC100407DA5F5AAD08BC0A'))

# Replace with the recipient address
bobAddress = 'TBNEN3NVDMKRDVMLIVDVAS4SLZMJRIBWFWOCERZV'

# Replace with node URL and connection port
node_url = 'http://95.216.73.245:7890'

# Set URLs for obtaining network time and to post transactions to
post_string = node_url + '/transaction/announce'
time_string = node_url + '/time-sync/network-time'

# Obtain network time
networkTimeRequest = requests.get(time_string)
# Convert from milliseconds to seconds
networkTime = NetworkTimestamp(int(networkTimeRequest.json()['sendTimeStamp'] / 1000))
# Set the deadline to 1 hour in the future
deadline = networkTime.add_hours(1).timestamp

aliceKeypair = NemFacade.KeyPair(alicePrivateKey)
alicePubkey = aliceKeypair.public_key
aliceAddress = facade.network.public_key_to_address(alicePubkey)

# Create a namespace transaction
namespace_def = facade.transaction_factory.create({
    'type': 'namespace_registration_transaction_v1',
    'signer_public_key': alicePubkey,
    'deadline': deadline,
		'rental_fee': 100000000, # Set 100 XEM rental fee
		'fee': 200000, # 0.2 XEM fee for the transaction
		'name': 'newnamespace', # Name the namespace "newnamespace"
		# Set the namespace rental fee sink address (this is the address for testnet)
		'rental_fee_sink': 'TAMESPACEWH4MKFMBCVFERDPOOP4FK7MTDJEYP35', 
		'timestamp': networkTime.timestamp # Add timestamp
})

# Sign the transaction and attach signature
signature = facade.sign_transaction(aliceKeypair, namespace_def)
tx = facade.transaction_factory.attach_signature(namespace_def, signature)

# Announce the transaction to the network
r = requests.post(post_string, json=json.loads(tx))
print(f"Status Code: {r.status_code}, Response: {r.json()}")

Mosaic definition

Like Symbol, NEM mosaics can be created. However, NEM mosaics must be associated with a namespace when they are registered and therefore will expire unless the parent namespace is renewed. In the example below Alice pays a flat fee of 10 XEM to the testnet mosaic sink address TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC. She creates the new mosaic “awesome_mosaic” which is associated with the namespace she created above “newnamespace”. Resulting in the mosaic newnamespace.awesome_mosaic.

Code

from symbolchain.nem.KeyPair import KeyPair
from symbolchain.facade.NemFacade import NemFacade
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.nem.Network import NetworkTimestamp
from binascii import unhexlify, hexlify
import requests
import datetime
import json


facade = NemFacade('testnet')

# Replace with your private key
alicePrivateKey = PrivateKey(unhexlify('9A243BD88D1F3EA4B46264EF0505EFE102A46E58E4EC100407DA5F5AAD08BC0A'))

# Replace with the recipient address
bobAddress = 'TBNEN3NVDMKRDVMLIVDVAS4SLZMJRIBWFWOCERZV'

# Replace with node URL and connection port
node_url = 'http://95.216.73.245:7890'

# Set URLs for obtaining network time and to post transactions to
post_string = node_url + '/transaction/announce'
time_string = node_url + '/time-sync/network-time'

# Obtain network time
networkTimeRequest = requests.get(time_string)
# Convert from milliseconds to seconds
networkTime = NetworkTimestamp(int(networkTimeRequest.json()['sendTimeStamp'] / 1000))
# Set the deadline to 1 hour in the future
deadline = networkTime.add_hours(1).timestamp

aliceKeypair = NemFacade.KeyPair(alicePrivateKey)
alicePubkey = aliceKeypair.public_key
aliceAddress = facade.network.public_key_to_address(alicePubkey)

# Create a NEM mosaic transaction
nem_mosaic = facade.transaction_factory.create({
    'type': 'mosaic_definition_transaction_v1',
    'signer_public_key': alicePubkey,
    'deadline': deadline,
		'rental_fee': 10000000, # Add 10 XEM rental fee
		'fee': 200000, # Add 0.2 XEM transaction fee
		# Set the mosaic sink address for testnet
		'rental_fee_sink': 'TBMOSAICOD4F54EE5CDMR23CCBGOAM2XSJBR5OLC',
		'timestamp': networkTime.timestamp, # Add timestamp
		'mosaic_definition': {
			'owner_public_key': alicePubkey,
			# Create the mosaic "awesome mosaic" and assign this to "newnamespace"
			'id': {'namespace_id': {'name': b'newnamespace'}, 'name': b'awesome_mosaic'},
			# Add a mosaic description
			'description': b'Just testing',
			# Set mosaic properties:
			# Divisibility = 0
			# Initial supply = 1000
			# Supply mutable = True
			# Transferable = True
			'properties': [
				{'property_': {'name': b'divisibility', 'value': b'0'}},
				{'property_': {'name': b'initialSupply', 'value': b'1000'}},
				{'property_': {'name': b'supplyMutable', 'value': b'true'}},
				{'property_': {'name': b'transferable', 'value': b'true'}}
				]
			}
})

# Sign the transaction and attach signature
signature = facade.sign_transaction(aliceKeypair, nem_mosaic)
tx = facade.transaction_factory.attach_signature(nem_mosaic, signature)

# Announce the transaction to the network
r = requests.post(post_string, json=json.loads(tx))
print(f"Status Code: {r.status_code}, Response: {r.json()}")

Mosaic supply change

Mosaic supply can be changed by the owner if the mosaic is created as mutable. In the example below Alice increases the supply of newnamespace.awesome_mosaic by 100 units. As mentioned previously, make sure to check the divisibility of the mosaic before setting the delta value. In this case the mosaic has a divisibility of 0 so 100 new tokens were created. The supply can be reduced by setting the action value to decrease.

Code

from symbolchain.nem.KeyPair import KeyPair
from symbolchain.facade.NemFacade import NemFacade
from symbolchain.CryptoTypes import PrivateKey
from symbolchain.nem.Network import NetworkTimestamp
from binascii import unhexlify, hexlify
import requests
import datetime
import json


facade = NemFacade('testnet')

# Replace with your private key
alicePrivateKey = PrivateKey(unhexlify('9A243BD88D1F3EA4B46264EF0505EFE102A46E58E4EC100407DA5F5AAD08BC0A'))

# Replace with the recipient address
bobAddress = 'TBNEN3NVDMKRDVMLIVDVAS4SLZMJRIBWFWOCERZV'

# Replace with node URL and connection port
node_url = 'http://95.216.73.245:7890'

# Set URLs for obtaining network time and to post transactions to
post_string = node_url + '/transaction/announce'
time_string = node_url + '/time-sync/network-time'

# Obtain network time
networkTimeRequest = requests.get(time_string)
# Convert from milliseconds to seconds
networkTime = NetworkTimestamp(int(networkTimeRequest.json()['sendTimeStamp'] / 1000))
# Set the deadline to 1 hour in the future
deadline = networkTime.add_hours(1).timestamp

aliceKeypair = NemFacade.KeyPair(alicePrivateKey)
alicePubkey = aliceKeypair.public_key
aliceAddress = facade.network.public_key_to_address(alicePubkey)

# Create a NEM mosaic modification transaction
nem_mosaic_mod = facade.transaction_factory.create({
    'type': 'mosaic_supply_change_transaction_v1',
    'signer_public_key': alicePubkey,
    'deadline': deadline,
		'fee': 200000, # Transaction fee
		'timestamp': networkTime.timestamp, # Network timestamp
		'mosaic_id': {
			# Specify the mosaic name to be modified and the namespace that it is
			# associated with
			'namespace_id': {'name': b'newnamespace'}, 
			'name': b'super_awesome_mosaic'
			},
		'action': 'increase', # Increase the number of units (can also be decreased)
		'delta': 100 # Number of units to add/remove
})

# Sign the transaction and attach signature
signature = facade.sign_transaction(aliceKeypair, nem_mosaic_mod)
tx = facade.transaction_factory.attach_signature(nem_mosaic_mod, signature)

# Announce the transaction to the network
r = requests.post(post_string, json=json.loads(tx))
print(f"Status Code: {r.status_code}, Response: {r.json()}")

Tags:
Avatar photo
NineLives
admin@symbolblog.com

I'm a Symbol and NEM enthusiast and run this blog to try to grow awareness of the platform in the English-speaking world. If you have any Symbol news you would like me to report on or you have an article that you would like to publish then please let me know!

No Comments

Post A Comment

two × 1 =