← Protocols
CosmWasm
Dev Tooling·Cosmos

CosmWasm

01Description

CosmWasm is a multi-chain WebAssembly smart-contract platform for the Cosmos ecosystem. Contracts are written in Rust, compiled to deterministic Wasm, and run on any Cosmos SDK chain that enables the `x/wasm` module (Neutron, Osmosis, Juno, Archway, Stargaze, Injective, Sei, etc.). Client-side, `@cosmjs/cosmwasm-stargate` provides `CosmWasmClient` (read-only) and `SigningCosmWasmClient` (signing) for store / instantiate / execute / query.

02Best for
  • 01Rust smart contracts deployed across multiple Cosmos chains
  • 02permissionless contract deployment on Neutron / Osmosis / Juno
  • 03cross-chain contract logic via IBC + CosmWasm
  • 04DAO frameworks (DAO DAO), lending (Mars), and AMMs (Astroport)
  • 05migrating from Solidity to a Rust + actor-model contract architecture
03Install
  • pnpm add @cosmjs/cosmwasm-stargate @cosmjs/proto-signing
04Environment variables
VariableScopeDescription
NEXT_PUBLIC_COSMWASM_RPC_URLClientCometBFT RPC URL of the wasm-enabled chain (e.g. https://rpc-kralum.neutron-1.neutron.org).
NEXT_PUBLIC_COSMWASM_CHAIN_IDClientChain ID, e.g. `neutron-1`, `osmosis-1`, `juno-1`, `phoenix-1`.
NEXT_PUBLIC_COSMWASM_BECH32_PREFIXClientBech32 prefix for the chain (`neutron`, `osmo`, `juno`, `terra`, …).
05Prompt snippet
Use `@cosmjs/cosmwasm-stargate`. Read-only: `const client = await CosmWasmClient.connect(rpcUrl); const result = await client.queryContractSmart(contractAddress, { get_count: {} });`. For signing, connect Keplr's offline signer and instantiate `SigningCosmWasmClient.connectWithSigner(rpcUrl, signer, { gasPrice: GasPrice.fromString('0.025untrn') })`. Execute: `await client.execute(sender, contractAddress, { increment: {} }, 'auto')`. Upload + instantiate: `const { codeId } = await client.upload(sender, wasmBytes, 'auto'); const { contractAddress } = await client.instantiate(sender, codeId, { count: 0 }, 'my-counter', 'auto', { admin: sender })`. Contract messages are JSON in `{ ExecuteMsg, QueryMsg }` schemas — generate TS types from the Rust schema with `cosmwasm-ts-codegen` to avoid string-typed messages.
06Gotchas
  • CosmWasm contracts use the actor model: a contract cannot synchronously call another contract — it returns `SubMsg::reply_on_success(...)` and the parent receives a callback in the `reply` entry point. Porting Solidity reentrant logic 1:1 leads to broken ordering and missed reply IDs.
  • Each chain pins a CosmWasm version (`v1.5`, `v2.0`, `v2.2`) and a Wasm gas table — a contract compiled for one version may fail to upload to another with `wasm code rejected: invalid module`. Match `cosmwasm-std` minor version to the target chain's module version.
  • Storage is keyed bytes via `cw-storage-plus` (`Item`, `Map`, `IndexedMap`). There is no automatic struct ABI — you serialize with `cw_serde` (`serde_json` JSON for messages, `bincode` / borsh elsewhere). Mixing serializers across versions silently corrupts state.
  • Permissioned vs permissionless deploy: Osmosis / Cosmos Hub gate code uploads behind governance proposals; Neutron, Juno, Stargaze, Archway are permissionless. A `MsgStoreCode` that succeeds locally on simulation can still revert with `unauthorized` on permissioned mainnets — check the `x/wasm` params.
  • Migrations require `admin` field set at instantiation; once `admin: None` the contract is immutable. Many tutorials omit `admin` and accidentally produce non-upgradeable contracts.
  • Gas accounting in CosmWasm is multiplied by a `gas multiplier` (typically 100x or 140x) over Cosmos SDK gas — a query that costs 1M Cosmos gas might cost 100M CosmWasm gas; under-budgeted txs fail with `out of gas` despite seemingly cheap operations.
  • IBC + CosmWasm requires the contract to declare an IBC entry point (`ibc_channel_open`, `ibc_packet_receive`); plain executes cannot send IBC packets. The `cw-ibc` examples set up channel handshakes — copying them carelessly leaves channels in a `INIT` state forever.
07Alternatives