Bolt TypeScript SDK

Integrate with Bolt Liquidity Protocol using TypeScript across multiple blockchain networks (Archway, SUI).

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

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

Yarn

yarn install @bolt-liquidity-hq/sui-client

PNPM

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

Initialize the Bolt Client

The SDK supports different environments:

type Environment = 'mainnet' | 'testnet';

Mainnet

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

const client = new BoltSuiClient();

Testnet

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

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

Execute a swap

import type { Signer } from '@mysten/sui/cryptography';

// 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(signer, {
  assetIn: '0x2::sui::SUI',
  amountIn: '1000000000', // 1 SUI (9 decimals)
  assetOut: '0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN', // USDC
  minimumAmountOut: '1900000', // Minimum 1.9 USDC (6 decimals)
});

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: 'testnet', // 'testnet' | 'mainnet'
  customOverride: {
    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: 'testnet',
  customOverride: {
    chainConfig: {
      id: 'sui-mainnet',
      name: 'Sui',
      rpcEndpoint: 'https://fullnode.mainnet.sui.io:443',
    },
    packageId: '0x1234...',
    contracts: {
      oracle: '0xoracle...',
      router: '0xrouter...',
    },
    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 Outpost contract address

Parameter
Type
Default (mainnet)
Default (testnet)
Description

contracts.oracle

string

0x...

0xecece01cfb23b5439e04b18fe656eaf2746b9087cf68f1d48797c8f71a3dd93b

Oracle contract address

contracts.router

string

0x...

0x3881fdcb4a7fbcda8edc230e6f92eb57b24c0be6b44af0b5e1d0b45564f3ed00

Router contract address

Override Bolt package ID

Parameter
Type
Default (mainnet)
Default (testnet)
Description

packageId

string

0x...

0x22384b1841229e2be878bb7e88833c03e23ff5dc39accd050fb932120602f85e

Bolt protocol package ID

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({ environment: 'testnet' });

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

  const health = {
    hasAdmin: !!config.admin,
    reasonableThreshold: parseFloat(config.priceThresholdRatio) > 0.001,
    reasonableExpiry: config.priceExpireTime?.secs > 300, // > 5 minutes
    isValid: true
  };

  health.isValid = health.hasAdmin && health.reasonableThreshold && health.reasonableExpiry;

  return health;
}
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({ environment: 'testnet' });

// 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',
  '0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN' // 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

getAllBaseAssetsLiquidity()

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 getAllBaseAssetsLiquidity(): Promise<Record<Address, BaseLiquidityDetails>>

Usage example

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

const client = new BoltSuiClient({ environment: 'testnet' });

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

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);

getAllPools()

Queries the router smart contract to retrieve information about all deployed pools with automatic pagination. Fetches a comprehensive list of all markets/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 for a settlement contract (liquidity pool). Queries a settlement 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);

getPoolByBaseAsset()

Queries the router smart contract to retrieve pool information for a specific base asset. Fetches market/pool details for a given base asset type.

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

Usage example

