Convert Figma logo to code with AI

CosmWasm logocosmwasm

Framework for building smart contracts in Wasm for the Cosmos SDK

1,052
328
1,052
73

Top Related Projects

Substrate: The platform for blockchain innovators

:chains: A Framework for Building High Value Public Blockchains :sparkles:

15,696

Hyperledger Fabric is an enterprise-grade permissioned distributed ledger framework for developing solutions and applications. Its modular and versatile design satisfies a broad range of industry use cases. It offers a unique approach to consensus that enables performance at scale while preserving privacy.

Go implementation of the Ethereum protocol

Reference client for NEAR Protocol

13,044

Web-Scale Blockchain for fast, secure, scalable, decentralized apps and marketplaces.

Quick Overview

CosmWasm is a smart contracting platform built for the Cosmos ecosystem. It allows developers to write multi-chain smart contracts using WebAssembly (Wasm) and provides a secure and efficient environment for executing these contracts across various Cosmos-based blockchains.

Pros

  • Cross-chain compatibility: Contracts can be deployed on any Cosmos-based blockchain that supports CosmWasm
  • Security: Utilizes Rust's strong type system and memory safety features
  • Efficiency: WebAssembly execution is fast and has low overhead
  • Interoperability: Easy integration with existing Cosmos ecosystem tools and services

Cons

  • Learning curve: Requires knowledge of Rust and WebAssembly
  • Limited ecosystem: Smaller developer community compared to Ethereum or other major smart contract platforms
  • Complexity: Setting up a development environment can be challenging for beginners
  • Nascent technology: Still evolving, which may lead to breaking changes in future updates

Code Examples

  1. Creating a simple CosmWasm contract:
use cosmwasm_std::{
    entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};

#[entry_point]
pub fn instantiate(
    _deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    _msg: InstantiateMsg,
) -> StdResult<Response> {
    Ok(Response::default())
}

#[entry_point]
pub fn execute(
    _deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    _msg: ExecuteMsg,
) -> StdResult<Response> {
    Ok(Response::default())
}

#[entry_point]
pub fn query(_deps: Deps, _env: Env, _msg: QueryMsg) -> StdResult<Binary> {
    Ok(Binary::default())
}
  1. Implementing a simple query:
use cosmwasm_std::{to_binary, Deps, StdResult};

#[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<CountResponse> {
    let state = STATE.load(deps.storage)?;
    Ok(CountResponse { count: state.count })
}
  1. Executing a state change:
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, StdResult};

#[entry_point]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: ExecuteMsg,
) -> StdResult<Response> {
    match msg {
        ExecuteMsg::Increment {} => try_increment(deps),
    }
}

pub fn try_increment(deps: DepsMut) -> StdResult<Response> {
    STATE.update(deps.storage, |mut state| -> StdResult<_> {
        state.count += 1;
        Ok(state)
    })?;

    Ok(Response::new().add_attribute("method", "try_increment"))
}

Getting Started

To start developing with CosmWasm:

  1. Install Rust and cargo-generate:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    cargo install cargo-generate --features vendored-openssl
    
  2. Create a new CosmWasm project:

    cargo generate --git https://github.com/CosmWasm/cw-template.git --name my-first-contract
    cd my-first-contract
    
  3. Build and test your contract:

    cargo wasm
    cargo test
    
  4. Deploy your contract using a CosmWasm-enabled blockchain's CLI or SDK.

Competitor Comparisons

Substrate: The platform for blockchain innovators

Pros of Substrate

  • More flexible and customizable blockchain framework
  • Supports multiple programming languages for runtime development
  • Larger ecosystem and community support

Cons of Substrate

  • Steeper learning curve due to its complexity
  • Requires more resources for development and deployment

Code Comparison

Substrate (Rust):

#[pallet::call]
impl<T: Config> Pallet<T> {
    #[pallet::weight(10_000)]
    pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
        let who = ensure_signed(origin)?;
        // Function logic here
        Ok(())
    }
}

CosmWasm (Rust):

pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::DoSomething { value } => do_something(deps, env, info, value),
    }
}

