npm package: @mantasm_/bitzy-sdk
Description: Bitzy Swap V3 Routes SDK for frontend and backend applications
Author: Bitzy Team
Latest version: 0.2.0

# Bitzy Aggregator SDK - Multi-DEX Route Aggregation

A comprehensive SDK for aggregating swap routes across multiple decentralized exchanges and executing optimal swaps. Provides both **common functions** for any environment and **React hooks** for frontend applications with intelligent route aggregation.

## **What This Package Provides**

- **Multi-DEX Aggregation** - Automatically finds the best routes across multiple decentralized exchanges
- **Common Functions** - Work in Node.js, browser, or any JavaScript environment
- **React Hooks** - Hot reloading with automatic updates and error handling
- **TypeScript Support** - Full type safety throughout
- **Intelligent Route Optimization** - Automatic aggregation based on token characteristics and liquidity
- **Multiple Networks** - Support for Botanix Mainnet and Testnet
- **Split Routing** - Distributes large swaps across multiple routes for optimal execution

## **Current Support Notice**

**Currently supports Bitzy V2 and Bitzy V3 liquidity sources only.**

This aggregator SDK begins with Bitzy's own DEX implementations. **Integration with additional external DEXs is planned for very soon.**


## **Quick Start**

### **Installation**

```bash
npm install @bitzy-app/bitzy-sdk
# or
yarn add @bitzy-app/bitzy-sdk
# or
pnpm add @bitzy-app/bitzy-sdk
```

## **1. Using Functions**

### **1.1 `fetchSwapRoute()` - Main Route Aggregation Function**

```typescript
import { fetchSwapRoute } from '@bitzy-app/bitzy-sdk';

// Basic usage with defaults
const result = await fetchSwapRoute({
  amountIn: '1.5',
  srcToken: { 
    address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', 
    symbol: 'BTC', 
    name: 'Bitcoin', 
    decimals: 18,
    chainId: 3637
  },
  dstToken: { 
    address: '0x29eE6138DD4C9815f46D34a4A1ed48F46758A402', 
    symbol: 'USDC.e', 
    name: 'Bridged USDC (Stargate)', 
    decimals: 6,
    chainId: 3637
  },
  chainId: 3637
});

console.log('Routes found:', result.routes.length);
console.log('Amount out:', result.amountOutBN.toFixed());
console.log('Distributions:', result.distributions);
```

**With Custom PublicClient (Optional):**

```typescript
import { fetchSwapRoute } from '@bitzy-app/bitzy-sdk';
import { createPublicClient, http, defineChain } from 'viem';

// Create your own PublicClient (e.g., from wagmi, or custom RPC)
const publicClient = createPublicClient({
  chain: defineChain({
    id: 3637,
    name: 'Botanix Mainnet',
    network: 'botanix-mainnet',
    nativeCurrency: {
      name: 'Bitcoin',
      symbol: 'BTC',
      decimals: 18,
    },
    rpcUrls: {
      default: { http: ['https://rpc.botanixlabs.com'] },
    },
  }),
  transport: http(),
});

// Use your custom PublicClient for better performance and connection reuse
const result = await fetchSwapRoute(
  {
    amountIn: '1.5',
    srcToken: btcToken,
    dstToken: usdcToken,
    chainId: 3637,
  },
  {
    publicClient: publicClient, // Optional: inject your own client
    headers: {
      'authen-key': 'your-api-key', // Optional: API key for authentication
    },
  }
);
```

**Note:** If you don't provide `publicClient`, the SDK will automatically create one using default RPC endpoints:
- **Botanix Mainnet (3637)**: `https://rpc.botanixlabs.com`
- **Botanix Testnet (3636)**: `https://node.botanixlabs.dev`

