Bolt Archway TypeScript SDK

Integrate with Bolt Liquidity Protocol on Archway network using TypeScript

Overview

The Bolt TypeScript SDK enables seamless integration with the Bolt Liquidity Protocol across multiple blockchain networks. Built with extensibility in mind, this SDK provides developers with a comprehensive, type-safe interface to access all protocol functionality including price feeds, token swaps, liquidity management, and pool operations.

Quickstart

1

Prerequisites

Before using the SDK, make sure you have:

2

Installation

npm install @bolt-liquidity-hq/cosmwasm-client
3

Initialize the Bolt Client

The SDK supports different environments:

type Environment = 'mainnet' | 'testnet';

Mainnet

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

Testnet

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient({
  environment: 'testnet',
});
4

Query all assets

// Get all supported assets
const assets = await client.getAssets();
assets.forEach((asset) => {
  console.log(`${asset.symbol} (${asset.name}): ${asset.denom}`);
  console.log(`  Decimals: ${asset.decimals}`);
});

// Find a specific asset
const archAsset = assets.find((a) => a.symbol === 'ARCH');
console.log(`ARCH denom: ${archAsset?.denom}`); // "aarch"
5

Execute a swap

import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';

// Get signer from wallet (implementation depends on wallet)
const signer = await DirectSecp256k1HdWallet.fromMnemonic("my mnemonic goes here", {
  prefix: 'archway',
});

// Execute a swap: exactly 1 ARCH for USDC
const result = await client.swap({
  assetIn: 'aarch',
  amountIn: '1000000000000000000', // 1 ARCH (18 decimals)
  assetOut: 'ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D', // USDC
  minimumAmountOut: '1900000', // Minimum 1.9 USDC (6 decimals)
, signer});

console.log(`Swapped 1 ARCH for ${result.amountOut} USDC`);
console.log(`Transaction hash: ${result.txHash}`);
console.log(`Gas cost: ${result.txOutput.gasUsed}`);
console.log(`Status: ${result.txOutput.code === 0 ? 'success' : 'failed'}`);

API

Client Initialization

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

// Initialize client
const client = new BoltCosmWasmClient({
  environment: 'mainnet', // 'testnet' | 'mainnet'
  customOverride: {  
    chainConfig: {
      rpcEndpoint: 'https://my-custom-rpc-endpoint...', // Remove this if you want to use default public RPC endpoint
    }
  }
});
Advanced client initialization
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

// Initialize client
const customClient = new BoltCosmWasmClient({
  customOverride: {
    chainConfig: {
      id: 'archway-custom-1',
      name: 'Archway Custom',
      rpcEndpoint: 'https://custom-rpc.example.com',
      restEndpoint: 'https://custom-rest.example.com'
     },
     contracts: {
       oracle: 'archway1custom_oracle...',
       router: 'archway1custom_router...'
     },
     nativeTokenDenom: 'aarch',
     assetsConfig: {
       'aarch': {
         symbol: 'ARCH',
         name: 'Archway',
         chainId: 'archway-custom-1',
         denom: 'aarch',
         decimals: 18,
         logo: 'https://example.com/arch.png',
         coingeckoId: 'archway'
       }
     }
   }
 });

Environment configuration

Parameter
Type
Default
Description

environment

mainnet | testnet

mainnet

Specifies to which network to connect.

Override chain configuration

Parameter
Type
Default (mainnet)
Default (testnet)
Description

chainConfig.id

string

archway-1

constantine-3

Chain identifier

chainConfig.name

string

Archway

Archway Testnet

Human-readable chain name

chainConfig.rpcEndpoint

string

RPC endpoint URL

chainConfig.restEndpoint

string

REST endpoint URL

Override Outpost contract address

Parameter
Type
Default (mainnet)
Default (testnet)
Description

contracts.oracle

string

archway1cr5l0tvhqsdjfzun4jkwqfzv7fadu598hultcra4jrljgwl639wsksmd28

archway1ehpghtr0v95kfx648dck7pvs08d6ah97l99xkx87t2zx8tcyen0s9n90x4

Oracle contract address

