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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ferra.ag/integration/damm/typescript-sdk/router.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
