Installing Smart Contracts
This document details the process of installing Casper smart contracts using the Casper command-line client and the put-deploy
command.
Prerequisites
- You have a compiled contract (
.wasm
file) to send to a Casper network - You have installed the Casper CLI client to interact with the network
- You have a Casper Account with a public and secret key pair to initiate the deploy
- You have enough CSPR tokens in your account's main purse to pay for deploys. If you plan to use the Casper Testnet, learn about the faucet to fund your testing account's main purse
Installing a Contract in Global State
To install a contract in global state, you need to send a deploy to the network with the contract Wasm. You can do so by using the put-deploy
command.
casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path [CONTRACT_PATH]/[CONTRACT_NAME].wasm
The arguments used above are:
node-address
- An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777chain-name
- The chain name to the network where you wish to send the deploy. For Mainnet, use casper. For Testnet, use casper-testsecret-key
- The file name containing the secret key of the account paying for the deploypayment-amount
- The payment for the deploy in motessession-path
- The path to the contract Wasm, which should point to wherever you compiled the contract (.wasm
file) on your computer
Once you call this command, it will return a deploy hash. You can use this hash to verify successful execution of the deploy.
Example - Install the contract:
Here we send a counter-v1.wasm
to a local NCTL network.
casper-client put-deploy \
--node-address http://localhost:11101 \
--chain-name casper-net-1 \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount 5000000000000 \
--session-path ./counter/target/wasm32-unknown-unknown/release/counter-v1.wasm
The payment amount varies based on each contract and network chainspec.
To verify the deploy, call get-deploy
and provide the deploy hash you received from put-deploy
.
casper-client get-deploy \
--node-address http://localhost:11101 [DEPLOY_HASH]
Video - Contract Installation Walkthrough
This video demonstrates the commands described above for installing a contract on-chain.
Querying Global State
Here we look at how to query global state to see details about a successfully installed contract.
Get the state root hash
The first step in querying the global state is obtaining the state root hash. The state root hash acts as an identifier for the current state of the network (global state). It is like a Git commit ID for commit history, and it provides a snapshot of the blockchain state at a specific point in time.
After sending deploys to the network, it's necessary to fetch the new state root hash in order to see the changes reflected in the global state. Without doing this, you would be querying past versions of the state.
To get the state root hash, use the get-state-root-hash
command:
casper-client get-state-root-hash --node-address [NODE_SERVER_ADDRESS]
Query global state
Next, query the state of a Casper network at a given time, specified by the state-root-hash
described above. You can dive into the data stored in global state using the optional query path argument -q
.
casper-client query-global-state \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [HASH_STRING] \
-q "[SESSION_NAME]/[SESSION_NAMED_KEY]"
The arguments used above are:
node-address
- An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777state-root-hash
- Hex-encoded hash of the state rootkey
- The identifier for the query. This must be one of the following: public key, account hash, contract package hash, transfer hash, or deploy hashq
- An optional query path argument that allows you to drill into the specifics of a query with respect to the key
Example - Query the account:
To find your account details, query global state using your account hash.
casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d
Here is how your account state would look. Notice that the sample response contains several named keys, including "counter", "counter_package_name", and "version". You can use these values to query the contract state further, as shown in the next example.
Sample account state
{
"id": -6831525034388467034,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[27614 hex chars]",
"stored_value": {
"Account": {
"account_hash": "account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d",
"weight": 1
}
],
"main_purse": "uref-d92e420120199f90005802bf3036362f368ab69bebf17e7e53856d6ac82e117f-007",
"named_keys": [
{
"key": "hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e",
"name": "counter"
},
{
"key": "uref-41c3f4ae3c1ce2446f6fd880a96e698ae5abc715151e45e357d88bb739489c03-007",
"name": "counter_access_uref"
},
{
"key": "hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"name": "counter_package_name"
},
{
"key": "uref-917762490591a1404cba59ed8dcf0bcfa7f644ef6c6be9bf5ea7b1641617cad0-007",
"name": "version"
}
]
}
}
}
}
If you don't know your account hash, you can run this command:
casper-client account-address --public-key [PATH_TO_PUBLIC_KEY]
Example - Query the contract:
This example shows how to query global state given a contract hash. We use the contract hash from the sample response above.
casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e
Here is how the sample contract would look and would contain details such as the contract_package_hash
, the contract entry_points
, and the named_keys
for the contract.
Sample contract state
{
"id": -4657473054587773855,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[21330 hex chars]",
"stored_value": {
"Contract": {
"contract_package_hash": "contract-package-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"contract_wasm_hash": "contract-wasm-576b1718711d524a79ab2f05ce801006a3fd32eb48b9f7dac69a9fa966d634e3",
"entry_points": [
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_get",
"ret": "I32"
},
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_inc",
"ret": "Unit"
}
],
"named_keys": [
{
"key": "uref-d40613e50c7b405b02795e3fe3252554bef49b4b522e31a55f39b87c442f922a-007",
"name": "count"
}
],
"protocol_version": "1.4.5"
}
}
}
}
Example - Query a value using its key and the contract hash:
Next, you can query a named key associated with the contract using the -q
option. This example comes from the Counter Contract Tutorial, where a "count" variable is incremented and stored under a named key.
casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [CONTRACT_HASH] \
-q "count"
Sample stored value
{
"id": -2540117660598287261,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[56562 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "00000000",
"cl_type": "I32",
"parsed": 0
}
}
}
}
Example - Query a value using the account hash and named keys:
It is also possible to check the state of a specific contract variable in global state given the account hash under which the contract was installed. Here we query the named key "count", stored under another key identifying the contract and named "counter".
casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d \
-q "counter/count"
The response should be the same as in Example 3, above.
Example - Query contract package state:
You can query information about a contract package, such as the latest contract hash and contract version, given its contract package hash.
casper-client query-global-state \
--node-address http://localhost:11101 \
--key hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e \
--state-root-hash 763e737cf55a298d54bcdfb4ee55526538a1a086128914b9cc25ccbdebbbb966
Here is how the contract package details would look. The response would contain the contract_hash
, which you would need to call a contract by hash in the next section. You would also see the access_key
for the ContractPackage
and the current contract_version
.
Sample contract package state
{
"id": -6225901853092301031,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[20964 hex chars]",
"stored_value": {
"ContractPackage": {
"access_key": "uref-41c3f4ae3c1ce2446f6fd880a96e698ae5abc715151e45e357d88bb739489c03-007",
"disabled_versions": [],
"groups": [],
"versions": [
{
"contract_hash": "contract-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e",
"contract_version": 1,
"protocol_version_major": 1
}
]
}
}
}
}
Video - Querying Walkthrough
This video shows you what to expect when querying the network.
What's Next?
- Learn different ways to call contracts using the Casper command-line client