Deploy a WASM contract
Overview
The x/wasm
Warden module allows executing WebAssembly smart contracts developed with CosmWasm and Rust.
This guide explains how to create and deploy a simple "Hello World" WASM contract on a Warden local chain or on Chiado testnet.
Prerequisites
Before you start, complete the following prerequisites:
-
Install Rust by running the following:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
Set up the CosmWasm development environment:
-
CosmWasm: The CosmWasm binary and its dependencies.
-
cargo-generate: A tool to help you get up and running quickly with a new Rust project by leveraging a pre-existing git repository as a template.
-
wasm-opt: A tool for optimizing the compiled WebAssembly (Wasm) code.
rustup target add wasm32-unknown-unknown
cargo install cargo-generate --features vendored-openssl
brew install binaryen -
1. Prepare the chain
Option 1. Run a local chain
To deploy a WASM contract locally, you need to run a local chain and make sure it's configured properly, as shown in the following steps:
-
Run a local chain as explained here: Run a local chain. Note that you'll need to install Go 1.22.3 or later and just 1.34.0 or later.
-
The next steps require your local account name, or key name. You can check the list of available keys by executing this command:
wardend keys list
tipIf you used our
just
script to run the node with default settings, the local account name isshulgin
. -
Check the local account balance to make sure it has funds:
- Local node: default settings
- Local node: custom settings
wardend query bank balances shulgin
wardend query bank balances my-key-name
Option 2. Connect to Chiado
To deploy a WASM contract on Chiado testnet, you need to install its binary and fund your key, as shown in the following steps:
-
If you haven't yet, install Go 1.22.3 or later and just 1.34.0 or later.
-
Clone the repository with Warden source code. Then build the binary and initialize the chain home folder:
git clone --depth 1 --branch v0.5.4 https://github.com/warden-protocol/wardenprotocol
cd wardenprotocol
just wardend build
just wardend install
wardend init my-chain-moniker -
Create a new key:
wardend keys add my-key-name
-
Write down the mnemonic phrase and the address of the new account. You'll need this information to interact with the chain and restore the account.
warningThe seed phrase is the only way to restore your keys. Losing it can result in the irrecoverable loss of WARD tokens.
tipYou can always check your public address by running this command:
wardend keys show my-key-name --address
-
Fund your key using Chiado faucet and the public address obtained in the previous step.
-
Check your balance. Here and in other commands, you need to add the
--node
flag with an RPC URL for connecting to Chiado.wardend query bank balances my-key-name --node https://rpc.chiado.wardenprotocol.org:443
2. Create a CosmWasm project
Create a new CosmWasm project template:
cargo generate --git https://github.com/CosmWasm/cw-template.git --name hello-world
cd hello-world
3. Modify the contract code
Now you need to modify files in the /src
directory as shown in the steps below.
-
Open the
contract.rs
file and replace its contents with this code:/hello-world/src/contract.rsuse cosmwasm_std::{
entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use cw2::set_contract_version;
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
const CONTRACT_NAME: &str = "crates.io:hello-world";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, ContractError> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
Ok(Response::new().add_attribute("method", "instantiate")
.add_attribute("owner", info.sender))
}
#[entry_point]
pub fn execute(
_deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::SayHello {} => Ok(Response::new()
.add_attribute("method", "say_hello")
.add_attribute("sender", info.sender)),
}
}
#[entry_point]
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::GetGreeting {} => to_json_binary(&"Hello, World!"),
}
} -
Open the
msg.rs
file and replace its contents with this code:/hello-world/src/msg.rsuse cosmwasm_schema::{cw_serde, QueryResponses};
#[cw_serde]
pub struct InstantiateMsg {}
#[cw_serde]
pub enum ExecuteMsg {
SayHello {},
}
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
#[returns(String)]
GetGreeting {},
} -
Open the
helpers.rs
file and replace its contents with this code:/hello-world/src/helpers.rsuse schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::{
to_json_binary, Addr, CosmosMsg, StdResult, WasmMsg
};
use crate::msg::{ExecuteMsg};
/// CwTemplateContract is a wrapper around Addr that provides a lot of helpers
/// for working with this.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct CwTemplateContract(pub Addr);
impl CwTemplateContract {
pub fn addr(&self) -> Addr {
self.0.clone()
}
pub fn call<T: Into<ExecuteMsg>>(&self, msg: T) -> StdResult<CosmosMsg> {
let msg = to_json_binary(&msg.into())?;
Ok(WasmMsg::Execute {
contract_addr: self.addr().into(),
msg,
funds: vec![],
}
.into())
}
}
4. Compile the contract
To compile the contract, run the following from the hello-world
directory:
cargo wasm
The contract should be compiled without any errors.
5. Optimize the code
Now you need to optimize your compiled Wasm code:
wasm-opt -Os -o target/wasm32-unknown-unknown/release/hello_world.wasm \
target/wasm32-unknown-unknown/release/hello_world.wasm
6. Store the contract on-chain
If you're deploying on a local chain, make sure it's running. You can start your chain by running wardend start
in a separate terminal window.
To store your contract on-chain, run the command below. Specify your key name from Step 1 in the --from
flag, also set the chain ID.
- Default node settings
- Custom node settings
- Chiado
wardend tx wasm store target/wasm32-unknown-unknown/release/hello_world.wasm \
--from shulgin \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
-y \
--chain-id warden_1337-1
wardend tx wasm store target/wasm32-unknown-unknown/release/hello_world.wasm \
--from my-key-name \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
-y \
--chain-id chain_123-1
wardend tx wasm store target/wasm32-unknown-unknown/release/hello_world.wasm \
--from my-key-name \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
-y \
--chain-id chain_123-1 \
--node https://rpc.chiado.wardenprotocol.org:443
The transaction should be successful without any errors.
7. Get the code ID
Get the code ID that identifies your Wasm code:
- Local chain
- Chiado
wardend query wasm list-code
wardend query wasm list-code --node https://rpc.chiado.wardenprotocol.org:443
Note down code_id
from the output.
8. Instantiate the contract
You can instantiate the contract by using the command below.
Before you proceed, replace 1
with the actual code ID you retrieved in previous step . Specify your key name in the --from
flag and the chain ID. Also note that you can either define an admin or pass --no-admin
to make it immutable, like in this example.
- Default node settings
- Custom node settings
- Chiado
wardend tx wasm instantiate 1 '{}' \
--from shulgin \
--label "Hello World" \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
--no-admin \
-y \
--chain-id warden_1337-1
wardend tx wasm instantiate 1 '{}' \
--from my-key-name \
--label "Hello World" \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
--no-admin \
-y \
--chain-id chain_123-1
wardend tx wasm instantiate 1 '{}' \
--from my-key-name \
--label "Hello World" \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
--no-admin \
-y \
--chain-id chain_123-1 \
--node https://rpc.chiado.wardenprotocol.org:443
9. Get the contract address
To get the contract address, run the following command. Replace 1
with the actual code ID:
wardend query wasm list-contract-by-code 1
Note down the contract address.
10. Execute the contract
Use the command below to exectute your contract. Replace my-contract-address
with your contract address. Specify your key name in the --from
flag and the chain ID.
- Default node settings
- Custom node settings
- Chiado
wardend tx wasm execute my-contract-address '{"say_hello":{}}' \
--from shulgin \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
-y \
--chain-id warden_1337-1
wardend tx wasm execute my-contract-address '{"say_hello":{}}' \
--from my-key-name \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
-y \
--chain-id chain_123-1
wardend tx wasm execute my-contract-address '{"say_hello":{}}' \
--from my-key-name \
--gas auto \
--gas-adjustment 1.3 \
--gas-prices 100000000000award \
-y \
--chain-id chain_123-1 \
--node https://rpc.chiado.wardenprotocol.org:443
11. Query the contract
You can query your contract with the following command. Replace my-contract-address
with your contract address.
wardend query wasm contract-state smart my-contract-address '{"get_greeting":{}}'
In the output, you should see this: data: Hello, World!
If you encounter any issues, please reach out to us in Discord or Twitter.
Happy coding! 🚀
Next steps
After deploying a basic WASM smart contract, you can deploy a cross-chain app using GMP.