Both projects use Rust, but Substrate offers a more complex and feature-rich framework for building custom blockchains, while CosmWasm focuses on smart contract development within the Cosmos ecosystem. Substrate provides greater flexibility and language support, but comes with a steeper learning curve. CosmWasm offers a simpler approach to smart contract development, but is limited to the Cosmos ecosystem.

:chains: A Framework for Building High Value Public Blockchains :sparkles:

Pros of cosmos-sdk

  • More comprehensive framework for building blockchain applications
  • Broader ecosystem support and integration with Cosmos Network
  • Extensive documentation and community resources

Cons of cosmos-sdk

  • Steeper learning curve due to its complexity
  • Less flexibility for custom smart contract development
  • Heavier codebase, potentially leading to longer development times

Code Comparison

cosmos-sdk:

func (app *SimApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
    return app.mm.BeginBlock(ctx, req)
}

cosmwasm:

pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    // Contract logic here
}

The cosmos-sdk example shows a typical BeginBlocker function in Go, while the cosmwasm example demonstrates a smart contract execution function in Rust. cosmwasm focuses on smart contract development, offering a more streamlined approach for contract-specific logic. cosmos-sdk provides a broader framework for building entire blockchain applications, including aspects like governance and staking.

15,696

Hyperledger Fabric is an enterprise-grade permissioned distributed ledger framework for developing solutions and applications. Its modular and versatile design satisfies a broad range of industry use cases. It offers a unique approach to consensus that enables performance at scale while preserving privacy.

Pros of Fabric

  • Mature enterprise-grade blockchain platform with extensive documentation
  • Supports multiple programming languages for smart contract development
  • Flexible architecture allowing for modular components and customization

Cons of Fabric

  • Steeper learning curve and more complex setup process
  • Higher resource requirements for deployment and operation
  • Less focus on interoperability with other blockchain networks

Code Comparison

Fabric chaincode (Go):

func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, value int) error {
    asset := Asset{ID: id, Value: value}
    assetJSON, err := json.Marshal(asset)
    if err != nil {
        return err
    }
    return ctx.GetStub().PutState(id, assetJSON)
}

CosmWasm contract (Rust):

pub fn execute_create_asset(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    id: String,
    value: u64,
) -> Result<Response, ContractError> {
    let asset = Asset { id, value };
    ASSETS.save(deps.storage, &asset.id, &asset)?;
    Ok(Response::new().add_attribute("action", "create_asset"))
}

Both examples demonstrate creating an asset, but Fabric uses Go and interacts with the chaincode stub, while CosmWasm uses Rust and leverages the CosmWasm SDK for state management.

Go implementation of the Ethereum protocol

Pros of go-ethereum

  • Mature ecosystem with extensive tooling and developer resources
  • Highly scalable and battle-tested in production environments
  • Supports a wide range of smart contract functionalities

Cons of go-ethereum

  • Higher gas fees and slower transaction times during network congestion
  • More complex development process for smart contracts
  • Limited interoperability with other blockchain networks

Code Comparison

go-ethereum (Solidity):

pragma solidity ^0.8.0;

contract SimpleStorage {
    uint256 private storedData;

    function set(uint256 x) public {
        storedData = x;
    }

    function get() public view returns (uint256) {
        return storedData;
    }
}

CosmWasm (Rust):

use cosmwasm_std::{entry_point, Deps, DepsMut, Env, MessageInfo, Response, StdResult};

#[entry_point]
pub fn instantiate(deps: DepsMut, _env: Env, _info: MessageInfo, msg: InstantiateMsg) -> StdResult<Response> {
    deps.storage.set(b"count", &msg.count.to_be_bytes());
    Ok(Response::default())
}

The go-ethereum example shows a simple Solidity contract, while the CosmWasm example demonstrates a Rust-based smart contract entry point. CosmWasm offers a more familiar development experience for Rust developers and provides better type safety and memory management.

Reference client for NEAR Protocol

Pros of nearcore

  • Implements a complete blockchain protocol, offering a full-stack solution
  • Written in Rust, providing strong performance and safety guarantees
  • Supports sharding for improved scalability

Cons of nearcore

  • Larger codebase, potentially more complex to understand and contribute to
  • Specific to the NEAR protocol, less flexible for other blockchain ecosystems
  • Steeper learning curve for developers new to blockchain development

