Common examples
Contents
Common examples#
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.
import fetch from 'isomorphic-fetch';
import { MsgSend, MnemonicKey, Coins, LCDClient } from '@terra-money/terra.js';
// Fetch gas prices and convert to `Coin` format.
const gasPrices = await (await fetch('https://bombay-fcd.terra.dev/v1/txs/gas_prices')).json();
const gasPricesCoins = new Coins(gasPrices);
const lcd = new LCDClient({
URL: "https://bombay-lcd.terra.dev/",
chainID: "bombay-12",
gasPrices: gasPricesCoins,
gasAdjustment: "1.5",
gas: 10000000,
});
Get wallet balance (native tokens)#
// Replace with address to check.
const address = 'terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const [balance] = await lcd.bank.balance(address);
console.log(balance.toData());
Example response:
[
{ denom: 'uluna', amount: '5030884' },
{ denom: 'uusd', amount: '433108784' }
]
Get wallet balance (CW20 tokens)#
// ANC on bombay-12
const tokenAddress = 'terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc';
const walletAddress = 'terra1f44ddca9awepv2rnudztguq5rmrran2m20zzd6';
const response = await lcd.wasm.contractQuery(tokenAddress, { balance: { address: walletAddress }});
console.log(response);
Example response:
{ balance: '70258667' }
Get transaction status#
// Replace with TX hash to lookup.
const hash = 'CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B';
const txInfo = await lcd.tx.txInfo(hash);
console.log(txInfo);
Example response (modified for readability):
TxInfo {
height: 8276372,
txhash: 'CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B',
raw_log: '[]',
logs: [
TxLog {
msg_index: 0,
log: '',
events: [Array],
eventsByType: [Object]
}
],
gas_wanted: 177808,
gas_used: 128827,
tx: Tx {},
timestamp: '2022-03-17T18:34:06Z',
code: 0,
codespace: ''
}
Get link to transaction#
const getTransactionLink = (hash, chainID) => `https://finder.terra.money/${chainID}/tx/${hash}`;
const hash = 'CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B';
console.log(getTransactionLink(hash, 'bombay-12'));
Example response:
https://finder.terra.money/bombay-12/tx/CAB264B3D92FF3DFE209DADE791A866876DE5DD2A320C1200F9C5EC5F0E7B14B
Get link to wallet address#
const getWalletLink = (address, chainID) => `https://finder.terra.money/${chainID}/address/${address}`;
const address = 'terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
console.log(getWalletLink(address, 'bombay-12'))
Example response:
https://finder.terra.money/bombay-12/address/terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Sending native tokens#
The following code example shows how to send native tokens:
import { LCDClient, MnemonicKey, MsgSend } from "@terra-money/terra.js";
// const lcd = new LCDClient(...);
const mk = new MnemonicKey({
mnemonic: 'satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn',
});
const wallet = lcd.wallet(mk);
// Transfer 1 Luna.
const send = new MsgSend(
wallet.key.accAddress,
"terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8",
{ uluna: "1000000" }
);
const tx = await wallet.createAndSignTx({ msgs: [send] });
const result = await lcd.tx.broadcast(tx);
console.log(result);
Sending CW20 tokens#
The following code example shows how to send CW20 tokens:
import {
LCDClient,
MnemonicKey,
MsgExecuteContract,
} from "@terra-money/terra.js";
// const lcd = new LCDClient(...);
const mk = new MnemonicKey({
mnemonic: 'satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn',
});
const wallet = lcd.wallet(mk);
// ANC on bombay-12
const tokenAddress = 'terra1747mad58h0w4y589y3sk84r5efqdev9q4r02pc';
// Transfer 1 ANC.
const cw20Send = new MsgExecuteContract(
wallet.key.accAddress,
tokenAddress,
{
transfer: {
amount: "1000000",
recipient: wallet.key.accAddress,
},
}
);
const tx = await wallet.createAndSignTx({ msgs: [cw20Send] });
const result = await lcd.tx.broadcast(tx);
console.log(result);
Swapping using the market module#
The following code example shows how to swap native Terra assets using the market module:
import {
LCDClient,
MnemonicKey,
MsgSwap,
Coin,
} from "@terra-money/terra.js";
// const lcd = new LCDClient(...);
const mk = new MnemonicKey({
mnemonic: 'satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn',
});
const wallet = lcd.wallet(mk);
// Swap 1 Luna to UST.
const swap = new MsgSwap(
wallet.key.accAddress,
new Coin('uluna', '1000000'),
'uusd'
);
const tx = await wallet.createAndSignTx({ msgs: [swap] });
const result = await lcd.tx.broadcast(tx);
console.log(result);
Swapping a native Terra 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.
import {
MsgExecuteContract,
MnemonicKey,
Coins,
LCDClient,
} from "@terra-money/terra.js";
// const lcd = new LCDClient(...);
const mk = new MnemonicKey({
mnemonic: 'satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn',
});
const wallet = lcd.wallet(mk);
// UST <> SCRT
const pool = "terra1tq4mammgkqrxrmcfhwdz59mwvwf4qgy6rdrt46";
// Fetch the number of each asset in the pool.
const { assets } = await lcd.wasm.contractQuery(pool, { pool: {} });
// Calculate belief price using pool balances.
const beliefPrice = (assets[0].amount / assets[1].amount).toFixed(18);
// Swap 1 UST to SCRT with 1% slippage tolerance.
const terraSwap = new MsgExecuteContract(
wallet.key.accAddress,
pool,
{
swap: {
max_spread: "0.01",
offer_asset: {
info: {
native_token: {
denom: "uusd",
},
},
amount: "1000000",
},
belief_price: beliefPrice,
},
},
new Coins({ uusd: '1000000' }),
);
const tx = await wallet.createAndSignTx({ msgs: [terraSwap] });
const result = await lcd.tx.broadcast(tx);
console.log(result);
Decoding Protobuf-encoded messages#
The following code example shows how to decode messages that have been encoded using Protobuf:
import {
LCDClient,
Tx,
} from '@terra-money/terra.js';
// const lcd = new LCDClient(...);
const blockData = await lcd.tendermint.blockInfo(5923213);
const txInfos = blockData.block.data.txs.map((tx) =>
Tx.unpackAny({ value: Buffer.from(tx, 'base64') })
);
// Find messages where a contract was initialized.
const initMessages = txInfos.map((tx) => tx.body.messages)
.flat()
.find(
(i) => i.constructor.name === 'MsgInstantiateContract'
);
console.log(initMessages);
Validate a Terra address#
The following code example shows how to do a basic verification on a Terra 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.
// basic address validation (no library required)
function isValid(address) {
// check the string format:
// - starts with "terra1"
// - length == 44 ("terra1" + 38)
// - contains only numbers and lower case letters
return /(terra1[a-z0-9]{38})/g.test(address);
}
console.log(isValid('terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8')); // true
console.log(isValid('terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')); // true (even if this doesn't have a valid checksum)
console.log(isValid('cosmos1zz22dfpvw3zqpeyhvhmx944a588fgcalw744ts')); // false
console.log(isValid('random string')); // false
This is a more advanced verification that requires the bech32 library which is used to verify the checksum.
import { bech32 } from 'bech32';
// advanced address validation, it verify also the bech32 checksum
function isValid(address) {
try {
const { prefix: decodedPrefix } = bech32.decode(address); // throw error if checksum is invalid
// verify address prefix
return decodedPrefix === 'terra';
} catch {
// invalid checksum
return false;
}
}
console.log(isValid('terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8')); // true
console.log(isValid('terra1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')); // false
console.log(isValid('cosmos1zz22dfpvw3zqpeyhvhmx944a588fgcalw744ts')); // false
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:
// sign the tx
wallet.createAndSignTx(YOUR_TX_HERE)
// use broadcastSync() instead of broadcast()
.then(tx => terra.tx.broadcastSync(tx))
.then(async result => {
// TODO: use a for or add a timeout to prevent infinite loops
while(true){
// query txhash
const data = await terra.tx.txInfo(result.txhash)
.catch(() => {})
// if hash is onchain return data
if(data) return data
// else wait 250ms and then repeat
await new Promise(resolve => setTimeout(resolve, 250))
}
})
.then(result => {
// this will be executed when the tx has been included into a block
console.log(result)
})