Skip to main content

Smart contracts

This document explains how to perform tasks related to working with smart contracts with Fluid.js.

Upload code

You will first need a compiled WASM smart contract's binary to upload.


_36
import { LCDClient, MsgStoreCode, MnemonicKey, isTxError } from '@terra-money/terra.js';
_36
import * as fs from 'fs';
_36
_36
// test1 key from localterra accounts
_36
const mk = new MnemonicKey({
_36
mnemonic: 'notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius'
_36
})
_36
_36
// connect to localterra
_36
const terra = new LCDClient({
_36
URL: 'http://localhost:1317',
_36
chainID: 'localterra'
_36
});
_36
_36
const wallet = terra.wallet(mk);
_36
_36
const storeCode = new MsgStoreCode(
_36
wallet.key.accAddress,
_36
fs.readFileSync('contract.wasm').toString('base64')
_36
);
_36
const storeCodeTx = await wallet.createAndSignTx({
_36
msgs: [storeCode],
_36
});
_36
const storeCodeTxResult = await terra.tx.broadcast(storeCodeTx);
_36
_36
console.log(storeCodeTxResult);
_36
_36
if (isTxError(storeCodeTxResult)) {
_36
throw new Error(
_36
`store code failed. code: ${storeCodeTxResult.code}, codespace: ${storeCodeTxResult.codespace}, raw_log: ${storeCodeTxResult.raw_log}`
_36
);
_36
}
_36
_36
const {
_36
store_code: { code_id },
_36
} = storeCodeTxResult.logs[0].eventsByType;

Create a contract

For Fluid smart contracts, there is a distinction between uploading contract code and creating a contract. This allows multiple contracts to share the same 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 for the contract.

To create or instantiate a smart contract, you must first know the code ID of an uploaded code. You will reference it 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/terra.js';
_29
_29
_29
const instantiate = new MsgInstantiateContract(
_29
wallet.key.accAddress,
_29
+code_id[0], // code ID
_29
{
_29
count: 0,
_29
}, // InitMsg
_29
{ uluna: 10000000, ukrw: 1000000 }, // init coins
_29
false // migratable
_29
);
_29
_29
const instantiateTx = await wallet.createAndSignTx({
_29
msgs: [instantiate],
_29
});
_29
const instantiateTxResult = await terra.tx.broadcast(instantiateTx);
_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 should provide any 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. The schema thus provides an analog to Ethereum contracts' ABI.


_14
import { MsgExecuteContract } from '@terra-money/terra.js';
_14
_14
const execute = new MsgExecuteContract(
_14
wallet.key.accAddress, // sender
_14
contract_address[0], // contract account address
_14
{ ...executeMsg }, // handle msg
_14
{ uluna: 100000 } // coins
_14
);
_14
_14
const executeTx = await wallet.createAndSignTx({
_14
msgs: [execute]
_14
});
_14
_14
const executeTxResult = await terra.tx.broadcast(executeTx);

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 -- it is a readonly operation. Therefore, a 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
);