Code comparison

nearcore (Rust):

pub fn process_block(
    &mut self,
    block: &Block,
    provenance: Provenance,
    challenges: &mut Vec<ChallengeBody>,
    on_challenge: Option<Box<dyn FnMut(ChallengeBody)>>,
) -> Result<(), Error> {
    // Block processing logic
}

cosmwasm (Rust):

pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    // Contract execution logic
}

Key differences

  • nearcore focuses on core blockchain functionality, while cosmwasm specializes in smart contract development
  • cosmwasm is designed to be blockchain-agnostic, whereas nearcore is specific to the NEAR protocol
  • nearcore provides a complete node implementation, while cosmwasm offers a framework for writing smart contracts
13,044

Web-Scale Blockchain for fast, secure, scalable, decentralized apps and marketplaces.

Pros of Solana

  • Higher transaction throughput and lower latency
  • Native support for parallel transaction processing
  • More established ecosystem with larger developer community

Cons of Solana

  • More complex programming model
  • Less flexibility in smart contract customization
  • Higher hardware requirements for validators

Code Comparison

Solana (Rust):

#[program]
pub mod hello_world {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
        Ok(())
    }
}

CosmWasm (Rust):

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    _msg: InstantiateMsg,
) -> StdResult<Response> {
    Ok(Response::default())
}

Both projects use Rust, but Solana's programming model is more tightly integrated with the blockchain's architecture, while CosmWasm provides a more flexible and modular approach to smart contract development. Solana's code tends to be more low-level and performance-oriented, while CosmWasm offers a higher level of abstraction and easier integration with other Cosmos ecosystem projects.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

CosmWasm

CircleCI

WebAssembly Smart Contracts for the Cosmos SDK.

Packages

The following packages are maintained here:

CrateUsageDownloadDocsCoverage
cosmwasm-cryptoInternal onlycosmwasm-crypto on crates.ioDocsCoverage
cosmwasm-deriveInternal onlycosmwasm-derive on crates.ioDocsCoverage
cosmwasm-schemaContract developmentcosmwasm-schema on crates.ioDocsCoverage
cosmwasm-coreInternal onlycosmwasm-core on crates.ioDocsCoverage
cosmwasm-stdContract developmentcosmwasm-std on crates.ioDocsCoverage
cosmwasm-vmHost environmentscosmwasm-vm on crates.ioDocsCoverage
cosmwasm-checkContract developmentcosmwasm-check on crates.iocosmwasm-check -hN/A

cosmwasm-storage is no longer maintained and has been dropped in favor of cw-storage-plus.

Overview

To get that contract to interact with a system needs many moving parts. To get oriented, here is a list of the various components of the CosmWasm ecosystem:

Standard library:

This code is compiled into Wasm bytecode as part of the smart contract.

  • cosmwasm-std - A crate in this workspace. Provides the bindings and all imports needed to build a smart contract.
  • cw-storage-plus - A crate which provides convenience helpers for interacting with storage with powerful types supporting composite primary keys, secondary indexes, automatic snapshotting, and more. This is used in most modern contracts.

Building contracts:

  • cosmwasm-template - A starter-pack to get you quickly building your custom contract compatible with the cosmwasm system.

  • cosmwasm-plus - Some sample contracts for use and inspiration. These provide usable primitives and interfaces for many use cases, such as fungible tokens, NFTs, multisigs, governance votes, staking derivatives, and more. Look in packages for docs on the various standard interfaces, and contracts for the implementations. Please submit your contract or interface via PR.

  • rust-optimizer - A docker image and scripts to take your Rust code and produce the smallest possible Wasm output, deterministically. This is designed both for preparing contracts for deployment as well as validating that a given deployed contract is based on some given source code, allowing a similar contract verification algorithm as Etherscan.

    Building locally instead of using the docker image can leak some information about the directory structure of your system and makes the build non-reproducible.

  • serde-json-wasm - A custom json library, forked from serde-json-core. This provides an interface similar to serde-json, but without any floating-point instructions (non-deterministic) and producing builds around 40% of the code size.