// Get pool for SUI base asset
const pool = await client.getPoolByBaseAsset('0x2::sui::SUI');

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}`);
});

getPoolConfigByBaseAsset()

Retrieves the configuration settings for a settlement contract identified by its base asset type. This is a convenience function that combines pool lookup and configuration retrieval.

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

Usage example

// Get pool configuration for SUI base asset
const config = await client.getPoolConfigByBaseAsset('0x2::sui::SUI');

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);

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(signer: Signer, params: SwapParams): 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';

async function simpleSwap() {
  const client = new BoltSuiClient({ environment: 'testnet' });

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

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

    console.log('Swap successful!');
    console.log(`Transaction hash: ${result.txHash}`);
    console.log(`Received: ${result.amountOut} ${result.assetOut}`);
    console.log(`Gas cost: ${result.txOutput.effects.gasUsed.computationCost}`);
  } catch (error) {
    console.error('Swap failed:', error.message);
  }
}
Swap with slippage protection
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

async function swapWithSlippageProtection() {
  const client = new BoltSuiClient({ environment: 'mainnet' });
  const signer: Signer = // ... obtain signer from wallet

  // Get current price to calculate minimum output
  const price = await client.getPrice(
    "0x2::sui::SUI",
    "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN"
  );

  const amountIn = "1000000000"; // 1 SUI
  const expectedOutput = BigInt(amountIn) * BigInt(price.price) / BigInt(10 ** 9);
  const slippageTolerance = 0.01; // 1%
  const minimumAmountOut = (expectedOutput * BigInt(99) / BigInt(100)).toString();

  const result = await client.swap(signer, {
    assetIn: "0x2::sui::SUI",
    amountIn,
    assetOut: "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
    minimumAmountOut,
  });

  console.log(`Expected: ${expectedOutput} USDC`);
  console.log(`Minimum: ${minimumAmountOut} USDC`);
  console.log(`Received: ${result.amountOut} USDC`);
}
Swap with custom receiver
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

async function swapToCustomReceiver() {
  const client = new BoltSuiClient({ environment: 'testnet' });
  const signer: Signer = // ... obtain signer from wallet

  const result = await client.swap(signer, {
    assetIn: "0x2::sui::SUI",
    amountIn: "500000000", // 0.5 SUI
    assetOut: "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
    receiver: "0x9876543210fedcba...", // Custom recipient
  });

  console.log(`Swapped to address: ${result.txOutput.effects.status.status}`);
}

Advanced usage examples

Batch swaps with error handling
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

async function batchSwaps() {
  const client = new BoltSuiClient({ environment: 'mainnet' });
  const signer: Signer = // ... obtain signer from wallet

  const swaps = [
    {
      assetIn: "0x2::sui::SUI",
      amountIn: "1000000000",
      assetOut: "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
      description: "SUI to USDC"
    },
    {
      assetIn: "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
      amountIn: "2000000",
      assetOut: "0x2::sui::SUI",
      description: "USDC to SUI"
    }
  ];

  const results = [];

  for (const swap of swaps) {
    try {
      console.log(`Executing: ${swap.description}`);

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

      results.push({
        success: true,
        description: swap.description,
        amountOut: result.amountOut,
        txHash: result.txHash
      });

      console.log(`✅ ${swap.description}: ${result.amountOut}`);

      // Wait between swaps to avoid rate limiting
      await new Promise(resolve => setTimeout(resolve, 2000));

    } catch (error) {
      results.push({
        success: false,
        description: swap.description,
        error: error.message
      });

      console.error(`❌ ${swap.description}: ${error.message}`);
    }
  }

  return results;
}
Smart swap with price monitoring
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

class SmartSwap {
  private client: BoltSuiClient;
  private signer: Signer;
  private priceHistory: Map<string, number[]> = new Map();

  constructor(client: BoltSuiClient, signer: Signer) {
    this.client = client;
    this.signer = signer;
  }

  async monitorPrice(baseDenom: string, quoteDenom: string, duration: number = 60000) {
    const startTime = Date.now();
    const prices: number[] = [];

    while (Date.now() - startTime < duration) {
      try {
        const price = await this.client.getPrice(baseDenom, quoteDenom);
        prices.push(parseFloat(price.price));

        await new Promise(resolve => setTimeout(resolve, 5000)); // 5 second intervals
      } catch (error) {
        console.warn('Price monitoring error:', error.message);
      }
    }

    this.priceHistory.set(`${baseDenom}:${quoteDenom}`, prices);
    return this.calculateOptimalSlippage(prices);
  }

  private calculateOptimalSlippage(prices: number[]): number {
    if (prices.length < 2) return 0.01; // Default 1%

    const volatility = Math.std(prices);
    const avgPrice = prices.reduce((a, b) => a + b, 0) / prices.length;
    const volatilityRatio = volatility / avgPrice;

    // Higher volatility = higher slippage tolerance
    return Math.min(Math.max(volatilityRatio * 2, 0.005), 0.05); // 0.5% to 5%
  }

  async executeOptimalSwap(params: SwapParams) {
    // Monitor price for 1 minute
    const slippage = await this.monitorPrice(params.assetIn, params.assetOut, 60000);

    // Get current price
    const price = await this.client.getPrice(params.assetIn, params.assetOut);
    const expectedOutput = BigInt(params.amountIn) * BigInt(price.price) / BigInt(10 ** 9);
    const minimumAmountOut = (expectedOutput * BigInt(Math.floor((1 - slippage) * 1000)) / BigInt(1000)).toString();

    console.log(`Optimal slippage: ${(slippage * 100).toFixed(2)}%`);
    console.log(`Minimum output: ${minimumAmountOut}`);

    return await this.client.swap(this.signer, {
      ...params,
      minimumAmountOut
    });
  }
}

// Usage
const smartSwap = new SmartSwap(client, signer);
const result = await smartSwap.executeOptimalSwap({
  assetIn: "0x2::sui::SUI",
  amountIn: "1000000000",
  assetOut: "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN"
});
DEX aggregator pattern
import { BoltSuiClient } from '@bolt-liquidity-hq/sui-client';
import type { Signer } from '@mysten/sui/cryptography';

class DexAggregator {
  private client: BoltSuiClient;
  private signer: Signer;

  constructor(client: BoltSuiClient, signer: Signer) {
    this.client = client;
    this.signer = signer;
  }

  async findBestRoute(assetIn: string, assetOut: string, amountIn: string) {
    // Get all pools
    const pools = await this.client.getAllPools();

    // Find pools that support this pair
    const relevantPools = pools.filter(pool =>
      (pool.baseDenom === assetIn && pool.quoteDenoms.includes(assetOut)) ||
      (pool.baseDenom === assetOut && pool.quoteDenoms.includes(assetIn))
    );

    // Get liquidity for each pool
    const liquidity = await this.client.getAllBaseAssetsLiquidity();

    // Calculate expected output for each route
    const routes = await Promise.all(
      relevantPools.map(async pool => {
        try {
          const price = await this.client.getPrice(assetIn, assetOut);
          const expectedOutput = BigInt(amountIn) * BigInt(price.price) / BigInt(10 ** 9);

          return {
            pool,
            expectedOutput: expectedOutput.toString(),
            liquidity: liquidity[pool.baseDenom]?.baseLiquidity.amount || "0"
          };
        } catch {
          return null;
        }
      })
    );

    // Filter out failed routes and sort by expected output
    return routes
      .filter(route => route !== null)
      .sort((a, b) => BigInt(b!.expectedOutput) - BigInt(a!.expectedOutput));
  }

  async executeBestSwap(assetIn: string, assetOut: string, amountIn: string) {
    const routes = await this.findBestRoute(assetIn, assetOut, amountIn);

    if (routes.length === 0) {
      throw new Error('No valid swap routes found');
    }

    const bestRoute = routes[0];
    console.log(`Best route: ${bestRoute.expectedOutput} expected output`);

    // Execute swap with 1% slippage tolerance
    const minimumAmountOut = (BigInt(bestRoute.expectedOutput) * BigInt(99) / BigInt(100)).toString();

    return await this.client.swap(this.signer, {
      assetIn,
      amountIn,
      assetOut,
      minimumAmountOut
    });
  }
}

// Usage
const aggregator = new DexAggregator(client, signer);
const result = await aggregator.executeBestSwap(
  "0x2::sui::SUI",
  "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
  "1000000000"
);

Best practices

Slippage protection
// Always set minimumAmountOut to protect against slippage
const calculateMinimumOutput = (amountIn: string, price: string, slippageTolerance: number = 0.01) => {
  const expectedOutput = BigInt(amountIn) * BigInt(price) / BigInt(10 ** 9);
  return (expectedOutput * BigInt(Math.floor((1 - slippageTolerance) * 1000)) / BigInt(1000)).toString();
};

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

const result = await client.swap(signer, {
  assetIn,
  amountIn,
  assetOut,
  minimumAmountOut
});
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(signer, params);

      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
async function estimateSwapGas(params: SwapParams) {
  // Get current gas price
  const gasPrice = await client.suiClient.getReferenceGasPrice();

  // Estimate gas for swap (this would be implemented when contracts are ready)
  const estimatedGas = 1000000; // Placeholder

  const gasCost = estimatedGas * gasPrice;

  console.log(`Estimated gas cost: ${gasCost} MIST`);
  return gasCost;
}

// Use in swap
const gasCost = await estimateSwapGas(params);
if (gasCost > 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(signer, params);

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

Key Differences between SUI and CosmWasm Client

  • Asset Identification: Uses Sui type strings (e.g., 0x2::sui::SUI) instead of denoms

  • Decimals: SUI uses 9 decimals vs 6 for many CosmWasm assets

  • Transaction Output: Returns SuiTransactionBlockResponse with Sui-specific fields

  • Signer Type: Uses Sui's Signer interface instead of OfflineSigner

SUI-specific Features

Object IDs

All contracts and pools are identified by Sui object IDs:

const poolAddress = '0x1234abcd...'; // Sui object ID

Type Arguments

Many functions use Sui's type system:

const suiType = '0x2::sui::SUI';
const customCoinType = '0xpackage::module::COIN';

Gas and Effects

Transaction results include Sui-specific information:

const gasUsed = result.txOutput.effects.gasUsed.computationCost;
const status = result.txOutput.effects.status.status;

Resources

Bolt TS SDK Reference

Github