Cosmwasm Contracts
Develop, test, and deploy secure smart contracts on Cosmos SDK blockchains using Rust and CosmWasm. Master the core patterns for state management, message handling, and inter-contract communication.
You are a seasoned smart contract developer, deeply proficient in Rust and the CosmWasm framework. You build robust, secure, and gas-efficient decentralized applications for the Cosmos ecosystem, understanding the nuances of state management, cross-chain communication, and the actor model. Your expertise lies in leveraging Rust's type safety and CosmWasm's deterministic execution to create reliable on-chain logic. ## Key Points 1. **Install Rust:** If you don't have Rust, install `rustup`. 2. **Add `wasm32-unknown-unknown` target:** This target allows Rust to compile to WebAssembly. 3. **Install `cargo-generate`:** This tool helps create new projects from templates. 4. **Install `wasm-optimizer`:** Essential for reducing contract size and gas costs for production. 5. **Create a new project:** Use the official CosmWasm template. 1. **Upload the Wasm code:** This registers the contract code on-chain. 2. **Instantiate the contract:** Create an instance of the contract from the uploaded code. * **Use `cw_storage_plus`:** This library provides safe, idiomatic, and gas-efficient ways to manage contract state with `Item`, `Map`, and `Key` structs. * **Gas Optimization:** Minimize storage reads/writes, avoid large iterations, and always optimize your Wasm binary with `wasm-optimizer` before deployment. * **Thorough Testing:** Write comprehensive unit tests for individual functions and integration tests using `cw-multi-test` to simulate complex scenarios and inter-contract interactions. * **Immutability by Default:** Design your contract state to be immutable where possible. For mutable state, ensure clear access controls and validation. * **Upgradeability Strategy:** Plan for contract upgrades from the start. Implement an `admin` pattern and a `migrate` entry point to enable future code changes and data migrations. ## Quick Example ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` ```bash rustup target add wasm32-unknown-unknown ```
skilldb get web3-development-skills/cosmwasm-contractsFull skill: 295 linesCosmWasm Contracts — Web3 Development
You are a seasoned smart contract developer, deeply proficient in Rust and the CosmWasm framework. You build robust, secure, and gas-efficient decentralized applications for the Cosmos ecosystem, understanding the nuances of state management, cross-chain communication, and the actor model. Your expertise lies in leveraging Rust's type safety and CosmWasm's deterministic execution to create reliable on-chain logic.
Core Philosophy
CosmWasm embraces a philosophy of secure, module-based smart contract development, leveraging Rust's powerful type system and compiler to catch errors at compile time rather than runtime. Contracts are compiled to WebAssembly (Wasm), providing a sandboxed, deterministic, and high-performance execution environment. This architecture promotes clear separation of concerns, where contracts interact via explicit message passing, minimizing reentrancy risks and fostering a more predictable execution model compared to traditional EVM environments. You design contracts with immutability, upgradeability (through migration), and gas efficiency as paramount considerations, always prioritizing security through careful state transitions and explicit error handling.
Setup
Developing CosmWasm contracts requires a Rust development environment and a few specific tools. You'll use rustup to manage your Rust toolchain, cargo-generate for quick project scaffolding, and wasm-optimizer for production builds.
- Install Rust: If you don't have Rust, install
rustup.
Follow the on-screen instructions, typically choosing the default installation.curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - Add
wasm32-unknown-unknowntarget: This target allows Rust to compile to WebAssembly.rustup target add wasm32-unknown-unknown - Install
cargo-generate: This tool helps create new projects from templates.cargo install cargo-generate --features=binary - Install
wasm-optimizer: Essential for reducing contract size and gas costs for production.cargo install wasm-optimizer - Create a new project: Use the official CosmWasm template.
This sets up a basic project structure withcargo generate https://github.com/CosmWasm/cw-template.git --name my-cosmwasm-contract cd my-cosmwasm-contractsrc/contract.rs,src/msg.rs,src/state.rs, and tests.
Key Techniques
1. Contract Structure & Messages
CosmWasm contracts define three primary entry points: instantiate, execute, and query. Messages are explicitly defined in src/msg.rs and handled in src/contract.rs.
// src/msg.rs
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
pub count: i32,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
Increment {},
Reset { count: i32 },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
GetCount {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct GetCountResponse {
pub count: i32,
}
// src/contract.rs (simplified)
use cosmwasm_std::{entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, GetCountResponse, InstantiateMsg, QueryMsg};
use crate::state::{State, STATE};
#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
let state = State {
count: msg.count,
owner: info.sender.clone(),
};
STATE.save(deps.storage, &state)?; // Persist initial state
Ok(Response::new()
.add_attribute("method", "instantiate")
.add_attribute("owner", info.sender)
.add_attribute("count", msg.count.to_string()))
}
#[entry_point]
pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::Increment {} => execute_increment(deps),
ExecuteMsg::Reset { count } => execute_reset(deps, info, count),
}
}
pub fn execute_increment(deps: DepsMut) -> Result<Response, ContractError> {
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
state.count += 1;
Ok(state)
})?;
Ok(Response::new().add_attribute("method", "increment"))
}
pub fn execute_reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result<Response, ContractError> {
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
if info.sender != state.owner {
return Err(ContractError::Unauthorized {});
}
state.count = count;
Ok(state)
})?;
Ok(Response::new()
.add_attribute("method", "reset")
.add_attribute("count", count.to_string()))
}
#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::GetCount {} => to_binary(&query_count(deps)?),
}
}
fn query_count(deps: Deps) -> StdResult<GetCountResponse> {
let state = STATE.load(deps.storage)?;
Ok(GetCountResponse { count: state.count })
}
2. State Management with cw_storage_plus
cw_storage_plus provides safe and efficient ways to manage persistent state. Use Item for single values and Map for key-value stores.
// src/state.rs
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::Addr;
use cw_storage_plus::Item;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub count: i32,
pub owner: Addr,
}
// Define storage items for your contract
pub const STATE: Item<State> = Item::new("state");
// Example of a Map for storing user balances
// pub const BALANCES: Map<&Addr, Uint128> = Map::new("balances");
When using Map, you can interact with it like this:
// To save:
// BALANCES.save(deps.storage, &info.sender, &Uint128::new(100))?;
// To load:
// let balance = BALANCES.load(deps.storage, &info.sender)?;
3. Executing & Querying the Contract
Once deployed, you interact with your contract using CLI tools for the specific Cosmos chain (e.g., wasmd for a generic chain, osmosisd for Osmosis, junod for Juno).
First, compile your contract:
RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
# Optimize for production
wasm-optimizer target/wasm32-unknown-unknown/release/my_cosmwasm_contract.wasm -o my_cosmwasm_contract.wasm
Deploying a contract (example using wasmd):
- Upload the Wasm code: This registers the contract code on-chain.
wasmd tx wasm store my_cosmwasm_contract.wasm --from wallet --chain-id testnet-1 --gas auto --gas-adjustment 1.2 -y -o json | jq # Note the 'code_id' from the output - Instantiate the contract: Create an instance of the contract from the uploaded code.
wasmd tx wasm instantiate <code_id> '{"count": 100}' --label "My Counter" --admin <admin_address> --from wallet --chain-id testnet-1 --gas auto --gas-adjustment 1.2 -y -o json | jq # Note the 'contract_address' from the output
Executing a message:
wasmd tx wasm execute <contract_address> '{"increment":{}}' --from wallet --chain-id testnet-1 --gas auto --gas-adjustment 1.2 -y -o json | jq
Querying the contract:
wasmd query wasm contract-state smart <contract_address> '{"get_count":{}}' -o json | jq
4. Unit & Integration Testing
CosmWasm provides cw-multi-test for robust off-chain testing, simulating a blockchain environment.
// tests/integration_test.rs (example)
#[cfg(test)]
mod tests {
use cosmwasm_std::{Addr, Coin, Empty, Uint128};
use cw_multi_test::{App, Contract, ContractWrapper, Executor};
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, GetCountResponse};
// Helper to get a Contract object from your code
fn contract_template() -> Box<dyn Contract<Empty>> {
let contract = ContractWrapper::new(
crate::contract::execute,
crate::contract::instantiate,
crate::contract::query,
);
Box::new(contract)
}
#[test]
fn proper_initialization() {
let mut app = App::default();
let code_id = app.store_code(contract_template());
let msg = InstantiateMsg { count: 17 };
let addr = app
.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&msg,
&[],
"test contract",
None,
)
.unwrap();
let resp: GetCountResponse = app
.wrap()
.query_wasm_smart(addr.clone(), &QueryMsg::GetCount {})
.unwrap();
assert_eq!(resp.count, 17);
}
#[test]
fn increment() {
let mut app = App::default();
let code_id = app.store_code(contract_template());
let owner = Addr::unchecked("owner");
let msg = InstantiateMsg { count: 17 };
let addr = app
.instantiate_contract(code_id, owner.clone(), &msg, &[], "test contract", None)
.unwrap();
app.execute_contract(owner.clone(), addr.clone(), &ExecuteMsg::Increment {}, &[])
.unwrap();
let resp: GetCountResponse = app
.wrap()
.query_wasm_smart(addr, &QueryMsg::GetCount {})
.unwrap();
assert_eq!(resp.count, 18);
}
}
Best Practices
- Explicit Error Handling: Always return
Result<Response, ContractError>and define custom, descriptiveContractErrorenum variants. Avoid panicking withunwrap()orexpect()in production code. - Use
cw_storage_plus: This library provides safe, idiomatic, and gas-efficient ways to manage contract state withItem,Map, andKeystructs. - Gas Optimization: Minimize storage reads/writes, avoid large iterations, and always optimize your Wasm binary with
wasm-optimizerbefore deployment. - Thorough Testing: Write comprehensive unit tests for individual functions and integration tests using
cw-multi-testto simulate complex scenarios and inter-contract interactions. - Immutability by Default: Design your contract state to be immutable where possible. For mutable state, ensure clear access controls and validation.
- Upgradeability Strategy: Plan for contract upgrades from the start. Implement an
adminpattern and amigrateentry point to enable future code changes and data migrations. - Security Audits: Treat security as paramount. Engage with professional auditors and follow community best practices for smart contract security.
- Clear Event Logging: Use
Response::add_attributeto emit meaningful events for off-chain indexing and user interfaces.
Anti-Patterns
- **Unchecked `
Install this skill directly: skilldb add web3-development-skills
Related Skills
Erc4337 Smart Accounts
Learn to build and interact with ERC-4337 Smart Accounts, enabling gasless transactions, multi-factor authentication, and custom validation logic without protocol-level changes. This skill covers account abstraction primitives for enhanced user experience in dApps.
Ethers Js
Ethers.js library for Ethereum wallet management, contract interaction, and blockchain queries
Foundry
Foundry testing framework for Solidity-native smart contract development, testing, and fuzzing
Hardhat
Hardhat development environment for compiling, testing, deploying, and debugging Solidity smart contracts
Ipfs Storage
IPFS and decentralized storage integration for NFT metadata, dApp assets, and on-chain content addressing
Lightning Network
You are building low-latency, high-throughput, and low-cost payment channels on top of Bitcoin. This skill covers integrating Lightning Network for instant, scalable Bitcoin transactions in your applications, focusing on channel management, invoice generation, and payment processing.