Routing a Swap

This section explains how to use Storyhunt's router to compute optimal routes and execute swaps.

Introduction

This section explains how to use Storyhunt's routing capabilities to compute optimal routes and execute swaps. Instead of relying on a single pool, smart routing utilizes multiple hops to ensure the best possible price for a swap. This example demonstrates trading between WIP and USDC, but any two currencies and input amounts can be configured.

The process includes:

  1. Getting required Trading Pools

  2. Constructing a route

  3. Executing a swap using the route

Get required Trading Pools

To get the pool data, one can use the graph data to efficiently fetch required pool data.

const tokenPoolResult = await executeGraphQuery<GraphPoolResponse>(
  POOLWTOKEN_QUERY,
  {
    token0: currencyIn.address.toLowerCase(),
    token1: currencyOut.address.toLowerCase(),
  });
  
const poolObj = new Pool(
  tokenA,
  tokenB,
  parseInt(pool.feeTier),
  JSBI.BigInt(pool.sqrtPrice),
  JSBI.BigInt(pool.liquidity),
  parseInt(pool.tick),
  tickDataProvider
);

Getting the optimal a Route

For the trade, get the best possible route from using multihop based on pool data. This example uses an EXACT_INPUT trade:

import { Trade } from '@storyhunt/v3-sdk';

const routes = await Trade.bestTradeExactIn(
  allPools,
  CurrencyAmount.fromRawAmount(
    currencyIn,
    JSBI.BigInt(amount.toString())
  ),
  currencyOut,
  { maxHops: 3, maxNumResults: 1 }
);

//select the best trade
const trade = routes[0];

Before proceeding, check if the route was successfully created:

if (!route || !route.methodParameters) {
  // Handle failed request
}

Swapping Using a Route

First, approve the SwapRouter smart contract to spend the input tokens:

import { ethers } from 'ethers';

const wallet = new ethers.Wallet(privateKey, provider);
const tokenContract = new ethers.Contract(
  CurrentConfig.tokens.in.address,
  ERC20ABI,
  wallet
);
const tokenApproval = await tokenContract.approve(
  SWAP_ROUTER_ADDRESS,
  ethers.BigNumber.from(rawTokenAmountIn.toString())
);

Construct and send the transaction:

import { SwapRouter } from '@storyhunt/v3-sdk';

const methodParameters = SwapRouter.swapCallParameters([uncheckedTrade], options);

Set the swap options, including slippage tolerance and deadline:

import { SwapOptions } from '@storyhunt/v3-sdk';
import { Percent } from '@storyhunt/sdk-core';

const options: SwapOptions = {
  slippageTolerance: new Percent(50, 10_000), // 0.50%
  deadline: Math.floor(Date.now() / 1000) + 60 * 20, // 20 minutes from now
  recipient: walletAddress,
};

Use the SwapRouter to get the call parameters for the trade:

import { SwapRouter } from '@storyhunt/v3-sdk';

const methodParameters = SwapRouter.swapCallParameters(trade, options);

Wait for the approval transaction to be confirmed before executing the trade. Then, use the route’s computed calldata, value, and gas values to send the transaction:

const txRes = await wallet.sendTransaction({
  data: route.methodParameters.calldata,
  to: SWAP_ROUTER_ADDRESS,
  value: route.methodParameters.value,
  from: wallet.address,
  maxFeePerGas: MAX_FEE_PER_GAS,
  maxPriorityFeePerGas: MAX_PRIORITY_FEE_PER_GAS,
});

After executing the trade, you should see the currency balances update once the transaction is confirmed.

Next Steps

Now that you're familiar with routing swaps, you can explore advanced topics such as providing liquidity to Storyhunt pools.