Bolt SUI TypeScript SDK

Integrate with Bolt Liquidity Protocol 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/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', // 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';

// Initialize 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
    }
  }
});
Advanced client initialization
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

// Initialize client
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

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

101

103

Chain identifier

chainConfig.name

string

SUI

SUITestnet

Human-readable chain name

Override Bolt package ID

Parameter
Type
Default (mainnet)
Description

packageId

string

0xbffcccd9d24e319c729e724a0a0e6d0a403b24a03f643da4bbdb0fe6c925f82b

Bolt protocol package ID

Override Outpost contract address

Parameter
Type
Default (mainnet)
Description

contracts.oracle

string

0xfa3975b98f3d0e3df18ed88ae6e69db31836b3f4212df02fae144b1e5a89ca8e

Oracle 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., '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

Parameter
Type
Description

suiClient

SuiClient

Pre-existing SuiClient instance to use 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',
  // Additional Sui client options...
});

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

Get oracle config

getOracleConfig()

The getOracleConfig method retrieves the current configuration settings from the Bolt Liquidity Protocol's Oracle smart contract on the Sui blockchain. 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';

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

// 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 { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

// 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 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 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 SUI/USDC price
const price = await client.getPrice(
  '0x2::sui::SUI',
  '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::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 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 { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

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

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 { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';

const client = new BoltSuiClient();

// 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 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 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

// Get pool configuration by contract address
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 asset on the Archway Blockchain, or a specific base/quote asset pair on the Sui Blockchain. Fetches pool details for the pool matching the provided asset denom(s).

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

Usage example

// Get pool for USDC/SUI 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 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 Sui Blockchain. 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 for USDC/SUI 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('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 SUI for USDC
const simulation = await client.simulateSwap({
  assetIn: "0x2::sui::SUI",
  amountIn: "1000000000", // 1 SUI (9 decimals)
  assetOut: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::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.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<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
};

Basic usage examples

Simple swap
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", // 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);
}
Swap with minimum amount out limit
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

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", // USDC
    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 { 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

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", // 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

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
// 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');
}
Transaction monitoring
async function monitorSwapTransaction(txHash: string) {
  const maxAttempts = 30; // 30 seconds
  let attempts = 0;

  while (attempts < maxAttempts) {
    try {
      const txResponse = await client.suiClient.getTransactionBlock({
        digest: txHash,
        options: { showEffects: true, showEvents: true }
      });

      if (txResponse.effects?.status.status === 'success') {
        console.log('✅ Transaction confirmed successfully');
        return txResponse;
      } else if (txResponse.effects?.status.status === 'failure') {
        throw new Error(`Transaction failed: ${txResponse.effects.status.error}`);
      }

    } catch (error) {
      console.log(`Transaction not yet confirmed (attempt ${attempts + 1}/${maxAttempts})`);
    }

    attempts++;
    await new Promise(resolve => setTimeout(resolve, 1000));
  }

  throw new Error('Transaction monitoring timeout');
}
Balance validation
async function validateSwapBalance(signer: Signer, assetIn: string, amountIn: string) {
  const address = await signer.getAddress();

  // Get balance for the specific asset
  const balance = await client.suiClient.getBalance({
    owner: address,
    coinType: assetIn
  });

  const requiredAmount = BigInt(amountIn);
  const currentBalance = BigInt(balance.totalBalance);

  if (currentBalance < requiredAmount) {
    throw new Error(`Insufficient balance: ${currentBalance} < ${requiredAmount}`);
  }

  console.log(`✅ Sufficient balance: ${currentBalance} >= ${requiredAmount}`);
  return true;
}

// Use before swap
await validateSwapBalance(signer, assetIn, amountIn);
const result = await client.swap(params, signer);

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