Extrinsics
In Portaldot, transactions are often more broadly referred to as (signed) extrinsics. The term extrinsic is generally used to mean any information that originates outside of the runtime. An extrinsic is basically a vehicle that carries the intention to execute a function call in the runtime, along with proof of the account that wants to execute it.
Creating extrinsics
Example:
call = portaldot.compose_call(
call_module='Balances',
call_function='transfer_keep_alive',
call_params={
'dest': '5E9oDs9PjpsBbxXxRE9uMaZZhnBAV38n2ouLB28oecBDdeQo',
'value': 1 * 10** 14
}
)
extrinsic = portaldot.create_signed_extrinsic(call=call, keypair=keypair)
try:
receipt = portaldot.submit_extrinsic(extrinsic, wait_for_inclusion=True)
print(f"Extrinsic '{receipt.extrinsic_hash}' sent and included in block '{receipt.block_hash}'")
except SubstrateRequestException as e:
print("Failed to send: {}".format(e))
The wait_for_inclusion keyword argument used in the example above
will block giving the result until it gets confirmation from the node
that the extrinsic is succesfully included in a block. The
wait_for_finalization keyword will wait until extrinsic is
finalized. Note this feature is only available for websocket
connections.
Extrinsic Receipts
The portaldot.submit_extrinsic() example above returns an
ExtrinsicReceipt object, which contains information about the
on-chain execution of the extrinsic. Because the block_hash is
necessary to retrieve the triggered events from storage, most
information is only available when wait_for_inclusion=True or
wait_for_finalization=True is used when submitting an extrinsic.
Examples:
receipt = portaldot.submit_extrinsic(extrinsic, wait_for_inclusion=True)
print(receipt.is_success) # False
print(receipt.weight)
print(receipt.total_fee_amount)
print(receipt.error_message['name']) # 'LiquidityRestrictions'
ExtrinsicReceipt objects can also be created for all existing
extrinsics on-chain:
receipt = portaldot.retrieve_extrinsic_by_identifier("5233297-1")
print(receipt.is_success)
print(receipt.extrinsic.call_module.name)
print(receipt.extrinsic.call.name)
print(receipt.weight)
print(receipt.total_fee_amount)
print(receipt.error_message['docs'])
for event in receipt.triggered_events:
print(f'* {event.value}')
Multisig extrinsics
Substrate has the functionality for multi-signature dispatch, allowing multiple signed origins (accounts) to coordinate and dispatch a call, derivable deterministically from the set of account IDs and the threshold number of accounts from the set that must approve it.
To initiate and finalize multisig extrinsics, the following helper functions are available:
Define the multisig account by supplying its signatories and threshold:
keypair_alice = Keypair.create_from_uri('//Alice', ss58_format=portaldot.ss58_format)
multisig_account = portaldot.generate_multisig_account(
signatories=[
keypair_alice.ss58_address,
'5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty',
'5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y'
],
threshold=2
)
Then initiate the multisig extrinsic by providing the call and a keypair of one of its signatories:
call = portaldot.compose_call(
call_module='System',
call_function='remark_with_event',
call_params={
'remark': 'Multisig test'
}
)
extrinsic = portaldot.create_multisig_extrinsic(call, keypair_alice, multisig_account, era={'period': 64})
receipt = portaldot.submit_extrinsic(extrinsic, wait_for_inclusion=True)
Then a second signatory approves and finalizes the call by providing the same call to another multisig extrinsic:
# Define the multisig account by supplying its signatories and threshold
keypair_charlie = Keypair.create_from_uri('//Charlie', ss58_format=portaldot.ss58_format)
multisig_account = portaldot.generate_multisig_account(
signatories=[
keypair_charlie.ss58_address,
'5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
'5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y'
],
threshold=2
)
extrinsic = portaldot.create_multisig_extrinsic(call, keypair_charlie, multisig_account, era={'period': 64})
receipt = portaldot.submit_extrinsic(extrinsic, wait_for_inclusion=True)
The call will be executed when the second and final multisig extrinsic is submitted, condition and state of the multig will be checked on-chain during processing of the multisig extrinsic.
Type decomposition of call params
The structure of certain call parameters can be quite complex, then the
get_param_info() function of the call function object can provide
more insight how to construct those parameters:
call_function = portaldot.get_metadata_call_function("POT", "transfer")
param_info = call_function.get_param_info()
Estimate of network fees
payment_info = portaldot.get_payment_info(call=call, keypair=keypair)
Mortal extrinsics
By default, immortal extrinsics are created, which means they have an indefinite lifetime for being included in a block. However, it is recommended to use specify an expiry window, so you know after a certain amount of time if the extrinsic is not included in a block, it will be invalidated.
extrinsic = portaldot.create_signed_extrinsic(call=call, keypair=keypair, era={'period': 64})
The period specifies the number of blocks the extrinsic is valid
counted from current head.