Smart router v1

Swap in the best router

Now, we support to seek the best swap route among all cetus pools. When there is no direct trading pool between two trading assets, the smart routing will automatically find the optimal trading path linked for the pair.

If there is a direct trading pool between the trading pairs, the smart routing will not only search through all direct trading pools but also explore the optimal trading path among other routes connected by intermediate tokens to compare.

It's important to note that if you want to use this feature, you need to pre-configure a trading path graph for this method. You'll need to maintain a list of pools and the corresponding decimals for each coin in the pools.

There are two methods to get all pools:

  1. (Stable) If you get all pools by sdk, like ask.Pool.getPools(), you can't get coin decimals, so you need to set coin decimal by yourself.

  2. (Speedy) Get pool list from our API. The coin decimals were provided.

  • Testnet: https://api-sui.cetus.zone/v2/sui/pools_info

  • Mainnet: https://api-sui.cetus.zone/v2/sui/pools_info

Pre-calculating

use sdk.Router.price() method.

Function input param

Please refer to the original function for specific parameter types.

  • from: coin type of from coin.

  • to: coin type of to coin.

  • amount: amount of from coin.

  • byAmountIn: true means fixed the amount of input, false means fixed the amount of output.

  • amount: the amount of input (byAmountIn = true) or output (byAmountIn = false).

  • priceSplitPoint: split point of price, it control the range of coin losses you may incur.

  • partner: Partner object id.

  • swapWithMultiPoolParams: This is an option about the coin pair what you want to do swap, this is to prevent potential pre-calculation errors in the SDK. In such cases, if there are direct trading pools available, the routing will undergo a downgrade process.

Build router v1 swap transaction

use TransactionUtil.buildRouterSwapTransaction method.

Function input param

Please refer to the original function for specific parameter types.

  • sdk: The sdk include all import config.

  • params: pre-calculating result.

    1. paths: paths of router swap result.

    2. partner: Partner object id.

    3. priceSlippagePoint: Slippage point of price, it control the range of coin losses you may incur.

  • byAmountIn: true means fixed the amount of input, false means fixed the amount of output.

  • allCoinAsset: user's all coin object id.

  • recipient: (Option) the address about all coins recipient. If recipient not set, transfer objects move call will use sender get by ctx.

Please update the SDK to the latest version 3.17.3+, and no longer use the SDK's default senderAddress as the recipient for transferObjects.

Example

All used type in /src/modules/routerModule.ts.

  1. Get all pools by SDK.


// get all pool info by `getPool`s.
const pools = await sdk.Pool.getPools([], 0, 200)

// prepare the data for constructing a transaction path graph.
const coinMap = new Map()
const poolMap = new Map()

for (let i = 0; i < pools.length; i += 1) {
  if (pools[i].is_pause) {
    continue
  }
  let coin_a = pools[i].coinTypeA
  let coin_b = pools[i].coinTypeB

  // Get coin decimals individual
  coinMap.set(coin_a, {
    address: coin_a,
    decimals: coin_a_decimal,
  })
  coinMap.set(coin_b, {
    address: coin_b,
    decimals: coin_b_decimal,
  })

  const pair = `${coin_a}-${coin_b}`
  const pathProvider = poolMap.get(pair)
  if (pathProvider) {
    pathProvider.addressMap.set(pools[i].fee_rate, pools[i].poolAddress)
  } else {
    poolMap.set(pair, {
      base: coin_a,
      quote: coin_b,
      addressMap: new Map([[pools[i].fee_rate, pools[i].poolAddress]]),
    })
  }
}

const coins: CoinProvider = {
  coins: Array.from(coinMap.values())
}
const paths: PathProvider = {
  paths: Array.from(poolMap.values())
}

// Load the path graph.
sdk.Router.loadGraph(coins, paths)

// The first two addresses requiring coin types.
const byAmountIn = false
const amount = new BN('1000000000000')
const result = await sdk.Router.price(ETH, CETUS, amount, byAmountIn, 0.05, '')

const params: SwapWithRouterParams = {
  paths: [result?.paths![0]!, result?.paths![1]!],
  partner: '',
  priceSplitPoint: 0.005,
}

// if find the best swap router, then send transaction.
if (!result?.isExceed) {
  const allCoinAsset = await sdk.Resources.getOwnerCoinAssets(sdk.senderAddress)
  const payload = await TransactionUtil.buildRouterSwapTransaction(sdk, params, byAmountIn, allCoinAsset)
  const signer = new RawSigner(sendKeypair, sdk.fullClient)
  const transferTxn = await sendTransaction(signer, payload)
}
  1. Get all pools from centralized API.

const coinMap = new Map()
const poolMap = new Map()

const resp: any = await fetch('https://api-sui.cetus.zone/v2/sui/pools_info', { method: 'GET' })
const poolsInfo = await resp.json()

if (poolsInfo.code === 200) {
  for (const pool of poolsInfo.data.lp_list) {
    if (pool.is_closed) {
      continue
    }

    let coin_a = pool.coin_a.address
    let coin_b = pool.coin_b.address

    coinMap.set(coin_a, {
      address: pool.coin_a.address,
      decimals: pool.coin_a.decimals,
    })
    coinMap.set(coin_b, {
      address: pool.coin_b.address,
      decimals: pool.coin_b.decimals,
    })

    const pair = `${coin_a}-${coin_b}`
    const pathProvider = poolMap.get(pair)
    if (pathProvider) {
      pathProvider.addressMap.set(Number(pool.fee) * 100, pool.address)
    } else {
      poolMap.set(pair, {
        base: coin_a,
        quote: coin_b,
        addressMap: new Map([[Number(pool.fee) * 100, pool.address]]),
      })
    }
  }
}

const coins: CoinProvider = {
  coins: Array.from(coinMap.values()),
}
const paths: PathProvider = {
  paths: Array.from(poolMap.values()),
}

sdk.Router.loadGraph(coins, paths)


// The first two addresses requiring coin types.
const byAmountIn = false
const amount = new BN('1000000000000')
const result = await sdk.Router.price(ETH, CETUS, amount, byAmountIn, 0.05, '')

const params: SwapWithRouterParams = {
  paths: result.paths,
  partner: '0x...',
  priceSlippagePoint: 0.01,
}

// if find the best swap router, then send transaction.
if (!result?.isExceed) {
  const allCoinAsset = await sdk.Resources.getOwnerCoinAssets(sdk.senderAddress)
    // If recipient not set, transfer objects move call will use ctx sender.
  const payload = await TransactionUtil.buildRouterSwapTransaction(sdk, params, byAmountIn, allCoinAsset)
  const signer = new RawSigner(sendKeypair, sdk.fullClient)
  const transferTxn = await sendTransaction(signer, payload)
}

Last updated