Deploying a Smart Contract in CUDOS — Update February 2022

blockscapeLab
5 min readNov 30, 2021

The Cudos Network is a special-purpose blockchain designed to provide high-performance, trust-less, permission-less cloud computing for all.

In this tutorial, we will be deploying a CosmWasm smart contract on the Cudos public testnet.

Prerequisites

1) RPC Node

First, you’ll have to set up your environment, during which you’ll create the binary-builder container, which we’ll be using to interact with the blockchain.

In order to upload the smart contract to the blockchain, you’ll also need access to an RPC node (=full node with port 26657 open). You can use this one, as long as its up: https://sentry1.gcp-uscentral1.cudos.org:26657.

If you don’t have access to an externally hosted RPC node (i.e. the node above is down for some reason), you can always set up and run your own one.

2) Rust

CosmWasm smart contracts are written in Rust, so we need to install the Rust compiler.

# Install rustup.
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Use the latest stable version.
$ rustup default stable
# Add the wasm32 target and make sure it was installed correctly.
$ rustup target add wasm32-unknown-unknown
$ rustup target list --installed

Smart Contract

Download an Existing Smart Contract

For the sake of simplicity, we’re going to be using the CW20 contract, which deploys a fungible token (much like ERC20) on the chain. If you’re trying to deploy your own smart contract, you can skip ahead to Compilation.

The CW20 smart contract can be downloaded from the CosmWasm/cw-plus repository on GitHub. For CUDOS, we’ll need to checkout v0.9.0.

$ git clone --depth 1 --branch v0.9.0 https://github.com/CosmWasm/cw-plus.git

Compilation

In the contract’s root directory, please run the following command.

# Go to root directory of CW20 contract.
$ cd cw-plus
# Optimize and compile the smart contract.
$ docker run --rm -v "$(pwd)":/code --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/workspace-optimizer:0.12.5

Once it’s done compiling, the .wasm executable needs to be copied into the binary-builder container.

# Make sure the "binary-builder" is in the list of running containers.
$ docker ps
# Copy the .wasm executable into the /usr/cudos directory of the binary-builder.
$ docker cp artifacts/cw20_base.wasm binary-builder:/usr/cudos
# Install jQuery.
$ docker exec -it binary-builder apt update -y
$ docker exec -it binary-builder apt install jq -y

Deployment

The CW20 smart contract needs an owner account, which among other things will be able to mint and burn tokens. If you don’t already have an account, please either create or recover an existing one that you’d like to use as the contract owner.

# Create a new owner account (if needed).
$ docker exec -it binary-builder cudos-noded keys add owner \
--keyring-backend file
# To recover an account, add the --recover flag to the command above.

In order to deploy the contract, the owner account needs some CUDOS tokens to pay for gas, so get some from the faucet.

# Check balance to see if the tokens from the faucet have arrived.
$ docker exec -it binary-builder cudos-noded q bank balances <OWNER_ADDR> --node https://sentry1.gcp-uscentral1.cudos.org:26657
  • <OWNER_ADDR> is the owner account’s cudos1... address.

Alright, we’re ready to deploy the smart contract.

$ docker exec -it binary-builder cudos-noded tx wasm store /usr/cudos/cw20_base.wasm \
--from owner \
--keyring-backend file \
--chain-id cudos-testnet-public-2 \
--node https://sentry1.gcp-uscentral1.cudos.org:26657 \
--gas auto \
--gas-adjustment 1.3 \
-y | tee /dev/tty | tail -1 | tr -d '\r' | jq -r '.logs[0].events[-1].attributes[-1].value' | tee /dev/tty

The output should give you the contract ID.

Instantiation

A deployed smart contract cannot be interacted with unless it is instantiated. The instantiation is essentially the process of passing custom values to the contract, like the name of the token, the symbol, decimals and so on, which in a sense “brings the contract to life”.

Let’s first set our custom initialization parameters.