Injecting your own client is useful when:
- You already have a `PublicClient` instance (e.g., from wagmi's `useAccount()`)
- You want to reuse connections for better performance
- You need to use a custom RPC endpoint

### **1.2 `fetchBatchSwapRoutes()` - Batch Route Aggregation**

```typescript
import { fetchBatchSwapRoutes } from '@bitzy-app/bitzy-sdk';

// Fetch multiple routes simultaneously
const results = await fetchBatchSwapRoutes([
  {
    options: {
      amountIn: '1.0',
      srcToken: btcToken,
      dstToken: usdcToken,
      chainId: 3637
    },
    config: { apiBaseUrl: 'https://api-public.bitzy.app' }
  },
  {
    options: {
      amountIn: '2.0',
      srcToken: ethToken,
      dstToken: usdtToken,
      chainId: 3637
    },
    config: { apiBaseUrl: 'https://api-public.bitzy.app' }
  }
]);

// Results array with success/error status for each
results.forEach((result, index) => {
  if (result.success) {
    console.log(`Route ${index + 1}:`, result.data.routes.length, 'routes');
  } else {
    console.error(`Route ${index + 1} failed:`, result.error);
  }
});
```

### **1.3 `getSwapQuote()` - Aggregated Price Quote**

```typescript
import { getSwapQuote } from '@bitzy-app/bitzy-sdk';

// Get a simple quote without full routing details
const quote = await getSwapQuote(
  srcToken,
  dstToken,
  '1.5',
  3637,
  { apiBaseUrl: 'https://api-public.bitzy.app' }
);

console.log('Amount out:', quote.amountOut);
console.log('Route count:', quote.routes);
```

### **1.4 `fetchSwapRouteSimple()` - Simple Aggregation**

```typescript
import { fetchSwapRouteSimple } from '@bitzy-app/bitzy-sdk';

// Simplified function with minimal parameters
const result = await fetchSwapRouteSimple(
  srcToken,
  dstToken,
  '1.0',
  3637
);

// Returns the same SwapResult as fetchSwapRoute
console.log('Best route:', result.routes[0]);
```

## **2. Using React Hooks**

### **2.1 `useSwapV3Routes()` - Main Aggregation React Hook**

```tsx
import { useSwapV3Routes } from '@bitzy-app/bitzy-sdk';

function SwapComponent() {
  const [srcToken, setSrcToken] = useState(btcToken);
  const [dstToken, setDstToken] = useState(usdcToken);
  const [amountIn, setAmountIn] = useState('1.0');

  // Basic usage with defaults
  // Get aggregated routes using SDK
  const {
    routes,
    distributions,
    amountOutRoutes,
    amountOutBN,
    amountInParts,
    isLoading,
    isAmountOutError,
    isFirstFetch,
    isWrap,
    error,
    fetchRoute,
    clearError
  } = useSwapV3Routes(srcToken, dstToken, amountIn, 3637);

  // Advanced usage with custom aggregation configuration
  const swapConfig = {
    apiBaseUrl: 'https://api-public.bitzy.app',
    config: {
      routerAddress: '0xA5E0AE4e5103dc71cA290AA3654830442357A489',
      bitzyQueryAddress: '0x...',
      wrappedAddress: '0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56',
      nativeAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
    },
    defaultPartCount: 5,
    timeout: 30000,
    publicClient: publicClient,
    types: [1, 2], // V2 and V3 liquidity sources
    enabledSources: [1], // Bitzy source
    useOnlinePartCount: true, // Enable intelligent routing
  };

  const advancedResult = useSwapV3Routes(
    srcToken, 
    dstToken, 
    amountIn, 
    3637, 
    swapConfig
  );

  return (
    <div>
      {isLoading ? (
        <div>Finding best routes...</div>
      ) : (
        <div>
          {routes.length > 0 ? (
            <div>
              <p>Amount out: {amountOutBN.toString()} {dstToken.symbol}</p>
              <p>Routes found: {routes.length}</p>
              <p>Is wrap: {isWrap || 'No'}</p>
            </div>
          ) : (
            <div>No routes found</div>
          )}
        </div>
      )}
      
      {error && (
        <div className="error">
          {error}
          <button onClick={clearError}>Dismiss</button>
        </div>
      )}
      
      <button onClick={fetchRoute}>Refresh Routes</button>
    </div>
  );
}
```

## **3. Prepare to Swap Using Response**

Based on the main repository implementation, here's how to use the aggregator SDK response to prepare and execute optimized swaps:

### **3.1 Complete Aggregated Swap Implementation**

Here are generic examples showing how to execute aggregated swaps using direct contract calls with the SDK response data:

#### **Example 1: Using Viem with BitzyAggregator Contract**

```tsx
import { useSwapV3Routes } from '@bitzy-app/bitzy-sdk';
import { useWriteContract, useAccount } from 'wagmi';
import { parseUnits, formatUnits } from 'viem';

function SwapComponent() {
  const [srcToken, setSrcToken] = useState(btcToken);
  const [dstToken, setDstToken] = useState(usdcToken);
  const [amountIn, setAmountIn] = useState('1.0'); // 1 BTC
  const [slippage, setSlippage] = useState(0.005); // 0.05%

  const { address, publicClient } = useAccount();
  const { writeContract } = useWriteContract();

  // Get aggregated routes using SDK
  const {
    routes,
    distributions,
    amountOutRoutes,
    amountOutBN,
    amountInParts,
    isLoading,
    isAmountOutError,
    isFirstFetch,
    isWrap,
    error,
    fetchRoute
  } = useSwapV3Routes(srcToken, dstToken, amountIn, 3637, {
    apiBaseUrl: 'https://api-public.bitzy.app',
    config: {
      routerAddress: '0xA5E0AE4e5103dc71cA290AA3654830442357A489',
      bitzyQueryAddress: '0x...',
      wrappedAddress: '0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56',
      nativeAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
    },
    defaultPartCount: 5,
    timeout: 30000,
    publicClient: publicClient,
    types: [1, 2],
    enabledSources: [1],
    useOnlinePartCount: true,
  });

  // Execute aggregated swap using direct contract call
  const handleSwap = useCallback(async () => {
    if (!srcToken || !dstToken || !routes.length || !address) return;

    const amountInBN = parseUnits(amountIn, srcToken.decimals);
    const amountOutBN = BigNumber(amountOutBN.toFixed());
    const slippageBN = BigNumber(slippage);
    const amountOutMin = amountOutBN.times(1 - slippageBN);

    // Handle wrap/unwrap cases
    if (isWrap === 'wrap') {
      // Native to Wrapped (e.g., ETH to WETH)
      await writeContract({
        address: wrappedAddress, // WETH contract
        abi: [
          {
            name: 'deposit',
            type: 'function',
            stateMutability: 'payable',
            inputs: [],
            outputs: []
          }
        ],
        functionName: 'deposit',
        value: amountInBN,
      });
      return;
    }

    if (isWrap === 'unwrap') {
      // Wrapped to Native (e.g., WETH to ETH)
      await writeContract({
        address: wrappedAddress, // WETH contract
        abi: [
          {
            name: 'withdraw',
            type: 'function',
            stateMutability: 'nonpayable',
            inputs: [{ name: 'amount', type: 'uint256' }],
            outputs: []
          }
        ],
        functionName: 'withdraw',
        args: [amountInBN],
      });
      return;
    }

    // Regular aggregated swap using splitTrade
    const tradeRoutes = routes.map((route, i) => {
      const amountInPart = amountInParts[i];
      const amountOutMinPart = amountOutRoutes[i].times(1 - slippageBN);
      const isRouterSource = route[0].from === '0x0000000000000000000000000000000000000000';

      return {
        srcToken: srcToken.address,
        dstToken: dstToken.address,
        amountIn: amountInPart.toFixed(0),
        amountOutMin: amountOutMinPart.toFixed(0),
        to: address,
        routes: route,
        isRouterSource: isRouterSource,
        isSourceFee: true,
      };
    });

    await writeContract({
      address: '0xA5E0AE4e5103dc71cA290AA3654830442357A489', // BitzyAggregator
      abi: [
        {
          name: 'splitTrade',
          type: 'function',
          stateMutability: 'payable',
          inputs: [
            { name: 'srcToken', type: 'address' },
            { name: 'dstToken', type: 'address' },
            { name: 'amountIn', type: 'uint256' },
            { name: 'amountOutMin', type: 'uint256' },
            { name: 'isSrcNative', type: 'bool' },
            { name: 'tradeRoutes', type: 'tuple[]' },
            { name: 'to', type: 'address' }
          ],
          outputs: []
        }
      ],
      functionName: 'splitTrade',
      args: [
        srcToken.address,
        dstToken.address,
        amountInBN.toFixed(0),
        amountOutMin.toFixed(0),
        srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // isSrcNative
        tradeRoutes,
        address
      ],
      value: srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? amountInBN : 0n,
    });
  }, [srcToken, dstToken, amountIn, routes, distributions, amountOutRoutes, amountInParts, slippage, address, writeContract, isWrap]);

  return (
    <div>
      <input
        value={amountIn}
        onChange={(e) => setAmountIn(e.target.value)}
        placeholder="Amount to swap"
      />
      
      {isLoading ? (
        <div>Finding best routes...</div>
      ) : (
        <div>
          {routes.length > 0 ? (
            <div>
              <p>Amount out: {formatUnits(amountOutBN.toFixed(), dstToken.decimals)} {dstToken.symbol}</p>
              <p>Routes found: {routes.length}</p>
              <p>Is wrap: {isWrap || 'No'}</p>
            </div>
          ) : (
            <div>No routes found</div>
          )}
        </div>
      )}
      
      {error && <div className="error">{error}</div>}
      
      <button onClick={handleSwap} disabled={!routes.length}>
        {isWrap ? capitalize(isWrap) : 'Swap'}
      </button>
      
      <button onClick={fetchRoute}>Refresh Routes</button>
    </div>
  );
}
```

#### **Example 2: Using Ethers.js**

```typescript
import { useSwapV3Routes } from '@bitzy-app/bitzy-sdk';
import { ethers } from 'ethers';

function SwapWithEthers() {
  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
  const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);

  // Get aggregated routes using SDK
  const {
    routes,
    distributions,
    amountOutRoutes,
    amountOutBN,
    amountInParts,
    isLoading,
    isWrap,
    error,
    fetchRoute
  } = useSwapV3Routes(srcToken, dstToken, amountIn, 3637);

  // Execute aggregated swap using ethers.js
  const executeSwap = async () => {
    if (!signer || !routes.length) return;

    const aggregatorContract = new ethers.Contract(
      '0xA5E0AE4e5103dc71cA290AA3654830442357A489', // BitzyAggregator
      [
        'function splitTrade(address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, bool isSrcNative, tuple[] tradeRoutes, address to) payable'
      ],
      signer
    );

    const amountInBN = ethers.parseUnits(amountIn, srcToken.decimals);
    const amountOutMin = amountOutBN.times(1 - slippage)

    const tradeRoutes = routes.map((route, i) => {
      const amountInPart = amountInParts[i];
      const amountOutMinPart = amountOutRoutes[i].times(1 - slippage);
      const isRouterSource = route[0].from === '0x0000000000000000000000000000000000000000';

      return [
        srcToken.address,
        dstToken.address,
        amountInPart.toFixed(0),
        amountOutMinPart.toFixed(0),
        userAddress,
        route,
        isRouterSource,
        true
      ];
    });

    const tx = await aggregatorContract.splitTrade(
      srcToken.address,
      dstToken.address,
      amountInBN.toFixed(0),
      amountOutMin.toFixed(0),
      srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
      tradeRoutes,
      userAddress,
      {
        value: srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? amountInBN.toFixed() : 0
      }
    );

    const receipt = await tx.wait();
    console.log('Swap completed:', receipt.transactionHash);
  };

  return (
    <div>
      {/* UI components */}
      <button onClick={executeSwap} disabled={!routes.length}>
        Execute Swap
      </button>
    </div>
  );
}
```

#### **Example 3: Using Web3.js**

```typescript
import { useSwapV3Routes } from '@bitzy-app/bitzy-sdk';
import Web3 from 'web3';

function SwapWithWeb3() {
  const [web3, setWeb3] = useState<Web3 | null>(null);
  const [account, setAccount] = useState<string | null>(null);

  // Get aggregated routes using SDK
  const {
    routes,
    distributions,
    amountOutRoutes,
    amountInParts,
    isLoading,
    isWrap,
    error,
    fetchRoute
  } = useSwapV3Routes(srcToken, dstToken, amountIn, 3637);

  // Execute aggregated swap using web3.js
  const executeSwap = async () => {
    if (!web3 || !account || !routes.length) return;

    const aggregatorContract = new web3.eth.Contract([
      {
        name: 'splitTrade',
        type: 'function',
        stateMutability: 'payable',
        inputs: [
          { name: 'srcToken', type: 'address' },
          { name: 'dstToken', type: 'address' },
          { name: 'amountIn', type: 'uint256' },
          { name: 'amountOutMin', type: 'uint256' },
          { name: 'isSrcNative', type: 'bool' },
          { name: 'tradeRoutes', type: 'tuple[]' },
          { name: 'to', type: 'address' }
        ],
        outputs: []
      }
    ], '0xA5E0AE4e5103dc71cA290AA3654830442357A489');

    const amountInBN = web3.utils.toWei(amountIn, 'ether');
    const amountOutMin = amountOutBN.times(1 - slippage)

    const tradeRoutes = routes.map((route, i) => {
      const amountInPart = amountInParts[i];
      const amountOutMinPart = amountOutRoutes[i].times(1 - slippage);
      const isRouterSource = route[0].from === '0x0000000000000000000000000000000000000000';

      return [
        srcToken.address,
        dstToken.address,
        amountInPart.toString(),
        amountOutMinPart.toString(),
        account,
        route,
        isRouterSource,
        true
      ];
    });

    const tx = await aggregatorContract.methods.splitTrade(
      srcToken.address,
      dstToken.address,
      amountInBN,
      amountOutMin.toFixed(0),
      srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
      tradeRoutes,
      account
    ).send({
      from: account,
      value: srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? amountInBN : '0'
    });

    console.log('Swap completed:', tx.transactionHash);
  };

  return (
    <div>
      {/* UI components */}
      <button onClick={executeSwap} disabled={!routes.length}>
        Execute Swap
      </button>
    </div>
  );
}
```

### **3.2 Key Data from Aggregator SDK Response**

The aggregator SDK provides all the necessary data for optimized swap execution:

```typescript
interface SwapResult {
  routes: SwapRoute[][];        // Array of route arrays
  distributions: number[];      // Liquidity distribution percentages
  amountOutRoutes: string[];    // Output amounts per route
  amountOutBN: BigNumber;       // Total output amount
  amountInParts: string[];      // Input amounts per part
  isWrap?: "wrap" | "unwrap";   // Wrap/unwrap indicator
}

// Example usage in your aggregated swap function:
swap(
  srcToken,
  dstToken,
  amountIn,        // User input
  amountOut,       // Calculated from amountOutBN
  routes,          // From aggregator SDK - optimized route details
  distributions,   // From aggregator SDK - how to split liquidity across DEXs
  amountOutRoutes, // From aggregator SDK - amounts per route
  amountInParts,   // From aggregator SDK - input amounts per part
  slippageNumber   // User setting
);
```

### **3.3 Environment Variables**

```bash
# .env file
NEXT_PUBLIC_BITZY_API_KEY=your-api-key-here
NEXT_PUBLIC_BITZY_API_URL=https://api-public.bitzy.app
```

```typescript
// The aggregator SDK will automatically use these environment variables
const result = useSwapV3Routes(srcToken, dstToken, amountIn, chainId);
// Uses process.env.NEXT_PUBLIC_BITZY_API_KEY if available
```

## **Advanced Features**

### **Hot Hook Features**

The `useSwapV3Routes` hook is designed for **hot reloading** and **real-time updates**:

- **Auto-updates** - Fetches fresh aggregated routes every 10 seconds
- **Debounced** - Prevents excessive API calls
- **Error handling** - Built-in error state and recovery
- **Hot reload** - Automatically reinitializes when config changes
- **📱 React Native ready** - Works in any React environment

### **Intelligent Route Aggregation**

The aggregator SDK automatically optimizes swap execution by aggregating routes across multiple DEXs based on token characteristics:

- **High-value pairs** (BTC-USDC, ETH-USDT): Uses `partCount = 5` for optimal multi-DEX aggregation
- **Mixed pairs** (BTC-MEME, ETH-SHIB): Uses `partCount = 1` for simplified aggregation  
- **Low-value pairs** (MEME-SHIB): Uses `partCount = 1` for simplified aggregation
- **Online mode**: Checks minimum amount thresholds from API to determine if multi-route aggregation is beneficial

### **High-Value Tokens (Network-Specific)**

```typescript
// Botanix Mainnet (3637)
const highValueTokens = [
  "0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56", // pBTC (Botanix)
  "0x29eE6138DD4C9815f46D34a4A1ed48F46758A402", // USDC.e (Bridged USDC Stargate)
  "0x9BC574a6f1170e90D80826D86a6126d59198A3Ef", // rovBTC (Rover BTC)
  "0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C", // USDC
  "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
];

// Botanix Testnet (3636)
const highValueTokens = [
  "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // ETH/BTC native
  "0x233631132FD56c8f86D1FC97F0b82420a8d20af3", // WBTC
  "0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C", // USDC
  "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
];
```

## 📚 **API Reference**

### **Functions**

#### **`fetchSwapRoute(options, config?)`**
Main function for aggregating swap routes across multiple DEXs in any environment.

**Parameters:**
- `options: SwapOptions` - Swap parameters
- `config?: FetchSwapRouteConfig` - Optional configuration

**Returns:** `Promise<SwapResult>`

**Note:** The `publicClient` is automatically created using default RPC endpoints if not provided. You can optionally inject your own `PublicClient` instance (e.g., from wagmi) for better performance and connection reuse.

#### **`fetchBatchSwapRoutes(requests)`**
Aggregate multiple routes simultaneously across different token pairs.

**Parameters:**
- `requests: Array<{options: SwapOptions, config?: FetchSwapRouteConfig}>`

**Returns:** `Promise<Array<{success: boolean, data?: SwapResult, error?: string}>>`

#### **`getSwapQuote(srcToken, dstToken, amountIn, chainId, config?)`**
Get an aggregated price quote without full routing details.

**Returns:** `Promise<{amountOut: string, routes: number}>`

#### **`fetchSwapRouteSimple(srcToken, dstToken, amountIn, chainId)`**
Simplified aggregation function with minimal parameters.

**Returns:** `Promise<SwapResult>`

### **React Hooks**

#### **`useSwapV3Routes(srcToken, dstToken, amountIn, chainId, config?)`**
Aggregation React hook for real-time route optimization.

**Parameters:**
- `srcToken: Token | null` - Source token
- `dstToken: Token | null` - Destination token  
- `amountIn: string` - Input amount
- `chainId: number` - Network chain ID
- `config?: UseSwapV3RoutesConfig` - Optional configuration

**Returns:**
```typescript
{
  routes: SwapRoute[][];        // Array of route arrays
  distributions: number[];      // Liquidity distribution percentages
  amountOutRoutes: string[];    // Output amounts per route
  amountOutBN: BigNumber;       // Total output amount
  amountInParts: string[];      // Input amounts per part
  fetchRoute: () => void;       // Manual fetch function
  isLoading: boolean;           // Loading state
  isAmountOutError: boolean;    // Error flag
  isFirstFetch: boolean;        // First fetch completed
  isWrap?: "wrap" | "unwrap";   // Wrap/unwrap indicator
  error: string | null;         // Error message
  clearError: () => void        // Clear error function
}
```

### **Types**

#### **`SwapOptions`**
```typescript
interface SwapOptions {
  amountIn: string;           // Input amount (e.g., "1.5")
  srcToken: Token;            // Source token
  dstToken: Token;            // Destination token
  chainId: number;            // Network chain ID
  partCount?: number;         // Optional: Aggregation parts
}
```

#### **`FetchSwapRouteConfig`**
```typescript
interface FetchSwapRouteConfig {
  apiBaseUrl?: string;         // Optional: API base URL (defaults to https://api-public.bitzy.app)
  networks?: Record<number, any>; // Optional: Custom network configs
  defaultPartCount?: number;  // Optional: Default aggregation parts (defaults to 5)
  timeout?: number;           // Optional: Request timeout (defaults to 30000)
  headers?: Record<string, string>; // Optional: Custom HTTP headers (defaults to {})
  forcePartCount?: number;    // Optional: Force specific partCount, overriding intelligent calculation
  publicClient?: PublicClient; // Optional: Viem PublicClient instance (auto-created if not provided)
}
```

#### **`UseSwapV3RoutesConfig`**
```typescript
interface UseSwapV3RoutesConfig {
  apiBaseUrl?: string;         // Base URL for the Bitzy API
  apiKey?: string;             // API key for authentication (optional)
  config?: UseSwapV3RoutesAddressConfig; // Contract addresses configuration
  defaultPartCount?: number;   // Default number of routes to split large swaps into
  timeout?: number;            // Request timeout in milliseconds
  headers?: Record<string, string>; // Additional HTTP headers
  refreshInterval?: number;    // Interval for automatic route refresh
  publicClient?: PublicClient; // Viem PublicClient instance
  types?: number[];            // Array of liquidity source types to include
  enabledSources?: number[];   // Array of enabled liquidity sources
  forcePartCount?: number;     // Override partCount calculation logic
  useOnlinePartCount?: boolean; // Use online API to determine optimal partCount
}
```

#### **`Token`**
```typescript
interface Token {
  address: Address;            // Token contract address
  symbol: string;              // Token symbol (e.g., "BTC", "USDC")
  name: string;                // Token name (e.g., "Bitcoin", "USD Coin")
  decimals: number;            // Token decimals
  chainId: number;             // Network chain ID
  logoURI?: string;            // Optional: Token logo URL
}
```

## 🎨 **Additional Examples**

### **Backend Usage (Node.js)**

```typescript
import { fetchSwapRoute, fetchBatchSwapRoutes } from '@bitzy-app/bitzy-sdk';

// Express.js endpoint
app.post('/api/swap/routes', async (req, res) => {
  try {
    const { amountIn, srcToken, dstToken, chainId } = req.body;
    
    const result = await fetchSwapRoute(
      { amountIn, srcToken, dstToken, chainId }
      // No config needed - uses defaults
    );
    
    res.json({ success: true, data: result });
  } catch (error) {
    res.status(500).json({ 
      success: false, 
      error: error.message 
    });
  }
});

// Batch aggregation processing
app.post('/api/swap/batch', async (req, res) => {
  const { swaps } = req.body;
  
  const results = await fetchBatchSwapRoutes(
    swaps.map(swap => ({
      options: swap,
      config: { apiBaseUrl: process.env.NEXT_PUBLIC_BITZY_API_URL }
    }))
  );
  
  res.json({ success: true, data: results });
});
```

### **Utility Functions**

```typescript
import { 
  isHighValueToken, 
  getPartCountOffline, 
  getPartCountOnline,
  getPartCountWithFallback,
  clearMinimumAmountsCache,
  APIClient
} from '@bitzy-app/bitzy-sdk';

// Check if token is high-value (requires chainId)
const isHighValue = isHighValueToken(token, 3637);

// Get offline partCount (requires chainId)
const partCount = getPartCountOffline(srcToken, dstToken, 3637, 5);

// Get online partCount with real-time data
const onlinePartCount = await getPartCountOnline(
  srcToken, dstToken, amountIn, 3637, apiBaseUrl
);

// Get partCount with fallback
const partCount = await getPartCountWithFallback(
  srcToken, dstToken, amountIn, 3637, apiBaseUrl, 5
);

// Cache management functions
clearMinimumAmountsCache(); // Clear cached minimum amounts data
APIClient.resetInstance();   // Reset singleton APIClient and cache
```

## **Configuration**

### **Network Configuration**

```typescript
interface NetworkConfig {
  routerAddress: string;      // Router contract address
  bitzyQueryAddress: string;  // Query contract address
  wrappedAddress: string;     // Wrapped token address (WETH, WBNB, etc.)
  nativeAddress: string;      // Native token address
}
```

### **Default Networks**

The package includes default configurations for:
- **Botanix Mainnet** (Chain ID: 3637)
- **Botanix Testnet** (Chain ID: 3636)

### **Default Values**

When no config is provided, the aggregator SDK uses these sensible defaults:

- **API URL**: `https://api-public.bitzy.app` (from `DEFAULT_API_BASE_URL`)
- **API Key**: From `NEXT_PUBLIC_BITZY_API_KEY` environment variable or fallback
- **Addresses**: Network-specific defaults from `CONTRACT_ADDRESSES`
- **RPC Endpoints**: 
  - Botanix Mainnet (3637): `https://rpc.botanixlabs.com`
  - Botanix Testnet (3636): `https://node.botanixlabs.dev`
- **PartCount**: `5` for high-value pairs, `1` for others
- **Timeout**: `30` seconds
- **Refresh**: `10` seconds
- **Mode**: Offline (fast and reliable)
- **Types**: `[1, 2]` (V2 typeId: 1, V3 typeId: 2)
- **Enabled Sources**: `[1]` (BITZY sourceId: 1)

## **Development**

### **Building**

```bash
cd sdk
npm install
npm run build
```

### **Testing**

```bash
npm test
npm run type-check
```

## 📦 **Package Structure**

```
src/
├── common/
│   └── FetchSwapRoute.ts     # Common functions
├── hooks/
│   └── useSwapV3Routes.ts    # React hook
├── services/
│   └── SwapV3Service.ts      # Core logic
├── types/
│   └── index.ts              # TypeScript interfaces
├── utils/
│   └── PartCount.ts          # Utility functions
└── index.ts                  # Main exports
```

## **Why This Design?**

- **Focused** - Just the essential aggregation functionality
- **Hot Reload** - Perfect for React development with real-time aggregation
- **Universal** - Common functions work everywhere for multi-DEX aggregation
- **Lightweight** - Minimal dependencies for efficient aggregation
- **Type Safe** - Full TypeScript support for aggregation operations

## 📄 **License**

MIT License - see LICENSE file for details.

## 🆘 **Support**

For questions and support:
- Create an issue on GitHub
- Check the examples folder
- Review the TypeScript types for guidance