The following provides a step-by-step set of examples including basic and advanced features to deploy contracts. Prior knowledge about permissions and execution semantics is recommended and can be found in our Techspec here.
- Install
rustup
. - Install the
casperlabs
package, which containscasperlabs-client
.
- Install
rustup
. - Build the
casperlabs-client
.
If you build from source, you will need to add the build directories to your PATH
, for example:
export PATH="<path-to-CasperLabs-repo>/client/target/universal/stage/bin:$PATH"
Or you can run the client commands from the root directory of the repo using explicit paths to the binaries.
Step 1: Clone the main repo to obtain the example contracts and set up your toolchain
git clone [email protected]:CasperLabs/CasperLabs.git
cd CasperLabs/execution-engine
rustup toolchain install $(cat rust-toolchain)
rustup target add --toolchain $(cat rust-toolchain) wasm32-unknown-unknown
Source code of contract examples are currently located in ./execution-engine/contracts/examples
directory inside the main repo as follows here.
make build-example-contracts
export COUNTER_DEFINE="$(pwd)/target/wasm32-unknown-unknown/release/counter_define.wasm"
Step 3: Create an account at clarity.casperlabs.io
Create an account with an account key, which automatically creates a new keypair. This keypair should be downloaded to the machine where you will deploy contracts.
You can add motes to the account using the faucet. Select the account key associated with the account you want to add motes to and "Request Tokens". When the process is complete, the status is updated with the available amount to use with your account.
casperlabs-client \
--host deploy.casperlabs.io \
deploy \
--private-key <path-to-private-key> \
--session $COUNTER_DEFINE \
--payment-amount 2000000
Note: --payment-amount
is used to define the maximum number of motes to spend on the execution of the deploy. As shown in the example, 2,000,000 is the amount needed to execute the counter define contract, see further details here.
Source code for the contract used in this example is found here.
You should see the following output:
Success!
Note: The deploy command is a convenience function combining multiple actions (make
, sign
, send
) in the case of a single signature. For signing with multiple keys, see Advanced usage in this document.
See the instructions here.
casperlabs-client \
--host deploy.casperlabs.io \
deploy \
--private-key <path-to-private-key> \
--session-name counter_inc \
--payment-amount 2000000
You should see the following output:
Success!
--session-name
tells the system to use a previous stored contract under the given name. In this case the counter_define
wasm we deployed in Step 5 stored a contract under the name counter_inc
, which we can now call.
Note: store_function
stores a contract under a URef
(Key::URef
), store_function_at_hash
stores a contract under a Hash
( Key::Hash
), a 256-bit unique identifier which is generated by the system. put_key
is used to associate a Key
with a human-readable name (this is only valid in the context where put_key
is run via a store_*
function.
--session-name
works with either storage function, --session-hash
works with contracts stored at hashes.
Note: when a contract is stored under a Hash
it is immutable (that Hash
will always point to exactly that contract), while storing under a URef
allows the contract to be upgraded, for example, with the upgrade_contract_at_uref
function, see CasperLabs Contract_API and source here for details.
For details about storage see the Contract API here.
export TRANSFER="$(pwd)/target/wasm32-unknown-unknown/release/transfer_to_account.wasm"
casperlabs-client \
--host deploy.casperlabs.io \
deploy \
--private-key <path-to-new-private-key> \
--session $TRANSFER \
--session-args '[{"name" : "target", "value" : {"bytes_value" : "<base-16-public-key>"}}, {"name": "amount", "value" : {"long_value" : 1000}}]' \
--payment-amount 2000000
<public-key-in-hex>
is the address to send the motes to.
Note: Transfers can be done in a more convenient way using the transfer
sub-command of the client, see casperlabs-client transfer --help
for details.
Smart contracts can be parametrized. A list of contract arguments can be specified on command line when the contract is deployed.
The client's deploy
command accepts parameter --session-args
that can be used to specify types and values of contract arguments as a serialized sequence of Arg values in a protobuf JSON format, with binary data represented in Base16 format.
Note: contract arguments are positional, and so the "name"
attribute is currently not used. However, we plan to change contract arguments to be keyword (named) arguments. The structure of the Arg
protobuf message and its JSON serialized form is ready for this change.
Supported types of contract arguments
protobuf Arg | Contract API type | Example value in protobuf JSON format |
---|---|---|
int_value |
u32 |
'[{"name": "amount", "value": {"int_value": 123456}}]' |
long_value |
u64 |
'[{"name": "amount", "value": {"long_value": 123456}}]' |
big_int |
u512 |
'[{"name": "amount", "value": {"big_int": {"value": "123456", "bit_width": 512}}}]' |
string_value |
String |
'[{"name": "surname", "value": {"string_value": "Nakamoto"}}]' |
optional_value |
Option<T> |
'{"name": "maybe_number", "value": {"optional_value": {}}} or {"name": "maybe_number", "value": {"optional_value": {"long_value": 1000000}}}' |
hash |
Key::Hash |
'{"name": "my_hash", "value": {"key": {"hash": {"hash": "9d39b7fba47d07c1af6f711efe604a112ab371e2deefb99a613d2b3dcdfba414"}}}}' |
address |
Key::Address |
'{"name": "my_address", "value": {"key": {"address": {"account": "9d39b7fba47d07c1af6f711efe604a112ab371e2deefb99a613d2b3dcdfba414"}}}}' |
uref |
Key::URef |
'{"name": "my_uref", "value": {"key": {"uref": {"uref": "9d39b7fba47d07c1af6f711efe604a112ab371e2deefb99a613d2b3dcdfba414", "access_rights": 5}}}}' |
local |
Key::Local |
'{"name": "my_local", "value": {"key": {"local": {"hash": "9d39b7fba47d07c1af6f711efe604a112ab371e2deefb99a613d2b3dcdfba414"}}}}' |
int_list |
Vec<i32> |
'{"name": "my_int_list", "value": {"int_list": {"values": [0, 1, 2]}}}' |
string_list |
Vec<String> |
'{"name": "my_string_list", "value": {"string_list": {"values": ["A", "B", "C"]}}}' |
Numeric values of access_rights
in uref
are defined in `enum AccessRights in state.proto.
The deploy
command on its own provides multiple actions strung together optimizing for the common case, with the capability to separate concerns between your key management and deploy creation. See details about generating account key pairs here.
Every account can associate multiple keys with it and give each a weight. Collective weight of signing keys decides whether an action of certain type can be made. In order to collect weight of different associated keys, a deploy has to be signed by corresponding private keys. The deploy
command creates a deploy, signs it and deploys to the node but doesn't allow for signing with multiple keys. Therefore, we split deploy
into separate commands:
make-deploy
- creates a deploy from input parameterssign-deploy
- signs a deploy with given private keyprint-deploy
- prints information of a deploysend-deploy
- sends a deploy to CasperLabs nodeshow-deploy
- queries the status of a deploy
To make a deploy signed with multiple keys: first make the deploy with make-deploy
, sign it with the keys calling sign-deploy
for each key, and then send it to the node with send-deploy
.
Commands read input deploy from both a file (-i
flag) and STDIN. They can also write to both file and STDOUT.
For more detailed description about deploy commands, use the --help
flag (casper-client --help
).
You can find detailed information about associated keys and weights here.
The following command will write a deploy in binary format to STDOUT:
casperlabs-client \
--host localhost \
make-deploy \
--session session-code.wasm \
--payment payment-code.wasm \
--from a1130120d27f6f692545858cc5c284b1ef30fe287caef648b0c405def88f543a
It is possible to write it to a file, by supplying -o
argument:
casperlabs-client \
--host localhost \
make-deploy \
--session session-code.wasm \
--payment payment-code.wasm \
--from a1130120d27f6f692545858cc5c284b1ef30fe287caef648b0c405def88f543a
-o /deploys/deploy_1
Time to live of a deploy
The time to live (TTL) of a deploy is the amount of time after its timestamp that the deploy may be included in a block. After the TTL has elapsed, if the deploy has not been included in a block, any node will discard it from the deploy buffer. The TTL can be specified (in units of milliseconds) from the CasperLabs client using the --ttl-millis
argument in the deploy
sub-command:
casperlabs-client\
--host deploy.casperlabs.io \
deploy \
--ttl-millis <arg>
A protocol-level maximum value for the TTL is given in the Chainspec; values larger than this will not be accepted. In addition, each node sets a minimum accepted value as part of its local configuration (set by the node operator). By default CasperLabs nodes set the minimum allowed TTL to be 24 hours. If no TTL is specified then the maximum value is used by default.
Deploy dependencies
casperlabs-client\
--host deploy.casperlabs.io \
deploy \
--dependencies <arg>...
This parameter provides a mechanism implemented to explicitly enforce an ordering to deploys as sometimes this is important. Use the CasperLabs client deploy
sub-command.--dependencies
passes the argument list of deploy hashes (base16 encoded) which must be executed before this deploy.
casperlabs-client \
--host localhost \
sign-deploy \
--public-key public-key.pem \
--private-key private-key.pem
This will read a deploy to sign from STDIN and output signed deploy to STDOUT. There are -i
and -o
flags for, respectively, reading a deploy from a file and writing signed deploy to a file.
Note: this step may be repeated multiple times to sign a deploy with multiple keys. This feature allows supporting multi-sig transactions out-of-the-box. You can see details about generating account keys here.
You can find more informatiom about Associated Keys and Weights here
casperlabs-client \
--host localhost \
print-deploy
This will print information of a deploy into STDOUT. There are --json
and --bytes-standard
flags for, respectively, using standard JSON vs Protobuf text encoding and standard ASCII-escaped for Protobuf or Base64 for JSON bytes encoding vs custom Base16. The same set of flags is also available for all show-*
and query-state
commands.
casperlabs-client \
--host localhost \
send-deploy
In the example above there is no -i
argument, meaning that the signed deploy will be read from STDIN.
Reading from STDIN and writing to STDOUT allows for piping output from one command to the input of another one (commands are incomplete for better readability):
casperlabs-client make-deploy [arguments] | \
casperlabs-client sign-deploy --private-key [private_key] --public-key [public_key] | \
casperlabs-client send-deploy
casperlabs-client\
--host deploy.casperlabs.io \
--port 40401 show-deploy <deploy-hash>
The show-deploy
command will return a status (pending, processed, finalized, discarded as well as information about its execution (success or error with message), and the block(s) it is included in (if any).
See a description of state provided here for the status' as listed:
PENDING
PROCESSED
FINALIZED
DISCARDED
You can also retrieve further information about a deploy from our platform (APIs, et. al.). See additional details here.
If you are testing with a local standalone node, you will need to change the --host
argument:
casperlabs-client \
--host 127.0.0.1 \
deploy \
--private-key <path-to-private-key> \
--session $COUNTER_DEFINE
You will also need to explicitly propose after making a deploy (or several deploys), in order for your deploys to be committed:
casperlabs-client --host 127.0.0.1 propose