A complete step by step guide to setting up and using multi signature transactions with cleos. Securing your accounts so no single key can act alone.
Each participant runs on their own machine. Never share private keys.
# On test1's machine $CLEOS wallet create --name test1wallet --to-console $CLEOS wallet unlock --name test1wallet $CLEOS wallet import --name test1wallet --private-key <PRIVATE_KEY_TEST1> # On test2's machine $CLEOS wallet create --name test2wallet --to-console $CLEOS wallet unlock --name test2wallet $CLEOS wallet import --name test2wallet --private-key <PRIVATE_KEY_TEST2> # On test3's machine $CLEOS wallet create --name test3wallet --to-console $CLEOS wallet unlock --name test3wallet $CLEOS wallet import --name test3wallet --private-key <PRIVATE_KEY_TEST3>
Replace <PRIVATE_KEY_*> with the actual private key for each account.
Change the active permission to require 2 of 3 partner approvals.
Our treasury account is test1. We want 2 out of 3 signers to approve any transaction.
test1 active key is imported and wallet is unlocked. Run $CLEOS wallet keys and cross check against $CLEOS get account test1. Once multisig is set, no single key can authorize actions anymore.$CLEOS set account permission test1 active '{"threshold":2,"keys":[],"accounts":[{"permission":{"actor":"test1","permission":"active"},"weight":1},{"permission":{"actor":"test2","permission":"active"},"weight":1},{"permission":{"actor":"test3","permission":"active"},"weight":1}],"waits":[]}' -p test1@active$CLEOS get account test1
active first, then owner last. If owner goes wrong you can still recover via active.Submit a proposal on chain that signers will review and approve.
test3 wants to send 50.0000 XPR from test1 to recipient1. At least one more approval is needed.
$CLEOS multisig propose testingprop '[{"actor":"test1","permission":"active"},{"actor":"test2","permission":"active"}]' '[{"actor":"test1","permission":"active"}]' eosio.token transfer '{"from":"test1","to":"recipient1","quantity":"50.0000 XPR","memo":"Q2 vendor payment"}' -p test3@active| Argument | What it is |
|---|---|
| testingprop | Proposal name: max 12 chars, a-z and 1-5 only |
| First array | Accounts that must approve before execution |
| Second array | Authority injected at execution time |
| eosio.token transfer | The contract and action being proposed |
| Last JSON | Parameters: from, to, quantity, memo |
| -p test3@active | test3 pays CPU/NET for this proposal |
test1@active or exec fails with missing_auth_exception.--expiration 86400 for 24 hours.Verify the full transaction details on chain before approving.
$CLEOS multisig review test3 testingprop
test3), not whoever is reviewing.Each signer approves individually using the proposer name as first argument.
# test1 approves (on test1 machine)
$CLEOS multisig approve test3 testingprop '{"actor": "test1", "permission": "active"}' -p test1@active
# test2 approves (on test2 machine)
$CLEOS multisig approve test3 testingprop '{"actor": "test2", "permission": "active"}' -p test2@activeWith 2 of 3 approvals the threshold is met. test3 does not need to approve.
$CLEOS get table eosio.msig test3 approvals2
Once the threshold is met, any account can trigger execution.
$CLEOS multisig exec test3 testingprop -p test3@active
$CLEOS get currency balance eosio.token test1 XPR $CLEOS get currency balance eosio.token recipient1 XPR
Only the original proposer can cancel before execution.
$CLEOS multisig cancel test3 testingprop -p test3@active
Even expired proposals must be cancelled explicitly to free on chain RAM.
$CLEOS wallet keys and compare against $CLEOS get account test1. Confirm key is imported and wallet is unlocked.cleos multisig approve test3 testingprop the first argument is always the proposer, not the approver.--expiration in seconds. Always cancel expired proposals to reclaim RAM.# 1. Set 2 of 3 multisig on test1
$CLEOS set account permission test1 active '{"threshold":2,"keys":[],"accounts":[{"permission":{"actor":"test1","permission":"active"},"weight":1},{"permission":{"actor":"test2","permission":"active"},"weight":1},{"permission":{"actor":"test3","permission":"active"},"weight":1}],"waits":[]}' -p test1@active
# 2. Propose
$CLEOS multisig propose testingprop '[{"actor":"test1","permission":"active"},{"actor":"test2","permission":"active"}]' '[{"actor":"test1","permission":"active"}]' eosio.token transfer '{"from":"test1","to":"recipient1","quantity":"50.0000 XPR","memo":"Q2 vendor payment"}' -p test3@active
# 3. Review
$CLEOS multisig review test3 testingprop
# 4. Approve
$CLEOS multisig approve test3 testingprop '{"actor":"test1","permission":"active"}' -p test1@active
$CLEOS multisig approve test3 testingprop '{"actor":"test2","permission":"active"}' -p test2@active
# 5. Execute
$CLEOS multisig exec test3 testingprop -p test3@active
# 6. Cancel
$CLEOS multisig cancel test3 testingprop -p test3@active