Bolt API
This documentation outlines the integration interface for existing Swap Providers wanting to use the Bolt Liquidity API for immediate settlement of best pricing on Sui.
Bolt also provides a TypeScript SDK for easy integration, see Bolt SDK.
Overview
As a Swap Provider, you interact with the PublicSettlementService
to discover Bolt Liquidity pools, create orders, and monitor trade execution. Trade settlement is handled by third-party Order Settlers who are monitoring incoming orders and executing at best price.
Public API Interface
Endpoint = *coming soon*
service PublicSettlementService {
rpc GetPools(GetPoolsRequest) returns (GetPoolsResponse);
rpc GetPool(GetPoolRequest) returns (GetPoolResponse);
rpc GetPoolByBaseAsset(GetPoolByBaseAssetRequest) returns (GetPoolByBaseAssetResponse);
rpc GetBalances(GetBalancesRequest) returns (GetBalancesResponse);
rpc GetTrade(GetTradeRequest) returns (GetTradeResponse);
rpc SubscribeTrades(SubscribeTradesRequest) returns (stream SubscribeTradesResponse);
rpc SettlementInfo(SettlementInfoRequest) returns (SettlementInfoResponse);
}
Core Data Structures
Pool
message Pool {
string base_asset = 1; // The main asset managed by the pool
string base_amount = 2; // Total amount of base asset in pool
repeated string quote_assets = 3; // Assets that can be used to acquire base
string lp_fee_ratio = 4; // Fee paid to liquidity providers
string protocol_fee_ratio = 5; // Fee paid to protocol
string min_base_out = 6; // Minimum amount of base that can be swapped
}
Trade
message Trade {
string id = 1; // Unique trade identifier
Balance input = 2; // Input asset and amount
Balance output = 3; // Output asset and amount
string source = 4; // Source of the trade (pool ID)
Balance fee = 5; // Fee paid for the trade
string sender = 6; // Trade initiator
uint64 height = 7; // Block height when trade occurred
}
Sync Settlement Flow
The Bolt API primarily uses an order-based synchronous settlement system across a range of assets per chain outpost
1. Pool Discovery
// Get all available pools
let pools_response = client.get_pools(GetPoolsRequest {}).await?;
let available_pools = pools_response.pools;
// Find a specific pool by base asset
let eth_pool_response = client.get_pool_by_base_asset(
GetPoolByBaseAssetRequest {
base_asset: "ETH".to_string()
}
).await?;
let eth_pool = eth_pool_response.pool;
// TypeScript
const poolsResponse = await client.getPools({});
const availablePools = poolsResponse.pools;
const ethPoolResponse = await client.getPoolByBaseAsset({
baseAsset: "ETH"
});
const ethPool = ethPoolResponse.pool;
2. Calculate Swap Details
// Get user balance
let balance_response = client.get_balances(
GetBalancesRequest {
user: "0xUSER_ADDRESS".to_string(),
base_asset: "ETH".to_string()
}
).await?;
// Get oracle price and calculate amounts
let price = price_oracle_client.get_price("USDC", "ETH").await?;
let input_amount = 1000.0; // 1000 USDC
let expected_output = input_amount * price.price * (1.0 - eth_pool.lp_fee_ratio - eth_pool.protocol_fee_ratio);
3. Create Order
Orders are the primary mechanism for executing trades. The order is created by the Swap Provider and settled by a third party Order Settler.
// Create order with attached funds
let create_order_resp = client.create_order(
ctx_with_funds, // Context with 1000 USDC attached
CreateOrderRequest {
wanted_asset: "ETH".to_string(),
limit_price: Some(price.price * 0.99), // 1% slippage
expiry_time: Some(UtcTime(current_time + 300000)) // 5 min expiry
}
).await?;
let order_id = create_order_resp.order_id;
// TypeScript
const createOrderResp = await client.createOrder(
{
wantedAsset: "ETH",
limitPrice: price * 0.99, // 1% slippage
expiryTime: Date.now() + 300000 // 5 min expiry
},
{ funds: { denom: "USDC", amount: "1000.0" } }
);
const orderId = createOrderResp.orderId;
4. Monitor Order Status
After submitting an order via Bolt, you can track its status to determine when it's settled.
// Poll for trade status
async fn wait_for_settlement(client: &PublicClient, order_id: &str) -> Result<Trade> {
let mut attempts = 0;
while attempts < 10 {
// Try to get trade info
let resp = client.get_trade(
GetTradeRequest {
id: order_id.to_string()
}
).await?;
if let Some(trade) = resp.trade {
return Ok(trade);
}
tokio::time::sleep(Duration::from_millis(1000)).await;
attempts += 1;
}
Err(anyhow::anyhow!("Trade settlement timeout"))
}
// TypeScript
async function waitForSettlement(client, orderId) {
for (let i = 0; i < 10; i++) {
try {
const resp = await client.getTrade({ id: orderId });
if (resp.trade) {
return resp.trade;
}
} catch (e) {
// Handle error or continue
}
await new Promise(r => setTimeout(r, 1000));
}
throw new Error("Trade settlement timeout");
}
5. Subscribe to Trade Events
For real-time updates on trades occurring in the pools:
// Subscribe to all trade events
let mut stream = client.subscribe_trades(SubscribeTradesRequest {}).await?;
while let Some(trade_event) = stream.message().await? {
println!("New trade: {} {} → {} {}",
trade_event.trade.input.amount, trade_event.trade.input.denom,
trade_event.trade.output.amount, trade_event.trade.output.denom);
// Handle the trade event (update UI, etc.)
}
Error Handling
match client.create_order(ctx, request).await {
Ok(response) => {
// Order created successfully
handle_new_order(response.order_id);
},
Err(e) if e.to_string().contains("pair not found") => {
// No trading pair available
display_error("This trading pair is not supported");
},
Err(e) if e.to_string().contains("order already expired") => {
// Expiry time in the past
display_error("Invalid order expiry time");
},
Err(e) => {
// Handle other errors
log::error!("Order creation failed: {}", e);
display_error("Failed to create order");
}
}
Best Practices
Trade Simulation - Before submitting a real order, simulating a trade on the frontend is advised
Validate Assets First - Check that both assets are supported by Bolt before creating orders
Handle Failed Settlements - Implement fallback logic when orders aren't settled in time
Cache Pool Information - Reduce API calls by caching pool data with short TTL
Event Types
NewOrderEvent
Emitted when an order is created
OrderSettledEvent
Emitted when an order is successfully settled
ZapEvent
Emitted when a direct swap occurs
Last updated