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.
- 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
- pnpm add @cosmjs/cosmwasm-stargate @cosmjs/proto-signing
| Variable | Scope | Description |
|---|---|---|
| NEXT_PUBLIC_COSMWASM_RPC_URL | Client | CometBFT RPC URL of the wasm-enabled chain (e.g. https://rpc-kralum.neutron-1.neutron.org). |
| NEXT_PUBLIC_COSMWASM_CHAIN_ID | Client | Chain ID, e.g. `neutron-1`, `osmosis-1`, `juno-1`, `phoenix-1`. |
| NEXT_PUBLIC_COSMWASM_BECH32_PREFIX | Client | Bech32 prefix for the chain (`neutron`, `osmo`, `juno`, `terra`, …). |
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.
- ⚑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.