Common examples guide
Use the following common examples to learn how to use feather.js. If this is your first time using feather.js, follow the feather.js tutorial.
If you are new to developing on Terra visit the getting started guide.
Configuring LCDClient​
The following code example shows how to initialize the LCDClient for one or multiple chains. The rest of the examples assume that you have initialized the LCDClient using this example or similar code.
_18import {_18  MsgSend,_18  MnemonicKey,_18  Coins,_18  LCDClient,_18} from '@terra-money/feather.js';_18_18const lcd = new LCDClient({_18  'pisco-1': {_18    chainID: 'pisco-1',_18    lcd: 'https://pisco-lcd.terra.dev',_18    gasAdjustment: 1.75,_18    gasPrices: {_18      uluna: 0.015,_18    },_18    prefix: 'terra', // bech32 prefix, used by the LCD to understand which is the right chain to query_18  },_18});
To configure the LCD for multiple chains, pass an object with multiple keys, each key being the chainID.
_20const lcd = new LCDClient({_20  'osmosis-1': {_20    chainID: 'osmosis-1',_20    lcd: 'https://lcd.osmosis.zone',_20    gasAdjustment: 1.75,_20    gasPrices: {_20      uosmo: 0.025,_20    },_20    prefix: 'osmo',_20  },_20  'phoenix-1': {_20    chainID: 'phoenix-1',_20    lcd: 'https://phoenix-lcd.terra.dev',_20    gasAdjustment: 1.75,_20    gasPrices: {_20      uluna: 0.015,_20    },_20    prefix: 'terra',_20  },_20});
You can also use the default configuration if you only want to connect to Terra.
_2const lcd = LCDClient.fromDefaultConfig('testnet'); // connect to testnet_2const lcd = LCDClient.fromDefaultConfig('mainnet'); // connect to mainnet
Get native wallet balance​
_10// The LCD will direct the query according to the bech32 prefix of the address_10const [terraBalance] = await lcd.bank.balance(_10  'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v',_10);_10console.log(terraBalance);_10_10const [osmoBalance] = await lcd.bank.balance(_10  'osmo1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v',_10);_10console.log(osmoBalance);
Example response:
_2[{ denom: 'uluna', amount: '5030884' }];_2[{ denom: 'uosmo', amount: '10000' }];
Queries that can't directly read the chain from the given address always require a chainID to be specified. See the below example.
_3// query the total circulating supply_3const total = await lcd.bank.total('phoenix-1');_3console.log(total);
Get wallet balance (CW20 tokens)​
_8// Check balance of token on pisco-1 using tokenAddress._8const tokenAddress = '<INSERT_TOKEN_ADDRESS>';_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, 'pisco-1'); // specify chainID to direct LCD to the correct chain_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}
Sending native tokens​
The following code example shows how to send native tokens:
_22import { LCDClient, MnemonicKey, MsgSend } from '@terra-money/feather.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('terra'), // requires prefix as a parameter_22  'terra1dcegyrekltswvyy0xy69ydgxn9x8x32zdtapd8',_22  { uluna: '1000000' },_22);_22_22const tx = await wallet.createAndSignTx({ msgs: [send], chainID: 'pisco-1' });_22const result = await lcd.tx.broadcast(tx, 'pisco-1');_22_22console.log(result);
Sending CW20 tokens​
The following code example shows how to send CW20 tokens:
_37import {_37  LCDClient,_37  MnemonicKey,_37  MsgExecuteContract,_37} from '@terra-money/feather.js';_37_37// const lcd = new LCDClient(...);_37_37const mk = new MnemonicKey({_37  mnemonic:_37    'satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn',_37});_37_37const wallet = lcd.wallet(mk);_37_37// Specify token address of desired token to send._37const tokenAddress = '<INSERT_TOKEN_ADDRESS>';_37_37// Transfer 1 token._37const cw20Send = new MsgExecuteContract(_37  wallet.key.accAddress('terra'),_37  tokenAddress,_37  {_37    transfer: {_37      amount: '1000000',_37      recipient: wallet.key.accAddress('terra'),_37    },_37  },_37);_37_37const tx = await wallet.createAndSignTx({_37  msgs: [cw20Send],_37  chainID: 'pisco-1',_37});_37const result = await lcd.tx.broadcast(tx, 'pisco-1');_37_37console.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.
_53import {_53  MsgExecuteContract,_53  MnemonicKey,_53  Coins,_53  LCDClient,_53} from '@terra-money/feather.js';_53_53// const lcd = new LCDClient(...);_53_53const mk = new MnemonicKey({_53  mnemonic:_53    'satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn',_53});_53_53const wallet = lcd.wallet(mk);_53_53// LUNA <> OTHER_TOKEN_53const pool = '<INSERT_TOKEN_POOL_ADDRESS>';_53_53// Fetch the number of each asset in the pool._53const { assets } = await lcd.wasm.contractQuery(pool, { pool: {} });_53_53// Calculate belief price using pool balances._53const beliefPrice = (assets[0].amount / assets[1].amount).toFixed(18);_53_53// Swap 1 LUNA with 1% slippage tolerance._53const terraSwap = new MsgExecuteContract(_53  wallet.key.accAddress,_53  pool,_53  {_53    swap: {_53      max_spread: '0.01',_53      offer_asset: {_53        info: {_53          native_token: {_53            denom: 'uluna',_53          },_53        },_53        amount: '1000000',_53      },_53      belief_price: beliefPrice,_53    },_53  },_53  new Coins({ uluna: '1000000' }),_53);_53_53const tx = await wallet.createAndSignTx({_53  msgs: [terraSwap],_53  chainID: 'pisco-1',_53});_53const result = await lcd.tx.broadcast(tx, 'pisco-1');_53_53console.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/feather.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 Terra address​
The following code example shows how to do the basic verification of Terra or other bech32 prefixed addresses.
_9import { AccAddress } from '@terra-money/feather.js';_9// validate length, prefix and bech32 checksum. The second parameter is the expected bech32 prefix._9AccAddress.validate('terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v', 'terra'); // true_9_9// to check just length and bech32 checksum (if you don't know the chain)._9AccAddress.validate('terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'); // true_9_9// Get the prefix of an address. It will throw an error if the address is invalid._9AccAddress.getPrefix('terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v'); // 'terra'
To validate bech32 encoded validator addresses, pubkey, etc. you can use the specific namespace:
- ValAddress: for 
*valoper...prefixed validator operator address - ValConsAddress: for 
*valcons...prefixed validator consensus address - AccPubKey: for 
*pub...prefixed account public key - ValPubKey: for 
*valoperpub...prefixed validator public key 
Avoid Status 500: timed out waiting for tx to be included in a block​
Occasionally, the broadcast function of feather.js and terra.py will throw the error Status 500: timed out waiting for tx to be included in a block. This occurs because the libraries use broadcast-mode = block by default, which causes the LCD (to which you are broadcasting the transaction) to send an http response to your request only when the transaction has been included in a block. If the chain is overloaded, the confirmation may take too long and trigger a timeout in the LCD.
To solve this problem, use broadcast-mode = sync and then iterate a request to the LCD with the txhash to ensure that it has been included in a block.
Javascript example:
_19// sign the tx_19wallet_19  .createAndSignTx(TX_HERE, CHAIN_ID_HERE)_19  // use broadcastSync() instead of broadcast()_19  .then((tx) => terra.tx.broadcastSync(tx, chainID))_19  .then(async (result) => {_19    while (true) {_19      // query txhash_19      const data = await terra.tx.txInfo(result.txhash).catch(() => {});_19      // if hash is onchain return data_19      if (data) return data;_19      // else wait 250ms and then repeat_19      await new Promise((resolve) => setTimeout(resolve, 250));_19    }_19  })_19  .then((result) => {_19    // this will be executed when the tx has been included into a block_19    console.log(result);_19  });