contracts.router

string

archway1vu2ctevyav3wlka9yn7hmcm0xnlltklnnceqaanpuh0eete80xgsymc3ln

archway1rtdlmwgedg2vnsdyp3l23yr8eh7gspndt0x5cv5n9vxnerm374cs8lxk25

Router contract address

Override assets configuration

Parameter
Type
Description

assetsConfig

Record<string, Asset>

Custom asset configurations indexed by denomination

Asset structure
type Asset = {
  symbol: string;        // Asset symbol (e.g., 'ARCH', 'USDC')
  name: string;          // Full asset name (e.g., 'Archway', 'Circle USDC')
  chainId: string;       // Chain identifier
  denom: string;         // Asset denomination
  decimals: number;      // Number of decimal places
  logo?: string;         // Optional logo URL
  coingeckoId?: string;  // Optional CoinGecko identifier
};

Override clients

Parameter
Type
Description

cosmWasmClient

CosmWasmClient | ArchwayClient

Pre-existing query client instance to use for blockchain interactions

signer

OfflineSigner

Pre-existing signer

signingCosmWasmClient

SigningCosmWasmClient | SigningArchwayClient

Pre-existing signing client instance to use for signing blockchain transactions

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';

// Create custom Cosm-Wasm client with specific configuration
const customCosmWasmClient = CosmWasmClient.connect('https://custom-rpc.example.com');

const client = new BoltCosmWasmClient({
  cosmWasmClient: customCosmWasmClient
});

Get oracle config

getOracleConfig()

The getOracleConfig method retrieves the current configuration settings from the Bolt Liquidity Protocol's Oracle smart contract on the Archway blockchain. This configuration governs how price feeds are managed, including update thresholds, expiration times, and administrative settings.

async getOracleConfig(): Promise<OracleConfig>

Usage example

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

// Initialize client
const client = new BoltCosmWasmClient();

// Get oracle configuration
const config = await client.getOracleConfig();

console.log('Oracle Admin:', config.admin);
console.log('Price Threshold:', config.priceThresholdRatio);
console.log('Price Expiry (seconds):', config.priceExpireTime?.secs);

Integration Examples

How to cache Oracle config (best practice)
// Cache configuration for performance
let cachedConfig: OracleConfig | null = null;
let lastFetchTime = 0;
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes

async function getCachedOracleConfig() {
  const now = Date.now();

  if (cachedConfig && (now - lastFetchTime) < CACHE_DURATION) {
    return cachedConfig;
  }

  cachedConfig = await client.getOracleConfig();
  lastFetchTime = now;
  return cachedConfig;
}
How to monitor for price updates
async function monitorOracleConfig() {
  const config = await client.getOracleConfig();

  // Monitor for configuration changes
  setInterval(async () => {
    const newConfig = await client.getOracleConfig();

    if (newConfig.priceThresholdRatio !== config.priceThresholdRatio) {
      console.log('Price threshold changed:', newConfig.priceThresholdRatio);
    }

    if (newConfig.priceExpireTime?.secs !== config.priceExpireTime?.secs) {
      console.log('Price expiry time changed:', newConfig.priceExpireTime?.secs);
    }
  }, 60000); // Check every minute
}

Query prices and assets

getAssets()

Retrieves all unique assets available in the Bolt protocol by querying oracle asset pairs and enriching them with additional metadata from the client's asset configuration.

async getAssets(): Promise<Asset[]>

Usage example

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

// Get all available assets
const assets = await client.getAssets();

console.log('Available assets:', assets.length);
assets.forEach(asset => {
  console.log(`${asset.symbol}: ${asset.name} (${asset.decimals} decimals)`);
});

/ Find a specific asset
const archAsset = assets.find((a) => a.symbol === 'ARCH');
console.log(`ARCH denom: ${archAsset?.denom}`); // "aarch"

getAllOracleAssetPairs()

Queries the oracle smart contract to retrieve all supported asset pairs with automatic pagination handling. Each asset pair represents a base/quote relationship that can be used for price queries and swaps.

async getAllOracleAssetPairs(): Promise<OracleAssetPair[]>

