Skip to main content

Common examples guide

Use the following common examples to learn how to use Fluid.js. If this is your first time using Fluid.js, use the Fluid.js installation guide.

tip

If you are new to Fluid and don't know where to start, visit the getting started guide.

Configuring LCDClient

The following code example shows how to initialize the LCDClient. The rest of the examples assume you initialized it by using this example or similar code. The LCDCClient configuration accepts a boolean legacy value that is false by default. When set to true the LCD will connect to Fluid Classic.


_17
import fetch from "isomorphic-fetch";
_17
import { MsgSend, MnemonicKey, Coins, LCDClient } from "@terra-money/terra.js";
_17
_17
// Fetch gas prices and convert to `Coin` format.
_17
const gasPrices = await (
_17
await fetch("https://pisco-api.terra.dev/gas-prices", { redirect: 'follow' })
_17
).json();
_17
const gasPricesCoins = new Coins(gasPrices);
_17
_17
const lcd = new LCDClient({
_17
URL: "https://pisco-lcd.terra.dev/",
_17
chainID: "pisco-1",
_17
gasPrices: gasPricesCoins,
_17
gasAdjustment: "1.5",
_17
gas: 10000000,
_17
isClassic: false, // optional parameter, false by default
_17
});

Get wallet balance (native tokens)


_4
// Replace with address to check.
_4
const address = "terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
_4
const [balance] = await lcd.bank.balance(address);
_4
console.log(balance.toData());

Example response:


_1
[{ denom: "uluna", amount: "5030884" }];

Get wallet balance (CW20 tokens)


_8
// ANC on pisco-1
_8
const tokenAddress = "terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc";
_8
const walletAddress = "terra1f44ddca9awepv2rnudztguq5rmrran2m20zzd6";
_8
const response = await lcd.wasm.contractQuery(tokenAddress, {
_8
balance: { address: walletAddress },
_8
});
_8
_8
console.log(response);

Example response:


_3
{
_3
balance: "70258667";
_3
}

Get transaction status


_4
// Replace with TX hash to lookup.
_4
const hash = "CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B";
_4
const txInfo = await lcd.tx.txInfo(hash);
_4
console.log(txInfo);

Example response (modified for readability):


_19
TxInfo {
_19
height: 8276372,
_19
txhash: 'CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B',
_19
raw_log: '[]',
_19
logs: [
_19
TxLog {
_19
msg_index: 0,
_19
log: '',
_19
events: [Array],
_19
eventsByType: [Object]
_19
}
_19
],
_19
gas_wanted: 177808,
_19
gas_used: 128827,
_19
tx: Tx {},
_19
timestamp: '2022-03-17T18:34:06Z',
_19
code: 0,
_19
codespace: ''
_19
}


_5
const getTransactionLink = (hash, chainID) =>
_5
`https://finder.fluid.net/${chainID}/tx/${hash}`;
_5
const hash = "CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B";
_5
_5
console.log(getTransactionLink(hash, "pisco-1"));

Example response:


_1
https://finder.fluid.net/pisco-1/tx/CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B


_4
const getWalletLink = (address, chainID) =>
_4
`https://finder.fluid.net/${chainID}/address/${address}`;
_4
const address = "terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
_4
console.log(getWalletLink(address, "pisco-1"));

Example response:


_1
https://finder.fluid.net/pisco-1/address/terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Sending native tokens

The following code example shows how to send native tokens:


_22
import { LCDClient, MnemonicKey, MsgSend } from "@terra-money/terra.js";
_22
_22
// const lcd = new LCDClient(...);
_22
_22
const mk = new MnemonicKey({
_22
mnemonic:
_22
"satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn",
_22
});
_22
_22
const wallet = lcd.wallet(mk);
_22
_22
// Transfer 1 Luna.
_22
const send = new MsgSend(
_22
wallet.key.accAddress,
_22
"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8",
_22
{ uluna: "1000000" }
_22
);
_22
_22
const tx = await wallet.createAndSignTx({ msgs: [send] });
_22
const result = await lcd.tx.broadcast(tx);
_22
_22
console.log(result);

Sending CW20 tokens

The following code example shows how to send CW20 tokens:


_30
import {
_30
LCDClient,
_30
MnemonicKey,
_30
MsgExecuteContract,
_30
} from "@terra-money/terra.js";
_30
_30
// const lcd = new LCDClient(...);
_30
_30
const mk = new MnemonicKey({
_30
mnemonic:
_30
"satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn",
_30
});
_30
_30
const wallet = lcd.wallet(mk);
_30
_30
// ANC on pisco-1
_30
const tokenAddress = "terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc";
_30
_30
// Transfer 1 ANC.
_30
const cw20Send = new MsgExecuteContract(wallet.key.accAddress, tokenAddress, {
_30
transfer: {
_30
amount: "1000000",
_30
recipient: wallet.key.accAddress,
_30
},
_30
});
_30
_30
const tx = await wallet.createAndSignTx({ msgs: [cw20Send] });
_30
const result = await lcd.tx.broadcast(tx);
_30
_30
console.log(result);

Swapping a native Fluid asset for a CW20 token using Terraswap

The following code example shows how to swap a native asset for CW20 using Terraswap.

Run this example on mainnet.


