@hikaru-fi/swap-router
Version:
Package for calculating optimal path for executing swaps
150 lines (134 loc) • 4.14 kB
JavaScript
const BN = require("bn.js");
const { toBN } = require("web3-utils");
const { WeightedPool } = require("../poolMath/weightedPool/weightedPool");
const { SwapTypes, getSwapType } = require("../utils/types");
const MAX_UINT256 = toBN(2).pow(toBN(256)).sub(toBN(1))
/**
* @typedef VirtualSwapInfo
* @property {String} pool
* @property {String} tokenIn
* @property {String} tokenOut
*/
/**
* @typedef RouteInfo
* @property {String} vault
* @property {VirtualSwapInfo[]} swapRoute
* @property {Number} swapType
* @property {String} swapAmount
* @property {String} minMaxAmount
* @property {String} receiver
* @property {String} deadline
*/
/**
* @typedef SwapData
* @property {BN} expectedResult
* @property {RouteInfo} swapRoute
*/
/**
* @param {Record<String, WeightedPool>} pools
* @param {import("./pathCalculation").SwapRoute} swap
* @param {BN} swapAmount
* @param {String} swapType
* @param {BN} expectedResult
* @returns {SwapData}
*/
function createSwapData(
pools,
swap,
swapAmount,
swapType,
expectedResult
) {
swapAmount = swapAmount.toString(10);
expectedResult = expectedResult.toString(10);
/**
* @type {RouteInfo}
*/
const swapRoute = {
vault: pools[swap.path[0].poolAddress].vaultAddress,
swapRoute: swap.path.map((val) => {return {pool: val.poolAddress, tokenIn: val.tokenIn, tokenOut: val.tokenOut}}),
swapType: getSwapType(swapType),
swapAmount,
minMaxAmount: '0',
receiver: '',
deadline: ''
}
return {
expectedResult,
swapRoute
}
}
/**
* @typedef BestSwapResults
* @property {BN} expectedResult
* @property {import("./pathCalculation").SwapRoute} path
*/
/**
* @param {Record<String, WeightedPool>} pools
* @param {import("./pathCalculation").SwapRoute[]} suitableSwaps
* @param {BN} swapAmount
* @param {String} swapType
* @returns {BestSwapResults}
*/
function getBestSwap(pools, suitableSwaps, swapAmount, swapType) {
const sell = swapType == SwapTypes.Sell;
/**
* @type {BN}
*/
let resultAmount = sell ? toBN(0) : MAX_UINT256;
/**
* @type {import("./pathCalculation").SwapRoute}
*/
let resultPath;
for (const route of suitableSwaps) {
switch (swapType) {
case (SwapTypes.Sell): {
let amountIn = swapAmount.clone();
let amountOut = toBN(0);
for (const swap of route.path) {
const pool = pools[swap.poolAddress];;
amountOut = pool.getSwapResult(
swap.tokenIn,
swap.tokenOut,
amountIn,
swapType
)
amountIn = amountOut.clone();
}
if (amountOut.gt(resultAmount)) {
resultAmount = amountOut.clone();
resultPath = route;
}
break;
}
case (SwapTypes.Buy): {
let amountIn = toBN(0);
let amountOut = swapAmount.clone();
for (let swapId = route.path.length - 1; swapId >= 0; swapId--) {
const swap = route.path[swapId];
const pool = pools[swap.poolAddress];
amountIn = pool.getSwapResult(
swap.tokenIn,
swap.tokenOut,
amountOut,
swapType
)
amountOut = amountIn.clone();
}
if (amountIn.lt(resultAmount)) {
resultAmount = amountIn.clone();
resultPath = route;
}
break;
}
}
}
return {
expectedResult: resultAmount,
path: resultPath
};
}
module.exports = {
createSwapData,
getBestSwap
}