Usage example

// Get all supported trading pairs
const assetPairs = await client.getAllOracleAssetPairs();

console.log('Supported trading pairs:', assetPairs.length);
assetPairs.forEach(pair => {
  console.log(`${pair.base.symbol}/${pair.quote.symbol} (${pair.base.precision}/${pair.quote.precision} decimals)`);
});

getAllPrices()

Queries the oracle smart contract to retrieve all available price feeds with automatic pagination. More efficient than making multiple individual price queries when you need prices for multiple pairs.

async getAllPrices(): Promise<Price[]>

Usage example

// Get all current prices
const allPrices = await client.getAllPrices();

console.log('Total prices available:', allPrices.length);
allPrices.forEach(price => {
  console.log(`Price: ${price.price}, Expires: ${new Date(Number(price.expiryTime) / 1000000)}`);
});

getPrice()

Queries the oracle smart contract to retrieve the current price for a specific asset pair. Fetches the latest price feed that is updated by authorized price feeders and validated against configured thresholds.

async getPrice(baseDenom: string, quoteDenom: string): Promise<InvertiblePrice>

Usage example

// Get ARCH/USDC price
const price = await client.getPrice(
  'aarch',
  'ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D' // USDC
);

console.log(`ARCH/USDC Price: ${price.price}`);
console.log(`Expires at: ${new Date(Number(price.expiryTime) / 1000000)}`);
console.log(`Asset Pair: ${price.assetPair}`);

Verify pool liquidity

getPoolBaseLiquidity()

Queries the router smart contract to retrieve the total base asset liquidity across all pools with automatic pagination. Fetches current liquidity levels for all base assets in their respective pools.

async getPoolBaseLiquidity(poolContractAddress: string): Promise<BaseLiquidityDetails>

Usage example

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

// Get base asset liquidity of a Pool by contract address
const poolAddress = "archway1f1e...";

const liquidity = await client.getAllBaseAssetsLiquidity(poolAddress);

console.log(`Base liquidity: ${liquidity.baseLiquidity.amount} ${liquidity.baseLiquidity.denom}`);
console.log(`Total shares: ${liquidity.totalShares}`);

getAllBaseAssetsLiquidity()

Queries the router smart contract to retrieve the base asset liquidity across all pools. Fetches current liquidity levels for all the base assets in their respective pools.

async getAllBaseAssetsLiquidity(): Promise<Record<Address, BaseLiquidityDetails>>

Usage example

import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

// Get all base asset liquidity
const liquidity = await client.getAllBaseAssetsLiquidity();

console.log('Base asset liquidity:', Object.keys(liquidity).length);
Object.entries(liquidity).forEach(([denom, details]) => {
  console.log(`${denom}: ${details.baseLiquidity.amount} (${details.totalShares} shares)`);
});

Get Router contract config

getRouterConfig()

Queries the router smart contract to retrieve its current configuration settings. Fetches router's configuration parameters that govern how swaps are executed, fees are collected, and new pools are deployed.

async getRouterConfig(): Promise<RouterConfig>

Usage example

// Get router configuration
const config = await client.getRouterConfig();

console.log('Router Admin:', config.admin);
console.log('Price Oracle:', config.defaultPriceOracleContract);
console.log('Protocol Fee Recipient:', config.defaultProtocolFeeRecipient);
console.log('Protocol Fee:', config.defaultProtocolFee);
console.log('LP Fee:', config.defaultLpFee);

Get liquidity pools information

getAllPools()

Queries the router smart contract to retrieve information about all deployed pools with automatic pagination. Fetches a comprehensive list of all pools in the Bolt protocol.

async getAllPools(): Promise<Pool[]>

Usage example

// Get all pools
const allPools = await client.getAllPools();

console.log(`Total pools available: ${allPools.length}`);

// Display all pools and their trading pairs
allPools.forEach((pool, index) => {
  console.log(`\nPool ${index + 1}: ${pool.poolAddress}`);
  console.log(`  Base asset: ${pool.baseDenom}`);
  console.log(`  Quote assets: ${pool.quoteDenoms.length}`);
  pool.quoteDenoms.forEach(quote => {
    console.log(`    - ${quote}`);
  });
});

