> For the complete documentation index, see [llms.txt](https://docs.ferra.ag/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ferra.ag/integration/damm/typescript-sdk/router.md).

# Router

### Table of Contents

* Overview
* Load Graph
* Find Best Route
* Pool TVL
* Utility Methods

***

### Overview

The Router module finds the best swap path by:

1. Building a graph of all available pools and coin pairs
2. Discovering all possible 1-hop and 2-hop paths
3. Simulating each candidate path on-chain
4. Returning the optimal route with the best output

```typescript
// Quick example: find best route for SUI -> USDC
const sdk = initFerraSDK({ network: 'mainnet', fullNodeUrl: '...', wallet: '0x...' })

await sdk.Router.loadGraphData()

const result = await sdk.Router.getBestInternalRouter(
  '0x2::sui::SUI',           // fromCoin
  '0x...::usdc::USDC',       // toCoin
  new BN('1000000000'),       // 1 SUI
  true,                       // isFixedInput
  100,                        // slippage (basis points, 100 = 1%)
  ''                          // partner object ID (empty if none)
)

if (result) {
  console.log('Best route found:')
  result.paths.forEach((path, i) => {
    console.log(`  Path ${i}: ${path.poolAddress.join(' -> ')}`)
    console.log(`  Amount out: ${path.amountOut.toString()}`)
  })
}
```

***

### Load Graph

Before routing, you must load the pool graph. This fetches all pool and coin data from the protocol.

#### From Remote API

```typescript
// Loads pool graph from the Ferra API
await sdk.Router.loadGraphData()

// Check if graph is loaded
console.log('Graph loaded:', sdk.Router.isGraphLoaded)
```

#### Custom Graph Data

Load graph with custom coin and path providers:

```typescript
const coinData = {
  coins: [
    { address: '0x2::sui::SUI', decimals: 9 },
    { address: '0x...::usdc::USDC', decimals: 6 }
  ]
}

const pathData = {
  paths: [
    {
      base: '0x2::sui::SUI',
      quote: '0x...::usdc::USDC',
      addressMap: new Map([[60, '0xPoolAddress...']])  // tickSpacing -> poolAddress
    }
  ]
}

sdk.Router.loadGraph(coinData, pathData)
```

***

### Find Best Route

#### Basic Usage

```typescript
await sdk.Router.loadGraphData()

const result = await sdk.Router.getBestInternalRouter(
  '0x2::sui::SUI',           // fromCoin
  '0x...::usdc::USDC',       // toCoin
  new BN('1000000000'),       // amount (1 SUI)
  true,                       // isFixedInput
  100,                        // slippage points (100 = 1%)
  ''                          // partner ID
)
```

#### Parameters

| Parameter       | Type                       | Description                                              |
| --------------- | -------------------------- | -------------------------------------------------------- |
| fromCoin        | string                     | Source coin type                                         |
| toCoin          | string                     | Destination coin type                                    |
| swapAmount      | BN                         | Amount to swap                                           |
| isFixedInput    | boolean                    | `true` = fix input amount, `false` = fix output          |
| slippagePoint   | number                     | Slippage in basis points (100 = 1%)                      |
| partnerObjectId | string                     | Partner object ID for fee sharing (empty string if none) |
| multiPoolParams | PreSwapWithMultiPoolParams | Optional fallback params for direct pool swap            |

#### Result Structure

```typescript
type BestInternalRouterResult = {
  paths: OnePath[]          // Optimal swap paths
  isExceed: boolean         // Whether liquidity is exceeded
}

type OnePath = {
  amountIn: BN              // Input amount for this path
  amountOut: BN             // Output amount for this path
  poolAddress: string[]     // Pool addresses in order (1 or 2 pools)
  a2b: boolean[]            // Direction for each pool hop
  rawAmountLimit: BN[]      // Slippage-adjusted limits per hop
  isExceed: boolean         // Whether this path exceeds liquidity
  coinType: string[]        // Coin types at each step
}
```

#### With Partner Fee

```typescript
const result = await sdk.Router.getBestInternalRouter(
  fromCoin,
  toCoin,
  amount,
  true,
  100,
  '0xPartnerObjectId...'   // Partner receives fee share
)
```

#### With Multi-Pool Fallback

If the graph doesn't contain a direct route, fall back to multi-pool preswap:

```typescript
const result = await sdk.Router.getBestInternalRouter(
  fromCoin,
  toCoin,
  amount,
  true,
  100,
  '',
  {
    poolAddresses: ['0xpool1...', '0xpool2...'],
    coinTypeA: fromCoin,
    coinTypeB: toCoin,
    a2b: true,
    byAmountIn: true,
    amount: '1000000000'
  }
)
```

#### Complete Example

```typescript
import { initFerraSDK } from '@ferra-labs/damm'
import BN from 'bn.js'

const sdk = initFerraSDK({
  network: 'mainnet',
  fullNodeUrl: 'https://...',
  wallet: '0x...'
})

async function routeSwap() {
  // 1. Load graph
  await sdk.Router.loadGraphData()

  const fromCoin = '0x2::sui::SUI'
  const toCoin = '0x...::usdc::USDC'
  const amount = new BN('1000000000')  // 1 SUI

  // 2. Find best route
  const result = await sdk.Router.getBestInternalRouter(
    fromCoin,
    toCoin,
    amount,
    true,   // fixed input
    50,     // 0.5% slippage
    ''
  )

  if (!result || result.isExceed) {
    console.log('No viable route found')
    return
  }

  // 3. Log route details
  for (const path of result.paths) {
    console.log({
      pools: path.poolAddress,
      directions: path.a2b,
      amountIn: path.amountIn.toString(),
      amountOut: path.amountOut.toString(),
      coins: path.coinType
    })
  }
}
```

***

### Pool TVL

Get all pools with their TVL (Total Value Locked) in USD:

```typescript
const poolsWithTvl = await sdk.Router.getPoolWithTVL()

poolsWithTvl.forEach(pool => {
  console.log({
    address: pool.address,
    tvl: pool.tvl
  })
})

// Sort by TVL
const topPools = poolsWithTvl.sort((a, b) => b.tvl - a.tvl)
```

***

### Utility Methods

#### Get Pool Address and Direction

Look up the pool address and swap direction for a coin pair:

```typescript
const info = sdk.Router.getPoolAddressMapAndDirection(
  '0x2::sui::SUI',
  '0x...::usdc::USDC'
)

if (info) {
  console.log('Direction (a2b):', info.direction)
  // addressMap: tickSpacing -> poolAddress
  info.addressMap.forEach((poolAddr, tickSpacing) => {
    console.log(`  Tick spacing ${tickSpacing}: ${poolAddr}`)
  })
}
```

#### Get Token Info

```typescript
const tokenInfo = sdk.Router.tokenInfo('0x2::sui::SUI')

if (tokenInfo) {
  console.log({
    address: tokenInfo.address,
    decimals: tokenInfo.decimals
  })
}
```

#### Get Fee Rate

```typescript
const feeRate = sdk.Router.getFeeRate(
  '0x2::sui::SUI',
  '0x...::usdc::USDC',
  '0xPoolAddress...'
)

console.log('Fee rate:', feeRate)
```

***

### Important Notes

* Always call `loadGraphData()` or `loadGraph()` before routing
* The router considers both 1-hop (direct) and 2-hop (intermediate) paths
* Up to 16 candidate paths are simulated to find the optimal route
* Multi-hop paths are sorted by TVL to prioritize liquid routes
* If no graph route is found, the router falls back to `preSwapWithMultiPool`
