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.
// Get all supported assetsconstassets=awaitclient.getAssets();assets.forEach((asset) => {console.log(`${asset.symbol} (${asset.name}): ${asset.denom}`);console.log(` Decimals: ${asset.decimals}`);});// Find a specific assetconstsuiAsset=assets.find((a) =>a.symbol ==='SUI');console.log(`SUI type: ${suiAsset?.denom}`); // "0x2::sui::SUI"
5
Execute a swap
importtype { Signer } from'@mysten/sui/cryptography';// Get signer from wallet (implementation depends on wallet)constsigner:Signer=awaitgetSuiWalletSigner();// Execute a swap: exactly 1 SUI for USDCconstresult=awaitclient.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}`);
import { DirectSecp256k1HdWallet } from'@cosmjs/proto-signing';// Get signer from wallet (implementation depends on wallet)constsigner=awaitDirectSecp256k1HdWallet.fromMnemonic("my mnemonic goes here", { prefix:'archway',});// Execute a swap: exactly 1 SUI for USDCconstresult=awaitclient.swap(signer, { assetIn:'aarch', amountIn:'1000000000000000000',// 1 ARCH (18 decimals) assetOut:'ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D',// USDC minimumAmountOut:'1900000',// Minimum 1.9 USDC (6 decimals)});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 { BoltSuiClient } from'@bolt-liquidity-hq/sui-client';// Initialize clientconstclient=newBoltSuiClient({ environment:'testnet',// 'testnet' | 'mainnet' customOverride: { rpcEndpoint:'https://my-custom-rpc-endpoint...',// Remove this if you want to use the default public RPC endpoint }});
import { BoltCosmWasmClient } from'@bolt-liquidity-hq/cosmwasm-client';// Initialize clientconstclient=newBoltCosmWasmClient({ environment:'testnet',// 'testnet' | 'mainnet' customOverride: { rpcEndpoint:'https://my-custom-rpc-endpoint...',// Remove this if you want to use default public RPC endpoint }});
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>
Returns a Promise object containing the oracle's configuration parameters:
type OracleConfig = {
admin: Address; // The Sui address authorized to update oracle settings and prices
priceThresholdRatio: string; // Minimum price change ratio required for updates (as decimal string)
priceExpireTime: Duration | null; // Time duration before prices become stale
};
type Duration = {
secs: number; // Seconds component
nanos: number; // Nanoseconds component (always 0 in current implementation)
};
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[]>
type Asset = {
symbol: string; // Trading symbol (e.g., "SUI", "USDC")
name: string; // Full asset name (e.g., "Sui", "USD Coin")
chainId: string; // Blockchain network identifier
denom: string; // Chain-specific denomination
decimals: number; // Number of decimal places
logo?: string; // Optional logo URL
coingeckoId?: string; // Optional CoinGecko identifier
};
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.
type OracleAssetPair = {
base: OracleAsset; // Base asset information
quote: OracleAsset; // Quote asset information
};
type OracleAsset = {
name: string; // Asset name (currently same as symbol)
symbol: string; // Trading symbol (e.g., "SUI", "ETH")
precision: number; // Number of decimal places
};
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[]>
type Price = {
assetPair: string; // Currently empty string due to contract limitations
price: string; // Current price as decimal string
expiryTime: string; // Unix timestamp in nanoseconds when price expires
};
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.
type InvertiblePrice = {
assetPair: string; // Trading pair in format "baseDenom:quoteDenom"
price: string; // Current price as decimal string
expiryTime: string; // Unix timestamp in nanoseconds when price expires
isInverse: boolean; // Always false in current implementation
};
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.
type BaseLiquidityDetails = {
baseLiquidity: Coin; // Base asset liquidity information
totalShares: string; // Total liquidity shares
};
type Coin = {
amount: string; // Quantity of base asset liquidity
denom: string; // Type of the base asset
};
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>
type RouterConfig = {
admin: string; // Sui address with administrative privileges
defaultPriceOracleContract: string; // Object ID of default price oracle
defaultProtocolFeeRecipient: string; // Sui address that receives protocol fees
defaultProtocolFee: string; // Protocol fee percentage (e.g., "0.003" = 0.3%)
defaultLpFee: string; // LP fee percentage (e.g., "0.002" = 0.2%)
};
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[]>
type Pool = {
poolAddress: string; // Sui object ID of the market/pool
baseDenom: string; // Type of the base asset
quoteDenoms: string[]; // Array of available quote asset types
};
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.
type PoolConfig = {
priceOracleContract: string; // Object ID of price oracle used by this pool
protocolFeeRecipient: string; // Sui address that receives protocol fees
protocolFee: string; // Protocol fee percentage (e.g., "0.003" = 0.3%)
lpFee: string; // LP fee percentage (e.g., "0.002" = 0.2%)
allowanceMode: string; // Allowance mode for pool operations
lps: string[]; // Array of authorized LP Sui addresses
minBaseOut: string; // Minimum base asset output amount for trades
};
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.
type Pool = {
poolAddress: string; // Sui object ID of the market/pool
baseDenom: string; // Type of the base asset
quoteDenoms: string[]; // Array of available quote asset types
};
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.
type PoolConfig = {
priceOracleContract: string; // Object ID of price oracle used by this pool
protocolFeeRecipient: string; // Sui address that receives protocol fees
protocolFee: string; // Protocol fee percentage (e.g., "0.003" = 0.3%)
lpFee: string; // LP fee percentage (e.g., "0.002" = 0.2%)
allowanceMode: string; // Allowance mode for pool operations
lps: string[]; // Array of authorized LP Sui addresses
minBaseOut: string; // Minimum base asset output amount for trades
};
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
};
type SwapResult<SuiTransactionBlockResponse> = {
txOutput: SuiTransactionBlockResponse; // Complete transaction response
amountOut: string; // Actual amount of output asset received
assetOut: string; // Output asset denomination
txHash: string; // Transaction hash for tracking
};
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;
}
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: