# Bolt Archway TypeScript SDK

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

{% stepper %}
{% step %}
**Prerequisites**

Before using the SDK, make sure you have:

* [x] Node.js 18+ installed.
* [x] An Archway-compatible wallet (Keplr, Leap, etc.) for signing transactions.
* [x] Access to Archway RPC endpoints (The client uses by default the public endpoint `https://rpc.mainnet.archway.io` for `mainnet`, and `https://rpc.constantine.archway.io` for `testnet`)
  {% endstep %}

{% step %}
**Installation**

{% tabs %}
{% tab title="NPM" %}

```bash
npm install @bolt-liquidity-hq/cosmwasm-client
```

{% endtab %}

{% tab title="YARN" %}

```bash
yarn add @bolt-liquidity-hq/cosmwasm-client
```

{% endtab %}

{% tab title="PNPM" %}

```bash
pnpm add @bolt-liquidity-hq/cosmwasm-client
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}
**Initialize the Bolt Client**

The SDK supports different environments:

```typescript
type Environment = 'mainnet' | 'testnet';
```

**Mainnet**

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();
```

**Testnet**

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient({
  environment: 'testnet',
});
```

{% endstep %}

{% step %}
**Query all assets**

```typescript
// 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 archAsset = assets.find((a) => a.symbol === 'ARCH');
console.log(`ARCH denom: ${archAsset?.denom}`); // "aarch"
```

{% endstep %}

{% step %}
**Execute a swap**

```typescript
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';

// Get signer from wallet (implementation depends on wallet)
const signer = await DirectSecp256k1HdWallet.fromMnemonic("my mnemonic goes here", {
  prefix: 'archway',
});

// Execute a swap: exactly 1 ARCH for USDC
const result = await client.swap({
  assetIn: 'aarch',
  amountIn: '1000000000000000000', // 1 ARCH (18 decimals)
  assetOut: 'ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D', // USDC
  minimumAmountOut: '1900000', // Minimum 1.9 USDC (6 decimals)
, signer});

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

{% endstep %}
{% endstepper %}

## API

### Client Initialization

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

