Deployment
How to Deploy a Smart Contract on CUDOS using cudos-noded - Fully Explained!
NOTE: As always, if you see angle brackets surrounding text, eg:
<your-wallet-name>, you need to fill in your own variable name.
Install the CUDOS node
The CUDOS node daemon,
cudos-noded, can be installed from here:cudos-noded.This will install the blockchain node daemon binary which will allow you to either run your own node locally or on the chain, or interact with other nodes via RPC using the same CLI.
Compile your rust source files down to
.wasmYou will need to have compiled your smart contract to the
.wasmartifacts. This can be done locally for testing purposes only.For production, you will need to compile your contract within the
rust-optimizerDocker container for reproducible and verifiable builds. This should only be done using Intel x86 processors. ARM processors cannot generate reproducible builds.Need some source file examples? You can start out by compiling all the CW contract files. These are the standard contracts for tokens in the Cosmos ecosystem and you can find them at the
cw-plusrepo. Sincecw-plusis a monorepo, use theworkspace-optimizerwithin therust-optimzermentioned above.Set environment variables
You will notice we use a lot of environment variables for all the flags of the CLI to keep things structured and avoid repetition. We use
_TNat the end of any flags to denote "testnet". Here is an example list of flags:# environment variables for testnet
export RPC_NODE_TN=https://rpc.testnet.cudos.org:443
export CHAIN_ID_TN=cudos-testnet-public-3
export GAS_TN=auto
export GAS_PRICES_TN=5000000000000acudos
export GAS_ADJUSTMENT_TN=1.3
export KEYRING_TN=os
# environment variables for mainnet
export RPC_NODE=https://rpc.cudos.org:443
export CHAIN_ID=cudos-1
export GAS=auto
export GAS_PRICES=5000000000000acudos
export GAS_ADJUSTMENT=1.3
export KEYRING=os
# contract address for cudos blockchain compute:
export CBC_ADDRESS=cudos1gn59sajfpqdlzxwmnnl69r7k2rxdt52l0nwwgalaa8nn2h8vrjzss2gz08
# the TX_FLAGS variables combines a number of the above variables
export TX_FLAGS_TN="--node=$RPC_NODE_TN --gas=$GAS_TN --gas-adjustment=$GAS_ADJUSTMENT_TN --gas-prices=$GAS_PRICES_TN --chain-id=$CHAIN_ID_TN --keyring-backend=$KEYRING_TN"
export TX_FLAGS="--node=$RPC_NODE --gas=$GAS --gas-adjustment=$GAS_ADJUSTMENT --gas-prices=$GAS_PRICES --chain-id=$CHAIN_ID --keyring-backend=$KEYRING"tipIt can be helpful to store this in a
vars.shfile and then to run:source vars.shinfoFor up to date flags for CUDOS (and other Cosmos blockchains), you can refer to the Cosmos Chain Registry. CUDOS testnet is here, and mainnet is here. (It's often good practice when building frontends to pull the chain info automatically from the
chain-registryrepo so that your configuration stays up-to-date).
Create a wallet address and add it to the CLI instance.
Create a CUDOS wallet address if you haven't already by following the instructions here, then add your mnemonic to your
cudos-nodedinstance to make transactions on the chain with your private key (remove the_TNfrom the end of any flags if you are working with the mainnet):cudos-noded keys add <your-wallet-name> --keyring-backend $KEYRING_TN --recoverThis will ask you to type your BIP-39 mnemonic phrase which will be secured using your operating system keyring which you set with the flag.
We now add this wallet to an environment variable as well, we call it
$OWNER_TNfor testnet:OWNER_TN=$( cudos-noded keys show -a <your-wallet-name> --keyring-backend "$KEYRING_TN" | tee /dev/tty | tail -1 | tr -d '\r' )⚠️ As always, keep your mnemonic phrase safe and secret.
Your wallet will also need funds to pay for gas fees, you can add testnet funds via the faucet icon on the bottom left of the testnet CUDOS Dashboard. Mainnet funds you will need to purchase on an exchange and either send to your address or bridge from the Ethereum ERC-20 version of the token once in your Ethereum wallet. Feel free to message in the CUDOS Discord if you need help, we may even send you a few cents worth of CUDOS to get you on your way with your first transaction on mainnet.
Deploy your compiled
.wasmcontract from before to the CUDOS blockchain.To do this we use the
cudos-nodedCLI to run thetx wasm storecommand which uploads the contract file to the chain. We set the output of that command to the$RESULTenvironment variable:STORE_RESULT=$(cudos-noded tx wasm store ./<path-to>/artifacts/<name-of-wasm-file.wasm> --from $OWNER_TN `echo $TX_FLAGS_TN`)Get the index of the contract file from the chain.
Cosmos blockchain store wasm contracts in an array, we need to find the index of your contract file in the array which is returned as part of the
$STORE_RESULTof the previous command.While you can sift through the output of the previous command, it's easier to get the index of your smart contract on the chain, here we use JQuery (
jq) to extract it from the JSON:CONTRACT_INDEX=$( echo $STORE_RESULT | jq -r '.logs[0].events[-1].attributes[-1].value' | tee /dev/tty )Instantiate your contract
This initialises the contract with its starting state. Your instantiation will require a JSON payload based off the fields in your
InstantiateMsgstruct withinmsg.rsof your contract source code. We set an environment variable for this too.Some contracts don't need a payload if the
InstantiateMsgstruct is empty:INST="{}"Here is an example of a payload for a standard CW20 token instantiation, we use
jqagain to format the JSON payload, note the use of the--argto pass an$addressargument based on your$OWNER_TNenvironment variable you set earlier:INST=$( jq -n --arg address $OWNER_TN '{ "name": "icecream", "symbol": "icream", "decimals": 6, "initial_balances": [ { "address": $address, "amount": "1000000" } ], "mint": { "minter": $address, "cap": "99900000000" } }' | tee /dev/tty )Before we instantiate our contract let's set two more variables, first we need a label name for the contract to give a human readable label:
$CONTRACT_LABEL="<label-name-for-contract>"Now we set an admin variable. For upgradeable smart contracts, we need to specify the address of the admin of the contract. While you can set the admin address to any address you like, in this case we use the owner address we used to store the contract:
ADMIN="--admin $OWNER_TN"Or, you can set this as
no-adminif you want the contract to remain immutable:ADMIN="--no-admin"🚀 Now we instantiate! This calls the
instantiatemethod on the stored contract and passes in the JSON from the$INSTvariable we set above. This gets stored in it's own$INST_RESPONSEvariable:INST_RESPONSE=$(cudos-noded tx wasm instantiate $CONTRACT_INDEX "$INST" --from $OWNER_TN --label $CONTRACT_LABEL `echo $TX_FLAGS_TN` $ADMIN)Get the contract address.
Now that our contract is instantiated, it has its own address on the network which was returned in the output of the instantiation, so we extract it with
jq, and set it as yet another environment variable:CONTRACT_ADDRESS=$(echo $INST_RESPONSE | jq -r '.logs[0].events[0].attributes[0].value' | tee /dev/tty | tail -1 | tr -d '\r')You have successfully deployed and instantiated a smart contract on CUDOS! Congratulations!
Having deployed and retrieved the contract address, you can now interact with the contract on the chain, you can do this with a frontend to build your project into a full decentralised application (dApp). Take a look at
create-cosmos-appto get going, it's a simple way of scaffolding a React frontend within the Cosmos ecosystem - CUDOS included. This YouTube video helps usecreate-cosmos-appfor CUDOS.BONUS: Execute functions on the contract from the CLI
While most end users will interact with the smart contract via a dApp frontend, you can also interact and execute functions on the contact with the
cudos-nodedCLI. Here's an example using the CW20 standard token contract again:We start by also creating our JSON payload, this is structured to map to the parameters of the type defined within
ExecuteMsgfound via thecontract.rsfile. In the case of the CW20 standard token contract, we can see here that the parameters for aTransferare therecipientand theamount.Transferis a base message to move tokens to another account without triggering actions. It is similar but different toTransferFromandSend. You can see more in themsg.rsfile for the standard CW20 token here.For our JSON payload, we need an address to send to so we set an environment variable for
$OLLIE:OLLIE="cudos1d7jw3ply86e4kcudmlv78ask32kdp7r2usf8xn"Now we structure our payload, again using
jq:TRANSFER_TO_OLLIE=$( jq -n --arg recipient $OLLIE '{ "transfer": { "recipient": $recipient, "amount": "1111" } }' | tee /dev/tty )Then we execute this on chain:
cudos-noded tx wasm execute $CONTRACT_ADDRESS "$TRANSFER_TO_OLLIE" --from $OWNER_TN `echo $TX_FLAGS_TN`BONUS 2: Query the contract state from the CLI
Similarly to Ethereum, queries on Cosmos chains don't cost gas fees.
We structure the JSON payload for a query similar to above:
BALANCE_OF_OLLIE=$( jq -n --arg address $OLLIE '{ "balance": { "address": $address } }' | tee /dev/tty )And we run it as a query from the CLI:
cudos-noded query wasm contract-state smart $CONTRACT_ADDRESS "$BALANCE_OF_OLLIE" --node $RPC_NODE_TNWhere we should get back the balance of the
$OLLIEaddress.
Congratulations on getting this far! You've done a lot!
Feel free to reach out on Discord if you have any questions, click the 💻 icon in the #role-assignment channel there to get access to the dev channels.
Now your next step, build that dApp frontend to interact with your contract from a great UI! Check the README for info on create-cosmos-app for more information!
Good luck fren!