UNPKG

@koyofinance/sor

Version:
539 lines (526 loc) 18.5 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { INFINITY: () => INFINITY, KoyoSor: () => KoyoSor, ONE: () => ONE, RouteProposer: () => RouteProposer, calculatePathLimits: () => calculatePathLimits, createPath: () => createPath, filterPoolsOfInterest: () => filterPoolsOfInterest, getBoostedGraph: () => getBoostedGraph, getBoostedPaths: () => getBoostedPaths, getLimitAmountSwapForPath: () => getLimitAmountSwapForPath, getNodesAndEdges: () => getNodesAndEdges, getOutputAmountSwap: () => getOutputAmountSwap, getPathInfo: () => getPathInfo, getRaisingToken: () => getRaisingToken, pathsInfoToPaths: () => pathsInfoToPaths, producePaths: () => producePaths, scale: () => scale }); module.exports = __toCommonJS(src_exports); // src/pools/handle.ts var import_sor2 = require("@balancer-labs/sor"); // src/utilities/oldBigNumber.ts var import_sor = require("@balancer-labs/sor"); var ONE = (0, import_sor.bnum)(1); var INFINITY = (0, import_sor.bnum)("Infinity"); function scale(input, decimalPlaces) { const scalePow = new import_sor.OldBigNumber(decimalPlaces.toString()); const scaleMul = new import_sor.OldBigNumber(10).pow(scalePow); return input.times(scaleMul); } __name(scale, "scale"); // src/pools/handle.ts function getOutputAmountSwap(pool, poolPairData, swapType, amount) { if (swapType === import_sor2.SwapTypes.SwapExactIn) { if (poolPairData.poolType !== import_sor2.PoolTypes.Linear && poolPairData.balanceIn.isZero()) { return import_sor2.ZERO; } return pool._exactTokenInForTokenOut(poolPairData, amount); } if (poolPairData.balanceOut.isZero()) { return import_sor2.ZERO; } else if (scale(amount, poolPairData.decimalsOut).gte(poolPairData.balanceOut.toString())) { return INFINITY; } return pool._tokenInForExactTokenOut(poolPairData, amount); } __name(getOutputAmountSwap, "getOutputAmountSwap"); // src/routes/boosted.ts var import_sor3 = require("@balancer-labs/sor"); // src/utilities/lbp.ts function getRaisingToken(pool, lbpRaisingTokens, token) { let theOtherToken; const { tokensList } = pool; if (tokensList.includes(token) && !lbpRaisingTokens.includes(token)) { for (let i = 0; i < 2; i++) { if (tokensList[i] === token) { theOtherToken = tokensList[1 - i]; } } } return theOtherToken; } __name(getRaisingToken, "getRaisingToken"); // src/utilities/routing.ts var import_constants = require("@ethersproject/constants"); function getNodesAndEdges(pools) { const edgesFromNode = {}; for (const pool of pools) { const n = pool.tokensList.length; for (let i = 0; i < n; i++) { if (!edgesFromNode[pool.tokensList[i]]) edgesFromNode[pool.tokensList[i]] = []; for (let j = 0; j < n; j++) { if (i === j) continue; const edge = [ pool.id, pool.tokensList[i], pool.tokensList[j] ]; edgesFromNode[pool.tokensList[i]].push(edge); } } } return edgesFromNode; } __name(getNodesAndEdges, "getNodesAndEdges"); function getPathInfo(edge, treeEdge, treeEdges) { const pathEdges = [ edge ]; pathEdges.unshift(treeEdge.edge); let indices = treeEdge.parentIndices; while (indices[0] !== -1) { pathEdges.unshift(treeEdges[indices[0]][indices[1]].edge); indices = treeEdges[indices[0]][indices[1]].parentIndices; } const pools = pathEdges.map((pathEdge) => pathEdge[0]); pools.splice(0, 1); const tokens = pathEdges.map((pathEdge) => pathEdge[2]); return [ tokens, pools ]; } __name(getPathInfo, "getPathInfo"); function pathsInfoToPaths(flexBoostedPathsInfo, poolsAllDict) { const paths = []; for (const boostedPathInfo of flexBoostedPathsInfo) { const pools = boostedPathInfo[1].map((id) => poolsAllDict[id]); if (pools.length > 2) { paths.push(createPath(boostedPathInfo[0], pools)); } } return paths; } __name(pathsInfoToPaths, "pathsInfoToPaths"); function createPath(tokens, pools) { let tI; let tO; const swaps = []; const poolPairData = []; let id = ""; for (let i = 0; i < pools.length; i++) { tI = tokens[i]; tO = tokens[i + 1]; const poolPair = pools[i].parsePoolPairData(tI, tO); poolPairData.push(poolPair); id += poolPair.id; const swap = { pool: pools[i].id, tokenIn: tI, tokenOut: tO, tokenInDecimals: poolPair.decimalsIn, tokenOutDecimals: poolPair.decimalsOut }; swaps.push(swap); } const path = { id, swaps, limitAmount: import_constants.Zero, poolPairData, pools }; return path; } __name(createPath, "createPath"); // src/routes/boosted.ts function getBoostedGraph(tokenIn, tokenOut, poolsAllDict, config) { const wethAddress = config.weth.toLowerCase(); const pools = [ ...Object.values(poolsAllDict) ]; const graphPoolsSet = /* @__PURE__ */ new Set(); const linearPools = []; const phantomPools = []; const relevantRaisingTokens = []; for (const pool3 of pools) { if (pool3.poolType === import_sor3.PoolTypes.Linear) { linearPools.push(pool3); graphPoolsSet.add(pool3); } else { const tokensList = pool3.tokensList.map((address) => address.toLowerCase()); if (tokensList.includes(pool3.address)) { phantomPools.push(pool3); } if (tokenIn !== wethAddress && tokenOut !== wethAddress && tokensList.includes(wethAddress)) { if (tokensList.length <= 3 && (tokensList.includes(tokenIn) || tokensList.includes(tokenOut))) { graphPoolsSet.add(pool3); } } if (config.lbpRaisingTokens) { const raisingTokens = config.lbpRaisingTokens.map((address) => address.toLowerCase()); if (pool3.isLBP) { const raisingTokenIn = getRaisingToken(pool3, raisingTokens, tokenIn); if (raisingTokenIn) { graphPoolsSet.add(pool3); relevantRaisingTokens.push(raisingTokenIn); } const raisingTokenOut = getRaisingToken(pool3, raisingTokens, tokenOut); if (raisingTokenOut) { graphPoolsSet.add(pool3); relevantRaisingTokens.push(raisingTokenOut); } } } } } if (linearPools.length === 0) return {}; const linearPoolsAddresses = linearPools.map((pool) => pool.address); const secondStepPoolsSet = /* @__PURE__ */ new Set(); for (const pool1 of phantomPools) { for (const linearPoolAddress of linearPoolsAddresses) { if (pool1.tokensList.includes(linearPoolAddress)) { graphPoolsSet.add(pool1); secondStepPoolsSet.add(pool1); } } } const secondStepPoolsAddresses = [ ...secondStepPoolsSet ].map((pool) => pool.address); for (const pool2 of pools) { for (const secondStepPoolAddress of secondStepPoolsAddresses) { if (pool2.tokensList.includes(secondStepPoolAddress)) { graphPoolsSet.add(pool2); } } const { tokensList } = pool2; for (const raisingToken of relevantRaisingTokens) { if (tokensList.includes(raisingToken) && tokensList.includes(wethAddress) && raisingToken !== wethAddress) { graphPoolsSet.add(pool2); } } } const graphPools = [ ...graphPoolsSet ]; const edgeDict = getNodesAndEdges(graphPools); return edgeDict; } __name(getBoostedGraph, "getBoostedGraph"); function getBoostedPaths(tokenIn, tokenOut, poolsAllDict, config) { const edgesFromNode = getBoostedGraph(tokenIn, tokenOut, poolsAllDict, config); const pathsInfo = []; const rootTreeEdge = { edge: [ "", "", tokenIn ], parentIndices: [ -1, -1 ], visitedNodes: [] }; const treeEdges = [ [ rootTreeEdge ] ]; let iterate = true; while (iterate) { const n = treeEdges.length; const newTreeEdges = []; for (let i = 0; i < treeEdges[n - 1].length; i++) { const treeEdge = treeEdges[n - 1][i]; const token = treeEdge.edge[2]; const edgesFromToken = edgesFromNode[token]; if (!edgesFromToken) continue; for (const edge of edgesFromToken) { if (treeEdge.visitedNodes.includes(edge[2]) || treeEdge.edge[0] === edge[0]) { continue; } if (edge[2] === tokenOut) { pathsInfo.push(getPathInfo(edge, treeEdge, treeEdges)); } const newTreeEdge = { edge, parentIndices: [ n - 1, i ], visitedNodes: treeEdge.visitedNodes.concat(edge[1]) }; newTreeEdges.push(newTreeEdge); } } if (newTreeEdges.length === 0) { iterate = false; } else treeEdges.push(newTreeEdges); } return pathsInfoToPaths(pathsInfo, poolsAllDict); } __name(getBoostedPaths, "getBoostedPaths"); // src/routes/filter.ts function filterPoolsOfInterest(allPools, tokenIn, tokenOut, maxPools) { const directPools = {}; const hopsIn = {}; const hopsOut = {}; Object.keys(allPools).forEach((id) => { const pool = allPools[id]; const tokenListSet = new Set(pool.tokensList); const containsTokenIn = tokenListSet.has(tokenIn.toLowerCase()); const containsTokenOut = tokenListSet.has(tokenOut.toLowerCase()); if (containsTokenIn && containsTokenOut) { directPools[pool.id] = pool; return; } if (maxPools > 1) { if (containsTokenIn && !containsTokenOut) { for (const hopToken of tokenListSet) { if (!hopsIn[hopToken]) hopsIn[hopToken] = /* @__PURE__ */ new Set([]); hopsIn[hopToken].add(pool.id); } } else if (!containsTokenIn && containsTokenOut) { for (const hopToken of [ ...tokenListSet ]) { if (!hopsOut[hopToken]) hopsOut[hopToken] = /* @__PURE__ */ new Set([]); hopsOut[hopToken].add(pool.id); } } } }); return [ directPools, hopsIn, hopsOut ]; } __name(filterPoolsOfInterest, "filterPoolsOfInterest"); // src/routes/pathLimits.ts var import_sor4 = require("@balancer-labs/sor"); var import_bignumber = require("@ethersproject/bignumber"); var import_constants2 = require("@ethersproject/constants"); function calculatePathLimits(paths, swapType) { let maxLiquidityAvailable = import_constants2.Zero; paths.forEach((path) => { path.limitAmount = getLimitAmountSwapForPath(path, swapType); maxLiquidityAvailable = maxLiquidityAvailable.add(path.limitAmount); }); const sortedPaths = paths.sort((a, b) => { return b.limitAmount.gt(a.limitAmount) ? 1 : -1; }); return [ sortedPaths, maxLiquidityAvailable ]; } __name(calculatePathLimits, "calculatePathLimits"); function getLimitAmountSwapForPath(path, swapType) { const { poolPairData } = path; let limit; if (swapType === import_sor4.SwapTypes.SwapExactIn) { limit = path.pools[poolPairData.length - 1].getLimitAmountSwap(poolPairData[poolPairData.length - 1], import_sor4.SwapTypes.SwapExactIn); for (let i = poolPairData.length - 2; i >= 0; i--) { const poolLimitExactIn = path.pools[i].getLimitAmountSwap(poolPairData[i], import_sor4.SwapTypes.SwapExactIn); const poolLimitExactOut = path.pools[i].getLimitAmountSwap(poolPairData[i], import_sor4.SwapTypes.SwapExactOut); if (poolLimitExactOut.lte(limit)) { limit = poolLimitExactIn; } else { const pulledLimit = getOutputAmountSwap(path.pools[i], path.poolPairData[i], import_sor4.SwapTypes.SwapExactOut, limit); limit = import_sor4.OldBigNumber.min(pulledLimit, poolLimitExactIn); } } if (limit.isZero()) return import_constants2.Zero; const result = (0, import_bignumber.parseFixed)(limit.dp(poolPairData[0].decimalsIn).toString(), poolPairData[0].decimalsIn); return result; } limit = path.pools[0].getLimitAmountSwap(poolPairData[0], import_sor4.SwapTypes.SwapExactOut); for (let i = 1; i < poolPairData.length; i++) { const poolLimitExactIn = path.pools[i].getLimitAmountSwap(poolPairData[i], import_sor4.SwapTypes.SwapExactIn); const poolLimitExactOut = path.pools[i].getLimitAmountSwap(poolPairData[i], import_sor4.SwapTypes.SwapExactOut); if (poolLimitExactIn.lte(limit)) { limit = poolLimitExactOut; } else { const pushedLimit = getOutputAmountSwap(path.pools[i], path.poolPairData[i], import_sor4.SwapTypes.SwapExactIn, limit); limit = import_sor4.OldBigNumber.min(pushedLimit, poolLimitExactOut); } } if (limit.isZero()) return import_constants2.Zero; return (0, import_bignumber.parseFixed)(limit.dp(poolPairData[poolPairData.length - 1].decimalsOut).toString(), poolPairData[poolPairData.length - 1].decimalsOut); } __name(getLimitAmountSwapForPath, "getLimitAmountSwapForPath"); // src/routes/produce.ts var import_sor5 = require("@balancer-labs/sor"); function producePaths(tokenIn, tokenOut, directPools, hopsIn, hopsOut, pools) { const paths = []; for (const directPool of [ ...Object.values(directPools) ]) { const path = createPath([ tokenIn, tokenOut ], [ pools[directPool.id] ]); paths.push(path); } for (const hopToken in hopsIn) { if (hopsOut[hopToken]) { let highestNormalizedLiquidityFirst = import_sor5.ZERO; let highestNormalizedLiquidityFirstPoolId; let highestNormalizedLiquiditySecond = import_sor5.ZERO; let highestNormalizedLiquiditySecondPoolId; for (const poolInId of [ ...hopsIn[hopToken] ]) { const poolIn = pools[poolInId]; const poolPairData = poolIn.parsePoolPairData(tokenIn, hopToken); const normalizedLiquidity = poolIn.getNormalizedLiquidity(poolPairData); if (normalizedLiquidity.isGreaterThanOrEqualTo(highestNormalizedLiquidityFirst)) { highestNormalizedLiquidityFirst = normalizedLiquidity; highestNormalizedLiquidityFirstPoolId = poolIn.id; } } for (const poolOutId of [ ...hopsOut[hopToken] ]) { const poolOut = pools[poolOutId]; const poolPairData = poolOut.parsePoolPairData(hopToken, tokenOut); const normalizedLiquidity = poolOut.getNormalizedLiquidity(poolPairData); if (normalizedLiquidity.isGreaterThanOrEqualTo(highestNormalizedLiquiditySecond)) { highestNormalizedLiquiditySecond = normalizedLiquidity; highestNormalizedLiquiditySecondPoolId = poolOut.id; } } if (highestNormalizedLiquidityFirstPoolId && highestNormalizedLiquiditySecondPoolId) { const path = createPath([ tokenIn, hopToken, tokenOut ], [ pools[highestNormalizedLiquidityFirstPoolId], pools[highestNormalizedLiquiditySecondPoolId] ]); paths.push(path); } } } return paths; } __name(producePaths, "producePaths"); // src/routes/proposer.ts var import_sor6 = require("@balancer-labs/sor"); var RouteProposer = class { constructor(config) { this.config = config; this.cache = {}; } getCandidatePaths(tokenIn, tokenOut, swapType, pools, swapOptions) { tokenIn = tokenIn.toLowerCase(); tokenOut = tokenOut.toLowerCase(); if (pools.length === 0) return []; const cache = this.cache[`${tokenIn}${tokenOut}${swapType}${swapOptions.timestamp}`]; if (!swapOptions.forceRefresh && Boolean(cache)) { return cache.paths; } const poolsAllDict = (0, import_sor6.parseToPoolsDict)(pools, swapOptions.timestamp); const [directPools, hopsIn, hopsOut] = filterPoolsOfInterest(poolsAllDict, tokenIn, tokenOut, swapOptions.maxPools); const pathData = producePaths(tokenIn, tokenOut, directPools, hopsIn, hopsOut, poolsAllDict); const boostedPaths = getBoostedPaths(tokenIn, tokenOut, poolsAllDict, this.config); const combinedPathData = pathData.concat(...boostedPaths); const [paths] = calculatePathLimits(combinedPathData, swapType); this.cache[`${tokenIn}${tokenOut}${swapType}${swapOptions.timestamp}`] = { paths }; return paths; } getCandidatePathsFromDict(tokenIn, tokenOut, swapType, poolsAllDict, maxPools) { tokenIn = tokenIn.toLowerCase(); tokenOut = tokenOut.toLowerCase(); if (Object.keys(poolsAllDict).length === 0) return []; const [directPools, hopsIn, hopsOut] = filterPoolsOfInterest(poolsAllDict, tokenIn, tokenOut, maxPools); const pathData = producePaths(tokenIn, tokenOut, directPools, hopsIn, hopsOut, poolsAllDict); const boostedPaths = getBoostedPaths(tokenIn, tokenOut, poolsAllDict, this.config); const combinedPathData = pathData.concat(...boostedPaths); const [paths] = calculatePathLimits(combinedPathData, swapType); return paths; } }; __name(RouteProposer, "RouteProposer"); // src/sor.ts var import_sor7 = require("@balancer-labs/sor"); var KoyoSor = class extends import_sor7.SOR { constructor(provider, config, poolDataService, tokenPriceService) { super(provider, config, poolDataService, tokenPriceService); this.routeProposer = new RouteProposer(config); } }; __name(KoyoSor, "KoyoSor"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { INFINITY, KoyoSor, ONE, RouteProposer, calculatePathLimits, createPath, filterPoolsOfInterest, getBoostedGraph, getBoostedPaths, getLimitAmountSwapForPath, getNodesAndEdges, getOutputAmountSwap, getPathInfo, getRaisingToken, pathsInfoToPaths, producePaths, scale }); //# sourceMappingURL=index.js.map