// Initialize client
const client = new BoltCosmWasmClient({
  environment: 'mainnet', // 'testnet' | 'mainnet'
  customOverride: {  
    chainConfig: {
      rpcEndpoint: 'https://my-custom-rpc-endpoint...', // Remove this if you want to use default public RPC endpoint
    }
  }
});
```

<details>

<summary>Advanced client initialization</summary>

<pre class="language-typescript"><code class="lang-typescript"><strong>import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
</strong>
// Initialize client
const customClient = new BoltCosmWasmClient({
  customOverride: {
    chainConfig: {
      id: 'archway-custom-1',
      name: 'Archway Custom',
      rpcEndpoint: 'https://custom-rpc.example.com',
      restEndpoint: 'https://custom-rest.example.com'
     },
     contracts: {
       oracle: 'archway1custom_oracle...',
       router: 'archway1custom_router...'
     },
     nativeTokenDenom: 'aarch',
     assetsConfig: {
       'aarch': {
         symbol: 'ARCH',
         name: 'Archway',
         chainId: 'archway-custom-1',
         denom: 'aarch',
         decimals: 18,
         logo: 'https://example.com/arch.png',
         coingeckoId: 'archway'
       }
     }
   }
 });
</code></pre>

**Environment configuration**

| Parameter   | Type                   | Default   | Description                            |
| ----------- | ---------------------- | --------- | -------------------------------------- |
| environment | `mainnet` \| `testnet` | `mainnet` | Specifies to which network to connect. |

**Override chain configuration**

<table data-full-width="true"><thead><tr><th>Parameter</th><th>Type</th><th>Default (mainnet)</th><th>Default (testnet)</th><th>Description</th></tr></thead><tbody><tr><td>chainConfig.id</td><td><code>string</code></td><td>archway-1</td><td>constantine-3</td><td>Chain identifier</td></tr><tr><td>chainConfig.name</td><td><code>string</code></td><td>Archway</td><td>Archway Testnet    </td><td>Human-readable chain name</td></tr><tr><td>chainConfig.rpcEndpoint</td><td><code>string</code></td><td><a href="https://rpc.mainnet.archway.io/">https://rpc.mainnet.archway.io/</a></td><td><a href="https://rpc.constantine.archway.io/">https://rpc.constantine.archway.io/</a></td><td>RPC endpoint URL</td></tr><tr><td>chainConfig.restEndpoint</td><td><code>string</code></td><td><a href="https://api.mainnet.archway.io/">https://api.mainnet.archway.io/</a></td><td><a href="https://api.constantine.archway.io/">https://api.constantine.archway.io/</a></td><td>REST endpoint URL</td></tr></tbody></table>

**Override Outpost contract address**

<table data-full-width="true"><thead><tr><th>Parameter</th><th>Type</th><th>Default (mainnet)</th><th>Default (testnet)</th><th>Description</th></tr></thead><tbody><tr><td>contracts.oracle</td><td><code>string</code></td><td><code class="expression">space.vars.BOLT_ARCHWAY_ORACLE_MAINNET</code></td><td><code class="expression">space.vars.BOLT_ARCHWAY_ORACLE_TESTNET</code></td><td>Oracle contract address</td></tr><tr><td>contracts.router</td><td><code>string</code></td><td><code class="expression">space.vars.BOLT_ARCHWAY_ROUTER_MAINNET</code></td><td><code class="expression">space.vars.BOLT_ARCHWAY_ROUTER_TESTNET</code></td><td>Router contract address</td></tr></tbody></table>

**Override assets configuration**

<table data-full-width="true"><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>assetsConfig</td><td><code>Record&#x3C;string, Asset></code></td><td>Custom asset configurations indexed by denomination</td></tr></tbody></table>

{% code title="Asset structure" %}

```typescript
type Asset = {
  symbol: string;        // Asset symbol (e.g., 'ARCH', 'USDC')
  name: string;          // Full asset name (e.g., 'Archway', 'Circle USDC')
  chainId: string;       // Chain identifier
  denom: string;         // Asset denomination
  decimals: number;      // Number of decimal places
  logo?: string;         // Optional logo URL
  coingeckoId?: string;  // Optional CoinGecko identifier
};
```

{% endcode %}

**Override clients**

<table data-full-width="true"><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>cosmWasmClient</td><td><code>CosmWasmClient</code> | <code>ArchwayClient</code></td><td>Pre-existing query client instance to use for blockchain interactions</td></tr><tr><td>signer</td><td><code>OfflineSigner</code></td><td>Pre-existing signer</td></tr><tr><td>signingCosmWasmClient</td><td><code>SigningCosmWasmClient</code> | <code>SigningArchwayClient</code></td><td>Pre-existing signing client instance to use for signing blockchain transactions</td></tr></tbody></table>

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';

// Create custom Cosm-Wasm client with specific configuration
const customCosmWasmClient = CosmWasmClient.connect('https://custom-rpc.example.com');

const client = new BoltCosmWasmClient({
  cosmWasmClient: customCosmWasmClient
});
```

</details>

### Get oracle config

{% hint style="info" %}
**getOracleConfig()**

The `getOracleConfig` method retrieves the current configuration settings from the Bolt Liquidity Protocol's Oracle smart contract on the Archway blockchain. This configuration governs how price feeds are managed, including update thresholds, expiration times, and administrative settings.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getOracleConfig(): Promise<OracleConfig>
```

{% endtab %}

{% tab title="Returns" %}
Returns a Promise object containing the oracle's configuration parameters:

```typescript
type OracleConfig = {
  admin: Address; // The Archway 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)
};
```

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

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

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

<details>

<summary>How to cache Oracle config (best practice)</summary>

```typescript
// 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;
}
```

</details>

<details>

<summary>How to monitor for price updates</summary>

```typescript
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
}
```

</details>

### Query prices and assets

{% hint style="info" %}
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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getAssets(): Promise<Asset[]>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

// 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 archAsset = assets.find((a) => a.symbol === 'ARCH');
console.log(`ARCH denom: ${archAsset?.denom}`); // "aarch"
```

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getAllOracleAssetPairs(): Promise<OracleAssetPair[]>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

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

