# Get started with Casper (Challenge)
###### tags: `casper` `hackathon` `gitcoin` `tutorial` `bounty`
>#### Challenge Description
>- [x] Create and deploy a simple, smart contract with [cargo casper and cargo test](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-of-rust-contract-sdk.html)
>- [x] Complete one of the [existing tutorials](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/index.html) for writing smart contracts
>- [x] Demonstrate [key management concepts](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/index.html) by modifying the client in the Multi-Sig tutorial to address one of the [additional scenarios](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html)
>- [x] Learn to transfer tokens to an account on the [Casper Testnet](https://testnet.cspr.live/). Check out [this documentation](https://docs.casperlabs.io/en/latest/workflow/transfer-workflow.html).
>- [x] Learn to Delegate and Undelegate on the [Casper Testnet](https://testnet.cspr.live/). Check out [these instructions](https://docs.casperlabs.io/en/latest/workflow/staking.html#delegating-tokens).[name=Gitcoin]
> Task #1 https://github.com/Loizage/casper-get-started-1
> Task #2 https://github.com/Loizage/casper-get-started-2
> Task #3 https://github.com/Loizage/casper-get-started-3
> [name=Loizage]
## Task #1 Create and deploy a simple, smart contract [with cargo casper and cargo test](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-of-rust-contract-sdk.html)
### 1. Prerequisites
#### Installing Rust
>Installed Rust
>Checked version
`rustup --version`
![](https://i.imgur.com/QHbf0TT.png)
#### Installing Dependencies
##### CMake
> Installed CMake
> And checked version
`cmake --version`
![](https://i.imgur.com/LwiNzkJ.png)
### 2. Development Environment Setup
#### Installing the Casper Crates
>Installed cargo-casper
>Checked version
`cargo install cargo-casper`
`cargo-casper --version`
![](https://i.imgur.com/wInz6ke.png)
#### Creating a Project
>Created sample Casper project
>Pushed to [GitHub](https://github.com/Loizage/casper-get-started-1)
`cargo casper casper-get-started-1`
#### Compiling to WASM
> Installed Rust toolchain
> Specified the target build as WebAssembly (wasm32)
`cd code/casper-get-started-1/`
`rustup install $(cat rust-toolchain)`
`rustup target add --toolchain $(cat rust-toolchain) wasm32-unknown-unknown`
![](https://i.imgur.com/ByZVfms.png)
### 3. Build and Test the Contract
>Built smart contract making test at the same time
`make test`
![](https://i.imgur.com/cYil1gq.gif)
#### Second test
>In attempt to test 'Casper Test' made changes to the code
>casper-get-started-1/contract/src/main.rs changing KEY value
![](https://i.imgur.com/386A5Lq.png)
>Made test.
>Test failed.
>Casper Test is working well :+1:
`make test`
![](https://i.imgur.com/8w4AN3A.png)
>Discard changes to the code
>Runed Casper test
`make test`
![](https://i.imgur.com/UvCFyNc.png)
### 4. Deploy the Contract
#### The Casper Client
>Installed Casper Client
>Checked version
```bash=
cd
rustup toolchain install nightly
cargo +nightly-2021-06-17 install casper-client --locked
casper-client --version
```
![](https://i.imgur.com/8Pg3uwN.png)
![](https://i.imgur.com/90Jj2cI.png)
![](https://i.imgur.com/uTIdgWz.png)
#### Account keys, Casper Signer and Faucet
>Created keys using *casper-client* command:
```bash=
casper-client keygen <TARGET DIRECTORY>
```
:::spoiler
<summary>Keys</summary>
![](https://i.imgur.com/P6OYibA.png)
:::
>Imported the keys to Casper Signer
>Obtained token from [Faucet](https://testnet.cspr.live/tools/faucet) on [testnet](https://testnet.cspr.live/)
:::spoiler
<summary>Faucet and recent requests</summary>
![](https://i.imgur.com/EmrMYwX.png)
:::
[Transfer from Faucet to my account](https://testnet.cspr.live/deploy/7d0a098911b3fbdb1b3083249c04b1253d07703f2bcb2912828a090af9ec97d5)
#### Sending a Deployment to the Testnet
>Deployed Casper sample contract to the Testnet
>*Provided required arguments for contract*
>*Payment amount increased, because ~~Out of gas error~~ errors*
```bash=
casper-client put-deploy --chain-name casper-test -n http://135.181.214.240:7777 -k /home/zage/code/casper/keys/hackathon_secret_key.pem -p 100000000000 -s /home/zage/code/casper-get-started-1/contract/target/wasm32-unknown-unknown/release/contract.wasm -a "message:string='hello_world_loizage'"
```
![](https://i.imgur.com/gKJtJr7.png)
>Deploy hash
>`beb8dfe6910c7408bae4d772414a50dc755aea637c048146334b0b1406fda6be`
>Checked deploy status
```bash=
casper-client get-deploy beb8dfe6910c7408bae4d772414a50dc755aea637c048146334b0b1406fda6be -n http://135.181.214.240:7777
```
![](https://i.imgur.com/YvnZTyS.gif)
>[Deploy on testnet block explorer](https://testnet.cspr.live/deploy/beb8dfe6910c7408bae4d772414a50dc755aea637c048146334b0b1406fda6be)
![](https://i.imgur.com/Lxr8IGJ.png)
## Task #2 Complete one of the [existing tutorials](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/index.html) for writing smart contracts
>I choosed [A counter on the Casper chain (Tutorial)](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/counter/index.html)
### 1. Clone the Contracts
`git clone https://github.com/casper-ecosystem/counter casper-get-started-2`
>My [GitHub clone](https://github.com/Loizage/casper-get-started-2)
### 2. Create a Local Network
`nctl-assets-setup && nctl-start`
![](https://i.imgur.com/VyLUMnt.png)
### 3. View the Network State
>To get current snapshot we need *account hash* and *state-root-hash*
#### Get *account hash*
`nctl-view-faucet-account`
![](https://i.imgur.com/CGGDW3F.png)
>account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136
#### Get *state root hash*:
```bash=
casper-client get-state-root-hash -n http://localhost:11101
```
![](https://i.imgur.com/lmYrUtD.png)
>2af9c7ddab099d88cf9568676a519c1ee0788f86952e6c94d900633f5c37dc89
#### Query the actual network state
>Substitute the *state root hash* and *account hash* values I just retrieved
>
```bash=
casper-client query-state \
-n http://localhost:11101 \
--state-root-hash 2af9c7ddab099d88cf9568676a519c1ee0788f86952e6c94d900633f5c37dc89 \
-k account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136
```
![](https://i.imgur.com/JE3ob1o.png)
>Current snapshot
### 4. Deploy the Counter contract
> *counter-define* contract:
> Compile
> Build in release mode
> Test contract before deploying
> Deploy on the chain
##### Set the WASM target
```bash=
cd
cd code/casper-get-started-2/
make prepare
```
![](https://i.imgur.com/uPKM3mf.png)
##### Build the contract and verify it
```bash=
make test
```
![](https://i.imgur.com/2EmYjEM.png)
##### Deploy contract
```bash=
casper-client put-deploy \
-n http://localhost:11101 \
--chain-name casper-net-1 \
-k /home/zage/code/casper/casper-node/utils/nctl/assets/net-1/faucet/secret_key.pem -p 5000000000000 -s target/wasm32-unknown-unknown/release/counter-define.wasm
```
![](https://i.imgur.com/Oo6XuW6.png)
>c4654b89782312197021335f54314d9cdfe89229b84111dc417b903184765491
##### Verify deployment
`casper-client get-deploy -n http://localhost:11101 c4654b89782312197021335f54314d9cdfe89229b84111dc417b903184765491`
![](https://i.imgur.com/wXVHQSQ.gif)
### 5. View the Updated Network State
##### Get new *state-root-hash*
>Since new deploy was write to te chain
`casper-client get-state-root-hash -n http://localhost:11101`
![](https://i.imgur.com/FWguMjb.png)
>9535647869f843d421b56ad1fc9d91c06deba5d48fa73b45db656c334ebe6422
##### Get the network state
`casper-client query-state -n http://localhost:11101 --state-root-hash 9535647869f843d421b56ad1fc9d91c06deba5d48fa73b45db656c334ebe6422 -k account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136`
![](https://i.imgur.com/GsfRQtN.png)
##### Retrieve the specific counter contract details
`casper-client query-state -n http://localhost:11101 --state-root-hash 9535647869f843d421b56ad1fc9d91c06deba5d48fa73b45db656c334ebe6422 -k account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136 -q "counter"`
![](https://i.imgur.com/RE6Okn6.png)
>Shows functions (entry points) and uref keys and names
##### Retrieve the specific counter variable details
`casper-client query-state -n http://localhost:11101 --state-root-hash 9535647869f843d421b56ad1fc9d91c06deba5d48fa73b45db656c334ebe6422 -k account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136 -q "counter/count"`
![](https://i.imgur.com/FBjZ6Nn.png)
>Shows current value of "count" key of "counter" contract
>Count = 0
##### Retrieve the specific deploy details
`casper-client query-state -n http://localhost:11101 --state-root-hash 9535647869f843d421b56ad1fc9d91c06deba5d48fa73b45db656c334ebe6422 -k deploy-c4654b89782312197021335f54314d9cdfe89229b84111dc417b903184765491`
![](https://i.imgur.com/JscgMAl.png)
>*Deploy-hash* used to query the state of the deploy
### 6. Increment the Counter
##### Call contract function (entry-point) *counter_inc*
`casper-client put-deploy -n http://localhost:11101 --chain-name casper-net-1 -k /home/zage/code/casper/casper-node/utils/nctl/assets/net-1/faucet/secret_key.pem -p 5000000000000 --session-name "counter" --session-entry-point "counter_inc"`
![](https://i.imgur.com/yW7Kfju.png)
### 7. View the Updated Network State Again
>Cause of changes on chain *state-root-hash* is updated
##### Get the NEW state-root-hash
`casper-client get-state-root-hash -n http://localhost:11101`
![](https://i.imgur.com/sLHOU8I.png)
>3deb0b87612d797b2fc8188ec08aef11afa3401f47e709fd312418898f884991
##### Get the network state, specifically for the count variable this time
`casper-client query-state -n http://localhost:11101 --state-root-hash 3deb0b87612d797b2fc8188ec08aef11afa3401f47e709fd312418898f884991 -k account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136 -q "counter/count"`
![](https://i.imgur.com/9n1yvwu.png)
>Count = 1
### 8. Increment the Counter Again
>Increment *count* value through deploying *counter-call* contract
`casper-client put-deploy -n http://localhost:11101 --chain-name casper-net-1 -k /home/zage/code/casper/casper-node/utils/nctl/assets/net-1/faucet/secret_key.pem -p 5000000000000 -s code/casper-get-started-2/target/wasm32-unknown-unknown/release/counter-call.wasm`
![](https://i.imgur.com/niPhLCx.png)
>*deploy hash*
>322b9b2ad29a5ee53853fbb20f42f8cc07890a4138d50b502d06df654943066d
### 9. View the Final Network
##### Get the NEW state-root-hash
```
casper-client get-state-root-hash -n http://localhost:11101
```
![](https://i.imgur.com/XMOgy1Q.png)
>*state_root_hash*
>7c81dc73e80b3037d69a10a2baf854e3f9199b9db8bd410d4a263cdebee04fde
##### Get the network state, specifically for the count variable this time
```
casper-client query-state -n http://localhost:11101 --state-root-hash 7c81dc73e80b3037d69a10a2baf854e3f9199b9db8bd410d4a263cdebee04fde -k account-hash-3daef079b4a4f5b8cf06890a7c46991cdab494d84ed047594ec3dfaad73cd136 -q "counter/count"
```
![](https://i.imgur.com/9hgNeaZ.png)
>Count = 1
## Task #3 Demonstrate [key management concepts](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/index.html) by modifying the client in the Multi-Sig tutorial to address one of the [additional scenarios](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html)
>First I will pass through [Multi-signature tuttorial](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/index.html)
### 1. Contract Example
This section covers an example smart contract used for key management.
#### Implementing the Smart Contract
>Clone [the example contract and client](https://github.com/casper-ecosystem/keys-manager) (keys-manager)
```
cd git clone https://github.com/casper-ecosystem/keys-manager
```
![](https://i.imgur.com/MqJaRNV.png)
#### Building the Smart Contract
>I already have installed [Rust Contract SDK](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-of-rust-contract-sdk.html) and [development environment seted up](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-of-rust-contract-sdk.html#development-environment-setup)
>Navigating to *keys-manager* folder
>Set up WASM compilation Rust toolchain
```
cd code/casper-get-started-3
rustup install $(cat rust-toolchain)
rustup target add --toolchain $(cat rust-toolchain) wasm32-unknown-unknown
```
![](https://i.imgur.com/DICUbI2.png)
>Checking *./contract* folder for a *Cargo.toml* file, which defines a smart contract called keys-manager :ok:
![](https://i.imgur.com/gjsUNuD.png)
>Compile smart contract and create WASM file
```
cd contract
cargo build --release
```
![](https://i.imgur.com/WKE9qsQ.gif)
>As a result *keys-manager.wasm* file compiled
![](https://i.imgur.com/wYoGi3l.png)
### 2. Client Example
This section covers an example client that invokes a smart contract for key management. In addition to the main account, the client code will add two additional accounts to perform deployments. The two deployment accounts will perform deployments but will not be able to add another account.
#### Prerequisites
>[:up:](https://hackmd.io/NAchgWMqQHmleHU868hEcg#Building-the-Smart-Contract) Compiled [example contract](https://github.com/casper-ecosystem/keys-manager) for key management
>Seted up the [NCTL](https://github.com/casper-network/casper-node/tree/master/utils/nctl) tool according to the [NCTL guide](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-nctl.html)
>On that stage I chose another virtual enviroment comparing to the one from the [NCTL guide](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-nctl.html)
>So I've got another virtual machine name
>Now it's "casper-S4Fe-a4b" (it was "env" in NCTL setup tuttorial)
>And I did additional updates inside of virtual machine
>Just several steps (7-9) from [NCTL guide](https://docs.casperlabs.io/en/latest/dapp-dev-guide/setup-nctl.html)
* Upgrade pip to the latest version
* Install jq, a command-line JSON processor
* Install supervisor, a cross-platform process manager
* Install toml, a configuration file parser
```bash=
(casper-S4Fe-a4b) $ pip install --upgrade pip
(casper-S4Fe-a4b) $ pip install jq
(casper-S4Fe-a4b) $ pip install supervisor
(casper-S4Fe-a4b) $ pip install toml
```
![](https://i.imgur.com/dp3kR79.png)
![](https://i.imgur.com/V66DtJe.png)
![](https://i.imgur.com/xzpxDyr.png)
![](https://i.imgur.com/DlaxKGH.png)
#### Setting up a local Casper Network
>Activate virtual environment
>Navigate to *casper-node* folder
>Activate the NCTL environment
>Compile the NCTL binary scripts
>Set up assets required to run a local network
>Run local network
```bash=
$ cd code/casper
$ pipenv shell
(casper-S4Fe-a4b) $ cd casper-node
(casper-S4Fe-a4b) $ source utils/nctl/activate
(casper-S4Fe-a4b) $ nctl-compile
(casper-S4Fe-a4b) $ nctl-assets-setup
(casper-S4Fe-a4b) $ nctl-start
```
![](https://i.imgur.com/jfEyec6.gif)
>Check faucet account details
```bash=
(casper-S4Fe-a4b) $ nctl-view-faucet-account
```
![](https://i.imgur.com/7e1lisz.png)
#### Setting up the Client
>Navigate to *keys-manager/client* folder
>Create an .env file to specify the required configurations
>"BASE_KEY_PATH" is *faucet a/c secret key* from *nctl-view-faucet-account*
```
BASE_KEY_PATH=/home/zage/code/casper/casper-node/utils/nctl/assets/net-1/faucet/
NODE_URL=http://localhost:11101/rpc
WASM_PATH=../contract/target/wasm32-unknown-unknown/release/keys-manager.wasm
NETWORK_NAME=casper-net-1
FUND_AMOUNT=10000000000000
PAYMENT_AMOUNT=100000000000
TRANSFER_AMOUNT=2500000000
```
![](https://i.imgur.com/uAcPB9a.png)
>Install nodejs
nvm install v14.17.6
![](https://i.imgur.com/WqOC0gW.png)
>Install the *JavaScript* packages in the *keys-manager/client* folder
```bash=
(casper-S4Fe-a4b) $ cd ../../casper-get-started-3/client/
(casper-S4Fe-a4b) $ npm install
```
![](https://i.imgur.com/JVHGhQq.gif)
#### Testing the Client
>Run *keys-manager* using npm
```bash=
npm run start:atomic
```
![](https://i.imgur.com/ctFVp1e.gif)
### 3. Additional Scenarios
>To create new *scenarios* navigate to scenarios folder *keys-manager/client/src*
>Create *Scenario-#.js* file that perfoms account actions required in scenario task
>Also it would be necessary to update *keys-manager/client/package.json* file
>To create a custom script, that will allow run our new *Scenarios*
Add to *keys-manager/client/package.json* that code line
```
"start:scenario-1": "node -r dotenv/config ./src/scenario-1.js",
"start:scenario-2": "node -r dotenv/config ./src/scenario-2.js",
"start:scenario-3": "node -r dotenv/config ./src/scenario-3.js",
"start:scenario-4": "node -r dotenv/config ./src/scenario-4.js",
"start:scenario-5": "node -r dotenv/config ./src/scenario-5.js",
"start:scenario-6": "node -r dotenv/config ./src/scenario-6.js",
```
:::spoiler
```bash=
{
"name": "keys-manager",
"version": "1.0.0",
"description": "Examples using casper-client-sdk",
"scripts": {
"start:atomic": "node -r dotenv/config ./src/scenario-atomic.js",
"start:all": "node -r dotenv/config ./src/scenario-all.js",
"start:scenario-1": "node -r dotenv/config ./src/scenario-1.js",
"start:scenario-2": "node -r dotenv/config ./src/scenario-2.js",
"start:scenario-3": "node -r dotenv/config ./src/scenario-3.js",
"start:scenario-4": "node -r dotenv/config ./src/scenario-4.js",
"start:scenario-5": "node -r dotenv/config ./src/scenario-5.js",
"start:scenario-6": "node -r dotenv/config ./src/scenario-6.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"dependencies": {
"casper-js-sdk": "^2.0.0",
"dotenv": "^10.0.0"
}
}
```
:::
#### [Scenario 1: Signing transactions with a single key](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html#scenario-1-signing-transactions-with-a-single-key)
###### Description:
In this example, only one key can sign transactions in the name of this account. The key is “account-hash-a1…” under the associated_keys. If you sign the transaction using “account-hash-a1…”, the signed transaction will have a weight equal to 1. For deployments or key management, the weight required is also 1. Therefore, the associated key meets the deployment and key management thresholds and can perform both actions.
:::spoiler
<summary>Faucet account in scenario 1:</summary>
```bash=
{
"api_version": "1.0.0",
"merkle_proof": "01000…..11",
"stored_value": {
"Account": {
"account_address": "account-address-a1…",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_address": "account-address-a1…",
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}
}
}
```
:::
:::spoiler
<summary>scenario-1.js:</summary>
```bash=
const keyManager = require('./key-manager');
const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000;
(async function () {
// Scenario #1 Description:
// In this example, only one key can sign transactions in the name of this account.
// The key is “account-hash-a1…” under the associated_keys.
// If you sign the transaction using “account-hash-a1…”, the signed transaction will have a weight equal to 1.
// For deployments or key management, the weight required is also 1.
// Therefore, the associated key meets the deployment and key management thresholds and can perform both actions.
// So we will need only one key.
// It would be 'mainAccount'.
// To achieve the task, we will:
// 1. Set weight of mainAccount to 1.
// 2. Set Keys Management Threshold to 1.
// 3. Set Deploy Threshold to 1.
const masterKey = keyManager.randomMasterKey();
const mainAccount = masterKey.deriveIndex(1);
console.log("Main account: " + mainAccount.publicKey.toHex());
let deploy;
console.log("\n0.1 Funding main account.");
await keyManager.fundAccount(mainAccount);
await keyManager.printAccount(mainAccount);
console.log("\n0.2 Install Keys Manager contract");
deploy = keyManager.keys.buildContractInstallDeploy(mainAccount);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
//Deploy and Key Managment threshholds are 1 out of 1
const deployThreshold = 1;
const keyManagementThreshold = 1;
//Weight of mainAccount is 1
const mainAccountWeight = 1;
// 1. Set weight of mainAccount to 1.
console.log("\n1. Set weight of mainAccount to 1.");
deploy = keyManager.keys.setKeyWeightDeploy(mainAccount,mainAccount,mainAccountWeight);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 2. Set Keys Management Threshold to 1.
console.log("\n2. Set Keys Management Threshold to 1.");
deploy = keyManager.keys.setKeyManagementThresholdDeploy(mainAccount, keyManagementThreshold);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 3. Set Deploy Threshold to 1.
console.log("\n3. Set Deploy Threshold to 1.");
deploy = keyManager.keys.setDeploymentThresholdDeploy(mainAccount, deployThreshold);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
})();
```
:::
Execute Scenario-1.js
```bash=
npm run start:scenario-1
```
![](https://i.imgur.com/j7S6TyS.gif)
:::spoiler
<summary>Full result</summary>
```bash=
> keys-manager@1.0.0 start:scenario-1 /home/zage/code/casper-get-started-3/client
> node -r dotenv/config ./src/scenario-1.js
Main account: 0203d634d4e747a87fb6bef6115f92289c9543555c40ff4afaefa1c5f24c384c3786
0.1 Funding main account.
Signed by: account-hash-88485a84a5ef7fa3ac04ec7d3a0a5f8e8d98277f7d622d5a237a2e082609361c
Deploy hash: 73746e5a48210a9ff423cc856e797051a61aa3f771626dfafd1dc8a9977bd6e8
Deploy result:
{
deploy: {
hash: '73746e5a48210a9ff423cc856e797051a61aa3f771626dfafd1dc8a9977bd6e8',
header: {
account: '0111bda4d4165a97b997722f3666649c8229b62f49ee91a5a0820b311d9556f36f',
timestamp: '2021-09-23T16:22:04.488Z',
ttl: '30m',
gas_price: 1,
body_hash: '832dff2df3766e7f075553c7f1ec9a6d4ba13f01cfeb9ca8f087c5f7e014d871',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { Transfer: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
namedKeys: [],
mainPurse: 'uref-a22ed5dd69df4e098ae705b0be8190b70b6347dbc22c209ca88dca3ff9b0b26e-007',
associatedKeys: [
{
accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
0.2 Install Keys Manager contract
Signed by: account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf
Deploy hash: bdaf248716459c0e72aa01276a92b0c98ce6fa95c6efcd940a7363e2c289b506
Deploy result:
{
deploy: {
hash: 'bdaf248716459c0e72aa01276a92b0c98ce6fa95c6efcd940a7363e2c289b506',
header: {
account: '0203d634d4e747a87fb6bef6115f92289c9543555c40ff4afaefa1c5f24c384c3786',
timestamp: '2021-09-23T16:23:10.462Z',
ttl: '30m',
gas_price: 1,
body_hash: '5e6f26e6f26d50c3c5023d1f7b70ed47006fcbf1704e99319ade074a87e5cce7',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { ModuleBytes: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-feb710ef9a7e8055f4ef5c23fc3b0a553e038a713f70f12586659b6e186f8968'
},
{
name: 'keys_manager_hash',
key: 'uref-7092c0cc9cdac7a635d62bcabac316b2c4ec97064d5ee00093f604050f6b6dde-007'
}
],
mainPurse: 'uref-a22ed5dd69df4e098ae705b0be8190b70b6347dbc22c209ca88dca3ff9b0b26e-007',
associatedKeys: [
{
accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. Set weight of mainAccount to 1.
Signed by: account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf
Deploy hash: 4ea11b078954f6d697b4096e45af574f1bda1fe0e03988e9975b3ee1fd8e046d
Deploy result:
{
deploy: {
hash: '4ea11b078954f6d697b4096e45af574f1bda1fe0e03988e9975b3ee1fd8e046d',
header: {
account: '0203d634d4e747a87fb6bef6115f92289c9543555c40ff4afaefa1c5f24c384c3786',
timestamp: '2021-09-23T16:24:16.731Z',
ttl: '30m',
gas_price: 1,
body_hash: '98c9773e3c444db1a3cb4fac34be65fa5025f50f2b18b72cec6dbc48556884fa',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-feb710ef9a7e8055f4ef5c23fc3b0a553e038a713f70f12586659b6e186f8968'
},
{
name: 'keys_manager_hash',
key: 'uref-7092c0cc9cdac7a635d62bcabac316b2c4ec97064d5ee00093f604050f6b6dde-007'
}
],
mainPurse: 'uref-a22ed5dd69df4e098ae705b0be8190b70b6347dbc22c209ca88dca3ff9b0b26e-007',
associatedKeys: [
{
accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
2. Set Keys Management Threshold to 1.
Signed by: account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf
Deploy hash: 34ee14fbfbf63aba79dde27d6acf32eda67587e1ea2b05b462f59f082a090bef
Deploy result:
{
deploy: {
hash: '34ee14fbfbf63aba79dde27d6acf32eda67587e1ea2b05b462f59f082a090bef',
header: {
account: '0203d634d4e747a87fb6bef6115f92289c9543555c40ff4afaefa1c5f24c384c3786',
timestamp: '2021-09-23T16:25:22.333Z',
ttl: '30m',
gas_price: 1,
body_hash: 'fcbeef2291716fba37f9f05b6883b80e5985a3e7ccdd8e779cca24912b24871b',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-feb710ef9a7e8055f4ef5c23fc3b0a553e038a713f70f12586659b6e186f8968'
},
{
name: 'keys_manager_hash',
key: 'uref-7092c0cc9cdac7a635d62bcabac316b2c4ec97064d5ee00093f604050f6b6dde-007'
}
],
mainPurse: 'uref-a22ed5dd69df4e098ae705b0be8190b70b6347dbc22c209ca88dca3ff9b0b26e-007',
associatedKeys: [
{
accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
3. Set Deploy Threshold to 1.
Signed by: account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf
Deploy hash: a6e8041aa3623afed431b506440cde36674eb44ffbf0f879497a21d9b219df28
Deploy result:
{
deploy: {
hash: 'a6e8041aa3623afed431b506440cde36674eb44ffbf0f879497a21d9b219df28',
header: {
account: '0203d634d4e747a87fb6bef6115f92289c9543555c40ff4afaefa1c5f24c384c3786',
timestamp: '2021-09-23T16:26:27.940Z',
ttl: '30m',
gas_price: 1,
body_hash: '4807b024a8e1e7c7d1da5a9101a21f38303d4689905d88d4585eec852fd7216b',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-feb710ef9a7e8055f4ef5c23fc3b0a553e038a713f70f12586659b6e186f8968'
},
{
name: 'keys_manager_hash',
key: 'uref-7092c0cc9cdac7a635d62bcabac316b2c4ec97064d5ee00093f604050f6b6dde-007'
}
],
mainPurse: 'uref-a22ed5dd69df4e098ae705b0be8190b70b6347dbc22c209ca88dca3ff9b0b26e-007',
associatedKeys: [
{
accountHash: 'account-hash-c1bb72d09306ad0ec8f7f1248e955c64c66f1ec0461a7ee225f1149d0776a4cf',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
```
:::
#### [Scenario 2: Deploying with special keys](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html#scenario-2-deploying-with-special-keys)
###### Description
In this example, you have two keys. One key can only perform deployments, while the second key can perform key management and deployments. The key with account address a1 can deploy and make account changes, but the second key with account address b2 can only deploy.
:::spoiler
<summary>Faucet account in scenario 2:</summary>
```bash=
{
"api_version": "1.0.0",
"merkle_proof": "01000…..11",
"stored_value": {
"Account": {
"account_address": "account-address-a1…",
"action_thresholds": {
"deployment": 1,
"key_management": 2
},
"associated_keys": [
{
"account_address": "account-address-a1…",
"weight": 2
},
{
"account_address": "account-address-b2…", // a deployment key
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}
}
}
```
:::
:::spoiler
<summary>scenario-2.js:</summary>
```bash=
const keyManager = require('./key-manager');
const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000;
(async function () {
// Scenario #2 Description:
// In this example, you have two keys.
// One key can only perform deployments, while the second key can perform key management and deployments.
// The key with account address a1 can deploy and make account changes, but the second key with account address b2 can only deploy.
// So we will need two keys.
// It would be 'mainAccount' and 'firstAccount'.
// To achieve the task, we will:
// 1. Set weight of mainAccount to 2.
// 2. Set weight of firstAccount to 1.
// 3. Set Keys Management Threshold to 2.
// 4. Set Deploy Threshold to 1.
const masterKey = keyManager.randomMasterKey();
const mainAccount = masterKey.deriveIndex(1);
const firstAccount = masterKey.deriveIndex(2);
console.log("Main account: " + mainAccount.publicKey.toHex());
console.log("First account: " + firstAccount.publicKey.toHex());
let deploy;
console.log("\n0.1 Funding main account.");
await keyManager.fundAccount(mainAccount);
await keyManager.printAccount(mainAccount);
console.log("\n0.2 Install Keys Manager contract");
deploy = keyManager.keys.buildContractInstallDeploy(mainAccount);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// Deploy threshhold is 1
const deployThreshold = 1;
// Key Managment threshhold is 2
const keyManagementThreshold = 2;
// Weight of mainAccount is 2
const mainAccountWeight = 2;
// Weight of firstAccount is 1
const firstAccountWeight = 1;
// 1. Set weight of mainAccount to 2.
console.log("\n1. Set weight of mainAccount to 2.");
deploy = keyManager.keys.setKeyWeightDeploy(mainAccount,mainAccount,mainAccountWeight);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 2. Set weight of firstAccount to 1.
console.log("\n1. 2. Set weight of firstAccount to 1.");
deploy = keyManager.keys.setKeyWeightDeploy(mainAccount,firstAccount,firstAccountWeight);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 3. Set Keys Management Threshold to 2.
console.log("\n2. 3. Set Keys Management Threshold to 2.");
deploy = keyManager.keys.setKeyManagementThresholdDeploy(mainAccount, keyManagementThreshold);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 4. Set Deploy Threshold to 1.
console.log("\n3. 4. Set Deploy Threshold to 1.");
deploy = keyManager.keys.setDeploymentThresholdDeploy(mainAccount, deployThreshold);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
})();
```
:::
Execute Scenario-2.js
```bash=
npm run start:scenario-2
```
![](https://i.imgur.com/r7Pr1JT.gif)
:::spoiler
<summary>Full result</summary>
```bash=
> keys-manager@1.0.0 start:scenario-2 /home/zage/code/casper-get-started-3/client
> node -r dotenv/config ./src/scenario-2.js
Main account: 02034eb6b820195f190801a57d43750eb05e934dd9956d7fc01e4d98eba933f3ccce
First account: 02026fd882621a0caef56546185fdf70b831b2ec07c6697281963d840947473d77a4
0.1 Funding main account.
Signed by: account-hash-88485a84a5ef7fa3ac04ec7d3a0a5f8e8d98277f7d622d5a237a2e082609361c
Deploy hash: cfbdf59372fe495f43fa4399212409ee10a9e63bddf1a0731d5be00fc606665d
Deploy result:
{
deploy: {
hash: 'cfbdf59372fe495f43fa4399212409ee10a9e63bddf1a0731d5be00fc606665d',
header: {
account: '0111bda4d4165a97b997722f3666649c8229b62f49ee91a5a0820b311d9556f36f',
timestamp: '2021-09-23T16:49:05.688Z',
ttl: '30m',
gas_price: 1,
body_hash: 'fc64d60a09f73d690bce315e4f2b37ddddefabe7f5ca110e96cb57fadce6bcf5',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { Transfer: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
namedKeys: [],
mainPurse: 'uref-e59903e0ef3247047aee63359cf6c2a24ae159dd11dca9886c3fab68d248f0aa-007',
associatedKeys: [
{
accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
0.2 Install Keys Manager contract
Signed by: account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756
Deploy hash: 406985d83412884ac0157547b8c3cda51ede9703fe221602499f62ed1d08a21c
Deploy result:
{
deploy: {
hash: '406985d83412884ac0157547b8c3cda51ede9703fe221602499f62ed1d08a21c',
header: {
account: '02034eb6b820195f190801a57d43750eb05e934dd9956d7fc01e4d98eba933f3ccce',
timestamp: '2021-09-23T16:50:12.631Z',
ttl: '30m',
gas_price: 1,
body_hash: '5e6f26e6f26d50c3c5023d1f7b70ed47006fcbf1704e99319ade074a87e5cce7',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { ModuleBytes: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5c28d5847cfe1aa456d67e73bf6b42ccdc88b1045ec638e8c512a8a20e74c7a5'
},
{
name: 'keys_manager_hash',
key: 'uref-fcc2398e8232e6a6599d2f4e345fee9c0c1e596caefea671d5ba3cbbce51e9c1-007'
}
],
mainPurse: 'uref-e59903e0ef3247047aee63359cf6c2a24ae159dd11dca9886c3fab68d248f0aa-007',
associatedKeys: [
{
accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. Set weight of mainAccount to 2.
Signed by: account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756
Deploy hash: dcb76929d1b4a1e6630c2914b6de949681d2688be85c0ce42fd232e08f1406f8
Deploy result:
{
deploy: {
hash: 'dcb76929d1b4a1e6630c2914b6de949681d2688be85c0ce42fd232e08f1406f8',
header: {
account: '02034eb6b820195f190801a57d43750eb05e934dd9956d7fc01e4d98eba933f3ccce',
timestamp: '2021-09-23T16:51:18.882Z',
ttl: '30m',
gas_price: 1,
body_hash: '6a15d714af09c0512063e234b015a3cddc4431e221ff8f366d424340e603bf4b',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5c28d5847cfe1aa456d67e73bf6b42ccdc88b1045ec638e8c512a8a20e74c7a5'
},
{
name: 'keys_manager_hash',
key: 'uref-fcc2398e8232e6a6599d2f4e345fee9c0c1e596caefea671d5ba3cbbce51e9c1-007'
}
],
mainPurse: 'uref-e59903e0ef3247047aee63359cf6c2a24ae159dd11dca9886c3fab68d248f0aa-007',
associatedKeys: [
{
accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
weight: 2
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. 2. Set weight of firstAccount to 1.
Signed by: account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756
Deploy hash: a2d99fff68481ba9af7d63a8275fbb5131f974de1ce4e09207eb413f91a9588a
Deploy result:
{
deploy: {
hash: 'a2d99fff68481ba9af7d63a8275fbb5131f974de1ce4e09207eb413f91a9588a',
header: {
account: '02034eb6b820195f190801a57d43750eb05e934dd9956d7fc01e4d98eba933f3ccce',
timestamp: '2021-09-23T16:52:23.512Z',
ttl: '30m',
gas_price: 1,
body_hash: '5a4caa0cc6ce982a64cb2010eee4cbf06516f23cc4ed4863c097ab5def887028',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5c28d5847cfe1aa456d67e73bf6b42ccdc88b1045ec638e8c512a8a20e74c7a5'
},
{
name: 'keys_manager_hash',
key: 'uref-fcc2398e8232e6a6599d2f4e345fee9c0c1e596caefea671d5ba3cbbce51e9c1-007'
}
],
mainPurse: 'uref-e59903e0ef3247047aee63359cf6c2a24ae159dd11dca9886c3fab68d248f0aa-007',
associatedKeys: [
{
accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
weight: 2
},
{
accountHash: 'account-hash-b45f2509c4790265805578cfad17d0de4658032bb26d9debdd9d830510615267',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
2. 3. Set Keys Management Threshold to 2.
Signed by: account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756
Deploy hash: 996eaf1f2203aaf3e2df2706c9c7c6e157261056facbc716cfabf8e3451b0f00
Deploy result:
{
deploy: {
hash: '996eaf1f2203aaf3e2df2706c9c7c6e157261056facbc716cfabf8e3451b0f00',
header: {
account: '02034eb6b820195f190801a57d43750eb05e934dd9956d7fc01e4d98eba933f3ccce',
timestamp: '2021-09-23T16:53:29.113Z',
ttl: '30m',
gas_price: 1,
body_hash: '9357475174b44041d5a89a9091cded242fedc567af82c7fa920d5ec13d5c7f74',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5c28d5847cfe1aa456d67e73bf6b42ccdc88b1045ec638e8c512a8a20e74c7a5'
},
{
name: 'keys_manager_hash',
key: 'uref-fcc2398e8232e6a6599d2f4e345fee9c0c1e596caefea671d5ba3cbbce51e9c1-007'
}
],
mainPurse: 'uref-e59903e0ef3247047aee63359cf6c2a24ae159dd11dca9886c3fab68d248f0aa-007',
associatedKeys: [
{
accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
weight: 2
},
{
accountHash: 'account-hash-b45f2509c4790265805578cfad17d0de4658032bb26d9debdd9d830510615267',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 2 }
}
3. 4. Set Deploy Threshold to 1.
Signed by: account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756
Deploy hash: 46ad9ef63f60b957c11d1796b391127e86bd85a67e967f64e54944572a7b6a4e
Deploy result:
{
deploy: {
hash: '46ad9ef63f60b957c11d1796b391127e86bd85a67e967f64e54944572a7b6a4e',
header: {
account: '02034eb6b820195f190801a57d43750eb05e934dd9956d7fc01e4d98eba933f3ccce',
timestamp: '2021-09-23T16:54:34.717Z',
ttl: '30m',
gas_price: 1,
body_hash: '4807b024a8e1e7c7d1da5a9101a21f38303d4689905d88d4585eec852fd7216b',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5c28d5847cfe1aa456d67e73bf6b42ccdc88b1045ec638e8c512a8a20e74c7a5'
},
{
name: 'keys_manager_hash',
key: 'uref-fcc2398e8232e6a6599d2f4e345fee9c0c1e596caefea671d5ba3cbbce51e9c1-007'
}
],
mainPurse: 'uref-e59903e0ef3247047aee63359cf6c2a24ae159dd11dca9886c3fab68d248f0aa-007',
associatedKeys: [
{
accountHash: 'account-hash-719252a6bb1fd21ba3b3323b6ee57d2a711d43840d4821ba687f02adb125f756',
weight: 2
},
{
accountHash: 'account-hash-b45f2509c4790265805578cfad17d0de4658032bb26d9debdd9d830510615267',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 2 }
}
```
:::
#### [Scenario 3: Signing transactions with multiple keys](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html#scenario-3-signing-transactions-with-multiple-keys)
###### Description
Sometimes you will require multiple associated keys to execute a transaction. In this example, we have two associated keys with a weight equal to 1. To make changes to the account, you need to use both keys to sign the transaction. However, for deployment, each key can sign separately and perform deployments independently.
:::spoiler
<summary>Faucet account in scenario 3:</summary>
```bash
{
"api_version": "1.0.0",
"merkle_proof": "01000…..11",
"stored_value": {
"Account": {
"account_address": "account-address-a1…",
"action_thresholds": {
"deployment": 1,
"key_management": 2
},
"associated_keys": [
{
"account_address": "account-address-a1…",
"weight": 1 // can deploy, but needs to sign with b2 to manage account
},
{
"account_address": "account-address-b2…",
"weight": 1 // can deploy, but needs to sign with a1 to manage account
}
],
"main_purse": "uref-1234…",
"named_keys": []
}
}
}
```
:::
:::spoiler
<summary>scenario-3.js:</summary>
```bash=
const keyManager = require('./key-manager');
const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000;
(async function () {
// Scenario #3 Description:
// Sometimes you will require multiple associated keys to execute a transaction.
// In this example, we have two associated keys with a weight equal to 1.
// To make changes to the account, you need to use both keys to sign the transaction.
// However, for deployment, each key can sign separately and perform deployments independently.
// So we will need two keys.
// It would be 'mainAccount' and 'firstAccount'.
// From that Scenario we will start using 'setAll' function of the keyManager.
// To achieve the task, we will:
// 1. Set weight of mainAccount and firstAccount to 1.
// 2. Set Keys Management Threshold to 2.
// 3. Set Deploy Threshold to 1.
// 4. Deploy account changes using 'setAll' function.
const masterKey = keyManager.randomMasterKey();
const mainAccount = masterKey.deriveIndex(1);
const firstAccount = masterKey.deriveIndex(2);
console.log("Main account: " + mainAccount.publicKey.toHex());
console.log("First account: " + firstAccount.publicKey.toHex());
let deploy;
console.log("\n0.1 Funding main account.");
await keyManager.fundAccount(mainAccount);
await keyManager.printAccount(mainAccount);
console.log("\n0.2 Install Keys Manager contract");
deploy = keyManager.keys.buildContractInstallDeploy(mainAccount);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 1. Set weight of mainAccount and firstAccount to 1.
// Weight of Accounts is 1
const AccountWeight = 1;
// Every account weight is set to 1
const accounts = [
{ publicKey: mainAccount.publicKey, weight: AccountWeight },
{ publicKey: firstAccount.publicKey, weight: AccountWeight },
];
// 2. Set Keys Management Threshold to 2.
const keyManagementThreshold = 2;
// 3. Set Deploy Threshold to 1.
const deployThreshold = 1;
// 4. Deploy account changes.
console.log("\n 1. Set weight of mainAccount and firstAccount to 1.");
console.log("\n 2. Set Keys Management Threshold to 2.");
console.log("\n 3. Set Deploy Threshold to 1.");
console.log("\n Update keys deploy.");
deploy = keyManager.keys.setAll(mainAccount, deployThreshold, keyManagementThreshold, accounts);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
})();
```
:::
Execute Scenario-3.js
```bash=
npm run start:scenario-3
```
![](https://i.imgur.com/DLmbag4.gif)
:::spoiler
<summary>Full result</summary>
```bash=
> keys-manager@1.0.0 start:scenario-3 /home/zage/code/casper-get-started-3/client
> node -r dotenv/config ./src/scenario-3.js
Main account: 0202b1f8856f512515446dc06dc65882efa106916d402e9a80569c3ce8c64ec4c41c
First account: 02023904fc688c7530c23ea7d9171a756c02630e6bdff1d48a2b122a070b3bc355e9
0.1 Funding main account.
Signed by: account-hash-88485a84a5ef7fa3ac04ec7d3a0a5f8e8d98277f7d622d5a237a2e082609361c
Deploy hash: 84ba1db6ab318b92dc345f3653c5fe49f609e84f90dcdadbe660b950af50dfec
Deploy result:
{
deploy: {
hash: '84ba1db6ab318b92dc345f3653c5fe49f609e84f90dcdadbe660b950af50dfec',
header: {
account: '0111bda4d4165a97b997722f3666649c8229b62f49ee91a5a0820b311d9556f36f',
timestamp: '2021-09-23T17:06:37.701Z',
ttl: '30m',
gas_price: 1,
body_hash: 'e3b1ed398948c6e793c21febea0d48288b43fdbdd318a34e17c90d257d79c830',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { Transfer: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a',
namedKeys: [],
mainPurse: 'uref-7bcd779a49e6013a9bb140b46e3ceaf5ba8ead7d34663838e75f495ef1d3c163-007',
associatedKeys: [
{
accountHash: 'account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
0.2 Install Keys Manager contract
Signed by: account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a
Deploy hash: ed40e487b38c77a4cf1edbe0c080488f723370a6f8820f45c867e98b6faa359a
Deploy result:
{
deploy: {
hash: 'ed40e487b38c77a4cf1edbe0c080488f723370a6f8820f45c867e98b6faa359a',
header: {
account: '0202b1f8856f512515446dc06dc65882efa106916d402e9a80569c3ce8c64ec4c41c',
timestamp: '2021-09-23T17:07:41.690Z',
ttl: '30m',
gas_price: 1,
body_hash: '5e6f26e6f26d50c3c5023d1f7b70ed47006fcbf1704e99319ade074a87e5cce7',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { ModuleBytes: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5f8edf3e7dc18a9bae823ef688278f1f50c834d7edc6eb43589b2b178c3d7ada'
},
{
name: 'keys_manager_hash',
key: 'uref-6e2fff909514f24ede1ed34eb98195266b5ee679d766679b4331b75babf0200c-007'
}
],
mainPurse: 'uref-7bcd779a49e6013a9bb140b46e3ceaf5ba8ead7d34663838e75f495ef1d3c163-007',
associatedKeys: [
{
accountHash: 'account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. Set weight of mainAccount and firstAccount to 1.
2. Set Keys Management Threshold to 2.
3. Set Deploy Threshold to 1.
Update keys deploy.
Signed by: account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a
Deploy hash: 56909debcdfa0bf0a47c6e26688b07c8bdee80331b707411da408fb186174e78
Deploy result:
{
deploy: {
hash: '56909debcdfa0bf0a47c6e26688b07c8bdee80331b707411da408fb186174e78',
header: {
account: '0202b1f8856f512515446dc06dc65882efa106916d402e9a80569c3ce8c64ec4c41c',
timestamp: '2021-09-23T17:08:46.882Z',
ttl: '30m',
gas_price: 1,
body_hash: '3da9512bb9ec41a8a674cf97fda3d00c318e41f3fcd66ee156278ecb0d975b82',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-5f8edf3e7dc18a9bae823ef688278f1f50c834d7edc6eb43589b2b178c3d7ada'
},
{
name: 'keys_manager_hash',
key: 'uref-6e2fff909514f24ede1ed34eb98195266b5ee679d766679b4331b75babf0200c-007'
}
],
mainPurse: 'uref-7bcd779a49e6013a9bb140b46e3ceaf5ba8ead7d34663838e75f495ef1d3c163-007',
associatedKeys: [
{
accountHash: 'account-hash-0fb39b10fa903095f287f8a55fbcc2e59fa7bab4bbe52b35ad1d33b04c7ff570',
weight: 1
},
{
accountHash: 'account-hash-2f37c6f85a3d4c5a6f5cecb41cd53c332dfd017b474fe4ccc4a77b973c84cc4a',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 2 }
}
```
:::
#### [Scenario 4: managing lost or stolen keys](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html#scenario-4-managing-lost-or-stolen-keys)
###### Description
In this example, you need two out of three associated keys to sign a transaction. Consider a transaction where you have one key in your browser, one key on your mobile phone, and one key in your safe. To do a transaction, first, you sign it with your browser extension (for example, Metamask). Afterward, a notification appears on your mobile phone requesting you to approve the transaction. With these two keys, you can complete the transaction. However, what if you lose the two keys on your browser and phone? Or, what if someone steals your browser and phone? In this case, you can use the safe key to remove the lost or stolen keys from the account. Notice that the safe key’s weight is 3, which gives you the option to manage your account and add or remove keys. Also, the stolen or lost keys can only enable deployments, and in this case, no one can use them to change your account.
:::spoiler
<summary>Faucet account in scenario 4:</summary>
```bash=
{
"api_version": "1.0.0",
"merkle_proof": "01000…..11",
"stored_value": {
"Account": {
"account_address": "account-address-a1…",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_address": "account-address-a1…", // a browser key
"weight": 1
},
{
"account_address": "account-address-b2…", // a mobile key
"weight": 1
},
{
"account_address": "account-address-c3…", // a safe key
"weight": 3
}
],
"main_purse": "uref-1234…",
"named_keys": []
}
}
}
```
:::
:::spoiler
<summary>scenario-4.js:</summary>
```bash=
const keyManager = require('./key-manager');
const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000;
(async function () {
// Scenario #4 Description:
// In this example, you need two out of three associated keys to sign a transaction.
// Consider a transaction where you have one key in your browser, one key on your mobile phone, and one key in your safe.
// To do a transaction, first, you sign it with your browser extension (for example, Metamask).
// Afterward, a notification appears on your mobile phone requesting you to approve the transaction.
// With these two keys, you can complete the transaction.
// However, what if you lose the two keys on your browser and phone?
// Or, what if someone steals your browser and phone? In this case, you can use the safe key to remove the lost or stolen keys from the account.
// Notice that the safe key’s weight is 3, which gives you the option to manage your account and add or remove keys.
// Also, the stolen or lost keys can only enable deployments, and in this case, no one can use them to change your account.
// So we will need three keys.
// It would be 'safeAccount','browserAccount' and 'mobileAccount'.
// To deploy updates to the Account we will use 'setAll' function of the keyManager.
// To achieve the task, we will:
// 1. Set weight of safeAccount to 3.
// 2. Set weight of browserAccount and mobileAccount to 1.
// 3. Set Keys Management Threshold to 3.
// 4. Set Deploy Threshold to 2.
// 5. Deploy account changes using 'setAll' function.
const masterKey = keyManager.randomMasterKey();
const safeAccount = masterKey.deriveIndex(1);
const browserAccount = masterKey.deriveIndex(2);
const mobileAccount = masterKey.deriveIndex(3);
console.log("Safe account: " + safeAccount.publicKey.toHex());
console.log("Browser account: " + browserAccount.publicKey.toHex());
console.log("Mobile account: " + mobileAccount.publicKey.toHex());
let deploy;
console.log("\n0.1 Funding safe account.");
await keyManager.fundAccount(safeAccount);
await keyManager.printAccount(safeAccount);
console.log("\n0.2 Install Keys Manager contract");
deploy = keyManager.keys.buildContractInstallDeploy(safeAccount);
await keyManager.sendDeploy(deploy, [safeAccount]);
await keyManager.printAccount(safeAccount);
// 1. Set weight of safeAccount to 3.
const safeAccountWeight = 3;
// 2. Set weight of browserAccount and mobileAccount to 1.
const keyAccountWeight = 1;
const accounts = [
{ publicKey: safeAccount.publicKey, weight: safeAccountWeight },
{ publicKey: browserAccount.publicKey, weight: keyAccountWeight },
{ publicKey: mobileAccount.publicKey, weight: keyAccountWeight },
];
// 3. Set Keys Management Threshold to 3.
const keyManagementThreshold = 3;
// 4. Set Deploy Threshold to 2.
const deployThreshold = 2;
// 5. Deploy account changes using 'setAll' function.
console.log("\n 1. Set weight of safeAccount to 3.");
console.log("\n 2. Set weight of browserAccount and mobileAccount to 1.");
console.log("\n 3. Set Keys Management Threshold to 3.");
console.log("\n 4. Set Deploy Threshold to 2.");
console.log("\n Update keys deploy.");
deploy = keyManager.keys.setAll(safeAccount, deployThreshold, keyManagementThreshold, accounts);
await keyManager.sendDeploy(deploy, [safeAccount]);
await keyManager.printAccount(safeAccount);
})();
```
:::
Execute Scenario-4.js
```bash=
npm run start:scenario-4
```
![](https://i.imgur.com/YYHLT9P.gif)
:::spoiler
<summary>Full result</summary>
```bash=
> keys-manager@1.0.0 start:scenario-4 /home/zage/code/casper-get-started-3/client
> node -r dotenv/config ./src/scenario-4.js
Safe account: 020241caf8274642556b5e0ab44d22ad3f8d695ad8d6d3f9d984c598745fda83568e
Browser account: 0203c5293d70e626b2fc0c1c89c624cdce232b9fe7fb8c556ade37ff61a312e19f6b
Mobile account: 02023d70418c42ee35ab6c5763fd8b194633a4592fff3955d233f0b79a0c182ae539
0.1 Funding safe account.
Signed by: account-hash-88485a84a5ef7fa3ac04ec7d3a0a5f8e8d98277f7d622d5a237a2e082609361c
Deploy hash: 563319584a57f24689f56ea08f9956a6b39ec3fe236e80dd3d64ca487747eac4
Deploy result:
{
deploy: {
hash: '563319584a57f24689f56ea08f9956a6b39ec3fe236e80dd3d64ca487747eac4',
header: {
account: '0111bda4d4165a97b997722f3666649c8229b62f49ee91a5a0820b311d9556f36f',
timestamp: '2021-09-23T17:14:49.418Z',
ttl: '30m',
gas_price: 1,
body_hash: '7053f02f9ea9c6a88c0f5945dcb8b047e72febbbe537f7d72064aa7725bbf600',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { Transfer: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d',
namedKeys: [],
mainPurse: 'uref-10215c945d6969e8b4a559f450c7fb1be0919e83f0633a518827e8fcdf6ef260-007',
associatedKeys: [
{
accountHash: 'account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
0.2 Install Keys Manager contract
Signed by: account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d
Deploy hash: 7075dbb286e9fd31d6c1f04740d3c89437936f9c2f450b8e6a174c5665d8c7d8
Deploy result:
{
deploy: {
hash: '7075dbb286e9fd31d6c1f04740d3c89437936f9c2f450b8e6a174c5665d8c7d8',
header: {
account: '020241caf8274642556b5e0ab44d22ad3f8d695ad8d6d3f9d984c598745fda83568e',
timestamp: '2021-09-23T17:15:52.551Z',
ttl: '30m',
gas_price: 1,
body_hash: '5e6f26e6f26d50c3c5023d1f7b70ed47006fcbf1704e99319ade074a87e5cce7',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { ModuleBytes: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-f180c126b4238f46ebe8f11050d3196866b71a8f405d77d662672055404d2376'
},
{
name: 'keys_manager_hash',
key: 'uref-8936ee5d2e9c6eccdb2526e18c323e5872c62b75635b227d108f33af0f1cbb1a-007'
}
],
mainPurse: 'uref-10215c945d6969e8b4a559f450c7fb1be0919e83f0633a518827e8fcdf6ef260-007',
associatedKeys: [
{
accountHash: 'account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. Set weight of safeAccount to 3.
2. Set weight of browserAccount and mobileAccount to 1.
3. Set Keys Management Threshold to 3.
4. Set Deploy Threshold to 2.
Update keys deploy.
Signed by: account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d
Deploy hash: 0db4a9b05b144fa922e640c99492d7f2e8d97a051a936d6959e90d7f34bd0aee
Deploy result:
{
deploy: {
hash: '0db4a9b05b144fa922e640c99492d7f2e8d97a051a936d6959e90d7f34bd0aee',
header: {
account: '020241caf8274642556b5e0ab44d22ad3f8d695ad8d6d3f9d984c598745fda83568e',
timestamp: '2021-09-23T17:16:58.921Z',
ttl: '30m',
gas_price: 1,
body_hash: '741540474550620ae5ed8327e9fc6c891551c8005ac78c38afaf2d0602ad776a',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-f180c126b4238f46ebe8f11050d3196866b71a8f405d77d662672055404d2376'
},
{
name: 'keys_manager_hash',
key: 'uref-8936ee5d2e9c6eccdb2526e18c323e5872c62b75635b227d108f33af0f1cbb1a-007'
}
],
mainPurse: 'uref-10215c945d6969e8b4a559f450c7fb1be0919e83f0633a518827e8fcdf6ef260-007',
associatedKeys: [
{
accountHash: 'account-hash-532fa4017895973a7634ee75aa42f923704fb68eaae811d7799cbd68b851ddfa',
weight: 1
},
{
accountHash: 'account-hash-ac0373dd91890535dba38a6bff7becfd18a6822893fcfbabe2b3d9300000551d',
weight: 3
},
{
accountHash: 'account-hash-bfa3b6a3e5581be888184ac2d38ea8832a48d7a3a7b49b69e824ff4bbb4f8cd7',
weight: 1
}
],
actionThresholds: { deployment: 2, keyManagement: 3 }
}
```
:::
#### [Scenario 5: managing accounts with multiple keys](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html#scenario-5-managing-accounts-with-multiple-keys)
###### Description
This example builds upon the previous example, where you can set up multiple safe keys for account management. In this scenario, the safe keys have the weight required to manage your keys and account.
:::spoiler
<summary>Faucet account in scenario 5:</summary>
```bash=
{
"api_version": "1.0.0",
"merkle_proof": "01000…..11",
"stored_value": {
"Account": {
"account_address": "account-address-a1…",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_address": "account-address-a1…", // a browser key
"weight": 1
},
{
"account_address": "account-address-b2…", // a mobile key
"weight": 1
},
{
"account_address": "account-address-c3…", // a safe key 1
"weight": 3
},
{
"account_address": "account-address-d4…", // a safe key 2
"weight": 3
},
{
"account_address": "account-address-e5…", // a safe key 3
"weight": 3
}
],
"main_purse": "uref-1234…",
"named_keys": []
}
}
}
```
:::
:::spoiler
<summary>scenario-5.js:</summary>
```bash=
const keyManager = require('./key-manager');
const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000;
(async function () {
// Scenario #5 Description:
// This example builds upon the Scenario #4 example, where you can set up multiple safe keys for account management.
// In this scenario, the safe keys have the weight required to manage your keys and account.
// So we will need 5 keys.
// It would be 'safeAccount','safeAccount1','safeAccount2','browserAccount' and 'mobileAccount'.
// To deploy updates to the Account we will use 'setAll' function of the keyManager.
// To achieve the task, we will:
// 1. Set weight of all safe accounts to 3.
// 2. Set weight of browserAccount and mobileAccount to 1.
// 3. Set Keys Management Threshold to 3.
// 4. Set Deploy Threshold to 2.
// 5. Deploy account changes using 'setAll' function.
const masterKey = keyManager.randomMasterKey();
const safeAccount = masterKey.deriveIndex(1);
const safeAccount1 = masterKey.deriveIndex(2);
const safeAccount2 = masterKey.deriveIndex(2);
const browserAccount = masterKey.deriveIndex(3);
const mobileAccount = masterKey.deriveIndex(4);
console.log("Main account: " + safeAccount.publicKey.toHex());
console.log("Safe account #1: " + safeAccount1.publicKey.toHex());
console.log("Safe account #2: " + safeAccount2.publicKey.toHex());
console.log("Browser account: " + browserAccount.publicKey.toHex());
console.log("Mobile account: " + mobileAccount.publicKey.toHex());
let deploy;
console.log("\n0.1 Funding safe account.");
await keyManager.fundAccount(safeAccount);
await keyManager.printAccount(safeAccount);
console.log("\n0.2 Install Keys Manager contract");
deploy = keyManager.keys.buildContractInstallDeploy(safeAccount);
await keyManager.sendDeploy(deploy, [safeAccount]);
await keyManager.printAccount(safeAccount);
// 1. Set weight of all safe accounts to 3.
const safeAccountWeight = 3;
// 2. Set weight of browserAccount and mobileAccount to 1.
const keyAccountWeight = 1;
const accounts = [
{ publicKey: safeAccount.publicKey, weight: safeAccountWeight },
{ publicKey: safeAccount1.publicKey, weight: safeAccountWeight },
{ publicKey: safeAccount2.publicKey, weight: safeAccountWeight },
{ publicKey: browserAccount.publicKey, weight: keyAccountWeight },
{ publicKey: mobileAccount.publicKey, weight: keyAccountWeight },
];
// 3. Set Keys Management Threshold to 3.
const keyManagementThreshold = 3;
// 4. Set Deploy Threshold to 2.
const deployThreshold = 2;
// 5. Deploy account changes using 'setAll' function.
console.log("\n 1. Set weight of both safe accounts to 3.");
console.log("\n 2. Set weight of browserAccount and mobileAccount to 1.");
console.log("\n 3. Set Keys Management Threshold to 3.");
console.log("\n 4. Set Deploy Threshold to 2.");
console.log("\n Update keys deploy.");
deploy = keyManager.keys.setAll(safeAccount, deployThreshold, keyManagementThreshold, accounts);
await keyManager.sendDeploy(deploy, [safeAccount]);
await keyManager.printAccount(safeAccount);
})();
```
:::
Execute Scenario-5.js
```bash=
npm run start:scenario-5
```
![](https://i.imgur.com/1wEL0tF.gif)
:::spoiler
<summary>Full result</summary>
```bash=
> keys-manager@1.0.0 start:scenario-5 /home/zage/code/casper-get-started-3/client
> node -r dotenv/config ./src/scenario-5.js
Main account: 0202a1c70f00fd7fb912aadb4f5b152c2415d5ec290981f235ae8fa92acdb23c3a1c
Safe account #1: 0202792f7eb21e470a981e9f1addcad64a08bb8204a30945a4d93914cdbf05560c28
Safe account #2: 02021e8c7e5ae4db6f6910ca2578b4846f8d36e7039bacc64396da645a1a5f378131
Browser account: 0202302dfe87479ca404e4f3efb6a4b3fea0b3f2ad61394a183cf55e5e5fd0a4996c
Mobile account: 0202210519b367760824641ca721feea41f98ebac38793f1da28bad9ce79ecd4adb6
0.1 Funding safe account.
Signed by: account-hash-88485a84a5ef7fa3ac04ec7d3a0a5f8e8d98277f7d622d5a237a2e082609361c
Deploy hash: 0edfc8bad40de00021bab0002e40b7df7e7b400d4a5a043c285d9eeb43b93764
Deploy result:
{
deploy: {
hash: '0edfc8bad40de00021bab0002e40b7df7e7b400d4a5a043c285d9eeb43b93764',
header: {
account: '0111bda4d4165a97b997722f3666649c8229b62f49ee91a5a0820b311d9556f36f',
timestamp: '2021-09-23T17:32:04.473Z',
ttl: '30m',
gas_price: 1,
body_hash: 'a8760f2f1f5beabd698c217aa1d5567c607f70d417849b65428b26c76800085c',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { Transfer: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28',
namedKeys: [],
mainPurse: 'uref-ef173e5a88aa5f74925f2baeae1ef6d7ee5877d0825df07ce7da2a5d056d81a4-007',
associatedKeys: [
{
accountHash: 'account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
0.2 Install Keys Manager contract
Signed by: account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28
Deploy hash: 6af9f966e1c1db31a3f3b0e51b5de543fceebbb61883d21e652ef9dc2d28d13e
Deploy result:
{
deploy: {
hash: '6af9f966e1c1db31a3f3b0e51b5de543fceebbb61883d21e652ef9dc2d28d13e',
header: {
account: '0202a1c70f00fd7fb912aadb4f5b152c2415d5ec290981f235ae8fa92acdb23c3a1c',
timestamp: '2021-09-23T17:33:09.517Z',
ttl: '30m',
gas_price: 1,
body_hash: '5e6f26e6f26d50c3c5023d1f7b70ed47006fcbf1704e99319ade074a87e5cce7',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { ModuleBytes: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-9e0d682906d125cf8410eaee46afad4083ce72c9e304a010184fb21a3d46d7d3'
},
{
name: 'keys_manager_hash',
key: 'uref-653b0a00e87509fd41ac74562647fbae91b92c2a014659a4df86e7e0faa7dc33-007'
}
],
mainPurse: 'uref-ef173e5a88aa5f74925f2baeae1ef6d7ee5877d0825df07ce7da2a5d056d81a4-007',
associatedKeys: [
{
accountHash: 'account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. Set weight of all safe accounts to 3.
2. Set weight of browserAccount and mobileAccount to 1.
3. Set Keys Management Threshold to 3.
4. Set Deploy Threshold to 2.
Update keys deploy.
Signed by: account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28
Deploy hash: 80935575e5f772d42fff34e1d9c07ee51defb6ec719955be7fae787af1dc6e6f
Deploy result:
{
deploy: {
hash: '80935575e5f772d42fff34e1d9c07ee51defb6ec719955be7fae787af1dc6e6f',
header: {
account: '0202a1c70f00fd7fb912aadb4f5b152c2415d5ec290981f235ae8fa92acdb23c3a1c',
timestamp: '2021-09-23T17:34:14.758Z',
ttl: '30m',
gas_price: 1,
body_hash: 'd27ac4563d50f2f16c701c211f2582126f4a292b4ad95f68c8a587cce04f194c',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-9e0d682906d125cf8410eaee46afad4083ce72c9e304a010184fb21a3d46d7d3'
},
{
name: 'keys_manager_hash',
key: 'uref-653b0a00e87509fd41ac74562647fbae91b92c2a014659a4df86e7e0faa7dc33-007'
}
],
mainPurse: 'uref-ef173e5a88aa5f74925f2baeae1ef6d7ee5877d0825df07ce7da2a5d056d81a4-007',
associatedKeys: [
{
accountHash: 'account-hash-1185065a7ae676f0e46363714d6e268b3a0afc2e7bdd0b85cdbb79093062c91e',
weight: 3
},
{
accountHash: 'account-hash-14c471c7acccbc4703d9a3bbd0eda234d37f50e175b591f7267b7cf2f56ce4c1',
weight: 3
},
{
accountHash: 'account-hash-9a9d9ddd8bd533192d54ee86b7fcd05d9505e5c5edc79e42b2aca899356f1e28',
weight: 3
},
{
accountHash: 'account-hash-b14126e7f5fd5e2f56e9552d2f0e0090dbda25ed78728852942662bbdee05bd7',
weight: 1
},
{
accountHash: 'account-hash-f917577dc56c310bcb8f2c8d7293aac07183d60c93dc2cd05ce13269bfa8f327',
weight: 1
}
],
actionThresholds: { deployment: 2, keyManagement: 3 }
}
```
:::
#### [Scenario 6: losing your primary account key](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html#scenario-6-losing-your-primary-account-key)
##### Description
Suppose you lose your account key; in this case, “account-hash-00…”, you can set up other keys to execute transactions. Although not recommended, you can throw away the private key of your account or set its weight to zero, and you would still be able to execute transactions if your faucet account has backup keys that can perform key management.
:::spoiler
<summary>Faucet account in scenario 6:</summary>
```bash=
{
"api_version": "1.0.0",
"merkle_proof": "01000…..11",
"stored_value": {
"Account": {
"account_address": "account-address-00…",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_address": "account-address-00…", // the account key
"weight": 0
},
{
"account_address": "account-address-a1…", // a browser key
"weight": 1
},
{
"account_address": "account-address-b2…", // a mobile key
"weight": 1
},
{
"account_address": "account-address-c3…", // a safe key 1
"weight": 3
},
{
"account_address": "account-address-d4…", // a safe key 2
"weight": 3
},
{
"account_address": "account-address-e5…", // a safe key 3
"weight": 3
}
],
"main_purse": "uref-1234…",
"named_keys": []
}
}
}
```
:::
:::spoiler
<summary>scenario-6.js:</summary>
```bash=
const keyManager = require('./key-manager');
const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000;
(async function () {
// Scenario #6 Description:
// Suppose you lose your account key; in this case, “account-hash-00…”, you can set up other keys to execute transactions.
// Although not recommended, you can throw away the private key of your account or set its weight to zero,
// and you would still be able to execute transactions if your faucet account has backup keys that can perform key management.
// So we will need 6 keys.
// It would be 'mainAccount','safeAccount','safeAccount1','safeAccount2','browserAccount' and 'mobileAccount'.
// To deploy updates to the Account we will use 'setAll' function of the keyManager.
// After losing the main key, we will set it's weight to 0
// To achieve the task, we will:
// 1. Set weight of mainAccount and safe accounts to 3.
// 2. Set weight of browserAccount and mobileAccount to 1.
// 3. Set Keys Management Threshold to 3.
// 4. Set Deploy Threshold to 2.
// 5. Deploy account changes using 'setAll' function.
// 6. Set weight of lost mainAccount key to 0.
const masterKey = keyManager.randomMasterKey();
const mainAccount = masterKey.deriveIndex(1);
const safeAccount1 = masterKey.deriveIndex(2);
const safeAccount2 = masterKey.deriveIndex(3);
const safeAccount3 = masterKey.deriveIndex(4);
const browserAccount = masterKey.deriveIndex(5);
const mobileAccount = masterKey.deriveIndex(6);
console.log("Main account: " + mainAccount.publicKey.toHex());
console.log("Safe account #1: " + safeAccount1.publicKey.toHex());
console.log("Safe account #2: " + safeAccount2.publicKey.toHex());
console.log("Safe account #3: " + safeAccount3.publicKey.toHex());
console.log("Browser account: " + browserAccount.publicKey.toHex());
console.log("Mobile account: " + mobileAccount.publicKey.toHex());
let deploy;
console.log("\n0.1 Funding safe account.");
await keyManager.fundAccount(mainAccount);
await keyManager.printAccount(mainAccount);
console.log("\n0.2 Install Keys Manager contract");
deploy = keyManager.keys.buildContractInstallDeploy(mainAccount);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 1. Set weight of mainAccount and safe accounts to 3.
const safeAccountWeight = 3;
// 2. Set weight of browserAccount and mobileAccount to 1.
const keyAccountWeight = 1;
const accounts = [
{ publicKey: mainAccount.publicKey, weight: safeAccountWeight },
{ publicKey: safeAccount1.publicKey, weight: safeAccountWeight },
{ publicKey: safeAccount2.publicKey, weight: safeAccountWeight },
{ publicKey: safeAccount3.publicKey, weight: safeAccountWeight },
{ publicKey: browserAccount.publicKey, weight: keyAccountWeight },
{ publicKey: mobileAccount.publicKey, weight: keyAccountWeight },
];
// 3. Set Keys Management Threshold to 3.
const keyManagementThreshold = 3;
// 4. Set Deploy Threshold to 2.
const deployThreshold = 2;
// 5. Deploy account changes using 'setAll' function.
console.log("\n 1. Set weight of mainAccount and safe accounts to 3.");
console.log("\n 2. Set weight of browserAccount and mobileAccount to 1.");
console.log("\n 3. Set Keys Management Threshold to 3.");
console.log("\n 4. Set Deploy Threshold to 2.");
console.log("\n 5. Update keys deploy.");
deploy = keyManager.keys.setAll(mainAccount, deployThreshold, keyManagementThreshold, accounts);
await keyManager.sendDeploy(deploy, [mainAccount]);
await keyManager.printAccount(mainAccount);
// 6. Set weight of lost mainAccount key to 0.
const lostAccountWeight = 0;
console.log("\n 6. Set weight of lost mainAccount key to 0.");
deploy = keyManager.keys.setKeyWeightDeploy(mainAccount,mainAccount,lostAccountWeight);
await keyManager.sendDeploy(deploy, [safeAccount1]);
await keyManager.printAccount(mainAccount);
})();
```
:::
Execute Scenario-6.js
```bash=
npm run start:scenario-6
```
![](https://i.imgur.com/ccNACXA.gif)
:::spoiler
<summary>Full result</summary>
```bash=
> keys-manager@1.0.0 start:scenario-6 /home/zage/code/casper-get-started-3/client
> node -r dotenv/config ./src/scenario-6.js
Main account: 02035c2879f7a80746bb1e7c86adcf39b342dbde26af83589f95d3b7b8b40dcc7249
Safe account #1: 0203e925c455b4c0b46a25f4870b25c1c5c5f64e5246d4cfc40f27e480297f46e09e
Safe account #2: 020315c68ed0e822d2d0403332f0b4fca38547c77f383bec425fee836d7867dcb3b6
Safe account #3: 02025930384d6449629e955f9b188cc961d61eddf278ff9ff53ca79428ada47d810d
Browser account: 0203e9e6cdc75e074698fb3f7c12950ff0f4debb6e423bf61590bede687271e3173f
Mobile account: 02030b7e7298d1ea4741f9c60eaa904830855c5649bb0e00258824ce036fb41f16f5
0.1 Funding safe account.
Signed by: account-hash-88485a84a5ef7fa3ac04ec7d3a0a5f8e8d98277f7d622d5a237a2e082609361c
Deploy hash: bb3b72ca2747fe98bbf4449ded20023d28a85ccfa88a4ebd621cc99956872c31
Deploy result:
{
deploy: {
hash: 'bb3b72ca2747fe98bbf4449ded20023d28a85ccfa88a4ebd621cc99956872c31',
header: {
account: '0111bda4d4165a97b997722f3666649c8229b62f49ee91a5a0820b311d9556f36f',
timestamp: '2021-09-23T17:52:39.087Z',
ttl: '30m',
gas_price: 1,
body_hash: '03131faa939267e77f876fd74cf4945a0ae453ec33800b6c5e7a6b26722d9a9a',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { Transfer: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
namedKeys: [],
mainPurse: 'uref-4f95ea17eff41e44872d5c993b7d0c0830c17b4769b947f70d33b1c09780807e-007',
associatedKeys: [
{
accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
0.2 Install Keys Manager contract
Signed by: account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5
Deploy hash: 88487ecbe6ba70a0ed6e6716de63581195993d254be1494d7d6fc24e43751c85
Deploy result:
{
deploy: {
hash: '88487ecbe6ba70a0ed6e6716de63581195993d254be1494d7d6fc24e43751c85',
header: {
account: '02035c2879f7a80746bb1e7c86adcf39b342dbde26af83589f95d3b7b8b40dcc7249',
timestamp: '2021-09-23T17:53:46.177Z',
ttl: '30m',
gas_price: 1,
body_hash: '5e6f26e6f26d50c3c5023d1f7b70ed47006fcbf1704e99319ade074a87e5cce7',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { ModuleBytes: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-ba4ae0565f7239927e7f19b07e95308482619321abc9a7ac9a36a15e237220ab'
},
{
name: 'keys_manager_hash',
key: 'uref-6a40c6574b25f27d304e96587d92057b618744c56cde8b2b3284762d4d4ee448-007'
}
],
mainPurse: 'uref-4f95ea17eff41e44872d5c993b7d0c0830c17b4769b947f70d33b1c09780807e-007',
associatedKeys: [
{
accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
weight: 1
}
],
actionThresholds: { deployment: 1, keyManagement: 1 }
}
1. Set weight of mainAccount and safe accounts to 3.
2. Set weight of browserAccount and mobileAccount to 1.
3. Set Keys Management Threshold to 3.
4. Set Deploy Threshold to 2.
5. Update keys deploy.
Signed by: account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5
Deploy hash: fb96233de09b14e237e804630b892577f6110d366e306ea439be38a3b4cc448d
Deploy result:
{
deploy: {
hash: 'fb96233de09b14e237e804630b892577f6110d366e306ea439be38a3b4cc448d',
header: {
account: '02035c2879f7a80746bb1e7c86adcf39b342dbde26af83589f95d3b7b8b40dcc7249',
timestamp: '2021-09-23T17:54:52.388Z',
ttl: '30m',
gas_price: 1,
body_hash: '3ea687262fb314d354be5544d8884e927752065b63dca210eb7c7ae044c787ac',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-ba4ae0565f7239927e7f19b07e95308482619321abc9a7ac9a36a15e237220ab'
},
{
name: 'keys_manager_hash',
key: 'uref-6a40c6574b25f27d304e96587d92057b618744c56cde8b2b3284762d4d4ee448-007'
}
],
mainPurse: 'uref-4f95ea17eff41e44872d5c993b7d0c0830c17b4769b947f70d33b1c09780807e-007',
associatedKeys: [
{
accountHash: 'account-hash-200ba113f6b253d6e702532557bc546773b6a0e57f2ac580301632ff42dda030',
weight: 1
},
{
accountHash: 'account-hash-6f260c4596639f9190f227cade8ca528ce56d1bc7ebab3a054c7423f8f5c5f5a',
weight: 3
},
{
accountHash: 'account-hash-771a8a4dd1dae2385c482f064b5285a0f4dcc9b93e5a1786292b2f4fec6270c2',
weight: 3
},
{
accountHash: 'account-hash-a35459670004116b31a95b1be48748923a43c616e5c4a46060a27d1efc921aa2',
weight: 1
},
{
accountHash: 'account-hash-a803499ec9cd980514d8b371ea0091a5d97376fd07e0e02001f535190ca9b1d3',
weight: 3
},
{
accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
weight: 3
}
],
actionThresholds: { deployment: 2, keyManagement: 3 }
}
6. Set weight of lost mainAccount key to 0.
Signed by: account-hash-771a8a4dd1dae2385c482f064b5285a0f4dcc9b93e5a1786292b2f4fec6270c2
Deploy hash: 42a036f2957d9a99f5b920bd9305eaf3001b585cd21e86d9e666fd168528f622
Deploy result:
{
deploy: {
hash: '42a036f2957d9a99f5b920bd9305eaf3001b585cd21e86d9e666fd168528f622',
header: {
account: '02035c2879f7a80746bb1e7c86adcf39b342dbde26af83589f95d3b7b8b40dcc7249',
timestamp: '2021-09-23T17:55:57.140Z',
ttl: '30m',
gas_price: 1,
body_hash: 'a93a5a12061ad5655535dd51ece02b12fc1296e6fcf7e9d9ec2025c0534c098d',
dependencies: [],
chain_name: 'casper-net-1'
},
payment: { ModuleBytes: [Object] },
session: { StoredContractByName: [Object] },
approvals: [ [Object] ]
}
}
[x] Current state of the account:
{
_accountHash: 'account-hash-c3e549a04b492a4135716248fa86336d86d9573ad2f8e4a5f24966eb86489cf5',
namedKeys: [
{
name: 'keys_manager',
key: 'hash-ba4ae0565f7239927e7f19b07e95308482619321abc9a7ac9a36a15e237220ab'
},
{
name: 'keys_manager_hash',
key: 'uref-6a40c6574b25f27d304e96587d92057b618744c56cde8b2b3284762d4d4ee448-007'
}
],
mainPurse: 'uref-4f95ea17eff41e44872d5c993b7d0c0830c17b4769b947f70d33b1c09780807e-007',
associatedKeys: [
{
accountHash: 'account-hash-200ba113f6b253d6e702532557bc546773b6a0e57f2ac580301632ff42dda030',
weight: 1
},
{
accountHash: 'account-hash-6f260c4596639f9190f227cade8ca528ce56d1bc7ebab3a054c7423f8f5c5f5a',
weight: 3
},
{
accountHash: 'account-hash-771a8a4dd1dae2385c482f064b5285a0f4dcc9b93e5a1786292b2f4fec6270c2',
weight: 3
},
{
accountHash: 'account-hash-a35459670004116b31a95b1be48748923a43c616e5c4a46060a27d1efc921aa2',
weight: 1
},
{
accountHash: 'account-hash-a803499ec9cd980514d8b371ea0091a5d97376fd07e0e02001f535190ca9b1d3',
weight: 3
}
],
actionThresholds: { deployment: 2, keyManagement: 3 }
}
```
:::
## Task #4 Learn to transfer tokens to an account on the [Casper Testnet](https://testnet.cspr.live/). Check out [this documentation](https://docs.casperlabs.io/en/latest/workflow/transfer-workflow.html).
### Transfer
#### Account creation and Funding
Account keys were created in [Task #1](https://hackmd.io/NAchgWMqQHmleHU868hEcg#Account-keys-Casper-Signer-and-Faucet) using ***casper-client*** command
Successfully exported to ***Casper Signer***
And funded by [Faucet](https://testnet.cspr.live/tools/faucet), finishing creation of accont on [Casper testnet](https://testnet.cspr.live/)
:::spoiler
<summary>Funding details</summary>
![](https://i.imgur.com/PKl6N2y.png)
![](https://i.imgur.com/eS9GJdx.png)
:::
>[Deploy](https://testnet.cspr.live/deploy/7d0a098911b3fbdb1b3083249c04b1253d07703f2bcb2912828a090af9ec97d5) transfer from account:
>**018afa98ca4be12d613617f7339a2d576950a2f9a92102ca4d6508ee31b54d2c02**
#### Transfer tokens
Some casper tokens were sent back to the address that funded our account
***Node address*** was choosen randomly from [list of peers](https://testnet.cspr.live/tools/peers) on test net website
***Transfer-id*** and ***Amount*** are respresenting date
```bash=
casper-client transfer \
-i 230921 \
-n http://178.170.48.18:7777 \
-a 23000000000 \
-k hackathon_secret_key.pem \
--chain-name casper-test \
-t 018afa98ca4be12d613617f7339a2d576950a2f9a92102ca4d6508ee31b54d2c02 \
-p 10000
```
:::spoiler
<summary>Transfer result</summary>
![](https://i.imgur.com/ZORMJ0l.png)
![](https://i.imgur.com/7VbmutC.png)
:::
>[Deploy](https://testnet.cspr.live/deploy/72718206145440a6bca6a272425aff70199a6d5847f67edf42d2b3400ed10f52) hash: **72718206145440a6bca6a272425aff70199a6d5847f67edf42d2b3400ed10f52**
#### State Root Hash
```bash=
casper-client get-state-root-hash \
-n http://178.170.48.18:7777
```
![](https://i.imgur.com/NRNnzak.png)
>**State root hash**:
>*198afb5dfe63229831c020756fdbb5680675419a8a111b54c7432f77a29dd88d*
#### Query the Source Account
```bash=
casper-client query-state \
-n http://178.170.48.18:7777 \
-s 198afb5dfe63229831c020756fdbb5680675419a8a111b54c7432f77a29dd88d \
-k hackathon_public_key_hex
```
![](https://i.imgur.com/a1iU6dF.png)
## Task #5 Learn to Delegate and Undelegate on the [Casper Testnet](https://testnet.cspr.live/). Check out [these instructions](https://docs.casperlabs.io/en/latest/workflow/staking.html#delegating-tokens).
### Delegating Tokens
>I went to [**Validators**](https://testnet.cspr.live/validators) page from the top navigation menu of Casper testent [website](https://testnet.cspr.live/)
>From the validators table, I chose an validator and clicked on it to access [details page](https://testnet.cspr.live/validator/01301a014e4fbedde8ae38b31b8b5de9c64736af5f6ed2620a642bf617b7f92673)
>Clicked the Delegate button
Delegation Details
Entered amount to delegate:
![](https://i.imgur.com/GXCBggN.png)
Confirmed delegation details:
![](https://i.imgur.com/i6F71Z4.png)
Checked transaction to sign:
![](https://i.imgur.com/2MB9Cns.png)
Signed transaction using *Casper Signer*:
![](https://i.imgur.com/RgjDocb.png)
"Delegation completed" page:
![](https://i.imgur.com/oYP7KxL.png)
[Deploy](https://testnet.cspr.live/deploy/2493064b6b99c14f5593ba28a53a4a0c538aa810ea19b9986824f2b0471ef1e8) hash: **2493064b6b99c14f5593ba28a53a4a0c538aa810ea19b9986824f2b0471ef1e8**
![](https://i.imgur.com/RNHnm3k.png)
Delegations of account:
![](https://i.imgur.com/fqhSafr.png)
### Undelegating Tokens
>I went to [**View account**](https://testnet.cspr.live/account/01847b33f608ef5153549433eb158be52d05b2e7acf5039b88344a8f7ee7c06416) page from the top navigation menu of Casper testent [website](https://testnet.cspr.live/)
![](https://i.imgur.com/WmfbSCk.png)
Chose **Delegations** tab:
![](https://i.imgur.com/fqhSafr.png)
Clicked **Undelegate** button under [Validator](https://testnet.cspr.live/validator/01301a014e4fbedde8ae38b31b8b5de9c64736af5f6ed2620a642bf617b7f92673)
![](https://i.imgur.com/S9gqEvv.png)
Confirmed undelegation details:
![](https://i.imgur.com/0YAnjfX.png)
Checked deploy to sign:
![](https://i.imgur.com/YyxwUqO.png)
Signed deploy in *Casper Signer*:
![](https://i.imgur.com/r6jIJqa.png)
Undelegation completed:
![](https://i.imgur.com/byUxITo.png)
Clicked [Deploy details](https://testnet.cspr.live/deploy/487bb67d9a1402b4058b4e110af8c417d957626968e0bc4601cb08f8a01ca5bc):
![](https://i.imgur.com/48POakG.png)
Deploy status became **Success** later on:
![](https://i.imgur.com/uIZcmfi.png)
## Conclusion
I've completed five task and learned a lot so far, and tried next:
1. Transfer tokens.
2. Delegate and stake.
3. Managed keys and learned about Multi-signature concepts.
4. Created and Deployed several contracts.
5. Learned about: casper-key-manager, casper-client, casper-node and casper nctl.
Thank you for that Getting started with casper Challenge!