// Find pools for specific base asset
const archPools = allPools.filter(pool =>
  pool.baseDenom === "aarch"
);
console.log(`ARCH pools found: ${archPools.length}`);

getPoolConfig()

Retrieves the configuration settings of a liquidity pool contract. Queries the contract to fetch its current configuration parameters including fees, LP settings, and oracle integration.

async getPoolConfig(contractAddress: Address): Promise<PoolConfig>

Usage example

// Get pool configuration by contract address
const poolAddress = "archway1f1e...";
const config = await client.getPoolConfig(poolAddress);

console.log('Pool Configuration:');
console.log('  Price Oracle:', config.priceOracleContract);
console.log('  Protocol Fee:', config.protocolFee);
console.log('  LP Fee:', config.lpFee);
console.log('  Allowance Mode:', config.allowanceMode);
console.log('  Min Base Out:', config.minBaseOut);

getPoolByDenom()

Queries the router smart contract to retrieve pool information for a specific base asset on the Archway Blockchain, or a specific base/quote asset pair on the Archway Blockchain. Fetches pool details for the pool matching the provided asset denom(s).

async getPoolByDenom(baseDenom: string): Promise<Pool>

Usage example

// Get pool for ATOM base asset
const pool = await client.getPoolByDenom('ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2');

console.log('Pool Address:', pool.poolAddress);
console.log('Base Asset:', pool.baseDenom);
console.log('Quote Assets:', pool.quoteDenoms.length);
pool.quoteDenoms.forEach(quote => {
  console.log(`  - ${quote}`);
});

getPoolConfigByDenom()

Retrieves the configuration settings of a liquidity pool contract identified by its base asset on the Archway Blockchain, or by the base/quote asset pair on the Archway Blockchain. This is a convenience function that combines pool lookup and configuration retrieval.

async getPooConfigByDenom(baseDenom: string): Promise<PoolConfig>

Usage example

// Get pool configuration for ATOM base asset
const config = await client.getPoolConfigByBaseAsset('ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2');

console.log('Price Oracle:', config.priceOracleContract);
console.log('Protocol Fee Recipient:', config.protocolFeeRecipient);
console.log('Protocol Fee:', config.protocolFee);
console.log('LP Fee:', config.lpFee);
console.log('Allowance Mode:', config.allowanceMode);
console.log('Authorized LPs:', config.lps.length);
console.log('Min Base Out:', config.minBaseOut);

Simulate a swap

getRouterConfig()

Simulates a swap operation to calculate the expected output amount without executing the transaction. Performs a dry run of the swap, taking into account current pool conditions, oracle prices, and fees. It's useful for getting accurate estimates before executing a swap.

async simulateSwap(): Promise<SimulateSwapResult>

Usage example

// Simulate swapping 1 ARCH for USDC
const simulation = await client.simulateSwap({
  assetIn: "aarch",
  amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
  assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D" // USDC
});

console.log(`Pool: ${simulation.poolAddress}`);
console.log(`Expected output: ${simulation.amountOut} ${simulation.assetOut}`);
console.log(`Protocol fee: ${simulation.protocolFee}`);
console.log(`LP fee: ${simulation.lpFee}`);
if (simulation.dynamicFee) {
  console.log(`Dynamic fee: ${simulation.dynamicFee}`);
}
console.log(`Total fees: ${simulation.totalFees}`);

How to execute a swap

swap()

The swap method executes a token swap transaction on the Bolt Liquidity Protocol through the router contract. It performs a "swap exact in" operation where users specify exactly how much of the input asset they want to swap, and receive a variable amount of the output asset based on current pool conditions.

async swap(params: SwapParams, signer: Signer): Promise<SwapResult<ExecuteResult>>

type SwapParams = {
  assetIn: string; // Denomination of the asset being sold
  amountIn: string; // Exact amount of input asset to swap (in minimal units)
  assetOut: string; // Denomination of the asset being bought
  minimumAmountOut?: string; // Optional minimum acceptable amount of output asset
  receiver?: Address; // Optional recipient address for swapped assets
};