{% hint style="info" %}
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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getAllPrices(): Promise<Price[]>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

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

{% hint style="info" %}
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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getPrice(baseDenom: string, quoteDenom: string): Promise<InvertiblePrice>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
// Get ARCH/USDC price
const price = await client.getPrice(
  'aarch',
  'ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D' // USDC
);

console.log(`ARCH/USDC Price: ${price.price}`);
console.log(`Expires at: ${new Date(Number(price.expiryTime) / 1000000)}`);
console.log(`Asset Pair: ${price.assetPair}`);
```

### Verify pool liquidity

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getPoolBaseLiquidity(poolContractAddress: string): Promise<BaseLiquidityDetails>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

Usage example

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

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

const liquidity = await client.getAllBaseAssetsLiquidity(poolAddress);

console.log(`Base liquidity: ${liquidity.baseLiquidity.amount} ${liquidity.baseLiquidity.denom}`);
console.log(`Total shares: ${liquidity.totalShares}`);
```

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getAllBaseAssetsLiquidity(): Promise<Record<Address, BaseLiquidityDetails>>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

Usage example

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';

const client = new BoltCosmWasmClient();

// 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 Router contract config

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getRouterConfig(): Promise<RouterConfig>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
// 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);
```

### Get liquidity pools information

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getAllPools(): Promise<Pool[]>
```

{% endtab %}

{% tab title="Returns" %}

```typescript
type Pool = {
  poolAddress: string; // Contract address or Sui object ID of the pool
  baseDenom: string; // Type of the base asset
  quoteDenoms: string[]; // Array of available quote asset types
};
```

{% endtab %}
{% endtabs %}

Usage example

```typescript
// 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 archPools = allPools.filter(pool =>
  pool.baseDenom === "aarch"
);
console.log(`ARCH pools found: ${archPools.length}`);
```

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getPoolConfig(contractAddress: Address): Promise<PoolConfig>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
// Get pool configuration by contract address
const poolAddress = "archway1f1e...";
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);
```

{% hint style="info" %}
**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 Archway Blockchain. Fetches pool details for the pool matching the provided asset denom(s).
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getPoolByDenom(baseDenom: string): Promise<Pool>
```

{% endtab %}

{% tab title="Returns" %}

```typescript
type Pool = {
  poolAddress: string; // Contract address or Sui object ID of the pool
  baseDenom: string; // Type of the base asset
  quoteDenoms: string[]; // Array of available quote asset types
};
```

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
// Get pool for ATOM base asset
const pool = await client.getPoolByDenom('ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2');

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

{% hint style="info" %}
**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 Archway Blockchain. This is a convenience function that combines pool lookup and configuration retrieval.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async getPooConfigByDenom(baseDenom: string): Promise<PoolConfig>
```

{% endtab %}

{% tab title="Returns" %}

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

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
// Get pool configuration for ATOM base asset
const config = await client.getPoolConfigByBaseAsset('ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2');

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

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async simulateSwap(): Promise<SimulateSwapResult>
```

{% endtab %}

{% tab title="Returns" %}

```typescript
type type SimulateSwapResult = {
  poolAddress: string; // Contract address or Sui object ID of the pool
  amountOut: string; // Amount expected to be received after the swap
  assetOut: string; // Denom of the asset that will be received after the swap
  protocolFee: string; // The protocol fee amount that would be charged
  lpFee: string; // The liquidity provider fee amount that would be charged
  dynamicFeePercentage?: string; // Percentage of the swap that goes to dynamic fees on the Sui Outpost
  totalFees: string; // The sum of protocolFee and lpFee (dynamic fee is distributed between both)
}
```