_50
import {
_50
MsgExecuteContract,
_50
MnemonicKey,
_50
Coins,
_50
LCDClient,
_50
} from "@terra-money/terra.js";
_50
_50
// const lcd = new LCDClient(...);
_50
_50
const mk = new MnemonicKey({
_50
mnemonic:
_50
"satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn",
_50
});
_50
_50
const wallet = lcd.wallet(mk);
_50
_50
// LUNA <> OTHER_TOKEN
_50
const pool = "<INSERT_TOKEN_POOL_ADDRESS>";
_50
_50
// Fetch the number of each asset in the pool.
_50
const { assets } = await lcd.wasm.contractQuery(pool, { pool: {} });
_50
_50
// Calculate belief price using pool balances.
_50
const beliefPrice = (assets[0].amount / assets[1].amount).toFixed(18);
_50
_50
// Swap 1 LUNA to SCRT with 1% slippage tolerance.
_50
const terraSwap = new MsgExecuteContract(
_50
wallet.key.accAddress,
_50
pool,
_50
{
_50
swap: {
_50
max_spread: "0.01",
_50
offer_asset: {
_50
info: {
_50
native_token: {
_50
denom: "uluna",
_50
},
_50
},
_50
amount: "1000000",
_50
},
_50
belief_price: beliefPrice,
_50
},
_50
},
_50
new Coins({ uluna: "1000000" })
_50
);
_50
_50
const tx = await wallet.createAndSignTx({ msgs: [terraSwap] });
_50
const result = await lcd.tx.broadcast(tx);
_50
_50
console.log(result);

Decoding Protobuf-encoded messages

The following code example shows how to decode messages that have been encoded using Protobuf:


_17
import { LCDClient, Tx } from "@terra-money/terra.js";
_17
_17
// const lcd = new LCDClient(...);
_17
_17
const blockData = await lcd.tendermint.blockInfo(5923213);
_17
_17
const txInfos = blockData.block.data.txs.map((tx) =>
_17
Tx.unpackAny({ value: Buffer.from(tx, "base64") })
_17
);
_17
_17
// Find messages where a contract was initialized.
_17
const initMessages = txInfos
_17
.map((tx) => tx.body.messages)
_17
.flat()
_17
.find((i) => i.constructor.name === "MsgInstantiateContract");
_17
_17
console.log(initMessages);

Validate a Fluid address

The following code example shows how to do a basic verification on a Fluid address.

This is a basic version of the verification, it does not require external libraries as it performs a simple comparison with a regex string. It could give false positives since it doesn't verify the checksum of the address.


_13
// basic address validation (no library required)
_13
function isValid(address) {
_13
// check the string format:
_13
// - starts with "terra1"
_13
// - length == 44 ("terra1" + 38)
_13
// - contains only numbers and lower case letters
_13
return /(terra1[a-z0-9]{38})/g.test(address);
_13
}
_13
_13
console.log(isValid("terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8")); // true
_13
console.log(isValid("terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); // true (even if this doesn't have a valid checksum)
_13
console.log(isValid("cosmos1zz22dfpvw3zqpeyhvhmx944a588fgcalw744ts")); // false
_13
console.log(isValid("random string")); // false

This is a more advanced verification that requires the bech32 library which is used to verify the checksum.


_18
import { bech32 } from "bech32";
_18
_18
// advanced address validation, it verify also the bech32 checksum
_18
function isValid(address) {
_18
try {
_18
const { prefix: decodedPrefix } = bech32.decode(address); // throw error if checksum is invalid
_18
// verify address prefix
_18
return decodedPrefix === "terra";
_18
} catch {
_18
// invalid checksum
_18
return false;
_18
}
_18
}
_18
_18
console.log(isValid("terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8")); // true
_18
console.log(isValid("terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); // false
_18
console.log(isValid("cosmos1zz22dfpvw3zqpeyhvhmx944a588fgcalw744ts")); // false
_18
console.log(isValid("random string")); // false

Avoid Status 500: timed out waiting for tx to be included in a block

Occasionally the broadcast function of terra.js and terra.py throws the error Status 500: timed out waiting for tx to be included in a block, even if transaction will confirmed onchain after a few seconds.

This happens because the libraries use by default the broadcast-mode = block, with this mode the LCD to which you are broadcasting the transaction sends an http response to your request only when the transaction has been included in a block, but if the chain is overloaded the confirmation may take too long and trigger a timeout in the LCD.

To solve this problem it is recommended to use the broadcast-mode = sync and then iterate a request to the LCD with the txhash to understand when it has been included in a block.

This is an example to do it in JavaScript:


_20
// sign the tx
_20
wallet
_20
.createAndSignTx(YOUR_TX_HERE)
_20
// use broadcastSync() instead of broadcast()
_20
.then((tx) => terra.tx.broadcastSync(tx))
_20
.then(async (result) => {
_20
// TODO: use a for or add a timeout to prevent infinite loops
_20
while (true) {
_20
// query txhash
_20
const data = await terra.tx.txInfo(result.txhash).catch(() => {});
_20
// if hash is onchain return data
_20
if (data) return data;
_20
// else wait 250ms and then repeat
_20
await new Promise((resolve) => setTimeout(resolve, 250));
_20
}
_20
})
_20
.then((result) => {
_20
// this will be executed when the tx has been included into a block
_20
console.log(result);
_20
});