Multisig extrinsics
Organizations can protect their wallets with multi-signature wallets
A multisignature wallet account requires several wallet accounts to sign off on any transaction that might take place. This is very useful for organizations - it increases security and distributes control of the account from one password to multiple passwords.
There are tutorials on how to create and use multisig accounts at polkadot.js
In this tutorial, we will look at the extrinsics that are created during a multisig event on chain. There are three events
- Multisig.as_multi
- Multisig.approve_as_multi
- Multisig.cancel_as_multi
The three stages of a multisig operation
- Start of the operation: Either
Multisig.as_multi
orMultisig.approve_as_multi
may kick off the operation.- In this step a
threshold
is set. This is the number of sigs required for the operation to be completed.- If the
Multisig.as_multi
is called,[args][call]
describes the extrinsics to be processed on chain upon completion. - If the
Multisig.approve_as_multi
is called, `[args][callHash]
is a hash that describes the extrinsics to be completed.
- If the
- A fee is paid when completing a multisig process. This will be deducted from the coldkey of the wallet starting the multisig process.
- In this step a
- Collect signatures In this step, subsequent calls are collected to reach the threshold. These can be
Multisig.as_multi
orMultisig.approve_as_multi
calls.- These transactions contain a
maybeTimepoint
argument with two parameters to connect with the inital multisig call.height
the block number of the original call.index
The exttrinsic index of the original call.
- These transactions contain a
- Complete the operation. Either
Multisig.as_multi
orMultisig.cancel
completes the operation.Multisig.as_multi
- completes the operation as successful. The threshold has been reached, and the calls denoted will now be run on chain.Multisig.cancel_as_multi
- as probably expected, this will cancel.- Cancel extrinsics have the
timepoint
extrinsic that matches themaybeTimepoint
from the collection step. On a cancel step, this is required, so it is not "maybe" included in the extrinsic. - The fee is refunded to the key that kicked off the process.
- Cancel extrinsics have the
Examples
Example 1:
In this example - more than threshold
calls are made - because the last call must be a as_multi
. This multisig is being used to transfer 13.2 tao.
Initial call
See it on Taostats: 4472647-0009
{
"id": "4472647-0009",
"extrinsic_id": "4472647-0009",
"parent_id": null,
"extrinsic_index": 9,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "approve_as_multi",
"full_name": "Multisig.approve_as_multi",
"args": {
"callHash": "0x536a4ae2fe64d59a3b8a4fa4f9db38c728aa1f8216570d69b1be6274b6b50fdc",
"maxWeight": {
"proofSize": "0",
"refTime": "0"
},
"otherSignatories": [
"0x34fff9eeda79435aba922eb7af06924065d9a96f516093bc6801009c4317ae56",
"0xd0a9c979be7514edc82b8f41d096212f8d5a2aacce2ddfe87a7f8ed1d9e06e55"
],
"threshold": 2
},
"origin": {
"__kind": "system",
"value": {
"__kind": "Signed",
"value": "0xa2d7f3250155801ebfae9c5cc0d522a479d9110499630409be004a5b53838c34"
}
},
"origin_address": "0xa2d7f3250155801ebfae9c5cc0d522a479d9110499630409be004a5b53838c34",
"timestamp": "2024-12-13T13:18:00Z",
"block_number": 4472647
},
In this initial call, the approve_as_multi
is called. The signer of the extrinsic can be found in origin_address
. There is a threshold
of two - meaning one additional signature is required (and there are two args/otherSignatories
that are eligible to complete the process).
Second call
See it on Taostats: 4472648-0009
{
"id": "4472648-0009",
"extrinsic_id": "4472648-0009",
"parent_id": null,
"extrinsic_index": 9,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "approve_as_multi",
"full_name": "Multisig.approve_as_multi",
"args": {
"callHash": "0x536a4ae2fe64d59a3b8a4fa4f9db38c728aa1f8216570d69b1be6274b6b50fdc",
"maxWeight": {
"proofSize": "0",
"refTime": "0"
},
"maybeTimepoint": {
"height": 4472647,
"index": 9
},
"otherSignatories": [
"0x34fff9eeda79435aba922eb7af06924065d9a96f516093bc6801009c4317ae56",
"0xa2d7f3250155801ebfae9c5cc0d522a479d9110499630409be004a5b53838c34"
],
"threshold": 2
},
"origin": {
"__kind": "system",
"value": {
"__kind": "Signed",
"value": "0xd0a9c979be7514edc82b8f41d096212f8d5a2aacce2ddfe87a7f8ed1d9e06e55"
}
},
"origin_address": "0xd0a9c979be7514edc82b8f41d096212f8d5a2aacce2ddfe87a7f8ed1d9e06e55",
"timestamp": "2024-12-13T13:18:12Z",
"block_number": 4472648
}
The second call is also approve_as_multi
. It is matched to the first call by the extrinsic:
"maybeTimepoint": {
"height": 4472647,
"index": 9
},
We can see that the origin_address
matches one of the other_signatories in the first call.
Threshold
The threshold for this Multisig process is 2, and this is the 2nd signature.
BUT The final multisig event must be a Multisig.as_multi. So this extrinsic does not complete the Multisig.
Third call
See it on Taostats: 4472650-0006
{
"id": "4472650-0006",
"extrinsic_id": "4472650-0006",
"parent_id": null,
"extrinsic_index": 6,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "as_multi",
"full_name": "Multisig.as_multi",
"args": {
"call": {
"__kind": "Utility",
"value": {
"__kind": "batch_all",
"calls": [
{
"__kind": "Balances",
"value": {
"__kind": "transfer_keep_alive",
"dest": {
"__kind": "Id",
"value": "0xf02df68b1a1a9f72d868ee45c53e3a215abaaa1bb01b1f400aee16829547554e"
},
"value": "13268437943"
}
},
{
"__kind": "System",
"value": {
"__kind": "remark",
"remark": "0x312d3078343061356638666237633661383839643765343563396636346566343830326233313238363831383932613633636439616633376330666539393263626334352d313934"
}
}
]
}
},
"maxWeight": {
"proofSize": "8811",
"refTime": "322610689"
},
"maybeTimepoint": {
"height": 4472647,
"index": 9
},
"otherSignatories": [
"0x34fff9eeda79435aba922eb7af06924065d9a96f516093bc6801009c4317ae56",
"0xd0a9c979be7514edc82b8f41d096212f8d5a2aacce2ddfe87a7f8ed1d9e06e55"
],
"threshold": 2
},
"origin": {
"__kind": "system",
"value": {
"__kind": "Signed",
"value": "0xa2d7f3250155801ebfae9c5cc0d522a479d9110499630409be004a5b53838c34"
}
},
"origin_address": "0xa2d7f3250155801ebfae9c5cc0d522a479d9110499630409be004a5b53838c34",
"timestamp": "2024-12-13T13:18:36.001Z",
"block_number": 4472650
}
This is a multisig.as_multi
and can conclude the multisig process. Note that the origin_address
matches the otherSignatories
from the previous calls, and the maybeTimepoint
also references the original multisig call.
We can finally see the extrinsics to be processed. A transfer of 13268437943
rao (13.27 tao) to wallet address 0xf02df68b1a1a9f72d868ee45c53e3a215abaaa1bb01b1f400aee16829547554e
will be processed now that the multisig has been completed.
Example 2:
in this example, the owners of Subnet 52 are setting the maximum registration cost to 8 tao.
First call:
This call sets the threshold at 2, and lists 3 other possible signers of the multisig:
See it on Taostats: 4470399-0007
"id": "4470399-0007",
"extrinsic_id": "4470399-0007",
"parent_id": null,
"extrinsic_index": 7,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "approve_as_multi",
"full_name": "Multisig.approve_as_multi",
"args": {
"callHash": "0x6a26028b812fbabfc55b511ad30d43d494f422380bda41bf770752a0d97fad84",
"maxWeight": {
"proofSize": "4697",
"refTime": "171339000"
},
"otherSignatories": [
"0x4aac8da05fd543a7289230071e07cf84472e879ee6f05a580c560eed0371aa78",
"0x8ad144093c8b47c08d87a4e2c720f27a1261257ef38a206b2c32b873fb2a0540",
"0x96f712f459001d62d24425d0515d406cc974485fc1184c6ff3de08ecfdcd1658"
],
"threshold": 2
},
"origin": {
"__kind": "system",
"value": {
"__kind": "Signed",
"value": "0x7843fc4a1bcb721d7dd67e613c33936ecc46dc898662f8bbd5554d9a53c6014e"
}
},
"origin_address": "0x7843fc4a1bcb721d7dd67e613c33936ecc46dc898662f8bbd5554d9a53c6014e",
"timestamp": "2024-12-13T05:48:24Z",
"block_number": 4470399
}
Second call:
The maybeTimepoint
matches the block/extrinisic of the first call. It is an as_multi
call, and meets the threshold, so will complete the extrinsic.
This call also exposes the calls that will be processed on chain - Admin.sudo_set_max_burn
, which is used to set the max registration cost for a subnet. In thi9s case, SN 52 now has a maximum registration of 8 tao.
See it on Taostats: 4470428-0008
{
"id": "4470428-0008",
"extrinsic_id": "4470428-0008",
"parent_id": null,
"extrinsic_index": 8,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "as_multi",
"full_name": "Multisig.as_multi",
"args": {
"call": {
"__kind": "AdminUtils",
"value": {
"__kind": "sudo_set_max_burn",
"maxBurn": "800000000",
"netuid": 52
}
},
"maxWeight": {
"proofSize": "4697",
"refTime": "171339000"
},
"maybeTimepoint": {
"height": 4470399,
"index": 7
},
"otherSignatories": [
"0x7843fc4a1bcb721d7dd67e613c33936ecc46dc898662f8bbd5554d9a53c6014e",
"0x8ad144093c8b47c08d87a4e2c720f27a1261257ef38a206b2c32b873fb2a0540",
"0x96f712f459001d62d24425d0515d406cc974485fc1184c6ff3de08ecfdcd1658"
],
"threshold": 2
},
"origin": {
"__kind": "system",
"value": {
"__kind": "Signed",
"value": "0x4aac8da05fd543a7289230071e07cf84472e879ee6f05a580c560eed0371aa78"
}
},
"origin_address": "0x4aac8da05fd543a7289230071e07cf84472e879ee6f05a580c560eed0371aa78",
"timestamp": "2024-12-13T05:54:12Z",
"block_number": 4470428
}
Example 3 (cancel)
First call
See it on Taostats: 4445415-0007
{
"id": "4445415-0007",
"extrinsic_id": "4445415-0007",
"parent_id": null,
"extrinsic_index": 7,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "approve_as_multi",
"full_name": "Multisig.approve_as_multi",
"args": {
"callHash": "0x0320ac365c31a9b66cc4b6819034f9ee0b5d739f1abb46155a3b5b7a65048777",
"maxWeight": {
"proofSize": "12296",
"refTime": "3118516090"
},
"otherSignatories": [
"0x103d4c4ee677d68bf2c73f370adbd03e7cbfbd3285c319f3d4b914d6db54f635",
"0x660a7a15ed4368f4c0a12a1e75a6725587934645db38c91e13900a76b495b87b"
],
"threshold": 3
},
"origin": {
"__kind": "system",
"value": {
"__kind": "Signed",
"value": "0xa0a381c42a7e069869a2489164b7532911a685d7011596aec733c49a80dd3214"
}
},
"origin_address": "0xa0a381c42a7e069869a2489164b7532911a685d7011596aec733c49a80dd3214",
"timestamp": "2024-12-09T18:31:36Z",
"block_number": 4445415
}
Second Call
In the cancel call, timepoint
connects to the initial extrinsic. This will cancel the multisig process.
See it on Taostats: 4445425-0005
{
"id": "4445425-0005",
"extrinsic_id": "4445425-0005",
"parent_id": null,
"extrinsic_index": 5,
"success": true,
"error": null,
"pallet": "Multisig",
"name": "cancel_as_multi",
"full_name": "Multisig.cancel_as_multi",
"args": {
"callHash": "0x0320ac365c31a9b66cc4b6819034f9ee0b5d739f1abb46155a3b5b7a65048777",
"otherSignatories": [
"0x103d4c4ee677d68bf2c73f370adbd03e7cbfbd3285c319f3d4b914d6db54f635",
"0x660a7a15ed4368f4c0a12a1e75a6725587934645db38c91e13900a76b495b87b"
],
"threshold": 3,
"timepoint": {
"height": 4445415,
"index": 7
}
},
"origin": {
"**kind": "system",
"value": {
"**kind": "Signed",
"value": "0xa0a381c42a7e069869a2489164b7532911a685d7011596aec733c49a80dd3214"
}
},
"origin_address": "0xa0a381c42a7e069869a2489164b7532911a685d7011596aec733c49a80dd3214",
"timestamp": "2024-12-09T18:33:36Z",
"block_number": 4445425
}
Updated 8 days ago