Basic usage examples

Simple swap
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { OfflineSigner } from '@cosmjs/proto-signing';

const client = new BoltArchwayClient();

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic

try {
 const result = await client.swap({
   assetIn: "aarch",
   amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
   assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
   minimumAmountOut: '1900000', // Minimum 1.9 USDC (6 decimals)
   receiver: "archway1..." // Optional custom receiver
 }, signer);

  console.log('Swap successful!');
  console.log(`Transaction hash: ${result.txHash}`);
  console.log(`Received: ${result.amountOut} ${result.assetOut}`);
} catch (error) {
  console.error('Swap failed:', error.message);
}
Swap with minimum amount out limit
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { OfflineSigner } from '@cosmjs/proto-signing';

const client = new BoltArchwayClient();

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic

const minimumAmountOut = "1900000"; // Minimum 1.9 USDC (6 decimals)

try {
 const result = await client.swap({
   assetIn: "aarch",
   amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
   assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
   minimumAmountOut
 }, signer);

  console.log(`Minimum: ${minimumAmountOut} USDC`);
  console.log(`Received: ${result.amountOut} USDC`);
} catch (error) {
  console.error('Swap failed:', error.message);
}
Swap with custom receiver
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { OfflineSigner } from '@cosmjs/proto-signing';

const client = new BoltArchwayClient();

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic

const receiver = "archway1e1f1..."; // Custom recipient

try {
 const result = await client.swap({
   assetIn: "aarch",
   amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
   assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
   receiver
 }, signer);

  console.log('Swap successful!');
  console.log(`Transaction hash: ${result.txHash}`);
  console.log(`Sent: ${result.amountOut} ${result.assetOut} to ${receiver}`);
} catch (error) {
  console.error('Swap failed:', error.message);
}

Best practices

Price slippage protection
// Always set minimumAmountOut to protect against price variations
const calculateMinimumOutput = (
  amountIn: string,
  price: string,
  priceSlippageTolerance: number = 0.01
) => {
  const expectedOutput = BigNumber(amountIn).multipliedBy(price);

  const slippageMultiplier = new BigNumber(1).minus(priceSlippageTolerance);

  return expectedOutput
    .multipliedBy(slippageMultiplier)
    .toFixed(0, BigNumber.ROUND_DOWN); // return as integer string
};

const price = await client.getPrice(assetIn, assetOut);
const minimumAmountOut = calculateMinimumOutput(amountIn, price.price, 0.01); // 1% slippage

const result = await client.swap({
  assetIn,
  amountIn,
  assetOut,
  minimumAmountOut
}, signer);
Error handling and retries
async function robustSwap(signer: Signer, params: SwapParams, maxRetries: number = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`Swap attempt ${attempt}/${maxRetries}`);

      const result = await client.swap(params, signer);

      console.log(`✅ Swap successful on attempt ${attempt}`);
      return result;

    } catch (error) {
      console.error(`❌ Attempt ${attempt} failed:`, error.message);

      if (attempt === maxRetries) {
        throw new Error(`Swap failed after ${maxRetries} attempts: ${error.message}`);
      }

      // Wait before retry (exponential backoff)
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Waiting ${delay}ms before retry...`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}
Gas estimation and optimization
import { OfflineSigner } from '@cosmjs/proto-signing';

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic
const result = await client.estimateSwapGasFees(
  {
    assetIn: "aarch",
    amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
    assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
  },
  signer
);

if (result.amount > maxGasBudget) {
  throw new Error('Gas cost exceeds budget');
}

Error Handling

The SDK provides custom error types for better error handling:

  • NotFoundError - Resource not found

  • InvalidParameterError - Invalid parameter provided

  • InvalidObjectError - Invalid object structure

  • InvalidTypeError - Invalid type provided

  • MissingParameterError - Required parameter missing

  • TransactionFailedError - Transaction execution failed

  • ParseError - Failed to parse response data

Resources

Bolt TS SDK Reference

Github