Deploy a CosmWasm Smart Contract

Generate an account

To generate an account on a Cosmos-based testnet, ours being XION, a user would typically use the Cosmos SDK and its associated libraries to interact with the blockchain. Here's a general outline of the steps you would take to generate an account.

It is important to have all prerequisites and dependencies installed and some knowledge known on them. You may find this information located inside the installation tab.

Generate Account Key Pair:

Use the Cosmos SDK's cryptographic tools to generate a key pair for your account. This key pair will include a public key and a private key.

To generate a key and add it to your local keybase:

xiond keys add <keyname>

You can get the public key of a key pair that you have previously generated by using the show command of the cosmos keys CLI. Please replace with the name of your key.

xiond keys show <keyname> -p

Create an Account on the Blockchain:

Use the generated key pair to create an account on the network. This involves sending a transaction to the network's blockchain to register your account. The simplest way to do this is to request testnet tokens from a member of the team or in discord.

Deploying Contracts

Use the CosmWasm CLI to deploy the created contract to the testnet. The specific command and options may vary depending depending on version.

xiond tx wasm store contract.tar.gz --from <sender_address> --chain-id <chain_id> --gas auto --gas-prices <gas_prices> --node <testnet_rpc_url>

Replace <sender_address>, <chain_id>, <gas_prices>, and <testnet_rpc_url> with the appropriate values for your testnet environment. These can be found in the Network section.

or use the populated version here:

 xiond tx wasm store ./contract.wasm \
    --chain-id xion-local-testnet-1 \
    --gas-adjustment 1.3 \
    --gas-prices 0uxion \
    --gas auto \
    --chain-id xion-testnet-1 \
    --from <sender_address>

Our testnet allows for zero gas price but will not be the case with our mainnet.

Where to find appropriate values?


This is the address of your account on the testnet. If you don't have one, you'll need to create an account on the XION's testnet and obtain the address. More information on how to generate a key pair and the associated address can be found here.


The chain ID is a unique identifier for the specific blockchain network you're deploying to. You can usually find the chain ID in the XION's testnet's documentation or information.


Gas prices are typically denominated in the native token of the blockchain. You may need to refer to the testnet's documentation or forums to find the appropriate gas prices.


You'll need this URL to submit transactions and query data. Testnets often provide RPC endpoints that you can use. These can be found in the XION's testnet's documentation or developer resources.

Remember that these values are specific to the XION testnet you''ll be deploying to.

Interacting with the Deployed Contract

Now that the contract is deployed, the user can interact with it using the CosmWasm CLI or other tools. For example, to execute a contract message, you can use a command such as the following.

xiond tx wasm execute <contract_address> '{"set": {"new_value": 42}}' --from <sender_address> --chain-id <chain_id> --gas auto --gas-prices <gas_prices> --node <testnet_rpc_url>

Replace <contract_address>, <sender_address>, <chain_id>, <gas_prices>, and <testnet_rpc_url> with the appropriate values.

Confirm Contract deployment and Derive code IDs

Confirm Contract deployment

  1. To deploy smart contracts, you must compile the code and make it an executable wasm binary file. We will compile the wasm contract with stable toolchain.

    Compile using the command below:

    # Set 'stable' as the default release channel:
    rustup default stable
    cargo wasm
    • toolchain means the compiler of Rust, and rust has three release channels: stable, beta, and nightly, of which the stable channel is the most recently released version. rustup helps you manage these different versions easily.

    • cargo is the Rust package manager. In the .cargo/config, you can view the wasm compilation options as follows:

      wasm = "build --release --target wasm32-unknown-unknown"

    So when we run the cargo wasm command, the cargo build --release —-target wasm32-unknown-unknown command is executed according to the option in the config file above.

After this compiles, it should produce a file in `target/wasm32-unknown-unknown/release/my_first_contract.wasm`. If you check the size of the file by using the `ls -lh` command, it shows around `1.8M`. This is a release build, but not stripped of all unneeded code. To produce a much smaller version, you can run this which tells the compiler to strip all unused code out:
RUSTFLAGS='-C link-arg=-s' cargo wasm

3. This produces a file about 155K. To reduce gas costs, the binary size should be as small as possible. This will result in a less costly deployment, and lower fees on every interaction.

Also, if you don’t use compilation optimization, CosmWasm smart contract will not be deployed well due to `exceeds limit` error.

Optimized Compilation

You can do further optimization using rust-optimizer. rust-optimizer produces reproducible builds of CosmWasm smart contracts and does heavy optimization on the build size, using binary stripping and wasm-opt.

sudo 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 \

