Initia (Closed Testnet)
  • Reminder
    • ⛔Confidentiality Disclaimer
  • WELCOME TO CLOSED TESTNET
    • Welcome to Closed Testnet
  • About Initia
    • What is the Initia Platform?
      • Architecture
        • Layer 1
        • Layer 2
      • Aligning Initia (coming soon!)
    • InitiaDEX
    • Enshrined Liquidity and Staking
  • Developers
    • Initiad
      • Download Initiad
      • Using Initiad
    • Get INIT token
    • Build your own Minitia
      • Simple Minitia Setup
      • Connect Minitia to L1
        • OPinit Stack
          • OPinit Module
          • OPinit Bots
        • Relayer
          • Fetching Oracle Prices
    • Virtual Machines
      • MoveVM
        • Interact with CLI
      • WasmVM
    • Contracts
      • Move Contracts
      • CosmWasm Contracts
      • EVM Contracts (Coming Soon)
    • Oracles
  • Initia Developer Tutorials
    • 1. Create account
    • 2. Send Move coin
    • 3. Interchain Message
    • 4. Create your own Move coin
    • 5. Create your own Move NFT
    • 6. Build and Publish Contracts
      • Move Module
      • CosmWasm Contract
  • Core Applications
    • Core Applications
      • Wallet
      • Initia App
      • Usernames
      • Initia Scan
  • Node Operators
    • Running Initia Node
      • Prerequisites
      • Oracle
      • Boot an Initia Node
      • Connect to Initia Network
      • Cosmovisor Guide
    • Configuring Initia Validator
  • References and Tools
    • Move Language
    • Rust Language (CosmWasm)
    • Closed Testnet Chain Information
    • Chain Parameters
    • Initia.js
    • API Docs
    • API Docs (minimove)
    • API Docs (miniwasm)
    • Whitelisted Tokens and Pairs
Powered by GitBook
On this page
  • Step 0: Clone cw-contracts
  • Step 1: Compile a contract
  • Step 1-1: Compile with rust-optimizer (Advanced)
  • Step 2: Store a contract
  • Step 3: Instantiate a contract
  • Step 4: Interact with a contract
  1. Initia Developer Tutorials
  2. 6. Build and Publish Contracts

CosmWasm Contract

This tutorial covers building, publishing and interacting with a CosmWasm contract on a Wasm Minitia.

PreviousMove ModuleNextCore Applications

Last updated 1 year ago

Note: CosmWasm contracts are only supported on Minitias that are using WasmVM.

Step 0: Clone cw-contracts

In this tutorial, we will use nameservice module of cw-contracts repository.

git clone https://github.com/deus-labs/cw-contracts.git
cd cw-contracts
git checkout main
cd contracts/nameservice

Step 1: Compile a contract

By using the command below, a Wasm binary to be published on Wasm Minitia is compiled.

RUSTFLAGS='-C link-arg=-s' cargo wasm

When compiling is completed, target/wasm32-unknown-unknown/release/cw_nameservice.wasm file will be generated.

Step 1-1: Compile with rust-optimizer (Advanced)

Docker must be installed in order to use rust-optimizer.

Wasm binary file must be as small as possible in order to reduce gas costs for both the deployment and for every interaction with the deployed contract. The is a tool which can be used to make the binary size as small as possible while ensuring that all contract features are still working.

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

By running the above command, the binary file will be generated within artifacts/cw_nameservice.wasm.


Step 2: Store a contract

Let's store cw_nameservice.wasm contract created in the previous step onto the Minitia.

> minitiad tx wasm store [binary-path] \
  --from test-account \
  --gas auto --gas-adjustment 1.5 \
  --gas-prices [gas-price] \
  --node [rpc-url]:[rpc-port] \
  --chain-id [chain-id]
import { LCDClient, MnemonicKey, MsgStoreCode, Wallet } from '@initia/initia.js';
import * as fs from 'fs';

const path =
  '${path_to_binary}';

async function storeContract() {
  const lcd = new LCDClient('[rest-url]', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic:
      'beauty sniff protect ...',
  });
  const wallet = new Wallet(lcd, key);

  const codeBytes = fs.readFileSync(
    ${path}
  );

  const msgs = [
    new MsgStoreCode(key.accAddress, codeBytes.toString('base64'))
  ];


  // sign tx
  const signedTx = await wallet.createAndSignTx({ msgs });
  // send(broadcast) tx
  lcd.tx.broadcastSync(signedTx).then(res => console.log(res));
  // {
  //   height: 0,
  //   txhash: '162AA29DE237BD060EFEFFA862DBD07ECD1C562EBFDD965AD6C34DF856B53DC2',
  //   raw_log: '[]'
  // }
}

storeContract();

Step 3: Instantiate a contract

In this step, we will instantiate a new contract using the stored code in the previous step.

First, codeId is required in order to instantiate the stored cw_nameservice.wasm contract. codeID can be fetched with the command line below.

> RES=$(minitiad q tx --type=hash [txhash] --node [rpc-url]:[rpc-port] --output json)
CODE_ID=$(echo $RES | jq -r '.events[-1].attributes[1].value') 
echo $CODE_ID
const lcd = new LCDClient('[rest-url]');

