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.
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.
_17import fetch from "isomorphic-fetch";_17import { MsgSend, MnemonicKey, Coins, LCDClient } from "@terra-money/terra.js";_17_17// Fetch gas prices and convert to `Coin` format._17const gasPrices = await (_17 await fetch("https://pisco-api.terra.dev/gas-prices", { redirect: 'follow' })_17).json();_17const gasPricesCoins = new Coins(gasPrices);_17_17const 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._4const address = "terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";_4const [balance] = await lcd.bank.balance(address);_4console.log(balance.toData());
Example response:
_1[{ denom: "uluna", amount: "5030884" }];
Get wallet balance (CW20 tokens)
_8// ANC on pisco-1_8const tokenAddress = "terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc";_8const walletAddress = "terra1f44ddca9awepv2rnudztguq5rmrran2m20zzd6";_8const response = await lcd.wasm.contractQuery(tokenAddress, {_8 balance: { address: walletAddress },_8});_8_8console.log(response);
Example response:
_3{_3 balance: "70258667";_3}
Get transaction status
_4// Replace with TX hash to lookup._4const hash = "CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B";_4const txInfo = await lcd.tx.txInfo(hash);_4console.log(txInfo);
Example response (modified for readability):
_19TxInfo {_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}
Get link to transaction
_5const getTransactionLink = (hash, chainID) =>_5 `https://finder.fluid.net/${chainID}/tx/${hash}`;_5const hash = "CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B";_5_5console.log(getTransactionLink(hash, "pisco-1"));
Example response:
_1https://finder.fluid.net/pisco-1/tx/CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B
Get link to wallet address
_4const getWalletLink = (address, chainID) =>_4 `https://finder.fluid.net/${chainID}/address/${address}`;_4const address = "terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";_4console.log(getWalletLink(address, "pisco-1"));
Example response:
_1https://finder.fluid.net/pisco-1/address/terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Sending native tokens
The following code example shows how to send native tokens:
_22import { LCDClient, MnemonicKey, MsgSend } from "@terra-money/terra.js";_22_22// const lcd = new LCDClient(...);_22_22const 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_22const wallet = lcd.wallet(mk);_22_22// Transfer 1 Luna._22const send = new MsgSend(_22 wallet.key.accAddress,_22 "terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8",_22 { uluna: "1000000" }_22);_22_22const tx = await wallet.createAndSignTx({ msgs: [send] });_22const result = await lcd.tx.broadcast(tx);_22_22console.log(result);
Sending CW20 tokens
The following code example shows how to send CW20 tokens:
_30import {_30 LCDClient,_30 MnemonicKey,_30 MsgExecuteContract,_30} from "@terra-money/terra.js";_30_30// const lcd = new LCDClient(...);_30_30const 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_30const wallet = lcd.wallet(mk);_30_30// ANC on pisco-1_30const tokenAddress = "terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc";_30_30// Transfer 1 ANC._30const cw20Send = new MsgExecuteContract(wallet.key.accAddress, tokenAddress, {_30 transfer: {_30 amount: "1000000",_30 recipient: wallet.key.accAddress,_30 },_30});_30_30const tx = await wallet.createAndSignTx({ msgs: [cw20Send] });_30const result = await lcd.tx.broadcast(tx);_30_30console.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.
_50import {_50 MsgExecuteContract,_50 MnemonicKey,_50 Coins,_50 LCDClient,_50} from "@terra-money/terra.js";_50_50// const lcd = new LCDClient(...);_50_50const 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_50const wallet = lcd.wallet(mk);_50_50// LUNA <> OTHER_TOKEN_50const pool = "<INSERT_TOKEN_POOL_ADDRESS>";_50_50// Fetch the number of each asset in the pool._50const { assets } = await lcd.wasm.contractQuery(pool, { pool: {} });_50_50// Calculate belief price using pool balances._50const beliefPrice = (assets[0].amount / assets[1].amount).toFixed(18);_50_50// Swap 1 LUNA to SCRT with 1% slippage tolerance._50const 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_50const tx = await wallet.createAndSignTx({ msgs: [terraSwap] });_50const result = await lcd.tx.broadcast(tx);_50_50console.log(result);
Decoding Protobuf-encoded messages
The following code example shows how to decode messages that have been encoded using Protobuf:
_17import { LCDClient, Tx } from "@terra-money/terra.js";_17_17// const lcd = new LCDClient(...);_17_17const blockData = await lcd.tendermint.blockInfo(5923213);_17_17const 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._17const initMessages = txInfos_17 .map((tx) => tx.body.messages)_17 .flat()_17 .find((i) => i.constructor.name === "MsgInstantiateContract");_17_17console.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)_13function 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_13console.log(isValid("terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8")); // true_13console.log(isValid("terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); // true (even if this doesn't have a valid checksum)_13console.log(isValid("cosmos1zz22dfpvw3zqpeyhvhmx944a588fgcalw744ts")); // false_13console.log(isValid("random string")); // false
This is a more advanced verification that requires the bech32 library which is used to verify the checksum.
_18import { bech32 } from "bech32";_18_18// advanced address validation, it verify also the bech32 checksum_18function 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_18console.log(isValid("terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8")); // true_18console.log(isValid("terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); // false_18console.log(isValid("cosmos1zz22dfpvw3zqpeyhvhmx944a588fgcalw744ts")); // false_18console.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_20wallet_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 });