Executing contracts:

  • cosmwasm-vm - A crate in this workspace. Uses the wasmer engine to execute a given smart contract. Also contains code for gas metering, storing, and caching wasm artifacts.
  • wasmvm - High-level go bindings to all the power inside cosmwasm-vm. Easily allows you to upload, instantiate and execute contracts, making use of all the optimizations and caching available inside cosmwasm-vm.
  • wasmd - A basic Cosmos SDK app to host WebAssembly smart contracts. It can be run as is, or you can import the x/wasm module from it and use it in your blockchain. It is designed to be imported and customized for other blockchains, rather than forked.
  • cosmwasm-check - A CLI tool and a crate in this workspace. Used to verify a Wasm binary is a CosmWasm smart contract suitable for uploading to a blockchain with a given set of capabilities.

Creating a Smart Contract

You can see some examples of contracts under the contracts directory, which you can look at. They are simple and self-contained, primarily meant for testing purposes, but that also makes them easier to understand.

You can also look at cw-plus for examples and inspiration on more production-like contracts and also how we call one contract from another. If you are working on DeFi or Tokens, please look at the cw20, cw721 and/or cw1155 packages that define standard interfaces as analogues to some popular ERC designs. (cw20 is also inspired by erc777).

If you want to get started building your own contract, the simplest way is to go to the cosmwasm-template repository and follow the instructions. This will give you a simple contract along with tests, and a properly configured build environment. From there you can edit the code to add your desired logic and publish it as an independent repo.

We also recommend you review our documentation site which contains a few tutorials to guide you in building your first contracts. You can find past recordings of hackathon / conference workshops and presentations on our YouTube channel, or join our Discord server to ask for help.

Minimum Supported Rust Version (MSRV)

See Minimum Supported Rust Version (MSRV).

API entry points

WebAssembly contracts are basically black boxes. They have no default entry points, and no access to the outside world by default. To make them useful, we need to add a few elements.

If you haven't worked with WebAssembly before, please read an overview on how to create imports and exports in general.

Exports

The required exports provided by the cosmwasm smart contract are:

// signal for 1.0 compatibility
extern "C" fn interface_version_8() -> () {}

// copy memory to/from host, so we can pass in/out Vec<u8>
extern "C" fn allocate(size: usize) -> u32;
extern "C" fn deallocate(pointer: u32);

// creates an initial state of a contract with a configuration send in the argument msg_ptr
extern "C" fn instantiate(env_ptr: u32, info_ptr: u32, msg_ptr: u32) -> u32;

Contracts may also implement one or more of the following to extend their functionality:

// modify the state of the contract
extern "C" fn execute(env_ptr: u32, info_ptr: u32, msg_ptr: u32) -> u32;

// query the state of the contract
extern "C" fn query(env_ptr: u32, msg_ptr: u32) -> u32;

// in-place contract migrations
extern "C" fn migrate(env_ptr: u32, msg_ptr: u32) -> u32;

// support submessage callbacks
extern "C" fn reply(env_ptr: u32, msg_ptr: u32) -> u32;

// expose privileged entry points to Cosmos SDK modules, not external accounts
extern "C" fn sudo(env_ptr: u32, msg_ptr: u32) -> u32;

// and to write an IBC application as a contract, implement these:
extern "C" fn ibc_channel_open(env_ptr: u32, msg_ptr: u32) -> u32;
extern "C" fn ibc_channel_connect(env_ptr: u32, msg_ptr: u32) -> u32;
extern "C" fn ibc_channel_close(env_ptr: u32, msg_ptr: u32) -> u32;
extern "C" fn ibc_packet_receive(env_ptr: u32, msg_ptr: u32) -> u32;
extern "C" fn ibc_packet_ack(env_ptr: u32, msg_ptr: u32) -> u32;
extern "C" fn ibc_packet_timeout(env_ptr: u32, msg_ptr: u32) -> u32;

allocate/deallocate allow the host to manage data within the Wasm VM. If you're using Rust, you can implement them by simply re-exporting them from cosmwasm::exports. instantiate, execute and query must be defined by your contract.

Imports

The imports provided to give the contract access to the environment are:

