Skip to main content
The Bolt TypeScript SDK provides a comprehensive, type-safe interface for integrating with Bolt’s zero slippage execution layer on Sui. Query oracle prices, inspect pools, simulate swaps off-chain, and execute trades programmatically.

Quickstart

1

Prerequisites

Before using the SDK, make sure you have:☑️ Node.js 18+ installed☑️ A Sui-compatible wallet (Sui Wallet, Suiet, etc.) for signing transactions☑️ Access to SUI RPC endpoints: The client uses
https://fullnode.mainnet.sui.io:443 for mainnet and https://fullnode.testnet.sui.io:443 for testnet by default
2

Installation

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

Initialize the Bolt client

The SDK supports different environments:
type Environment = 'mainnet' | 'testnet';
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();
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 suiAsset = assets.find((a) => a.symbol === 'SUI');
console.log(`SUI type: ${suiAsset?.denom}`); // "0x2::sui::SUI"
5

Execute a swap

// Get signer from wallet (implementation depends on wallet)
const signer: Signer = await getSuiWalletSigner();

// Execute a swap: exactly 1 SUI for USDC
const result = await client.swap({
  assetIn: '0x2::sui::SUI',
  amountIn: '1000000000', // 1 SUI (9 decimals)
  assetOut: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
  minimumAmountOut: '1900000', // Minimum 1.9 USDC (6 decimals)
}, signer);

console.log(`Swapped 1 SUI for ${result.amountOut} USDC`);
console.log(`Transaction digest: ${result.txHash}`);
console.log(`Gas cost: ${result.txOutput.effects.gasUsed.computationCost}`);
console.log(`Status: ${result.txOutput.effects.status.status}`);

API

Client initialization

import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

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

// Initialise client with full custom configuration
const client = new BoltSuiClient({
  environment: 'mainnet',
  customOverride: {
    chainConfig: {
      id: 'sui-mainnet',
      name: 'Sui',
      rpcEndpoint: 'https://fullnode.mainnet.sui.io:443',
    },
    packageId: '0x1234...',
    contracts: {
      oracle: '0xoracle...',
    },
    assetsConfig: {
      '0x2::sui::SUI': {
        symbol: 'SUI',
        name: 'Sui',
        chainId: 'sui-mainnet',
        denom: '0x2::sui::SUI',
        decimals: 9,
        logo: 'https://...',
        coingeckoId: 'sui',
      },
    },
  },
});
Environment configuration
ParameterTypeDefaultDescription
environmentmainnet | testnetmainnetNetwork to connect to
Override chain configuration
ParameterTypeDefault (mainnet)Default (testnet)Description
chainConfig.idstring101103Chain identifier
chainConfig.namestringSUISUITestnetHuman-readable chain name
chainConfig.rpcEndpointstringhttps://fullnode.mainnet.sui.io:443https://fullnode.testnet.sui.io:443RPC endpoint URL
Override Bolt package ID
ParameterTypeDefault (mainnet)Description
packageIdstring0x0c6b6b0ec858d76381f7f5f787eb8cd6479d65df24ca6f726e9ae246d4ace339Bolt protocol package ID
Override Outpost contract address
ParameterTypeDefault (mainnet)Description
contracts.oraclestring0xfa3975b98f3d0e3df18ed88ae6e69db31836b3f4212df02fae144b1e5a89ca8eOracle contract address
Override assets configuration
ParameterTypeDescription
assetsConfigRecord<string, Asset>Custom asset configurations indexed by denomination
type Asset = {
  symbol: string;        // Asset symbol (e.g., 'SUI', 'USDC')
  name: string;          // Full asset name (e.g., 'Sui', 'Circle USDC')
  chainId: string;       // Chain identifier
  denom: string;         // Asset denomination/address
  decimals: number;      // Number of decimal places
  logo?: string;         // Optional logo URL
  coingeckoId?: string;  // Optional CoinGecko identifier
};
Override SUI client
ParameterTypeDescription
suiClientSuiClientPre-existing SuiClient instance for blockchain interactions
import { SuiClient } from '@mysten/sui/client';

// Create custom Sui client with specific configuration
const customSuiClient = new SuiClient({
  url: 'https://custom-rpc.example.com',
});

const client = new BoltSuiClient({
  suiClient: customSuiClient
});

Get oracle config

