Setting up a Multi-sig Account
In this section, we will explore the commands to setup an account with associated keys and restrict access for deployment and key management to specific keys within the account.
In this example, we will set up an account with the following weights and thresholds:
- Three associated keys (Manager, Supervisor, and Clerk)
- Weights of the associated keys:
- Manager - 4
- Supervisor - 2
- Clerk - 1
- Weights of the thresholds:
- Key management - 4
- Deploy - 3
note
For all the commands used in this tutorial, here are a few pointers:
- The
node-address
attribute is a combination of a peer node IP address from the Mainnet or Testnet prefixed with7777
, which is the RPC port. - The
chain-name
attribute, iscasper-test
for Testnet andcasper
for Mainnet. - The
amount
attribute is the cost of the transaction in motes. - Hexadecimal public key is found in the
public_key_hex
file. Copy the contents of this file and paste it in the command that calls for it.
Creating Accounts
Create three sets of keys one each for the Manager, Supervisor and Clerk.
To create accounts on the Casper blockchain, you need to generate keys and fund your accounts. For more information see Account and Cryptographic Keys.
To fund your Testnet account, see Funding Testnet Accounts.
Deploying the Keys Manager Contract
Before you deploy the keys manager contract, you must clone the keys-manager repository and build the contract.
You can deploy the keys manager contract using the put-deploy
command as illustrated below.
casper-client put-deploy \
--chain-name casper-test \
--node-address http://[NODE_IP_ADDRESS]:7777 \
--secret-key <path to secret_key.pem> \
--session-path <path to keys-manager.wasm> \
--payment-amount 10000000000
Sample output with deploy hash
{ "id": -4915929071409710835, "jsonrpc": "2.0", "result": { "api_version": "1.4.4", "deploy_hash": "3d55c71ae0892c9f5b63be56c8ca3e107e39e812ebc925383881cfa003aaced7" } }
Check deploy status
The deploy hash from the previous output is used to find the deploy status. The deploy usually takes a few minutes to execute, so please be patient.
casper-client get-deploy <deploy hash> \
--node-address http://[NODE_IP_ADDRESS]:7777
Sample output showing deploy status
{ "id": -470146583313425542, "jsonrpc": "2.0", "result": { "api_version": "1.4.4", "deploy": { "approvals": [ { "signature": "015fa28d6a68000a05c323cf9933c3a93f1b0126a8c769048342b2059cab51b00232e6454abd31dfc2405887e8b4 8c38e38412a04290311883ba9f8f51bde5b0c", "signer": "01b00d1991357e1db95a52101ad7050d552c75a54ac6724c11756f514a181d520a" } ], "hash": "3d55c71ae0892c9f5b63be56c8ca3e107e39e812ebc925383881cfa003aaced7", "header": { "account": "01b00d1991357e1db95a52101ad7050d552c75a54ac6724c11756f514a181d520a", "body_hash": "21ae03fecc7491959bba4d290e2fc494163b5f29dd044143514d568eab7e9cab", "chain_name": "casper-test", "dependencies": [], "gas_price": 1, "timestamp": "2022-02-18T11:26:12.240Z", "ttl": "30m" }, "payment": { "ModuleBytes": { "args": [ [ "amount", { "bytes": "0500e8764817", "cl_type": "U512", "parsed": "100000000000" } ] ], "module_bytes": "" } }, "session": { "ModuleBytes": { "args": [], "module_bytes": "[381268 hex chars]" } } }, "execution_results": [ { "block_hash": "ed652d9cc06e5cd24429c67eb977e17e710fd57863c883c08efcdb88f0749607", "result": { "Success": { "cost": "74678904670", "effect": { "operations": [], "transforms": [ { "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401", "transform": "Identity" }, { "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5", "transform": "Identity" }, { "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7", "transform": "Identity" }, { "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e", "transform": "Identity" }, { "key": "balance-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a", "transform": "Identity" }, { "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6", "transform": "Identity" }, { "key": "balance-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a", "transform": { "WriteCLValue": { "bytes": "0500282e8cd1", "cl_type": "U512", "parsed": "900000000000" } } }, { "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6", "transform": { "AddUInt512": "100000000000" } }, { "key": "uref-39e68561186ebe397246cc3e8da6b09edfa33ff8b114ca7f66b65a62b73f40df-000", "transform": { "WriteCLValue": { "bytes": "", "cl_type": "Unit", "parsed": null } } }, { "key": "hash-1096cb5a529e1eebeb3522cb5e3e7b60f3dd47de68b70ccc8a83560cd3a216db", "transform": "WriteContractPackage" }, { "key": "hash-1096cb5a529e1eebeb3522cb5e3e7b60f3dd47de68b70ccc8a83560cd3a216db", "transform": "Identity" }, { "key": "hash-0d90baf0b1e6b7a8bd45d172896a6d24616b457f1e1ee28081d821a00ffe62b3", "transform": "WriteContractWasm" }, { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "transform": "WriteContract" }, { "key": "hash-1096cb5a529e1eebeb3522cb5e3e7b60f3dd47de68b70ccc8a83560cd3a216db", "transform": "WriteContractPackage" }, { "key": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "transform": { "AddKeys": [ { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "name": "keys_manager" } ] } }, { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-000", "transform": { "WriteCLValue": { "bytes": "fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "cl_type": { "ByteArray": 32 }, "parsed": "fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476" } } }, { "key": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "transform": { "AddKeys": [ { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-007", "name": "keys_manager_hash" } ] } }, { "key": "deploy-3d55c71ae0892c9f5b63be56c8ca3e107e39e812ebc925383881cfa003aaced7", "transform": { "WriteDeployInfo": { "deploy_hash": "3d55c71ae0892c9f5b63be56c8ca3e107e39e812ebc925383881cfa003aaced7", "from": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "gas": "74678904670", "source": "uref-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a-007", "transfers": [] } } }, { "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6", "transform": "Identity" }, { "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401", "transform": "Identity" }, { "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7", "transform": "Identity" }, { "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e", "transform": "Identity" }, { "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6", "transform": "Identity" }, { "key": "balance-34b99d631b7545a56af663801f8b86c0f38cc014b002e9f7e0c0b2a19e789f14", "transform": "Identity" }, { "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6", "transform": { "WriteCLValue": { "bytes": "00", "cl_type": "U512", "parsed": "0" } } }, { "key": "balance-34b99d631b7545a56af663801f8b86c0f38cc014b002e9f7e0c0b2a19e789f14", "transform": { "AddUInt512": "100000000000" } } ] }, "transfers": [] } } } ] } }
View account details
The following command gets the account details after the deploy is successful:
casper-client get-account-info \
--public-key <hexadecimal public key> \
--node-address http://[NODE_IP_ADDRESS]:7777
In the output of this command, you can see the key weight, key management threshold, and deploy threshold. Also, observe the main purse structure, which has the keys_manager_hash
uref address. In the next steps, this uref address is used to find the smart contract's session hash.
Sample output with named keys for the keys manager contract
{ "id": 3805776763924596530, "jsonrpc": "2.0", "result": { "account": { "account_hash": "account-hash-694c000a8282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "action_thresholds": { "deployment": 1, "key_management": 1 }, "associated_keys": [ { "account_hash": "account-hash-694c000a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "weight": 1 } ], "main_purse": "uref-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a-007", "named_keys": [ { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "name": "keys_manager" }, { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-007", "name": "keys_manager_hash" } ] }, "api_version": "1.4.4", "merkle_proof": "[26588 hex chars]" } }
In the above output, you can see the named keys for the contract and the uref for keys_manager_hash
. This uref hash will be used to find the session hash of the contract.
Find session hash
To find the session hash, we need the state root hash and the uref hash of the keys manager contract.
State root hash
Use the following command to find the state root hash:
casper-client get-state-root-hash --node-address http://[NODE_IP_ADDRESS]:7777
Sample output with state root hash
{ "id": -1255673544684673900, "jsonrpc": "2.0", "result": { "api_version": "1.4.4", "state_root_hash": "61743f2d702a36bae49faa57f221caf10725e0bff5481c2ec568ea4f0a28f69b" } }
You can use this state root hash in the next section to find the session hash of the smart contract.
Uref hash of the keys manager contract
You can find the uref hash in the account information of the account used to deploy the keys manager contract, see View Account Details.
Session hash for keys manager contract
Use the following command to get the session hash of the smart contract:
casper-client query-state \
--node-address http://[NODE_IP_ADDRESS]:7777 \
--key <uref of keys_manager_hash> \
--state-root-hash <network state root hash>
In the following output, the parsed value is the session hash fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476
.
Sample output with session hash
{ "id": -3744898570362638107, "jsonrpc": "2.0", "result": { "api_version": "1.4.4", "block_header": null, "merkle_proof": "[34692 hex chars]", "stored_value": { "CLValue": { "bytes": "fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "cl_type": { "ByteArray": 32 }, "parsed": "fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476" } } } }
Setting the Manager's Key Weight to 4
Let's setup the main account (Manager) with a key weight of 4.
casper-client put-deploy \
--chain-name casper-test \
--node-address http://[NODE_IP_ADDRESS]:7777 \
--secret-key <local path of secret_key.pem file> \
--session-hash <session hash of keys manager contract>\
--payment-amount 1000000000 \
--session-entry-point set_key_weight \
--session-arg "account:public_key='01b2200091357e1db95a52101ad7050d552c75a54ac6724c11756f514a181d520a'" \
--session-arg "weight:u8='4'"
In the above command, observe the following:
- The
secret-key
attribute should point to thesecret_key.pem
file - The
session-entry-point
attribute value isset_key_weight
, which remains the same for setting keys weights for all the keys. - The
session-arg
forset_key_weight
are the hexadecimal public key of the key pair that you want to set the weight for and the new weight for the key. In this example, the hex public key is of the Manager's account.
Sample output with deploy hash
{ "id": -8205577127765151372, "jsonrpc": "2.0", "result": { "api_version": "1.4.4", "deploy_hash": "70f8f95afdcf5729b58a5000f1b566448305890c99c21ded1a2bdc70773fdbc1" } }
You can use the deploy hash from the above output to find the deploy status.
Viewing the Account Structure with an Associated Account
You view the updated account structure using the following command:
casper-client get-account-info \
--public-key <hex public key of Manager account> \
--node-address http://[NODE_IP_ADDRESS]:7777
Sample output with one associated key
{ "id": -244324861334765287, "jsonrpc": "2.0", "result": { "account": { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "action_thresholds": { "deployment": 1, "key_management": 1 }, "associated_keys": [ { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "weight": 4 }, { "account_hash": "account-hash-f19e3269ae27a44d5debfcd2df0a5b5dd6c31961d335a09dcd5f782ddebb3683", "weight": 2 } ], "main_purse": "uref-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a-007", "named_keys": [ { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "name": "keys_manager" }, { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-007", "name": "keys_manager_hash" } ] }, "api_version": "1.4.4", "merkle_proof": "[26654 hex chars]" } }
Linking the Other Accounts and Setting Key Weights
You can link an account and set the key weight for that account in one command. To do this, use the secret_key.pem file of the main account and the hexadecimal primary key of the account to link. An example of how the put-deploy
command is used to link accounts and set weights, is shown here:
casper-client put-deploy \
--chain-name casper-test \
--node-address http://[NODE_IP_ADDRESS]:7777 \
--secret-key <path to Manager secret_key.pem> \
--session-hash <session hash of keys manager contract> \
--payment-amount 1000000000 \
--session-entry-point set_key_weight \
--session-arg "account:public_key='01e6c6000a88f122d463ed083e81f77da2c58cb92529eb422274641e4b3b2126a'" \
--session-arg "weight:u8='2'"
In the above command, observe the following:
- The
secret-key
should point to thesecret_key.pem
file of the main account (Manager). The amount for the transaction will be deducted from the main purse of this account. - The hexadecimal public key should be of the account you wish to associate with the main account. In this case, it is the Supervisor's account.
note
You can use this command to set the weight for the Clerk's account as well. To do so, replace the hexadecimal public key with that of the Clerk's account and keep the weight as 1.
Viewing Account Structure with All Associated Keys
You can view the updated account structure using the following command:
casper-client get-account-info \
--public-key <hex public key of Manager account> \
--node-address http://[NODE_IP_ADDRESS]:7777
Sample output showing the account structure with all associated keys
{ "id": 2242895416442018609, "jsonrpc": "2.0", "result": { "account": { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "action_thresholds": { "deployment": 1, "key_management": 1 }, "associated_keys": [ { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "weight": 4 }, { "account_hash": "account-hash-b3ff5309f983f2b30c70fc5fdf36eecab8460759e3465cccb1f7718704ebba27", "weight": 1 }, { "account_hash": "account-hash-f19e3269ae27a44d5debfcd2df0a5b5dd6c31961d335a09dcd5f782ddebb3683", "weight": 2 } ], "main_purse": "uref-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a-007", "named_keys": [ { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "name": "keys_manager" }, { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-007", "name": "keys_manager_hash" } ] }, "api_version": "1.4.4", "merkle_proof": "[26720 hex chars]" } }
Setting Key Management Threshold to 4
To set the key management threshold we will use the set_key_management_threshold
entry point. Also, keep in mind these restrictions while setting the thresholds for account management. You can use the following command to set the key management threshold:
casper-client put-deploy \
--chain-name casper-test \
--node-address http://[NODE_IP_ADDRESS]:7777 \
--secret-key <path to Manager secret_key.pem> \
--session-hash <session hash of keys manager contract> \
--payment-amount 5000000000 \
--session-entry-point set_key_management_threshold \
--session-arg "weight:u8='4'"
Use the following command to see the updated account structure:
casper-client get-account-info \
--public-key <hex public key of Manager account> \
--node-address http://[NODE_IP_ADDRESS]:7777
Sample output with the updated key management threshold
{ "id": 2760750489916445167, "jsonrpc": "2.0", "result": { "account": { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "action_thresholds": { "deployment": 1, "key_management": 4 }, "associated_keys": [ { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "weight": 4 }, { "account_hash": "account-hash-b3ff5309f983f2b30c70fc5fdf36eecab8460759e3465cccb1f7718704ebba27", "weight": 1 }, { "account_hash": "account-hash-f19e3269ae27a44d5debfcd2df0a5b5dd6c31961d335a09dcd5f782ddebb3683", "weight": 2 } ], "main_purse": "uref-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a-007", "named_keys": [ { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "name": "keys_manager" }, { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-007", "name": "keys_manager_hash" } ] }, "api_version": "1.4.4", "merkle_proof": "[26720 hex chars]" } }
Setting Deploy Threshold to 3
You can use the following command to set the deploy threshold to 3.
casper-client put-deploy \
--chain-name casper-test \
--node-address http://[NODE_IP_ADDRESS]:7777 \
--secret-key <path to Manager secret_key.pem> \
--session-hash <session hash of keys manager contract> \
--payment-amount 5000000000 \
--session-entry-point set_deployment_threshold \
--session-arg "weight:u8='3'"
Viewing Final Account Structure
Once again we will use the get-account-info
command to view the main account structure.
casper-client get-account-info \
--public-key <hex public key of Manager account> \
--node-address http://[NODE_IP_ADDRESS]:7777
The following account structure will be visible after all the key weights and thresholds are set.
Sample final account structure
{ "id": -1053187261000032037, "jsonrpc": "2.0", "result": { "account": { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "action_thresholds": { "deployment": 3, "key_management": 4 }, "associated_keys": [ { "account_hash": "account-hash-694c109a08282d039ace20fbad7a692f4d800a7fd6db08848bc95f8a9f7e4273", "weight": 4 }, { "account_hash": "account-hash-b3ff5309f983f2b30c70fc5fdf36eecab8460759e3465cccb1f7718704ebba27", "weight": 1 }, { "account_hash": "account-hash-f19e3269ae27a44d5debfcd2df0a5b5dd6c31961d335a09dcd5f782ddebb3683", "weight": 2 } ], "main_purse": "uref-250554daef44c5274f726f2556b62da7dbd6d997d6a93dea925104529db12e6a-007", "named_keys": [ { "key": "hash-fc8eaf47329d45c76c4f80ec4e6fdb08e74dbe4ae0391447c5ebd15f1c962476", "name": "keys_manager" }, { "key": "uref-3141039f23ae092028da3b8222ebb5ae5d8409e745b507903e5f7600fa42aada-007", "name": "keys_manager_hash" } ] }, "api_version": "1.4.4", "merkle_proof": "[26720 hex chars]" } }
Key Management Restrictions
This section explains a few rules that apply to key management:
- Set the deployment threshold lower than or equal to the key-management threshold
- Set the deployment threshold lower than or equal to all other thresholds
- Ensure the account used to set the thresholds has sufficient permissions
- Set the thresholds to a value lower than the total weight of associated keys
We offer some additional examples of account management in the next section.
tip
To make a transfer using your multisig account, see Transferring Tokens using a Multisig Account.