Smart contracts
This document explains how to perform tasks related to working with smart contracts using Feather.js.
Upload code
You will first need a compiled WASM smart contract's binary to upload.
_48import {_48 LCDClient,_48 MsgStoreCode,_48 MnemonicKey,_48 isTxError,_48} from '@terra-money/feather.js';_48import * as fs from 'fs';_48_48// test1 key from localterra accounts_48const mk = new MnemonicKey({_48 mnemonic:_48 'notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius',_48});_48_48// connect to localterra_48const terra = new LCDClient({_48 localterra: {_48 lcd: 'http://localhost:1317',_48 chainID: 'localterra',_48 gasAdjustment: 1.75,_48 gasPrices: { uluna: 0.015 },_48 prefix: 'terra', // bech32 prefix_48 },_48});_48_48const wallet = terra.wallet(mk);_48_48const storeCode = new MsgStoreCode(_48 wallet.key.accAddress('terra'),_48 fs.readFileSync('contract.wasm').toString('base64'),_48);_48const storeCodeTx = await wallet.createAndSignTx({_48 msgs: [storeCode],_48 chainID: 'pisco-1',_48});_48const storeCodeTxResult = await terra.tx.broadcast(storeCodeTx, 'pisco-1');_48_48console.log(storeCodeTxResult);_48_48if (isTxError(storeCodeTxResult)) {_48 throw new Error(_48 `store code failed. code: ${storeCodeTxResult.code}, codespace: ${storeCodeTxResult.codespace}, raw_log: ${storeCodeTxResult.raw_log}`,_48 );_48}_48_48const {_48 store_code: { code_id },_48} = storeCodeTxResult.logs[0].eventsByType;
Create a contract
For Terra smart contracts, there is a distinction between uploading contract code and instantiating a contract. This separation allows multiple contracts to share the same uploaded code if there are only minor variations in their logic which can be configured at contract creation. This configuration is passed in an InitMsg
and provides the initial state of the contract.
To create or instantiate a smart contract, you must first know the code_id
of an uploaded code. You will reference this code_id
in a MsgInstantiateContract
alongside the InitMsg
to create the contract. Upon successful creation, your contract will be located at an address that you specify.
_29import { MsgInstantiateContract } from '@terra-money/feather.js';_29_29const instantiate = new MsgInstantiateContract(_29 wallet.key.accAddress('terra'),_29 code_id[0], // code ID_29 {_29 count: 0,_29 }, // InitMsg_29 { uluna: 10000000 }, // init coins_29 false, // migratable_29);_29_29const instantiateTx = await wallet.createAndSignTx({_29 msgs: [instantiate],_29 chainID: 'pisco-1',_29});_29const instantiateTxResult = await terra.tx.broadcast(instantiateTx, 'pisco-1');_29_29console.log(instantiateTxResult);_29_29if (isTxError(instantiateTxResult)) {_29 throw new Error(_29 `instantiate failed. code: ${instantiateTxResult.code}, codespace: ${instantiateTxResult.codespace}, raw_log: ${instantiateTxResult.raw_log}`,_29 );_29}_29_29const {_29 instantiate_contract: { contract_address },_29} = instantiateTxResult.logs[0].eventsByType;
Execute a contract
Smart contracts respond to JSON messages called HandleMsg
which can exist as different types. The smart contract writer must provide end-users of the smart contract with the expected format of all the varieties of HandleMsg
the contract is supposed to understand, in the form of a JSON schema. This schema is analogous to Ethereum contracts' ABI.
_15import { MsgExecuteContract } from '@terra-money/feather.js';_15_15const execute = new MsgExecuteContract(_15 wallet.key.accAddress('terra'), // sender_15 contract_address[0], // contract account address_15 { ...executeMsg }, // handle msg_15 { uluna: 100000 }, // coins_15);_15_15const executeTx = await wallet.createAndSignTx({_15 msgs: [execute],_15 chainID: 'pisco-1',_15});_15_15const executeTxResult = await terra.tx.broadcast(executeTx, 'pisco-1');
Query data from a contract
A contract can define a query handler, which understands requests for data specified in a JSON message called a QueryMsg
. Unlike the message handler, the query handler cannot modify the contract's or blockchain's state. Queries are read-only operations. Therefore, querying data from a contract does not use a message and transaction, but works directly through the LCDClient
API.
_4const result = await terra.wasm.contractQuery(_4 contract_address[0],_4 { query: { queryMsgArguments } }, // query msg_4);