lcd.tx
  .txInfo('13F0DE1D8E394F9CCE879AF0DAEFCA3D717E8C97B075B23BB7E799FFC18F0473')
  .then(res =>
    console.log(
      `codeId: ${res.events[res.events.length - 1].attributes[1].value}`
    )
  );

Let's instantiate a new wasm contract using the stored code.

> INIT='{"purchase_price":{"amount":"100","denom":"l2/2588fd87a8e081f6a557f43ff14f05dddf5e34cb27afcefd6eaf81f1daea30d0"},"transfer_price":{"amount":"100","denom":"l2/2588fd87a8e081f6a557f43ff14f05dddf5e34cb27afcefd6eaf81f1daea30d0"}}'

minitiad tx wasm instantiate 1 "$INIT" --label=nameservice --no-admin \
  --from test-account \
  --gas auto --gas-adjustment 1.5 \
  --gas-prices [gas-price] \
  --node [rpc-url]:[rpc-port] \
  --chain-id [chain-id]
import {
  LCDClient,
  MnemonicKey,
  MsgInstantiateContract,
  Wallet,
  Coins,
} from '@initia/initia.js';

async function instantiateContract() {
  const lcd = new LCDClient('[rest-url]', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic:
      'beauty sniff protect ...',
  });
  const wallet = new Wallet(lcd, key);

  const instantiateMsg = {
    purchase_price: {
      amount: '100',
      denom:
        '[denom]',
    },
    transfer_price: {
      amount: '100',
      denom:
        '[denom]',
    },
  };

  const msgs = [
    new MsgInstantiateContract(
      key.accAddress,
      undefined,
      1,
      'nameservice',
      Buffer.from(JSON.stringify(instantiateMsg)).toString('base64'),
      new Coins()
    ),
  ];


  // sign tx
  const signedTx = await wallet.createAndSignTx({ msgs });
  // send(broadcast) tx
  await lcd.tx.broadcastSync(signedTx).then(res => console.log(res));
  // {
  //   height: 0,
  //   txhash: '162AA29DE237BD060EFEFFA862DBD07ECD1C562EBFDD965AD6C34DF856B53DC2',
  //   raw_log: '[]'
  // }
}

instantiateContract();

Step 4: Interact with a contract

We are now ready to interact with the instantiated CosmWasm contract.

Contract address is required in order to interact with the instantiated contract. The contract address can be found by using the below command:

> RES=$(minitiad q tx --type=hash [txhash] --node [rpc-url]:[rpc-port] --output json)
CONTRACT_ADDRESS=$(echo $RES | jq -r '.events[-1].attributes[0].value') 
echo $CONTRACT_ADDRESS
const lcd = new LCDClient('[rest-url]');

lcd.tx
  .txInfo('2C578BF0CD21B98CE89182746B59C3524F3C44A67E4307C8646143F310CD1759')
  .then(res =>
    console.log(
      `contractAddress: ${
        res.events[res.events.length - 1].attributes[0].value
      }`
    )
  );

Execute a contract function

In this example, we will use the register function from the published contract, to register test as a name service domain.

> REGISTER='{"register":{"name":"test"}}'
minitiad tx wasm execute [contract_address] "$REGISTER" --amount 100[denom]  \
  --from test-account \
  --gas auto --gas-adjustment 1.5 \
  --gas-prices [gas-price] \
  --node [rpc-url]:[rpc-port] \
  --chain-id [chain-id]
import {
  LCDClient,
  MnemonicKey,
  MsgExecuteContract,
  Wallet,
} from '@initia/initia.js';

async function executeContract() {
  const lcd = new LCDClient('[rest-url]', {
    gasPrices: '0.15uinit',
    gasAdjustment: '1.5',
  });

  const key = new MnemonicKey({
    mnemonic: 'beauty sniff protect ...',
  });
  const wallet = new Wallet(lcd, key);

  const executeMsg = { register: { name: 'test' } };
  const msgs = [
    new MsgExecuteContract(
      key.accAddress,
      '[contract address]',
      Buffer.from(JSON.stringify(executeMsg)).toString('base64'),
      '100[denom]'
    ),
  ];

  // sign tx
  const signedTx = await wallet.createAndSignTx({ msgs });
  // send(broadcast) tx
  await lcd.tx.broadcastSync(signedTx).then(res => console.log(res));
  // {
  //   height: 0,
  //   txhash: '162AA29DE237BD060EFEFFA862DBD07ECD1C562EBFDD965AD6C34DF856B53DC2',
  //   raw_log: '[]'
  // }
}

executeContract();

Query Results

Once the register function is successfully executed, we can confirm the name that was registered through a contract query.

> NAME_QUERY='{"resolve_record": {"name": "test"}}'
minitiad query wasm contract-state smart [contract_address] "$NAME_QUERY" --node [rpc-url]:[rpc-port]
# data:
#   address: init150748hf2e3mjed5w0xqkp9wn8xs55nnzneg452
const lcd = new LCDClient('[rest-url]');

lcd.wasm
  .smartContractState(
    '[contract_address]',
    Buffer.from('{"resolve_record": {"name": "test"}}').toString('base64')
  )
  .then(res => console.log(res));

rust-optimizer