Binary file will be at artifacts/my_first_contract.wasm folder and its size will be about 130K, which is more smaller than when only RUTFLAGS was used.

Store to Xion Testnet chain

We have the wasm binary executable ready. Now it is time to store the code to the Xion Testnet blockchain.

# store the code on chain
RES=$(xiond tx wasm store artifacts/my_first_contract.wasm --from wallet --gas-prices 0.1uxion --gas auto --gas-adjustment 1.3 -y --output json -b block)
  • xiond tx wasm store : upload a wasm binary

  • --from : name or address of private key with which to sign.

  • --gas-prices : gas prices in decimal format to determine the transaction fee.

  • --gas : gas limit to set per-transaction. set to "auto" to calculate sufficient gas automatically

  • --gas-adjustment : adjustment factor to be multiplied against the estimate returned by the tx simulation.

  • -y : to skip tx broadcasting prompt confirmation.

  • --output : output format.

  • -b : transaction broadcasting mode

Once that is complete, you can get the CODE_ID easily using jq.

jq is an open source that helps extract data from JSON. Install it according to your OS using the following command:

# Linux
sudo apt-get install jq

# Mac
brew install jq

If you are using an operating system other than the one listed above, please refer to the official document.

Set the $RES Variable to Parse Output

The user can directly set the output of the xiond keys add myaccount command to a variable, and then use string manipulation to extract the address.

Here's an example:

// Run the command and store the output in the variable $RES
RES=$(xiond keys add myaccount --output json)
// Extract the address using string manipulation
ADDRESS=$(echo $RES | jq -r '.address')
// Print the extracted address
echo "Generated Address: $ADDRESS"

In this example, we're using the jq tool to parse the JSON output and extract the address.

Make sure to have jq installed for this approach.

Pipe xiond Output to jq for Parsing

A user can pipe the output of xiond keys add myaccount directly into jq for parsing:

// Run the command and pipe output to jq for parsing
ADDRESS=$(xiond keys add my account --output json | jq -r '.address')
// Print the extracted address
echo "Generated Address: $ADDRESS"

In this case, the output of xiond keys add myaccount --output json is directly passed to jq for parsing, and the address is extracted.

Run the following command to set the CODE_ID as a variable:

# get CODE_ID
CODE_ID=$(echo $RES | jq -r '.logs[0].events[-1].attributes[0].value')
echo $CODE_ID

Instantiate the contract

We can now create an instance of this wasm contract. First, set the initial state of the instance in the INIT variable and run the instantiate command.

# set the initial state of the instance

# instantiate the contract
xiond tx wasm instantiate $CODE_ID "$INIT" \
    --from wallet --label "my first contract" --gas-prices 0.025uxion --gas auto --gas-adjustment 1.3 -b block -y --no-admin
  • xiond tx wasm instantiate : instantiate a wasm contract using CODE_ID of the uploaded binary.

  • --label : human-readable name for this contract in lists.

  • --no-admin : you must set this explicitly if you don’t want an admin.

If you have succeeded in instantiating the contract, you can search for output txhash in Xion Explorer to verify your deployment.

Get the contract address using the command following:

CONTRACT_ADDR=$(xiond query wasm list-contract-by-code $CODE_ID --output json | jq -r '.contracts[0]')
  • xiond query wasm list-contract-by-code : list wasm all bytecode on the chain for given code id

Execute the Contract

Now, let's see if the contract we deployed works well.

Get contract’s count

Send a get_count query to check the count value. The previously set INIT state is output as it is.: {"data":{"count":100}}

xiond query wasm contract-state smart $CONTRACT_ADDR "$QUERY" --output json
  • xiond query wasm contract-state smart : calls contract with given address with query data and prints the returned result

Increment contract’s count

This time, let's send an increment transaction that increases the count value by +1. Because the transaction changes the internal state of the contract, you must pay gas fees.

If you run the get_count query again after sending the increment transaction, you can see that +1 has increased from the previous count value.

TRY_INCREMENT='{"increment": {}}'
xiond tx wasm execute $CONTRACT_ADDR "$TRY_INCREMENT" --from wallet --gas-prices 0.025uxion --gas auto --gas-adjustment 1.3 -y
  • xiond tx wasm execute : execute a command on a wasm contract

Reset contract’s count

Lastly, let’s send a reset transaction. Like increment, reset transaction also changes the internal state of contract, so you must pay gas fees.

RESET='{"reset": {"count": 0}}'
xiond tx wasm execute $CONTRACT_ADDR "$RESET" --from wallet --gas-prices 0.025uxion --gas auto --gas-adjustment 1.3 -y


Last updated