getOracleConfig()Retrieves the current configuration settings from the Bolt Oracle smart contract on Sui. This configuration governs how price feeds are managed, including update thresholds, expiration times, and administrative settings.
async getOracleConfig(): Promise<OracleConfig>
Usage example
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

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);
// 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;
}
async function monitorOracleConfig() {
  const config = await client.getOracleConfig();

  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 execution layer by querying oracle asset pairs and enriching them with additional metadata from the client’s asset configuration.
async getAssets(): Promise<Asset[]>
Usage example
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

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 suiAsset = assets.find((a) => a.symbol === 'SUI');
console.log(`SUI type: ${suiAsset?.denom}`); // "0x2::sui::SUI"

getAllOracleAssetPairs()Queries the oracle smart contract to retrieve all supported asset pairs with automatic pagination. Each asset pair represents a base/quote relationship that can be used for price queries and swaps.
async getAllOracleAssetPairs(): Promise<OracleAssetPair[]>
Usage example
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
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 authorised price feeders and validated against configured thresholds.
async getPrice(baseDenom: string, quoteDenom: string): Promise<InvertiblePrice>
Usage example
// Get SUI/USDC price
const price = await client.getPrice(
  '0x2::sui::SUI',
  '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
);

console.log(`SUI/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 for a specific pool. Fetches current liquidity levels for the base asset in the specified pool.
async getPoolBaseLiquidity(poolContractAddress: string): Promise<BaseLiquidityDetails>
Usage example
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

const poolAddress = "0x...";
const liquidity = await client.getPoolBaseLiquidity(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 { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

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 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 execution layer.
async getAllPools(): Promise<Pool[]>
Usage example
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 suiPools = allPools.filter(pool =>
  pool.baseDenom === "0x2::sui::SUI"
);
console.log(`SUI pools found: ${suiPools.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
const poolAddress = "0x1234567890abcdef...";
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/quote asset pair on Sui. Fetches pool details for the pool matching the provided asset denominations.
async getPoolByDenom(baseDenom: string, quoteDenom: string): Promise<Pool>
Usage example
// Get pool for SUI/USDC pair on the Bolt Sui Outpost
const pool = await client.getPoolByDenom(
  '0x2::sui::SUI',
  '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
);

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 pool configuration by base/quote asset pair. This is a convenience function that combines pool lookup and configuration retrieval.
async getPoolConfigByDenom(baseDenom: string, quoteDenom: string): Promise<PoolConfig>
Usage example
// Get pool configuration for SUI/USDC pair on the Bolt Sui Outpost
const config = await client.getPoolConfigByDenom(
  '0x2::sui::SUI',
  '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
);

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('Authorised LPs:', config.lps.length);
console.log('Min Base Out:', config.minBaseOut);

Simulate a swap

simulateSwap() Simulates a swap operation to calculate the expected output amount without executing the transaction. Performs a dry run taking into account current pool conditions, oracle prices, and fees. Use this for accurate estimates before executing.
async simulateSwap(params: SwapParams): Promise<SimulateSwapResult>
Usage example
// Simulate swapping 1 SUI for USDC
const simulation = await client.simulateSwap({
  assetIn: "0x2::sui::SUI",
  amountIn: "1000000000", // 1 SUI (9 decimals)
  assetOut: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::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.dynamicFeePercentage) {
  console.log(`Dynamic fee: ${simulation.dynamicFeePercentage}`);
}
console.log(`Total fees: ${simulation.totalFees}`);

Execute a swap

swap() Executes a token swap transaction on the Bolt execution layer through the router contract. It performs a “swap exact in” operation where you specify exactly how much of the input asset to swap, and receive a variable amount of the output asset based on current pool conditions.
async swap(params: SwapParams, signer: Signer): Promise<SwapResult<SuiTransactionBlockResponse>>

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
  swapType?: 'buy' | 'sell'; // Optional swap type to execute on the pool, defaults to 'buy'
};

Usage examples

import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

const client = new BoltSuiClient();

// Get signer from wallet (e.g., Sui Wallet, Suiet, etc.)
const signer: Signer = // ... obtain signer from wallet

try {
  const result = await client.swap({
    assetIn: "0x2::sui::SUI",
    amountIn: "1000000000", // 1 SUI (9 decimals)
    assetOut: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
  }, 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);
}
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

const client = new BoltSuiClient();
const signer: Signer = // ... obtain signer from wallet

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

try {
  const result = await client.swap({
    assetIn: "0x2::sui::SUI",
    amountIn: "1000000000", // 1 SUI (9 decimals)
    assetOut: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
    minimumAmountOut,
  }, signer);

  console.log(`Minimum: ${minimumAmountOut} USDC`);
  console.log(`Received: ${result.amountOut} USDC`);
} catch (error) {
  console.error('Swap failed:', error.message);
}
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

const client = new BoltSuiClient();
const signer: Signer = // ... obtain signer from wallet

const receiver = "0x..."; // Custom recipient

try {
  const result = await client.swap({
    assetIn: "0x2::sui::SUI",
    amountIn: "1000000000", // 1 SUI (9 decimals)
    assetOut: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
    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

// 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);
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));
    }
  }
}
// Get signer from wallet (implementation depends on wallet)
const signer: Signer = await getSuiWalletSigner();

const result = await client.estimateSwapGasFees(
  {
    assetIn: "0x2::sui::SUI",
    amountIn: '10000',
    assetOut: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
  },
  signer
);

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

Error Handling

The SDK provides custom error types for better error handling:

Error Type

Error Description

NotFoundErrorResource not found
InvalidParameterErrorInvalid parameter provided
InvalidObjectErrorInvalid object structure
InvalidTypeErrorInvalid type provided
MissingParameterErrorRequired parameter missing
TransactionFailedErrorTransaction execution failed
ParseErrorFailed to parse response data

Sui Outpost Addresses

Contract addresses for mainnet and testnet.

Off-Chain Quoting

Build price discovery using deterministic quoting.

Contract Math

Understand the pricing formula behind simulateSwap().

Pool State Indexing

Index pool state for real-time integration.