{% endtab %}
{% endtabs %}

**Usage example**

```typescript
// Simulate swapping 1 ARCH for USDC
const simulation = await client.simulateSwap({
  assetIn: "aarch",
  amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
  assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D" // 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

{% hint style="info" %}
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.
{% endhint %}

{% tabs %}
{% tab title="Method Signature" %}

```typescript
async swap(params: SwapParams, signer: Signer): Promise<SwapResult<ExecuteResult>>

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

{% endtab %}

{% tab title="Returns" %}

```typescript
type SwapResult<ExecuteResult> = {
  txOutput: ExecuteResult; // Complete transaction response
  amountOut: string; // Actual amount of output asset received
  assetOut: string; // Output asset denomination
  txHash: string; // Transaction hash for tracking
};
```

{% endtab %}
{% endtabs %}

Basic usage examples

<details>

<summary>Simple swap</summary>

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { OfflineSigner } from '@cosmjs/proto-signing';

const client = new BoltArchwayClient();

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic

try {
 const result = await client.swap({
   assetIn: "aarch",
   amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
   assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
   minimumAmountOut: '1900000', // Minimum 1.9 USDC (6 decimals)
   receiver: "archway1..." // Optional custom receiver
 }, 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);
}
```

</details>

<details>

<summary>Swap with minimum amount out limit</summary>

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { OfflineSigner } from '@cosmjs/proto-signing';

const client = new BoltArchwayClient();

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic

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

try {
 const result = await client.swap({
   assetIn: "aarch",
   amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
   assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
   minimumAmountOut
 }, signer);

  console.log(`Minimum: ${minimumAmountOut} USDC`);
  console.log(`Received: ${result.amountOut} USDC`);
} catch (error) {
  console.error('Swap failed:', error.message);
}
```

</details>

<details>

<summary>Swap with custom receiver</summary>

```typescript
import { BoltCosmWasmClient } from '@bolt-liquidity-hq/cosmwasm-client';
import { OfflineSigner } from '@cosmjs/proto-signing';

const client = new BoltArchwayClient();

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic

const receiver = "archway1e1f1..."; // Custom recipient

try {
 const result = await client.swap({
   assetIn: "aarch",
   amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
   assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
   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);
}
```

</details>

Best practices

<details>

<summary>Price slippage protection</summary>

```typescript
// 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);
```

</details>

<details>

<summary>Error handling and retries</summary>

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

</details>

<details>

<summary>Gas estimation and optimization</summary>

```typescript
import { OfflineSigner } from '@cosmjs/proto-signing';

const signer: OfflineSigner = // ... obtain signer from wallet or mnemonic
const result = await client.estimateSwapGasFees(
  {
    assetIn: "aarch",
    amountIn: "1000000000000000000", // 1 ARCH (18 decimals)
    assetOut: "ibc/43897B9739BD63E3A08A88191999C632E052724AB96BD4C74AE31375C991F48D", // USDC IBC denom
  },
  signer
);

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

</details>

## Error Handling

The SDK provides custom error types for better error handling:

* <mark style="color:orange;">**NotFoundError**</mark> - Resource not found
* <mark style="color:orange;">**InvalidParameterError**</mark> - Invalid parameter provided
* <mark style="color:orange;">**InvalidObjectError**</mark> - Invalid object structure
* <mark style="color:orange;">**InvalidTypeError**</mark> - Invalid type provided
* <mark style="color:orange;">**MissingParameterError**</mark> - Required parameter missing
* <mark style="color:orange;">**TransactionFailedError**</mark> - Transaction execution failed
* <mark style="color:orange;">**ParseError**</mark> - Failed to parse response data