$ INIT=$(jq -n --arg address <OWNER_ADDR> '{"name":"<TOKEN_NAME>","symbol":"<TOKEN_SYMBOL>","decimals":<DECIMALS>,"initial_balances":[<ACCOUNTS>],"mint":{"minter":$address,"cap":"<TOKEN_CAP>"}}' | tee /dev/tty)
  • <OWNER_ADDR> is the owner account’s
  • <TOKEN_NAME> is the name you’d like to give your CW20 token, e.g. “Super Cudos”
  • <TOKEN_SYMBOL> is the denominator of your CW20 token, e.g. “scudos”
  • <DECIMALS> is the number of decimal places your token should have, e.g. 3 (=smallest value would be 0.001)
  • <ACCOUNTS> is an array of one or more JSON objects like {"address": "<CUDOS_ADDR>","amount":<TOKEN_AMOUNT>} , where <CUDOS_ADDR> is the cudos1... address that is given <TOKEN_AMOUNT> tokens on contract instantiation, e.g. {"address": "cudos1d0new9u2f80rcmmlw0zftxeh0385c2gwpmdv8v","amount":1000}
  • <TOKEN_CAP> is the maximum amount of tokens the minter can mint, e.g. “1000000000000”

Now that we’ve customized our CW20 contract, let’s instantiate it.

$ docker exec -it binary-builder cudos-noded tx wasm instantiate <CONTRACT_ID> $INIT --from owner --label "CW20" --keyring-backend file --chain-id cudos-testnet-public-2 --node https://sentry1.gcp-uscentral1.cudos.org:26657 --gas auto --gas-adjustment 1.3 -y
  • <CONTRACT_ID> is the contract’s ID we got from deploying it

Now, check the contract state to make sure it’s actually instantiated.

$ docker exec -it binary-builder cudos-noded q wasm list-contract-by-code <CONTRACT_ID> --node https://sentry1.gcp-uscentral1.cudos.org:26657 --output json | jq -s

Interacting with the Contract

In order to interact with the contract, you need the contract’s address.

$ CONTRACT_ADDR=$(docker exec -it binary-builder cudos-noded q wasm list-contract-by-code <CONTRACT_ID> --node https://sentry1.gcp-uscentral1.cudos.org:26657 --output json | jq -r '.contracts[-1]' | tee /dev/tty | tail -1 | tr -d '\r')

Each contract must provide schema files, which tell you how you can interact with it, much like an ABI in Ethereum. You can generate them yourself inside the repository’s root directory using the following command.

$ cd /path/to/cw-plus/contracts/<CONTRACT>
$ cargo schema
  • In our case, <CONTRACT> is cw20-base

Let’s take the transfer method for example. The schema tells us that we need to pass in a "transfer" object, with an "amount" and a "recipient" .

$ TRANSFER=$(jq -n --arg address <RECIPIENT_ADDR> '{"transfer":{"amount":"1000000","recipient":$address}}')
  • <RECIPIENT_ADDR> is the cudos1... address of any account you want to send tokens to

To fire the transaction, use the following command. Note that you’ll have to pay gas for it, as you’re altering the state of the ledger.

$ docker exec -it binary-builder cudos-noded tx wasm execute $CONTRACT_ADDR $TRANSFER --from owner --keyring-backend file --chain-id cudos-testnet-public-2 --node https://sentry1.gcp-uscentral1.cudos.org:26657 --gas auto --gas-adjustment 1.3 -y

An example for a query would be checking an account’s token balance. This does not alter the state of the ledger and thus does not require paying for gas.

$ BALANCE=$(jq -n --arg address <RECIPIENT_ADDR> '{"balance":{"address":$address}}')

Pass that into the following command and you’ll get the address’s balance.

$ docker exec -it binary-builder cudos-noded q wasm contract-state smart $CONTRACT_ADDR $BALANCE --node https://sentry1.gcp-uscentral1.cudos.org:26657

And there you go, you’ve successfully deployed, instantiated and interacted with a smart contract! Feel free to experiment with other endpoints and contracts! Hopefully, you found this guide useful! Leave us a clap if you did!

Until next time!

--

--