I'm writing a client in Go that needs to scan balance transfers in Substrate chains - initially focused on Polkadot.
My current objective is to determine all balance transfers in a given block, and to record the sender & destination IDs along with the value transferred.
To simplify decoding & storage access I'm using Sidecar.
Balance Transfer Summary
If I understand correctly, balance transfers can be made by methods in the balances
and utility
pallets.
Balance transfer methods in balances
pallet:
transfer
transferAll
transferKeepAlive
Balance transfer methods in utilities
pallet:
batch
batchAll
Data Required
The data I need is the destination ID, sender ID and the value transferred.
In all cases, I am getting the sender ID directly from the Extrinsic signature.
For "standard" balance transfers that use balances.transfer
, this data is present in the Extrinsic. Westend example here
This is not the case for balances.TransferAll
- the Extrinsic does not directly hold data for value
of the transfer - this must be obtained from the balances.Transfer
event for that Extrinsic. Polkadot example here
For batched transactions under the utilities
pallet, data for destination ID and value is obtained by looping over the Extrinsic.Arg.Calls
and inspecting the Args
of any balance transfer methods.
Current Approach
My app scans for Extrinsics that relate to balance transfers.
In the case of a utilities.batch
or utilities.batchAll
:
- Get sender ID from Extrinsic
- Loop over the Extrinsic Calls
- Skip Calls whose methods do not relate to balance transfer (
balances
pallet,transfer
,transferAll
,transferKeepAlive
methods) - Get destination ID and Value for balance transfer events from the call Args
In the case of balances.transfer
, balances.transferAll
or balances.transferKeepAlive
Extrinsics:
- Get sender ID from Extrinsic
- Get destination ID from Extrinsic
- Loop over Extrinsic Events
- Skip those that are not:
balances.Transfer
,balances.TransferAll
,balances.TransferKeepAlive
- Get value from the
data
field of the Event
The data
field of a balance transfer event as provided by Sidecar is an array of unlabeled strings. For example:
{
"method": {
"pallet": "balances",
"method": "Transfer"
},
"data": [
"1qnJN7FViy3HZaxZK9tGAA71zxHSBeUweirKqCaox4t8GT7",
"15uph1CrsXQgZYKFaumLC7wZEgC6gEnB2fZBpcDejt4xaEGd",
"999000000000"
]
},
curl http://path-to-polkadot-mainnet-node-with-sidecar:8080/blocks/11555568 | jq '.extrinsics[3].events[3]'
Question
- Is my understanding of balance transfers correct?
- Am I missing any potential balance transfer events?
Most importantly, can I rely on the third element in a balances transfer array provided by sidecar (as shown above) representing value?
It seems odd that this is not a named field, and it feels hacky accessing this data by means of an array index.
Thanks!