var img = document.createElement('img'); img.src = "https://terradocs.matomo.cloud//piwik.php?idsite=1&rec=1&url=https://docs.terra.money" + location.pathname; img.style = "border:0"; img.alt = "tracker"; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(img,s);
Skip to main content

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.


_48
import {
_48
LCDClient,
_48
MsgStoreCode,
_48
MnemonicKey,
_48
isTxError,
_48
} from '@terra-money/feather.js';
_48
import * as fs from 'fs';
_48
_48
// test1 key from localterra accounts
_48
const 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
_48
const 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
_48
const wallet = terra.wallet(mk);
_48
_48
const storeCode = new MsgStoreCode(
_48
wallet.key.accAddress('terra'),
_48
fs.readFileSync('contract.wasm').toString('base64'),
_48
);
_48
const storeCodeTx = await wallet.createAndSignTx({
_48
msgs: [storeCode],
_48
chainID: 'pisco-1',
_48
});
_48
const storeCodeTxResult = await terra.tx.broadcast(storeCodeTx, 'pisco-1');
_48
_48
console.log(storeCodeTxResult);
_48
_48
if (isTxError(storeCodeTxResult)) {
_48
throw new Error(
_48
`store code failed. code: ${storeCodeTxResult.code}, codespace: ${storeCodeTxResult.codespace}, raw_log: ${storeCodeTxResult.raw_log}`,
_48
);
_48
}
_48
_48
const {
_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.


_29
import { MsgInstantiateContract } from '@terra-money/feather.js';
_29
_29
const 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
_29
const instantiateTx = await wallet.createAndSignTx({
_29
msgs: [instantiate],
_29
chainID: 'pisco-1',
_29
});
_29
const instantiateTxResult = await terra.tx.broadcast(instantiateTx, 'pisco-1');
_29
_29
console.log(instantiateTxResult);
_29
_29
if (isTxError(instantiateTxResult)) {
_29
throw new Error(
_29
`instantiate failed. code: ${instantiateTxResult.code}, codespace: ${instantiateTxResult.codespace}, raw_log: ${instantiateTxResult.raw_log}`,
_29
);
_29
}
_29
_29
const {
_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.


_15
import { MsgExecuteContract } from '@terra-money/feather.js';
_15
_15
const 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
_15
const executeTx = await wallet.createAndSignTx({
_15
msgs: [execute],
_15
chainID: 'pisco-1',
_15
});
_15
_15
const 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.


_4
const result = await terra.wasm.contractQuery(
_4
contract_address[0],
_4
{ query: { queryMsgArguments } }, // query msg
_4
);