// This interface will compile into required Wasm imports.
// A complete documentation of those functions is available in the VM that provides them:
// https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta/packages/vm/src/instance.rs#L89-L206
extern "C" {
    fn db_read(key: u32) -> u32;
    fn db_write(key: u32, value: u32);
    fn db_remove(key: u32);

    // scan creates an iterator, which can be read by consecutive next() calls
    #[cfg(feature = "iterator")]
    fn db_scan(start_ptr: u32, end_ptr: u32, order: i32) -> u32;
    #[cfg(feature = "iterator")]
    fn db_next(iterator_id: u32) -> u32;

    fn addr_validate(source_ptr: u32) -> u32;
    fn addr_canonicalize(source_ptr: u32, destination_ptr: u32) -> u32;
    fn addr_humanize(source_ptr: u32, destination_ptr: u32) -> u32;

    /// Verifies message hashes against a signature with a public key, using the
    /// secp256k1 ECDSA parametrization.
    /// Returns 0 on verification success, 1 on verification failure, and values
    /// greater than 1 in case of error.
    fn secp256k1_verify(message_hash_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32;

    fn secp256k1_recover_pubkey(
        message_hash_ptr: u32,
        signature_ptr: u32,
        recovery_param: u32,
    ) -> u64;

    /// Verifies message hashes against a signature with a public key, using the
    /// secp256r1 ECDSA parametrization.
    /// Returns 0 on verification success, 1 on verification failure, and values
    /// greater than 1 in case of error.
    fn secp256r1_verify(message_hash_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32;

    fn secp256r1_recover_pubkey(
      message_hash_ptr: u32,
      signature_ptr: u32,
      recovery_param: u32,
    ) -> u64;

    /// Verifies a message against a signature with a public key, using the
    /// ed25519 EdDSA scheme.
    /// Returns 0 on verification success, 1 on verification failure, and values
    /// greater than 1 in case of error.
    fn ed25519_verify(message_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32;

    /// Verifies a batch of messages against a batch of signatures and public keys, using the
    /// ed25519 EdDSA scheme.
    /// Returns 0 on verification success, 1 on verification failure, and values
    /// greater than 1 in case of error.
    fn ed25519_batch_verify(messages_ptr: u32, signatures_ptr: u32, public_keys_ptr: u32) -> u32;

    /// Writes a debug message (UFT-8 encoded) to the host for debugging purposes.
    /// The host is free to log or process this in any way it considers appropriate.
    /// In production environments it is expected that those messages are discarded.
    fn debug(source_ptr: u32);

    /// Executes a query on the chain (import). Not to be confused with the
    /// query export, which queries the state of the contract.
    fn query_chain(request: u32) -> u32;
}

(from imports.rs)

You could actually implement a WebAssembly module in any language, and as long as you implement these functions, it will be interoperable, given the JSON data passed around is in the proper format.

Note that these u32 pointers refer to Region instances, containing the offset and length of some Wasm memory, to allow for safe access between the caller and the contract:

/// Describes some data allocated in Wasm's linear memory.
/// A pointer to an instance of this can be returned over FFI boundaries.
///
/// This struct is crate internal since the cosmwasm-vm defines the same type independently.
#[repr(C)]
pub struct Region {
    /// The beginning of the region expressed as bytes from the beginning of the linear memory
    pub offset: u32,
    /// The number of bytes available in this region
    pub capacity: u32,
    /// The number of bytes used in this region
    pub length: u32,
}

(from memory.rs)

Implementing the Smart Contract

If you followed the instructions above, you should have a runable smart contract. You may notice that all of the Wasm exports are taken care of by lib.rs, which you shouldn't need to modify. What you need to do is simply look in contract.rs and implement instantiate and execute functions, defining your custom InstantiateMsg and ExecuteMsg structs for parsing your custom message types (as json):

#[entry_point]
pub fn instantiate(
  deps: DepsMut,
  env: Env,
  info: MessageInfo,
  msg: InstantiateMsg,
) -> Result<Response, ContractError> {}

#[entry_point]
pub fn execute(
  deps: DepsMut,
  env: Env,
  info: MessageInfo,
  msg: ExecuteMsg,
) -> Result<Response, ContractError> {}

#[entry_point]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<Binary, ContractError> {}

#[entry_point]
pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {}

The low-level db_read and db_write imports are nicely wrapped for you by a Storage implementation (which can be swapped out between real Wasm code and test code). This gives you a simple way to read and write data to a custom sub-database that this contract can safely write to as it wants. It's up to you to determine which data you want to store here:

/// Storage provides read and write access to a persistent storage.
/// If you only want to provide read access, provide `&Storage`
pub trait Storage {
    /// Returns None when key does not exist.
    /// Returns Some(Vec<u8>) when key exists.
    ///
    /// Note: Support for differentiating between a non-existent key and a key with empty value
    /// is not great yet and might not be possible in all backends. But we're trying to get there.
    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;

    #[cfg(feature = "iterator")]
    /// Allows iteration over a set of key/value pairs, either forwards or backwards.
    ///
    /// The bound `start` is inclusive and `end` is exclusive.
    ///
    /// If `start` is lexicographically greater than or equal to `end`, an empty range is described, no matter of the order.
    fn range<'a>(
        &'a self,
        start: Option<&[u8]>,
        end: Option<&[u8]>,
        order: Order,
    ) -> Box<dyn Iterator<Item = Record> + 'a>;

    fn set(&mut self, key: &[u8], value: &[u8]);

    /// Removes a database entry at `key`.
    ///
    /// The current interface does not allow to differentiate between a key that existed
    /// before and one that didn't exist. See https://github.com/CosmWasm/cosmwasm/issues/290
    fn remove(&mut self, key: &[u8]);
}

(from traits.rs)

Testing the Smart Contract (rust)

For quick unit tests and useful error messages, it is often helpful to compile the code using native build system and then test all code except for the extern "C" functions (which should just be small wrappers around the real logic).

If you have non-trivial logic in the contract, please write tests using rust's standard tooling. If you run cargo test, it will compile into native code using the debug profile, and you get the normal test environment you know and love. Notably, you can add plenty of requirements to [dev-dependencies] in Cargo.toml and they will be available for your testing joy. As long as they are only used in #[cfg(test)] blocks, they will never make it into the (release) Wasm builds and have no overhead on the production artifact.

Note that for tests, you can use the MockStorage implementation which gives a generic in-memory hashtable in order to quickly test your logic. You can see a simple example of how to write a test in our sample contract.

Testing the Smart Contract (wasm)

You may also want to ensure the compiled contract interacts with the environment properly. To do so, you will want to create a canonical release build of the <contract>.wasm file and then write tests with the same VM tooling we will use in production. This is a bit more complicated but we added some tools to help in cosmwasm-vm which can be added as a dev-dependency.

You will need to first compile the contract using cargo wasm, then load this file in the integration tests. Take a look at the sample tests to see how to do this... it is often quite easy to port a unit test to an integration test.

Production Builds

The above build process (cargo wasm) works well to produce wasm output for testing. However, it is quite large, around 1.5 MB likely, and not suitable for posting to the blockchain. Furthermore, it is very helpful if we have reproducible build step so others can prove the on-chain wasm code was generated from the published rust code.

For that, we have a separate repo, rust-optimizer that provides a docker image for building. For more info, look at rust-optimizer README, but the quickstart guide is:

docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/optimizer:0.15.0

It will output a highly size-optimized build as contract.wasm in $CODE. With our example contract, the size went down to 126kB (from 1.6MB from cargo wasm). If we didn't use serde-json, this would be much smaller still...

Benchmarking

You may want to compare how long the contract takes to run inside the Wasm VM compared to in native rust code, especially for computationally intensive code, like hashing or signature verification.

TODO add instructions

Developing

The ultimate auto-updating guide to building this project is the CI configuration in .circleci/config.yml.

For manually building this repo locally during development, here are a few commands. They assume you use a stable Rust version by default and have a nightly toolchain installed as well.

Workspace

# Compile and lint
./devtools/check_workspace.sh

# Run tests
./devtools/test_workspace.sh

Contracts

StepDescriptionCommand
1fast checks, rebuilds lock files./devtools/check_contracts_fast.sh
2medium fast checks./devtools/check_contracts_medium.sh
3slower checks./devtools/check_contracts_full.sh