UNPKG

@swapnet-xyz/sdk

Version:
101 lines (100 loc) 4.17 kB
import { Interface } from 'ethers'; // @ts-ignore import universalRouterData from '../../abi/universalRouter.json' with { type: "json" }; import { universalRouterUname } from '../../common/unames.js'; import { PERMIT2_ADDRESS } from '../../ethers-override/permit2AsIf.js'; import { RouterBase, resolveEncodeOptions } from '../routerBase.js'; import { deployedAddressesByChainId } from './addresses.js'; import { CommandType, CONTRACT_BALANCE, RoutePlanner, ROUTER_AS_RECIPIENT, SENDER_AS_RECIPIENT } from './routerCommands.js'; import { universalRouterPluginByLiquiditySourceUname } from '../../liquiditySourcePlugins/universalRouterPlugins.js'; const universalRouterInterface = new Interface(universalRouterData.abi); export class UniversalRouter extends RouterBase { constructor(_chainId, _routerAddress, _tokenProxyAddress = PERMIT2_ADDRESS){ super(universalRouterUname, _chainId, _routerAddress, _tokenProxyAddress); } encode(routingPlan, options) { const { amountOutMinimum, wrapInput, unwrapOutput, deadline } = resolveEncodeOptions(routingPlan, options); let { inputTokenPermit, recipientAddress } = options; if (recipientAddress === undefined) { recipientAddress = SENDER_AS_RECIPIENT; } const { tokenOps, amountIn, fromToken, toToken } = routingPlan; const planner = new RoutePlanner(); if (inputTokenPermit !== undefined) { const { permit, signature } = inputTokenPermit; planner.addCommand(CommandType.PERMIT2_PERMIT, [ permit, signature ]); } if (wrapInput) { planner.addCommand(CommandType.WRAP_ETH, [ ROUTER_AS_RECIPIENT, amountIn ]); } else { planner.addCommand(CommandType.PERMIT2_TRANSFER_FROM, [ fromToken, ROUTER_AS_RECIPIENT, amountIn ]); } tokenOps.forEach((tokenOp)=>{ const { toSwaps } = tokenOp; if (toSwaps.length === 0) { return; } toSwaps.sort((r1, r2)=>Number(BigInt(r1.amountIn) - BigInt(r2.amountIn))); toSwaps.forEach((toSwap, j)=>{ const fromTokenAddress = tokenOp.tokenInfo.address; const toTokenAddress = toSwap.toTokenOp.tokenInfo.address; const { liquidityInfo } = toSwap; let { amountIn } = toSwap; if (j === toSwaps.length - 1) { amountIn = CONTRACT_BALANCE; } const plugin = universalRouterPluginByLiquiditySourceUname[liquidityInfo.source]; if (plugin === undefined) { throw new Error(`Unknown liquidity source ${liquidityInfo.source}!`); } plugin.addToPlanner(fromTokenAddress, toTokenAddress, amountIn, liquidityInfo, planner); }); }); if (unwrapOutput) { planner.addCommand(CommandType.UNWRAP_WETH, [ recipientAddress, amountOutMinimum ]); } else { planner.addCommand(CommandType.SWEEP, [ toToken, recipientAddress, amountOutMinimum ]); } const { commands, inputs } = planner; let calldata; if (deadline === undefined) { calldata = universalRouterInterface.encodeFunctionData('execute(bytes,bytes[])', [ commands, inputs ]); } else { calldata = universalRouterInterface.encodeFunctionData('execute(bytes,bytes[],uint256)', [ commands, inputs, options.deadline ]); } return calldata; } } export const universalRouterByChainId = {}; Object.entries(deployedAddressesByChainId).map(([chainIdStr, routerAddress])=>{ const chainId = parseInt(chainIdStr); Object.assign(universalRouterByChainId, { [chainId]: new UniversalRouter(chainId, routerAddress) }); });