# CasperMD Introduction Tutorial Welcome to the Casper (CSPR) tutorial. This tutorial is funded by the Casper Gitcoin hackathon which is currently taking place and I am happy to collaborate. First of all, thank to each one of the community members present in the Casper-Network _Discord Channel_ who made this possible. Let's get to it. ## Setting up your Docker container For my case, I would create a _Docker_-based environment. The reason behind this decision is to make clear the slim requirements needed for this solution to work under any other environments and start from scratch. In the case you do not have _Docker_ installed under your system, please refer to some guide about this if you want to replicate this tutorial that way, but there is no need to do so. This part of the tutorial is **optional**, as you might not want to use _Docker_, and this is fine. We are going to be using the `ubuntu:latest` image for our _Docker_ container, which worked pretty fine for me after some testing. The commands needed for getting this machine up and running are the next ones presented. First of all, we create the `ubuntu:latest`-based container by using the next command: ```bash= docker create --name casper -it ubuntu:latest ``` Then, we could take a look at the available containers by running the next command: ```bash= docker container ls --all ``` We should get a list like the one shown below (the _Container ID_ would change during the tutorial, do not worry for that): ![](https://i.imgur.com/54xhTMW.png) We are ready to launch and connect to our `casper` container, just use the next commands: ```bash= docker start casper docker exec -it casper bash ``` And we should see a nice root shell prompt such as the one shown below: ![](https://i.imgur.com/eozFow4.png) Now we could execute some commands under the shell. We would setup our environment by creating another user named `tbd` (You could use the name that you would like), getting `sudo` and getting that new user into the `sudo` user group with the next commands: ```bash= adduser tbd apt update apt install sudo -y usermod -aG sudo tbd ``` When running the `adduser` command some details would be asked, please take in mind that the _password_ that you set would be needed in further steps as we would work under a secure environment (a non-root environment). Now we are ready to test our user, in order to do so just execute the next command: ```bash= su - tbd whoami ``` The `whoami` command output shows us that we are currently logged in as `tbd`, our newly shiny created user. Nice! If we need to run commands as a superuser (root), we just need to prepend `sudo` before those special commands. In this part of the tutorial I would like to recommend you installing your prefered console text editor. In my case, I like to use _Neovim_, so I would install it in this point using the next commands: ```bash= sudo apt update sudo apt install neovim -y ``` ## Create your local Casper Node ### Installing git Before going into the first task of the challenge, we need to face the `casper-node` local installation. In order to do so, we are going to use _Rust_, _Git_ and so on. No problem, we would explain what are these words about in just a minute. _Casper_ is an open-source project, which bases its developments on incremental curated community-based contributions. They use _Git_ repositories for storing their applications and you could access to their applications source-code and install them under your system in some easy steps. How could we create our local _Casper Node_? In order to do so, we just need to _clone_ the needed source code (grab it from the remote _Git_ repository to our system), build the _Casper Node_ application (Maybe using the _Rust Compiler_) and run the _Casper Node_ compiled solution under our system. First of all, install _Git_ under your computer by using the next command: ```bash= sudo apt update sudo apt install git -y ``` ### Cloning casper-node and casper-node-launcher repos After that, just point your browser to _Google_ and search for the _Casper_ project `casper-node` repository in _Github_ this way: ![](https://i.imgur.com/9Lqm2kX.png) **Bingo!** The first result is the correct one, click on it. What you are seeing now is the _Github_ page pointing to the `casper-node` repository under the `casper-network` organization, which is the official organization under _Casper_. Now, click on the green button titled _Code_ and copy the _HTTPS URL_ shown there by clicking the clipboard button. **Do not Download ZIP**. ![](https://i.imgur.com/nEEepvm.png) The _URL_ that you might have under your clipboard is `https://github.com/casper-network/casper-node.git`. So we are going to clone it under our machine in just a second. But first, let's create and navigate to a special folder called `dev-casper` under the _home_ folder for our current user by using the next commands: ```bash= mkdir ~/dev-casper cd ~/dev-casper ``` Now, let's _clone_ the `casper-node` repository by using the next command: ```bash= git clone https://github.com/casper-network/casper-node.git ``` You would be receiving objects and a new folder would show up, which you could see by using the `ls` command under your shell. ![](https://i.imgur.com/ioO51QA.png) The newly `casper-node` folder has the same name as the repository, and this would repeat with each one of the repositories that we would clone. In order to build `casper-node` we need a sibling folder next to it, which must be a _clone_ of the repository `casper-node-launcher`. So, while we are at the `dev-casper` repository we just run the next command: ```bash= git clone https://github.com/casper-network/casper-node-launcher.git ``` Now, both folders should be siblings. ![](https://i.imgur.com/DMNZHJX.png) ### Installing the required dependencies If you look close to the `README` files of both repositories cloned, you would see that there are some requirements that we should meet. First of all, install some packages by using `apt`: ```bash= sudo apt update sudo apt install cmake libssl-dev pkg-config gcc g++ -y ``` Now, get to install _Rust_ by using the _single-liner_ command shown at its [Webpage](https://www.rust-lang.org/learn/get-started). ```bash= curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` **And maybe some error would appear!** ![](https://i.imgur.com/AkCSgpO.png) What could we do? Hopefully you know, if we do not have an application we could use `apt` for installing it. If that error appears just use the next command for being able to re-execute the _single-liner_ _Rust_ installer command newly: ```bash= sudo apt update sudo apt install curl -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` Now just use the first option (proceed with installation), refresh your environment and `cargo` could be invoked as shown below. ```bash= source ~/.cargo/env cargo --version ``` ![](https://i.imgur.com/B19EfEZ.png) Now, we need some _Python_ dependencies and create a _Python_ virtual environment for ensuring that we do not alter system-wide packages. I like to use `pipenv` for that purpose, so we could install it the next way: ```bash= sudo apt update sudo apt install python3 python3-pip pipenv -y ``` Once this is accomplished we must create a _Python_ virtual environment and activate it. We could create a blank `Pipfile` file and invoke `pipenv shell` to get the default configuration. After that, we install the needed dependencies by using `pip` under the virtual environment. ```bash= touch Pipfile pipenv shell pip install jq toml supervisor sudo apt update sudo apt install jq lsof supervisor -y ``` We are ready to go now! Let's build `casper-node`. ### Building casper-node Get into the `casper-node` folder and run the next commands as stated in the `README.md` file of the repository: ```bash= cd casper-node make setup-rs cargo build -p casper-node --release ``` This would take some time, it is alright. The `setup-rs` command would get the needed _Rust_ toolchain for the project, which is `nightly-2021-06-17`. This toolchain name is important, as we would use it later when installing `casper-client`. Once the build process is accomplished we could use the `nctl` (node control) utilities. In order to get them under our current scope, we should use the next command under the `casper-node` folder: ```bash= source utils/nctl/activate ``` **Warning**: This command does not throw any error, if it does so, maybe you should verify that you are using `bash` and not `zsh` or any other. Once you have activate the `nctl` toolset, you should use the next command to build your node properly: ```bash= nctl-compile ``` It would take some time, maybe the last steps would seem to stall the process, but they just take some more time. After that, use the next commands to create a new _Casper_ node and start it: ```bash= nctl-assets-setup nctl-start ``` The first command create a _Node_ configuration from scratch, so it is good that you always run that command before starting your node. Your output should be something like the one shown below: ![](https://i.imgur.com/zkXqooN.png) You could ensure that you are running these nodes of your current local network by using the `nctl-status` command. Now, we have a local _casper_ node network running under our system at `http://localhost:7777`, this would be our _Node URL_, remember this. ### Install the `casper-client` As the last step, you should install the `casper-client` by using the next command: ```bash= cargo +nightly-2021-06-17 install casper-client --locked ``` We used the `nightly` channel as we mentioned earlier. And, after this, you could use the next command without any inconvenience: ```bash= casper-client --version ``` That would lead you to an output like the one shown below: ![](https://i.imgur.com/NS9xlq8.png) Yes, the `casper-client` is into the `casper-node/client` folder, but given some toolchain details, the pointed out form is simpler for getting a system-wide `casper-client`. ## 1. Create and deploy a simple, smart contract with cargo casper and cargo test Let's start now with the first task given. First, you must ensure that you are currently working under a _blank_ new _Casper_ network. To do so, we need to setup the assets and start the network by using the next _nctl_ commands: ```bash= nctl-assets-setup && nctl-start ``` If everything went corrent you should see an output such as the one presented below, where some _Docker_ commands are also present. ![](https://i.imgur.com/qguWe83.png) Once you have your _localhost_ network nodes running and you are under your development user directory (`~/dev-casper` in my case) you should run the next commands to install the `cargo-casper` _Rust_ package by using `cargo`: ```bash= cargo install cargo-casper ``` That command would installe the `cargo-casper` utility, which lets you to create a test project for the purpose of this tutorial. You could base your _Casper_ developments in projects created by the `cargo-casper` tool. Once `cargo-casper` has been succesfully installed you could run the next command to create a _Casper_ project named `my-project`: ```bash= cargo casper my-project ``` You should see a new folder created under your environment named `my-project`, which contains a `Makefile`, a `contract` folder, a `rust-toolchain` text file, and a `tests` folder. ![](https://i.imgur.com/XSEbp4Z.png) We must install the required _Rust_ toolchain for this project by using the next commands under the `my-project` folder: ```bash= rustup install $(cat rust-toolchain) rustup target add --toolchain $(cat rust-toolchain) wasm32-unknown-unknown ``` Once these requirements are fulfilled, we could build the test contract present under the `contract` folder by using the next commands: ```bash= cd contract cargo build --release ``` This would lead to a _WebAssembly_ binary output file located at `my-project/contract/target/wasm32-unknown-unknown/release/contract.wasm`. Before testing the contract, let's look at its source code by opening up the `my-project/contract/src/main.rs` file in our favourite editor (_Neovim_): ```bash= nvim src/main.rs ``` The content of the file is included next: ```rust= #![no_main] ... #[no_mangle] pub extern "C" fn call() { // The key shouldn't already exist in the named keys. let missing_key = runtime::get_key(KEY_NAME); if missing_key.is_some() { runtime::revert(Error::KeyAlreadyExists); } // This contract expects a single runtime argument to be provided. The arg is named "message" // and will be of type `String`. let value: String = runtime::get_named_arg(RUNTIME_ARG_NAME); // Store this value under a new unforgeable reference a.k.a `URef`. let value_ref = storage::new_uref(value); // Store the new `URef` as a named key with a name of `KEY_NAME`. let key = Key::URef(value_ref); runtime::put_key(KEY_NAME, key); // The key should now be able to be retrieved. Note that if `get_key()` returns `None`, then // `unwrap_or_revert()` will exit the process, returning `ApiError::None`. let retrieved_key = runtime::get_key(KEY_NAME).unwrap_or_revert(); if retrieved_key != key { runtime::revert(Error::KeyMismatch); } } ``` As you could see, this contract stores the value given as a string into a _(key,value)_ pair. Ok, let's go into the testing part now. Standing into the `my-project` folder we need to run the `make test` command: ```bash= cd .. make test ``` First, it would start compiling some _Rust_ code by using _cargo_. After that, we should see some tests being executed with success. ![](https://i.imgur.com/sqL4HFC.png) The `make test` command details could be found out in the `Makefile` file. When you open the `Makefile` file in your editor you could see the logic of the command, which already contains the `cargo test` command specified in the exercise header. ```bash= test: build-contract mkdir -p tests/wasm cp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm cd tests && cargo test ``` The first task has been accomplished. Greetings. ## 2. Complete one of the existing tutorials for writing smart contracts Moving on to the second task, we would go into details with smart contracts. For our case we would go with the [_A Counter Contract Tutorial_](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/counter/index.html) where we would attach a new contract with a counter that could increment by contract calls in the _Casper_ network. Once in the `~/dev-casper` folder and having our _localhost_ _Casper_ network with the `casper-client` user-wide installation, we should clone the `counter` repository by using the next command: ```bash= git clone https://github.com/casper-ecosystem/counter cd counter ``` This repository contains contracts for _defining_ the counter in the network and also for _calling_ that contract. We are interested in the _definition_ of the contract, as we would call the contract entry points by using the `casper-client` application. First, ensure that your _Casper_ network is clean and running by executing the next commands: ```bash= nctl-assets-setup && nctl-start ``` Now, let's talk about the _Faucet_ account. The _Faucet_ account is a test _super-user_ account that is present at test networks (_testnets_) such as your _localhost_ already running network. We could get the _Faucet_ account details by running the next command: ```bash= nctl-view-faucet-account ``` Something similar to the next output should be printed out: ![](https://i.imgur.com/8LpGxBn.png) We could get details on the current state of the _Faucet_ account (for example, the contracts it has deployed) by getting the current `state-root-hash` of the network (this is something like the commit number in a _Git_ repository and its got by using `casper-client` as specified below) and specifying the _Faucet_ account hash, which is already present in the last screenshot (this would change for your machine). We run the next command: ```bash= casper-client get-state-root-hash --node-address http://localhost:11101 casper-client query-state \ --node-address http://localhost:11101 \ --state-root-hash [THE_RETURNED_HASH] \ --key account-hash-686d8fa3e3c58ad0aa73c4a4131b03d165bb8b7b52b2d443b041101b563af848 ``` Please, change `[THE_RETURNED_HASH]` by the hash returned by the previous `casper-client` command as shown in the image below: ![](https://i.imgur.com/V9Bn6OL.png) As you could see there is no `counter` contract present in the current state of the _Faucet_ account. This would change in a minute, as we are going to deploy our `counter-define` contract to the network by using the next commands. Firstly, compile the contract by using the next commands: ```bash= make prepare make test ``` ![](https://i.imgur.com/1ApUCD3.png) Now, get to deploy the current contract by using `casper-client` the next way while in the `counter` folder: ```bash= casper-client put-deploy \ --node-address http://localhost:11101 \ --chain-name casper-net-1 \ --secret-key [SECRET_KEY_PATH] \ --payment-amount 5000000000000 \ --session-path ./target/wasm32-unknown-unknown/release/counter-define.wasm ``` Just ensure that you modify `[SECRET_KEY_PATH]` with your current _Faucet_ account secret key path, which could be obtained by using the `nctl-view-faucet-account` command as in the next screenshot: ![](https://i.imgur.com/EIhfMeK.png) Hooray! Our counter contract has been deployed successfully by using the _Faucet_ account into our _localhost_ _Casper_ network. But how could we interact with this contract? Well, let's take a look into the source code of the _counter definition_ contract: ```bash= nvim contracts/counter-define/src/main.rs ``` We see the next source code (stripped): ```rust= ... const COUNT_KEY: &str = "count"; const COUNTER_INC: &str = "counter_inc"; const COUNTER_GET: &str = "counter_get"; const COUNTER_KEY: &str = "counter"; ... #[no_mangle] pub extern "C" fn call() { let counter_local_key = storage::new_uref(0); //initialize counter // Create initial named keys of the contract. let mut counter_named_keys: BTreeMap<String, Key> = BTreeMap::new(); let key_name = String::from(COUNT_KEY); counter_named_keys.insert(key_name, counter_local_key.into()); // Create entry point let mut counter_entry_points = EntryPoints::new(); counter_entry_points.add_entry_point(EntryPoint::new( COUNTER_INC, Vec::new(), CLType::Unit, EntryPointAccess::Public, EntryPointType::Contract, )); counter_entry_points.add_entry_point(EntryPoint::new( COUNTER_GET, Vec::new(), CLType::I32, EntryPointAccess::Public, EntryPointType::Contract, )); let (stored_contract_hash, _) = storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None); runtime::put_key(COUNTER_KEY, stored_contract_hash.into()); } ``` We could see that there exists a `count` key under the `counter` contract, which would hold the value for the counter. Even more, we could see two entry points: `counter_inc` and `counter_get`, which would increment the counter and would get the value of the counter respectively. We need to use `casper-client` to do the next tasks: 1. Get the value of the `count` variable directly 2. Increment the `count` variable by using the `counter_inc` contract end point 3. Repeat steps 1-2 as many times as you would like Let's query the value of the `count` variable in the `counter` contract associated with our _Faucet_ account by using `casper-client` the next way: ```bash= casper-client get-state-root-hash --node-address http://localhost:11101 casper-client query-state \ --node-address http://localhost:11101 \ --state-root-hash a6d67a5b7668aea23fc1b9cce3c536c7b503057ead35c242c1c86f3e70fe1e36 \ --key account-hash-686d8fa3e3c58ad0aa73c4a4131b03d165bb8b7b52b2d443b041101b563af848 \ -q counter/count ``` Remember to change the `state-root-hash` and `key` values according to the `casper-client get-state-root-hash` and `nctl-view-faucet-account` output. You should obtain an answer such as the one presented below, which states that the `count` value is equal to 0, as shown in the `parsed` element value. ![](https://i.imgur.com/AGYm4M7.png) Let's increment the `count` variable by using the `counter_inc` `counter` contract entry point. In order to do so we just must slightly modify the `casper-client` command used to deploy the contract and run it the next way: ```bash= casper-client put-deploy \ --node-address http://localhost:11101 \ --chain-name casper-net-1 \ --secret-key /home/tbd/dev-casper/casper-node/utils/nctl/assets/net-1/faucet/secret_key.pem \ --payment-amount 5000000000000 \ --session-name "counter" \ --session-entry-point "counter_inc" ``` Then, the counter should be equal to one. Let's check this by querying the value of `count` with the updated `state-root-hash`: ```bash= casper-client get-state-root-hash --node-address http://localhost:11101 casper-client query-state \ --node-address http://localhost:11101 \ --state-root-hash 34beceeaa0c816039367702159ccd710e2a44bc39a703f73d07303c5c6fd2d6d \ --key account-hash-686d8fa3e3c58ad0aa73c4a4131b03d165bb8b7b52b2d443b041101b563af848 \ -q counter/count ``` Example output is shown below: ![](https://i.imgur.com/L5f9Puj.png) The `count` variable has changed! **Warning** This change is not reflected instantly, please wait for a minute or so to ask for a new `state-root-hash` and query the `count` variable newly. We could repeat the process as many times as we want, and we would get the increment of the `count` variable as expected. The example query output after repeting the `counter_inc` call is shown below: ![](https://i.imgur.com/z3K7EwT.png) ## 3. Demonstrate key management concepts by modifying the client in the Multi-Sig tutorial to address one of the additional scenarios Returning to our `~/dev-casper` root development directory, we would start by resetting our _localhost_ _Casper_ network by running the famous command: ```bash= nctl-assets-setup && nctl-start ``` Once we are at the scratch starting point, we are going to clone the `keys-manager` repository by using the next command: ```bash= git clone https://github.com/casper-ecosystem/keys-manager cd keys-manager ``` When in the repository folder, you could see a `Makefile` file for performing different tasks, a `README.md` describing the repository, a `client` folder containing some _NodeJS_ project, a `contract` folder containing a _Rust_ contract, and a `rust-toolchain` text file containing the needed toolchain for building our contract by using `cargo`. Firstly, compile the given contract by using the next commands: ```bash= rustup install $(cat rust-toolchain) rustup target add --toolchain $(cat rust-toolchain) wasm32-unknown-unknown cd contract cargo build --release ``` Now we are going to setup our `client` _NodeJS_ project. But before, let's install _NodeJS_ by using the _Node Version Manager_ (`nvm`), which is my preferred way to go: ```bash= curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash source ~/.bashrc nvm install v14.17.6 ``` Once installed the current _LTS_ version of _NodeJS_, we proceed installing the current _NodeJS_ project dependencies under the client folder by using the next commands: ```bash= cd ../client npm i ``` Some warnings should appear as shown below, but do not worry about this. ![](https://i.imgur.com/g0Bcdxg.png) Then, we need to setup some environment variables for the project. These environment variables are setup in a `.env` file in the current `client` folder. Just open your favourite editor and write into the `.env` file the next content: ```bash= BASE_KEY_PATH=/home/tbd/dev-casper/casper-node/utils/nctl/assets/net-1/faucet/ NODE_URL=http://localhost:11101/rpc ``` The `BASE_KEY_PATH` must contain the path shown in `nctl-view-faucet-account` secret key (whitout the `secret_key.pem` in the end). Now, let's explore under the `package.json` what commands could we run by using `npm run`. We could see a `scripts` section, which contains `start:atomic` and `start:all`. We are interested in the `start:atomic` command. The `start:atomic` command runs the `./src/scenario-atomic.js` file, so we open that file to see its content with our favourite editor to find the next comment describing the main function: ```javascript= // In this example the 2 additional accounts will be added to // the mainAccount to perform deploys, but they will not be // able to add another account. // To achive the task, we will: // 1. Set mainAccount's weight to 3. // 2. Set Keys Management Threshold to 3. // 3. Set Deploy Threshold to 2. // 4. Add first new key with weight 1 (first account). // 5. Add second new key with weight 1 (second account). // 6. Make a transfer from mainAccount using the new accounts. // 7. Remove first account. // 8. Remove second account. ``` We could run this function just by executing the next command under the `client` folder: ```bash= npm run start:atomic ``` For each one of the steps shown in the `scenario-atomic.js` we would get some console output as dictated by the source code javascript file. We would end up with an output such as this one: ![](https://i.imgur.com/jsEUnTS.png) Now, we must create some new _scenario_ that would accomplish any of the tasks presented in the [_additional scenarios_](https://docs.casperlabs.io/en/latest/dapp-dev-guide/tutorials/multi-sig/examples.html). Basing ourselves in the `src/scenario-atomic.js` file, we would create a sibling file named `src/scenario-5.js` that performs the required actions specified by the fifth additional scenario. The source code is attached below. <details> <summary>Click here to see source code</summary> ```javascript= const keyManager = require('./key-manager'); const TRANSFER_AMOUNT = process.env.TRANSFER_AMOUNT || 2500000000; (async function () { // This is the fifth additional scenario. // Deployment threshold is set to 2, while key management threshold // is set to 3. // A set of two keys with weight 1 for each one is created, and // a set of three keys with weight 3 (safe keys) are created as well. // To achive the task, we will: // 1. Set mainAccount's weight to 1 (browser key). // 2. Add first new key with weight 1 (mobile key). // 3. Add second new key with weight 3 (safe key 1). // 4. Add third new key with weight 3 (safe key 2). // 5. Add fourth new key with weight 3 (safe key 3). // 6. Set Keys Management Threshold to 3. // 7. Set Deploy Threshold to 2. // 8. Make a transfer from mainAccount to recvAccount (new account // created) by using the mobile and browser keys together. let deploy; // 0. Initial state of the account. // There should be only one associated key (faucet) with weight 1. // Deployment Threshold should be set to 1. // Key Management Threshold should be set to 1. let masterKey = keyManager.randomMasterKey(); let mainAccount = masterKey.deriveIndex(1); let firstAccount = masterKey.deriveIndex(2); let secondAccount = masterKey.deriveIndex(3); let thirdAccount = masterKey.deriveIndex(4); let fourthAccount = masterKey.deriveIndex(5); let recvAccount = masterKey.deriveIndex(6); console.log("\n0.1 Fund main account.\n"); await keyManager.fundAccount(mainAccount); await keyManager.printAccount(mainAccount); console.log("\n[x]0.2 Install Keys Manager contract"); deploy = keyManager.keys.buildContractInstallDeploy(mainAccount); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 1. Set mainAccount's weight to 1 console.log("\n1. Set browser key weight to 1\n"); deploy = keyManager.keys.setKeyWeightDeploy(mainAccount, mainAccount, 1); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 2. Add mobile key (weight 1) console.log("\n2. Add mobile key (weight 1)\n"); deploy = keyManager.keys.setKeyWeightDeploy(mainAccount, firstAccount, 1); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 3. Add safe key 1 (weight 3) console.log("\n3. Add safe key 1 (weight 3)\n"); deploy = keyManager.keys.setKeyWeightDeploy(mainAccount, secondAccount, 3); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 4. Add safe key 2 (weight 3) console.log("\n4. Add safe key 2 (weight 3)\n"); deploy = keyManager.keys.setKeyWeightDeploy(mainAccount, thirdAccount, 3); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 5. Add safe key 3 (weight 3) console.log("\n5. Add safe key 3 (weight 3)\n"); deploy = keyManager.keys.setKeyWeightDeploy(mainAccount, fourthAccount, 3); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 6. Set Keys Management Threshold to 3. console.log("\n6. Set Keys Management Threshold to 3\n"); deploy = keyManager.keys.setKeyManagementThresholdDeploy(mainAccount, 3); await keyManager.sendDeploy(deploy, [mainAccount]); await keyManager.printAccount(mainAccount); // 7. Set Deploy Threshold to 2. console.log("\n7. Set Deploy Threshold to 2.\n"); deploy = keyManager.keys.setDeploymentThresholdDeploy(mainAccount, 2); await keyManager.sendDeploy(deploy, [secondAccount]); await keyManager.printAccount(mainAccount); // 8. Make a transfer from faucet using the new accounts. console.log("\n8. Make a transfer from mainAccount to recvAccount using browser and mobile keys.\n"); deploy = keyManager.transferDeploy(mainAccount, recvAccount, TRANSFER_AMOUNT); await keyManager.sendDeploy(deploy, [mainAccount, firstAccount]); await keyManager.printAccount(mainAccount); await keyManager.printAccount(recvAccount); })(); ``` </details> After that, we could create a custom _script_ in `package.json` file, resulting in the source shown below. <details> <summary>Click here to see source code</summary> ```json= { "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:fifth": "node -r dotenv/config ./src/scenario-5.js", "start:all": "node -r dotenv/config ./src/scenario-all.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "dependencies": { "casper-js-sdk": "^2.0.0", "dotenv": "^10.0.0" } } ``` </details> Then ,just run the next command under the `client` folder to get our scenario up and running: ```bash= npm run start:fifth ``` The obtained output would be something like what is seen in the screenshot below. ![](https://i.imgur.com/apIOfvr.png) <details> <summary>Click here to see the complete output</summary> ```bash 0.1 Fund main account. Signed by: account-hash-a3b57d2c2b345a6d8249be63dffcec47067c002776de68d9cf7be76b89ee3c38 Deploy hash: a800e3d4bccdd3770f2b0c9fa4446892e23ae9ba289c0929359340931fefcb50 Deploy result: { deploy: { hash: 'a800e3d4bccdd3770f2b0c9fa4446892e23ae9ba289c0929359340931fefcb50', header: { account: '0134b9f5c0b64799a5053e12ed145f0d58318030bdfbf741140a8ad2d3eeff2199', timestamp: '2021-09-19T00:16:08.470Z', ttl: '30m', gas_price: 1, body_hash: '7a27803ccb0156e7e92b8805fec447bc36863931c1b855007ca3103f6971dfae', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { Transfer: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } [x]0.2 Install Keys Manager contract Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: d8f9427471201bc2219ada751b1e0f135525bc6692927420fee4036799604fd7 Deploy result: { deploy: { hash: 'd8f9427471201bc2219ada751b1e0f135525bc6692927420fee4036799604fd7', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:17:12.004Z', ttl: '30m', gas_price: 1, body_hash: 'ac811eac779de9458663a2c2f61b2d5f842b6f2af091362b6c08d8c07313d7d5', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { ModuleBytes: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } 1. Set browser key weight to 1 Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: 67f24ddc6d979df672d0ffdfb667bb54943fd7dc18eda3d4cc888e669f4afb5e Deploy result: { deploy: { hash: '67f24ddc6d979df672d0ffdfb667bb54943fd7dc18eda3d4cc888e669f4afb5e', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:18:17.559Z', ttl: '30m', gas_price: 1, body_hash: '21deea7b17316701c924e050ca6336ca374552555b536c8cc885fa382b7ad956', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } 2. Add mobile key (weight 1) Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: 60d132e62dec66446280b5ce2728246dcdc9875cc38b73006c46aa1661caa318 Deploy result: { deploy: { hash: '60d132e62dec66446280b5ce2728246dcdc9875cc38b73006c46aa1661caa318', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:19:23.893Z', ttl: '30m', gas_price: 1, body_hash: 'ce71647de1b6cde5ea81a3834e34857837d64484a9fc51c99a35bc8590071d0e', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } 3. Add safe key 1 (weight 3) Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: ca9847ebee4547c80b9fc853b7c1239a51c946465fddb655f7d42ce6d6e01f83 Deploy result: { deploy: { hash: 'ca9847ebee4547c80b9fc853b7c1239a51c946465fddb655f7d42ce6d6e01f83', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:20:29.197Z', ttl: '30m', gas_price: 1, body_hash: '10efc05b136b10a8b821ab3cac20ab0375b4c6f70b980e4807a5d39f36be2720', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5', weight: 3 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } 4. Add safe key 2 (weight 3) Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: 5821b4b04fde8732986d46f823128c214c6eeb6137a27789f7b256fb9143ac01 Deploy result: { deploy: { hash: '5821b4b04fde8732986d46f823128c214c6eeb6137a27789f7b256fb9143ac01', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:21:34.489Z', ttl: '30m', gas_price: 1, body_hash: 'bc64b6ed6accd84c922e4647c35a2697702903fa71fc38ecad5d79c9d3c85d28', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-5a03058584acb8404567fd91b01884bb135e4a17b86a561db5b0ef4020aa9cf8', weight: 3 }, { accountHash: 'account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5', weight: 3 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } 5. Add safe key 3 (weight 3) Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: cfda000d819b6e131e05dfe38028adb4afaee56954ce1d6bd865afa1a1c6eb15 Deploy result: { deploy: { hash: 'cfda000d819b6e131e05dfe38028adb4afaee56954ce1d6bd865afa1a1c6eb15', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:22:39.775Z', ttl: '30m', gas_price: 1, body_hash: 'ac0e0ab4e0cb50e437112e50b271925ce8e164f9e0ec8b6a8a9714f72d5524f3', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-5606ff7094d23ee4372b2ff6cd58e11506906396fa91b42e139762c17d15cc7b', weight: 3 }, { accountHash: 'account-hash-5a03058584acb8404567fd91b01884bb135e4a17b86a561db5b0ef4020aa9cf8', weight: 3 }, { accountHash: 'account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5', weight: 3 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } 6. Set Keys Management Threshold to 3 Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Deploy hash: 5d6a5cb61e0f0c3b55817ed0684606f48e4d8a4eadfe2f5168ca667d21eacc42 Deploy result: { deploy: { hash: '5d6a5cb61e0f0c3b55817ed0684606f48e4d8a4eadfe2f5168ca667d21eacc42', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:23:46.099Z', ttl: '30m', gas_price: 1, body_hash: '3f3394304ff22fe422511e62eed631bc501385f67fdd1fe71891f7d375550324', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-5606ff7094d23ee4372b2ff6cd58e11506906396fa91b42e139762c17d15cc7b', weight: 3 }, { accountHash: 'account-hash-5a03058584acb8404567fd91b01884bb135e4a17b86a561db5b0ef4020aa9cf8', weight: 3 }, { accountHash: 'account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5', weight: 3 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 3 } } 7. Set Deploy Threshold to 2. Signed by: account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5 Deploy hash: f5cbc404af80e5e4e4d3552d548c70c2417d8c049e0e7007871623b4c69fc968 Deploy result: { deploy: { hash: 'f5cbc404af80e5e4e4d3552d548c70c2417d8c049e0e7007871623b4c69fc968', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:24:51.407Z', ttl: '30m', gas_price: 1, body_hash: '609e820d1eb41cd0fe90e6c5c4cf179afd2c9d9ba19bb0f21ca310a85450f228', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { StoredContractByName: [Object] }, approvals: [ [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-5606ff7094d23ee4372b2ff6cd58e11506906396fa91b42e139762c17d15cc7b', weight: 3 }, { accountHash: 'account-hash-5a03058584acb8404567fd91b01884bb135e4a17b86a561db5b0ef4020aa9cf8', weight: 3 }, { accountHash: 'account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5', weight: 3 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 2, keyManagement: 3 } } 8. Make a transfer from mainAccount to recvAccount using browser and mobile keys. Signed by: account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500 Signed by: account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b Deploy hash: 1a237580c67d20bbb3decabbec113def5ee5ec6a3185809809f7b6677ecb3f77 Deploy result: { deploy: { hash: '1a237580c67d20bbb3decabbec113def5ee5ec6a3185809809f7b6677ecb3f77', header: { account: '02023bd35c3c177f4a51b59ef6a2799df4c8abe8d94975fbf3ba65fc9f0f45144a84', timestamp: '2021-09-19T00:25:56.709Z', ttl: '30m', gas_price: 1, body_hash: '9360a9e3afe0068a48b38f40ab8f3afccb7f44569a1800118416cde4d98e00a5', dependencies: [], chain_name: 'casper-net-1' }, payment: { ModuleBytes: [Object] }, session: { Transfer: [Object] }, approvals: [ [Object], [Object] ] } } [x] Current state of the account: { _accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', namedKeys: [ { name: 'keys_manager', key: 'hash-de8025ee35f238c2c9c82ba45bb1e04c5f4ff3bdfcfb9698eecd31304bebc7bf' }, { name: 'keys_manager_hash', key: 'uref-ee78609e3c28a176225a566cf7d9d9585c82b099b6f06601aebe46242a6114c8-007' } ], mainPurse: 'uref-681b591737b9cef4356c133ada22f71b41ec9357c45b9390334410277aab413c-007', associatedKeys: [ { accountHash: 'account-hash-28fdcff4d5114b66bd38f9ec0009bc21726912a3960214ccbe54449e2d11cb8b', weight: 1 }, { accountHash: 'account-hash-5606ff7094d23ee4372b2ff6cd58e11506906396fa91b42e139762c17d15cc7b', weight: 3 }, { accountHash: 'account-hash-5a03058584acb8404567fd91b01884bb135e4a17b86a561db5b0ef4020aa9cf8', weight: 3 }, { accountHash: 'account-hash-85410e45c51394ee9aec99a068c76b3f562faecaf54d3026c1ddb29377246fc5', weight: 3 }, { accountHash: 'account-hash-9aebc0b802cf323686cd276c3e37b8d78238e8abb3f54fbc914effa4f5209500', weight: 1 } ], actionThresholds: { deployment: 2, keyManagement: 3 } } [x] Current state of the account: { _accountHash: 'account-hash-28d6932a581ec3a8e6f1e9af602205486376012bde0b561d487248bf88721588', namedKeys: [], mainPurse: 'uref-06e608d5dfa0bd86adcbaa4531e0d1fe1ca579df8b1633bb7efd8b1f0051868b-007', associatedKeys: [ { accountHash: 'account-hash-28d6932a581ec3a8e6f1e9af602205486376012bde0b561d487248bf88721588', weight: 1 } ], actionThresholds: { deployment: 1, keyManagement: 1 } } ``` </details> We could verify that our transaction to `recvAccount` was successful just by typing the next command, taking into account that the `purse-uref` must be the `recvAccount` `mainPurse` hash. ```bash= nctl-view-chain-balance \ purse-uref=uref-06e608d5dfa0bd86adcbaa4531e0d1fe1ca579df8b1633bb7efd8b1f0051868b-007 ``` We got the expected output as shown below: ![](https://i.imgur.com/UYXQPuh.png) Now, we have succesfully completed this step of the hackathon. Let's move on to the official _Casper_ online `testnet`. ## 4. Learn to transfer tokens to an account on the Casper Testnet. We move out of the console for some time. Now, we are going to testdrive the _Casper_ official _testnet_, whose web UI is located at [https://testnet.cspr.live/](https://testnet.cspr.live/). We get into the webpage to see this screen: ![](https://i.imgur.com/Vz7Pl1v.png) The upper menu let us to navigate through different routes. First of all, we must ensure that we are under the _CSPR_ _Testnet_ (and not in its _mainnet_). To do so, just clic at the rightmost icon in the upper menu and ensure that _testnet_ is selected. ![](https://i.imgur.com/CXQ6Okw.png) After that, we must create a wallet. In order to do so we could use the _CasperLabs Signer_ _Google Chrome_ plugin or use the keygen present at our `casper-client`. Maybe, the second option seems to be more nerdy, but let's go over it! In your terminal run the next commands under your development environment (`~/dev-casper`): ```bash= mkdir testnet-keys cd testnet-keys casper-client keygen . ``` Then, you should see your public key file, your public key hash, and your secret key file. ![](https://i.imgur.com/vsxO3M8.png) The next step is to load up our _Casper_ account main purse with some fake money. In order to do so, go to _Sign in_ and _Download Signer_ for getting the _Google Chrome_ plugin. After you installed the signer plugin, click _Sign In_. A new window would appear and you could set your own _Signer Vault_ for storing your keys. ![](https://i.imgur.com/zUlncKl.png) Set a password as expected for your vault. ![](https://i.imgur.com/ubTmRHl.png) Then, click on _Import account_: ![](https://i.imgur.com/3UIWmIO.png) Set an alias for your account, something like `testnetkey` is alright, and upload the `secret_key.pem` file generated before. If you are using _Docker_ you could copy your _secret key file_ to your current real system folder by using a command such as the one shown below: ```bash= docker cp casper:/home/tbd/dev-casper/testnet-keys/secret_key.pem . ``` Then, just click import: ![](https://i.imgur.com/KQtXS3Q.png) Then, the upper menu bar should change, where it would now contain your current wallet address, click on it and you would get your wallet details. ![](https://i.imgur.com/cMicn10.png) You should check that this wallet _Public Key_ is the same as the content of the `public_key_hex` file generated before. Now, we are ready to ask for some _CSPR_ in the _testnet_ for our wallet. In order to do so, go into _Tools_, _Faucet_. Then, click on _Request Tokens_, you would get an output such as the one presented below: ![](https://i.imgur.com/7O3YKw3.png) We should wait some time until the transaction is completed and our _testnet_ account is funded. When the status get to success (you could refresh the webpage) you could get the details on the transaction by clicking on it. ![](https://i.imgur.com/5HsdLu7.png) Why not returning some _CSPR_ back to the _Faucet_ account for testing? Just copy the _public key_ of the origin account and let's get to the terminal. But before returning to the terminal, let's look for the _connected peers_ and get one of them. ![](https://i.imgur.com/UO8GQqj.png) ![](https://i.imgur.com/twGaail.png) In my case I would randomly select `128.199.116.202:35000` for my experiments. Then, in the terminal under the `testnet-key` run the next command (substitute when needed): ```bash= casper-client transfer \ --node-address http://128.199.116.202:7777 \ --secret-key secret_key.pem \ --amount 2500000000 \ --target-account 018afa98ca4be12d613617f7339a2d576950a2f9a92102ca4d6508ee31b54d2c02 \ --chain-name casper-test \ --transfer-id 1337 \ --payment-amount 10000 ``` We should obtain a `deploy_hash` output as shown below: ![](https://i.imgur.com/iNOvsuk.png) My `deploy_hash` is `c83e2b834a1823e06c576030acda85f697536753be62c40739c28292824ae3ce`, so I would paste it under the _Search bar_ in the _testnet_ web UI. ![](https://i.imgur.com/ilu3DlM.png) Hooray! Our transaction could be seen in [https://testnet.cspr.live/deploy/c83e2b834a1823e06c576030acda85f697536753be62c40739c28292824ae3ce](https://testnet.cspr.live/deploy/c83e2b834a1823e06c576030acda85f697536753be62c40739c28292824ae3ce), this would be the link that you would send to your friend with a _Casper_ wallet as a proof for the transfer. By the way, the _Transfer ID_ used is equal to `1337`, which is some _hacker slang_ (_haxor_) for _elite_. You could replace this reference by any other number such as: - The number of your ticket in the pizza place - The user ID of your _League of Legends_ character for obtaining some skin - A verified CRC to ensure that the transaction was made by using some custom backend and not by the end user These are some minor examples but other use cases could be here. ## 5. Learn to Delegate and Undelegate on the Casper Testnet Delegating is a synonym of _Staking_ for _Casper_. We could _stake_ our funds, attaching it to some validator, obtaining _rewards_ that way. We could delegate our funds by using the _testnet_ web UI presented before, where we already have installed under our browser our _testnetkey_ wallet. In the upper menu of [https://testnet.cspr.live/](https://testnet.cspr.live/) click on _Validators_ and select a random one. I would select the first one for this example. ![](https://i.imgur.com/rtKkUso.png) Then, click on _Delegate Stake_ (the red button). ![](https://i.imgur.com/DZareA7.png) Delegate the amount of _CSPR_ that you would like. In my case, I would be delegating 500 _CSPR_ to this validator. ![](https://i.imgur.com/kR4KPR6.png) Then, click _Next_ and ensure that the _Deploy Hash_ is the same in the _Testnet_ web UI than in the _CasperLabs Signer_ extension window. ![](https://i.imgur.com/6if2rYg.png) ![](https://i.imgur.com/j2mbiaR.png) ![](https://i.imgur.com/wMiFZZv.png) You are good to go, you already delegated 500 _CSPR_ to the validator of your choice. If, at some point you would like to _Undelegate_ your funds from a validator the process is straightforward. Just go to _Wallet_, _Undelegate Stake_, select your validator and _Undelegate_ the amount of your choice. ![](https://i.imgur.com/qjft5xH.png) ![](https://i.imgur.com/Cyne3Fg.png) ![](https://i.imgur.com/BCcFVAb.png) Remember to always check the _CasperLabs Signer_ window and that the deploy hashes match. ## That's all Thank you for taking the time to read this tutorial. Hopefully it would help more people to grow up as _Blockchain developers_ and get into _Casper_. Regards, [https://github.com/sisco0](https://github.com/sisco0)