From 87b8f79f4726e0d6bd7c2f90d7bec09d73fb311d Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 11 Nov 2023 11:51:38 -0600 Subject: [PATCH 1/6] chore: changesets tests --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf7b563..88beb27 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,6 @@ Docs will be available on a vitepress site. You can run the site locally with th ``` $ yarn docs:dev -``` \ No newline at end of file +``` + +this is a test pr change for changesets automation \ No newline at end of file From 51c7ea4a7b04e5fe32feb60214775fbf7e8840ea Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 13 Nov 2023 22:03:12 -0600 Subject: [PATCH 2/6] feat: add router, modify pool info data model --- docs/queries/swap.md | 6 +- src/contracts/services/swap.ts | 11 +- src/lib/swap/router.test.ts | 552 ++++++++ src/lib/swap/router.ts | 412 ++++++ src/lib/utils.test.ts | 23 + src/lib/utils.ts | 48 + src/test/mocks/swap/batchPairsInfoParsed.ts | 6 - src/test/mocks/swap/pairInfoParsed.ts | 4 +- src/test/mocks/swap/router.ts | 1274 +++++++++++++++++++ src/types/contracts/swap/model.ts | 4 +- src/types/shared.ts | 10 + src/types/swap/router.ts | 26 + 12 files changed, 2353 insertions(+), 23 deletions(-) create mode 100644 src/lib/swap/router.test.ts create mode 100644 src/lib/swap/router.ts create mode 100644 src/test/mocks/swap/router.ts create mode 100644 src/types/shared.ts create mode 100644 src/types/swap/router.ts diff --git a/docs/queries/swap.md b/docs/queries/swap.md index c02fe2b..b79affb 100644 --- a/docs/queries/swap.md +++ b/docs/queries/swap.md @@ -327,18 +327,16 @@ type PairInfo = { isStable: boolean, token0Amount: string, token1Amount: string, - priceRatio: string | null, pairSettings: { lpFee: number, daoFee: number, - stableLpFee: number, - stableDaoFee: number, stableParams: StableParams | null }, contractVersion: number, } type StableParams = { + priceRatio: string, alpha: string, gamma1: string, gamma2: string, @@ -413,7 +411,6 @@ console.log(output) "token0Amount": "4268251730565", "token1Amount": "365239579269", "lpTokenAmount": "487393298891", - "priceRatio": null, "pairSettings": { "lpFee": 0.0029, "daoFee": 0.0001, @@ -448,7 +445,6 @@ console.log(output) "token0Amount": "95199329571", "token1Amount": "377657768", "lpTokenAmount": "5708789507", - "priceRatio": null, "pairSettings": { "lpFee": 0.0029, "daoFee": 0.0001, diff --git a/src/contracts/services/swap.ts b/src/contracts/services/swap.ts index 0095331..e9d3418 100644 --- a/src/contracts/services/swap.ts +++ b/src/contracts/services/swap.ts @@ -187,14 +187,13 @@ function parsePairInfo( token0Amount: pairInfo.amount_0, token1Amount: pairInfo.amount_1, lpTokenAmount: pairInfo.total_liquidity, - priceRatio: stableInfo ? stableInfo.p : null, pairSettings: { - lpFee: fees.lp_fee.nom / fees.lp_fee.denom, - daoFee: fees.shade_dao_fee.nom / fees.shade_dao_fee.denom, - stableLpFee: fees.stable_lp_fee.nom / fees.stable_lp_fee.denom, - stableDaoFee: fees.stable_shade_dao_fee.nom / fees.stable_shade_dao_fee.denom, - + lpFee: pairInfo.pair[2] ? fees.stable_lp_fee.nom / fees.stable_lp_fee.denom + : fees.lp_fee.nom / fees.lp_fee.denom, + daoFee: pairInfo.pair[2] ? fees.stable_shade_dao_fee.nom / fees.stable_shade_dao_fee.denom + : fees.shade_dao_fee.nom / fees.shade_dao_fee.denom, stableParams: stableInfo ? { + priceRatio: stableInfo.p!, // if stable params exist, we know price ratio will be available alpha: stableInfo.stable_params.a, gamma1: stableInfo.stable_params.gamma1, gamma2: stableInfo.stable_params.gamma2, diff --git a/src/lib/swap/router.test.ts b/src/lib/swap/router.test.ts new file mode 100644 index 0000000..71b2fdf --- /dev/null +++ b/src/lib/swap/router.test.ts @@ -0,0 +1,552 @@ +import { + test, + expect, +} from 'vitest'; +import { + getPossiblePaths, + forwardCalculateRoute, + getRoutes, +} from '~/lib/swap/router'; +import BigNumber from 'bignumber.js'; +import { + batchPairsInfoMock, + batchPairsInfoMockForComplexRoute, + tokenConfigMock, +} from '~/test/mocks/swap/router'; +import { GasMultiplier } from '~/types/swap/router'; + +test('it can generate possible route paths', () => { + // Returns single pair + // + // pair1 + // (A-B) + const output1 = [['CONTRACT_ADDRESS_PAIR_1']]; + expect(getPossiblePaths({ + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_B_CONTRACT_ADDRESS', + maxHops: 5, + pairs: batchPairsInfoMock, + })).toStrictEqual(output1); + + // ************************************************** + // Returns a linear path + // + // pair1 -> pair2 -> pair3 + // (A-B) -> (B-C) -> (D-C) + const output2 = [[ + 'CONTRACT_ADDRESS_PAIR_1', + 'CONTRACT_ADDRESS_PAIR_2', + 'CONTRACT_ADDRESS_PAIR_3', + ]]; + expect(getPossiblePaths({ + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_D_CONTRACT_ADDRESS', + maxHops: 5, + pairs: batchPairsInfoMock, + })).toStrictEqual(output2); + + // ************************************************** + // Returns circular pair of routes + // + // E -- pair4 -- F -- pair5 -- G -- pair6 + // (E-F) (G-F) (G-H) + // | | + // F H + // | | + // pair7 -- I -- pair8 -- H -- pair9 -- J + // (F-I) (I-H) (H-J) + const output3 = [ + [ + 'CONTRACT_ADDRESS_PAIR_4', + 'CONTRACT_ADDRESS_PAIR_5', + 'CONTRACT_ADDRESS_PAIR_6', + 'CONTRACT_ADDRESS_PAIR_9', + ], + [ + 'CONTRACT_ADDRESS_PAIR_4', + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_9', + ], + ]; + expect(getPossiblePaths({ + inputTokenContractAddress: 'TOKEN_E_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_J_CONTRACT_ADDRESS', + maxHops: 5, + pairs: batchPairsInfoMock, + })).toStrictEqual(output3); + + // ************************************************** + // A complex route + // F + // / \ + // / \ + // 1 2 + // (A-F) (F-D) + // / \ + // / 3 \ 4 + // A --- (A-D) --- D --- (D-G) --- G + // |\ / | + // | \ / | + // | 5 6 | + // | (A-C) (D-C) | + // | \ / | + // 7 \ / 8 + // (A-B) C (D-E) + // | / \ | + // | 9 10 | + // | (C-B) (C-E) | + // | / \ | + // | / 11 \ | + // B --- (B-E) --- E + + const output4 = [ + [ + 'CONTRACT_ADDRESS_PAIR_1', + 'CONTRACT_ADDRESS_PAIR_2', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_3', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_3', + 'CONTRACT_ADDRESS_PAIR_6', + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_4', + ], + ['CONTRACT_ADDRESS_PAIR_3', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_6', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_5', + 'CONTRACT_ADDRESS_PAIR_6', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_5', + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_5', + 'CONTRACT_ADDRESS_PAIR_9', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_5', + 'CONTRACT_ADDRESS_PAIR_9', + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_3', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_9', + 'CONTRACT_ADDRESS_PAIR_6', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_6', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_9', + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_8', + 'CONTRACT_ADDRESS_PAIR_4', + ], + [ + 'CONTRACT_ADDRESS_PAIR_7', + 'CONTRACT_ADDRESS_PAIR_9', + 'CONTRACT_ADDRESS_PAIR_5', + 'CONTRACT_ADDRESS_PAIR_3', + 'CONTRACT_ADDRESS_PAIR_4', + ], + ]; + expect(getPossiblePaths({ + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_G_CONTRACT_ADDRESS', + maxHops: 5, + pairs: batchPairsInfoMockForComplexRoute, + }).sort()).toStrictEqual(output4.sort()); +}); + +test('it can calculate the output of a single pool swap route', () => { + // Single Pool calculations + // + // Pool 1: A-B + // + // Pool A-B params + // Liquidity A: 111,111,111 + // Liquidity B: 222,222,222 + // Dao Fee: 0.1 + // LP Fee: 0.2 + // + + const output = { + inputAmount: BigNumber('1000000000'), + quoteOutputAmount: BigNumber('1939982540'), + quoteShadeDaoFee: BigNumber(0.01), + quoteLPFee: BigNumber(0.02), + priceImpact: BigNumber('0.000009000000009'), + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_B_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_1'], + gasMultiplier: GasMultiplier.CONSTANT_PRODUCT, + }; + expect(forwardCalculateRoute({ + inputTokenAmount: BigNumber('1000000000'), + inputTokenContractAddress: output.inputTokenContractAddress, + path: ['CONTRACT_ADDRESS_PAIR_1'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + })).toStrictEqual(output); +}); + +test('it can calculate the output of a multi-hop constant product swap route', () => { + // ************************************************** + // Constant Product Rule Only + // + // Pool 2 has order of token0 and token1 flipped + // i.e. A-B -> C-B -> C-D + // + // Pool A-B params + // Liquidity A: 111,111,111 + // Liquidity B: 222,222,222 + // dao Fee: 0.01 + // liquidity provider Fee: 0.02 + // + // Pool C-B params + // Liquidity C: 333,333,333 + // Liquidity B: 4,444,444,444 + // dao Fee: 0.01 + // liquidity provider Fee: 0.01 + // + // Pool C-B params + // Liquidity C: 5,555,555,555 + // Liquidity D: 66,666,666 + // dao Fee: 0.02 + // liquidity provider Fee: 0.02 + + // Pool A-B + const constantProductSwap1Output = forwardCalculateRoute({ + inputTokenAmount: BigNumber('1000000000'), + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_1'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // pool C-B + const constantProductSwap2Output = forwardCalculateRoute({ + inputTokenAmount: constantProductSwap1Output, + inputTokenContractAddress: 'TOKEN_B_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_2'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // pool C-D + const constantProductSwap3Output = forwardCalculateRoute({ + inputTokenAmount: constantProductSwap2Output, + inputTokenContractAddress: 'TOKEN_C_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_3'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // combine into multi-hop routing (FORWARD) + const calulatedRouteResult = forwardCalculateRoute({ + inputTokenAmount: BigNumber('1000000000'), + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_1', + 'CONTRACT_ADDRESS_PAIR_2', + 'CONTRACT_ADDRESS_PAIR_3', + ], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }); + + const output = { + inputAmount: BigNumber('1000000000'), + quoteOutputAmount: BigNumber('1642621'), + quoteShadeDaoFee: BigNumber(0.04), + quoteLPFee: BigNumber(0.05), + priceImpact: BigNumber('0.000009462162038267'), + inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_D_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_1', + 'CONTRACT_ADDRESS_PAIR_2', + 'CONTRACT_ADDRESS_PAIR_3', + ], + gasMultiplier: GasMultiplier.CONSTANT_PRODUCT * 3, + }; + + // Output Object validation + expect(calulatedRouteResult).toStrictEqual(output); + + // Output Amount validation + expect(calulatedRouteResult.quoteOutputAmount).toStrictEqual(constantProductSwap3Output); +}); + +test('it can calculate the output of a multi-hop stable swap route', () => { + // ************************************************** + // Stable Swaps in all pools + // + // 2nd has order of token0 and token1 flipped + // i.e. K-L -> M-L -> M-N + // + // Pool K-L params + // Liquidity K: 999,999,999 + // Liquidity L: 325,000,000 + // priceRatio: 3 + // a: 10, + // gamma1: 4, + // gamma2: 5, + // dao Fee: 0.01 + // liquidity provider Fee: 0.01 + // + // Pool M-L params + // Liquidity M: 999,999,999 + // Liquidity L: 325,000,000 + // priceRatio: 3 + // a: 10, + // gamma1: 4, + // gamma2: 5, + // dao Fee: 0.01 + // liquidity provider Fee: 0.01 + // + // Pool M-N params + // Liquidity M: 999,999,999 + // Liquidity N: 325,000,000 + // priceRatio: 3 + // a: 10, + // gamma1: 4, + // gamma2: 5, + // dao Fee: 0.01 + // liquidity provider Fee: 0.01 + + // First simulate indidual swaps using outputs as inputs of the following + + // Pool K-L + const stableSwap1Output = forwardCalculateRoute({ + inputTokenAmount: BigNumber('100000000'), + inputTokenContractAddress: 'TOKEN_K_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_10'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // pool M-L + const stableSwap2Output = forwardCalculateRoute({ + inputTokenAmount: stableSwap1Output, + inputTokenContractAddress: 'TOKEN_L_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_11'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // pool M-N + const stableSwap3Output = forwardCalculateRoute({ + inputTokenAmount: stableSwap2Output, + inputTokenContractAddress: 'TOKEN_M_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_12'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // combine into multi-hop routing + const calulatedStableRouteResult = forwardCalculateRoute({ + inputTokenAmount: BigNumber('100000000'), + inputTokenContractAddress: 'TOKEN_K_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_12', + ], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }); + + // expected output object + const output = { + inputAmount: BigNumber('100000000'), + quoteOutputAmount: BigNumber('36551499'), + quoteShadeDaoFee: BigNumber('0.03'), + quoteLPFee: BigNumber('0.03'), + priceImpact: BigNumber('6.23997608623458059756756e-7'), + inputTokenContractAddress: 'TOKEN_K_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_N_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_10', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_12', + ], + gasMultiplier: GasMultiplier.STABLE * 3, + }; + + // Output Object validation + expect(calulatedStableRouteResult).toStrictEqual(output); + + // Output Amount validation + expect(calulatedStableRouteResult.quoteOutputAmount).toStrictEqual(stableSwap3Output); +}); + +test('it can calculate the output of a multi-hop mixed swap route', () => { + // ************************************************** + // Mix of constant product -> stableswap -> constant product + // pools: O-L -> M-L -> M-P + // + // Pool O-L params + // Liquidity O: 111,111,111 + // Liquidity L: 222,222,222 + // dao Fee: 0.01 + // liquidity provider Fee: 0.02 + // + // Pool M-L params + // Liquidity M: 999,999,999 + // Liquidity L: 325,000,000 + // priceRatio: 3 + // a: 10, + // gamma1: 4, + // gamma2: 5, + // dao Fee: 0.01 + // liquidity provider Fee: 0.01 + // + // Pool M-P params + // Liquidity A: 111,111,111 + // Liquidity B: 222,222,222 + // dao Fee: 0.01 + // liquidity provider Fee: 0.02 + + // First simulate indidual swaps using outputs as inputs of the following + // Pool O-L + + const mixedSwapConstantProduct1Output = forwardCalculateRoute({ + inputTokenAmount: BigNumber('100000000'), + inputTokenContractAddress: 'TOKEN_O_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_13'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // pool M-L + const mixedSwapStableSwapOutput = forwardCalculateRoute({ + inputTokenAmount: mixedSwapConstantProduct1Output, + inputTokenContractAddress: 'TOKEN_L_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_11'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // pool M-P + const mixedSwapConstantProduct2Output = forwardCalculateRoute({ + inputTokenAmount: mixedSwapStableSwapOutput, + inputTokenContractAddress: 'TOKEN_M_CONTRACT_ADDRESS', + path: ['CONTRACT_ADDRESS_PAIR_14'], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }).quoteOutputAmount; + + // combined multi-hop + const mixedMultiHopResult = forwardCalculateRoute({ + inputTokenAmount: BigNumber('100000000'), + inputTokenContractAddress: 'TOKEN_O_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_13', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_14', + ], + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }); + + expect(mixedMultiHopResult.quoteOutputAmount).toStrictEqual(mixedSwapConstantProduct2Output); + + const output = { + inputAmount: BigNumber('100000000'), + quoteOutputAmount: BigNumber('949728643'), + quoteShadeDaoFee: BigNumber('0.03'), + quoteLPFee: BigNumber('0.05'), + priceImpact: BigNumber('0.000006366091506753980711557256'), + inputTokenContractAddress: 'TOKEN_O_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_P_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_13', + 'CONTRACT_ADDRESS_PAIR_11', + 'CONTRACT_ADDRESS_PAIR_14', + ], + gasMultiplier: GasMultiplier.CONSTANT_PRODUCT * 2 + GasMultiplier.STABLE, + }; + + // Output Object validation + expect(mixedMultiHopResult).toStrictEqual(output); + + // Output Amount validation + expect(mixedMultiHopResult.quoteOutputAmount).toStrictEqual(mixedSwapConstantProduct2Output); +}); + +test('it can calculate all routes for input + output token', () => { + const result = getRoutes({ + inputTokenAmount: BigNumber('100000000'), + inputTokenContractAddress: 'TOKEN_Q_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_T_CONTRACT_ADDRESS', + maxHops: 5, + pairs: batchPairsInfoMock, + tokens: tokenConfigMock, + }); + + const output1 = { + inputAmount: BigNumber('100000000'), + quoteOutputAmount: BigNumber('36551499'), + quoteShadeDaoFee: BigNumber('0.03'), + quoteLPFee: BigNumber('0.03'), + priceImpact: BigNumber('6.23997608623458059756756e-7'), + inputTokenContractAddress: 'TOKEN_Q_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_T_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_15', + 'CONTRACT_ADDRESS_PAIR_16', + 'CONTRACT_ADDRESS_PAIR_17', + ], + gasMultiplier: GasMultiplier.STABLE * 3, + }; + + const output2 = { + inputAmount: BigNumber('100000000'), + quoteOutputAmount: BigNumber('96039896'), + quoteShadeDaoFee: BigNumber('0.02'), + quoteLPFee: BigNumber('0.02'), + priceImpact: BigNumber('0.000001081968422993497890830615'), + inputTokenContractAddress: 'TOKEN_Q_CONTRACT_ADDRESS', + outputTokenContractAddress: 'TOKEN_T_CONTRACT_ADDRESS', + path: [ + 'CONTRACT_ADDRESS_PAIR_18', + 'CONTRACT_ADDRESS_PAIR_17', + ], + gasMultiplier: GasMultiplier.STABLE * 2, + }; + + expect(result).toStrictEqual([output2, output1]); +}); diff --git a/src/lib/swap/router.ts b/src/lib/swap/router.ts new file mode 100644 index 0000000..a352c90 --- /dev/null +++ b/src/lib/swap/router.ts @@ -0,0 +1,412 @@ +import { + constantProductSwapToken0for1, + constantProductSwapToken1for0, + stableSwapToken0for1, + stableSwapToken1for0, + constantProductPriceImpactToken0for1, + constantProductPriceImpactToken1for0, + stableSwapPriceImpactToken0For1, + stableSwapPriceImpactToken1For0, +} from '~/lib/swap/swapCalculations'; +import BigNumber from 'bignumber.js'; +import { BatchPairsInfo } from '~/types/contracts/swap/model'; +import { + GasMultiplier, + Route, +} from '~/types/swap/router'; +import { TokensConfig } from '~/types/shared'; +import { + convertCoinToUDenom, + convertCoinFromUDenom, + getTokenDecimalsByTokenConfig, +} from '~/lib/utils'; + +/** +* retuns possible paths through one or multiple pools to complete a trade of two tokens +*/ +function getPossiblePaths({ + inputTokenContractAddress, + outputTokenContractAddress, + maxHops, + pairs, +}:{ + inputTokenContractAddress:string, + outputTokenContractAddress:string + maxHops: number + pairs: BatchPairsInfo +}) { + // keeps track of the current path we are exploring + const path: string[] = []; + // keeps track of all the paths found from the starting token to the ending token + const result: string[][] = []; + // keeps track of the pools that have been visited to avoid loops + const visited = new Set(); + + // depth-first search function + function dfs(tokenContractAddress: string, depth: number) { + // if the current depth exceeds the maximum number of hops, return + if (depth > maxHops) { + return; + } + + // if we have reached the ending token, add the current path to the result and return + if (tokenContractAddress === outputTokenContractAddress) { + result.push([...path]); + return; + } + + // iterate through all the pools + Object.values(pairs).forEach((pair) => { + const { + pairContractAddress, + pairInfo, + } = pair; + + // if the current pool has already been visited, return + if (visited.has(pairContractAddress)) { + return; + } + + // if the current pool contains the token we are currently exploring, + // add it to the path and mark it as visited + if (pairInfo.token0Contract.address === tokenContractAddress + || pairInfo.token1Contract.address === tokenContractAddress) { + path.push(pairContractAddress); + visited.add(pairContractAddress); + + // if the token we are currently exploring is token0 in the current pool, + // explore token1 tokenAddress + if (pairInfo.token0Contract.address === tokenContractAddress) { + dfs(pairInfo.token1Contract.address, depth + 1); + } else { + // if the token we are currently exploring is token1 in the current pool, + // explore token0 next + dfs(pairInfo.token0Contract.address, depth + 1); + } + + // backtrack by removing the current pool from the path and marking it as unvisited + visited.delete(pairContractAddress); + path.pop(); + } + }); + } + + // start exploring from the starting token + dfs(inputTokenContractAddress, 0); + return result; +} + +/** +* calculates the estimated output of swapping through a route given an input token amount +* and also transforms the data collected in each pool into the Route data model +*/ +function forwardCalculateRoute({ + inputTokenAmount, + inputTokenContractAddress, + path, + pairs, + tokens, +}:{ + inputTokenAmount: BigNumber, + inputTokenContractAddress: string, + path: string[], + pairs: BatchPairsInfo, + tokens: TokensConfig, // list of all possible swap tokens +}): Route { + // calculate output of the route + const routeCalculation = path.reduce((prev, poolContractAddress) => { + const { + // set previous pool swap output as the new input + outputTokenContractAddress: currentTokenContractAddress, + quoteOutputAmount: inputAmount, + quoteShadeDaoFee, + quotePriceImpact, + quoteLPFee, + gasMultiplier, + } = prev; + + let swapAmountOutput; + let swapPriceImpact; + let poolMultiplier; + let daoFee; + let lpFee; + + const pairArr = pairs.filter( + (pair) => pair.pairContractAddress === poolContractAddress, + ); + if (pairArr.length === 0) { + throw new Error(`Pair ${poolContractAddress} not available`); + } + + if (pairArr.length > 1) { + throw new Error(`Duplicate ${poolContractAddress} pairs found`); + } + + // at this point we have determined there is a single match + const pair = pairArr[0]; + + const { + pairInfo: { + token0Contract, + token1Contract, + token0Amount, + token1Amount, + pairSettings, + isStable, + }, + } = pair; + // Convert pool liquidity from human readable to raw number for + // constant product swap calculations + // at this point we have determined there is a single match + const poolToken0Decimals = getTokenDecimalsByTokenConfig( + token0Contract.address, + tokens, + ); + const poolToken1Decimals = getTokenDecimalsByTokenConfig( + token1Contract.address, + tokens, + ); + + const poolToken0AmountHumanReadable = convertCoinFromUDenom( + token0Amount, + poolToken0Decimals, + ); + const poolToken1AmountHumanReadable = convertCoinFromUDenom( + token1Amount, + poolToken1Decimals, + ); + + // converts input amount from raw number to human readable for use as an input + // to the stableswap calculations. + const inputTokenDecimals = getTokenDecimalsByTokenConfig( + currentTokenContractAddress, + tokens, + ); + + const inputAmountHumanReadable = convertCoinFromUDenom( + inputAmount, + inputTokenDecimals, + ); + + // determine token id of the output token in the swap + let outputTokenContractAddress; + if (currentTokenContractAddress === token0Contract.address) { + outputTokenContractAddress = token1Contract.address; + } else { + outputTokenContractAddress = token0Contract.address; + } + + // determine decimals of the output token + const outputTokenDecimals = getTokenDecimalsByTokenConfig( + outputTokenContractAddress, + tokens, + ); + + // Stable Pool calculations + const { stableParams } = pairSettings; + if (isStable && stableParams) { + poolMultiplier = GasMultiplier.STABLE; + + // token0 as the input + if (currentTokenContractAddress === token0Contract.address) { + const swapParams = { + inputToken0Amount: inputAmountHumanReadable, + poolToken0Amount: poolToken0AmountHumanReadable, + poolToken1Amount: poolToken1AmountHumanReadable, + priceRatio: BigNumber(stableParams.priceRatio), + alpha: BigNumber(stableParams.alpha), + gamma1: BigNumber(stableParams.gamma1), + gamma2: BigNumber(stableParams.gamma2), + liquidityProviderFee: BigNumber(pairSettings.lpFee), + daoFee: BigNumber(pairSettings.daoFee), + minTradeSizeToken0For1: BigNumber(stableParams.minTradeSizeXForY), + minTradeSizeToken1For0: BigNumber(stableParams.minTradeSizeYForX), + priceImpactLimit: BigNumber(stableParams.maxPriceImpactAllowed), + }; + + const swapAmountOutputHumanReadable = stableSwapToken0for1(swapParams); + + swapAmountOutput = BigNumber(convertCoinToUDenom( + swapAmountOutputHumanReadable, + outputTokenDecimals, + )); + swapPriceImpact = stableSwapPriceImpactToken0For1(swapParams); + // token1 as the input + } else if (currentTokenContractAddress === token1Contract.address) { + const swapParams = { + inputToken1Amount: inputAmountHumanReadable, + poolToken0Amount: poolToken0AmountHumanReadable, + poolToken1Amount: poolToken1AmountHumanReadable, + priceRatio: BigNumber(stableParams.priceRatio), + alpha: BigNumber(stableParams.alpha), + gamma1: BigNumber(stableParams.gamma1), + gamma2: BigNumber(stableParams.gamma2), + liquidityProviderFee: BigNumber(pairSettings.lpFee), + daoFee: BigNumber(pairSettings.daoFee), + minTradeSizeToken0For1: BigNumber(stableParams.minTradeSizeXForY), + minTradeSizeToken1For0: BigNumber(stableParams.minTradeSizeYForX), + priceImpactLimit: BigNumber(stableParams.maxPriceImpactAllowed), + }; + + const swapAmountOutputHumanReadable = stableSwapToken1for0(swapParams); + + swapAmountOutput = BigNumber(convertCoinToUDenom( + swapAmountOutputHumanReadable, + outputTokenDecimals, + )); + swapPriceImpact = stableSwapPriceImpactToken1For0(swapParams); + } else { + throw Error('stableswap parameter error'); + } + // set fees + daoFee = BigNumber(pairSettings.daoFee); + lpFee = BigNumber(pairSettings.lpFee); + } else { + poolMultiplier = GasMultiplier.CONSTANT_PRODUCT; + // non-stable pools using constant product rule math + // token0 as the input + if (currentTokenContractAddress === token0Contract.address) { + swapAmountOutput = constantProductSwapToken0for1({ + token0LiquidityAmount: BigNumber(token0Amount), + token1LiquidityAmount: BigNumber(token1Amount), + token0InputAmount: inputAmount, + fee: BigNumber(pairSettings.lpFee).plus(pairSettings.daoFee), + }); + + swapPriceImpact = constantProductPriceImpactToken0for1({ + token0LiquidityAmount: BigNumber(token0Amount), + token1LiquidityAmount: BigNumber(token1Amount), + token0InputAmount: inputAmount, + }); + // non-stable pools using constant product rule math + // token1 as the input + } else if (currentTokenContractAddress === token1Contract.address) { + swapAmountOutput = constantProductSwapToken1for0({ + token0LiquidityAmount: BigNumber(token0Amount), + token1LiquidityAmount: BigNumber(token1Amount), + token1InputAmount: inputAmount, + fee: BigNumber(pairSettings.lpFee).plus(pairSettings.daoFee), + }); + + swapPriceImpact = constantProductPriceImpactToken1for0({ + token0LiquidityAmount: BigNumber(token0Amount), + token1LiquidityAmount: BigNumber(token1Amount), + token1InputAmount: inputAmount, + }); + } else { + throw Error('constant product rule swap parameter error'); + } + daoFee = BigNumber(pairSettings.daoFee); + lpFee = BigNumber(pairSettings.lpFee); + } + + // output data for the reduce function + return { + outputTokenContractAddress, + quoteOutputAmount: swapAmountOutput, + quoteShadeDaoFee: quoteShadeDaoFee.plus(daoFee), + quoteLPFee: quoteLPFee.plus(lpFee), + quotePriceImpact: quotePriceImpact.plus(swapPriceImpact), + gasMultiplier: gasMultiplier + poolMultiplier, + }; + + // reduce function starting values + }, { + outputTokenContractAddress: inputTokenContractAddress, + quoteOutputAmount: inputTokenAmount, + quoteShadeDaoFee: BigNumber(0), + quoteLPFee: BigNumber(0), + quotePriceImpact: BigNumber(0), + gasMultiplier: 0, + }); + + // formulate the Routes data model + const { + outputTokenContractAddress, + quoteOutputAmount, + quoteShadeDaoFee, + quoteLPFee, + quotePriceImpact, + gasMultiplier, + } = routeCalculation; + + return { + inputAmount: inputTokenAmount, + quoteOutputAmount, + quoteShadeDaoFee, + quoteLPFee, + priceImpact: quotePriceImpact, + inputTokenContractAddress, + outputTokenContractAddress, + path, + gasMultiplier, + }; +} + +/** +* retrieves all potential route options and the outputs of each route. +* returns an array of routes in the order that will give the highest quoted +* output amount +*/ +function getRoutes({ + inputTokenAmount, + inputTokenContractAddress, + outputTokenContractAddress, + maxHops, + pairs, + tokens, +}: { + inputTokenAmount: BigNumber, + inputTokenContractAddress: string, + outputTokenContractAddress: string, + maxHops: number, + pairs: BatchPairsInfo, + tokens: TokensConfig, +}) { + // generates possible routes as the swap path + const possiblePaths = getPossiblePaths({ + inputTokenContractAddress, + outputTokenContractAddress, + maxHops, + pairs, + }); + + if (possiblePaths.length === 0) { + return []; + } + + const routes = possiblePaths.reduce((prev, path) => { + try { + const newRoute = forwardCalculateRoute({ + inputTokenAmount, + inputTokenContractAddress, + path, + pairs, + tokens, + }); + prev.push(newRoute); + return prev; + // for any errors skip the path as a possible route + } catch { + return prev; + } + }, [] as Route[]); + + // returns routes in the order that maximizes the users output + return routes.sort((a: Route, b: Route) => { + // sort by output amounts + + if (a.quoteOutputAmount.isGreaterThan(b.quoteOutputAmount)) { + return -1; // sort a before b + } + if (a.quoteOutputAmount.isLessThan(b.quoteOutputAmount)) { + return 1; // sort a after b + } + return 0; // keep original order of a and b + }); +} +export { + getPossiblePaths, + forwardCalculateRoute, + getRoutes, +}; diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index 4659c3c..450871e 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -1,3 +1,4 @@ +import BigNumber from 'bignumber.js'; import { test, expect, @@ -7,6 +8,8 @@ import { encodeJsonToB64, decodeB64ToJson, randomPadding, + convertCoinFromUDenom, + convertCoinToUDenom, } from './utils'; test('It encodes a JSON into a base64 string', () => { @@ -38,3 +41,23 @@ test('Generates random padding of length 8-15', () => { vi.spyOn(global.Math, 'random').mockReturnValue(0); expect(randomPadding()).toBe('AAAAAAAA'); }); + +test('It converts token from U denom V2', () => { + expect(convertCoinFromUDenom(1000, 2)).toStrictEqual(BigNumber(10)); + expect(convertCoinFromUDenom('1000', 2)).toStrictEqual(BigNumber(10)); + expect(convertCoinFromUDenom('1000000000000000000000000000', 2)).toStrictEqual(BigNumber('10000000000000000000000000')); + expect(convertCoinFromUDenom(1e100, 2)).toStrictEqual(BigNumber(1e98)); + expect(convertCoinFromUDenom('1e100', 2)).toStrictEqual(BigNumber(1e98)); + expect(convertCoinFromUDenom('100000000000000000000005555.123456789123456789', 2)).toStrictEqual(BigNumber('1000000000000000000000055.551234567891234568')); + expect(convertCoinFromUDenom(BigNumber('987654321987654321987654321'), 18)).toStrictEqual(BigNumber('987654321.987654321987654321')); +}); + +test('It converts token to U denom V2', () => { + const testBigNumber1 = BigNumber(1000); + expect(convertCoinToUDenom(testBigNumber1, 2)).toBe('100000'); + const testBigNumber2 = BigNumber('0.123456789123456789'); + expect(convertCoinToUDenom(testBigNumber2, 18)).toBe('123456789123456789'); + const testBigNumber3 = BigNumber('123456789123456789.123456789123456789'); + expect(convertCoinToUDenom(testBigNumber3, 18)).toBe('123456789123456789123456789123456789'); + expect(convertCoinToUDenom('1111.123456789101213141', 18)).toBe('1111123456789101213141'); +}); diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 677d517..aa17360 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,3 +1,6 @@ +import BigNumber from 'bignumber.js'; +import { TokensConfig } from '~/types/shared'; + const encodeJsonToB64 = (toEncode:any) : string => Buffer.from(JSON.stringify(toEncode), 'utf8').toString('base64'); const decodeB64ToJson = (encodedData: string) => JSON.parse(Buffer.from(encodedData, 'base64').toString('utf8')); @@ -20,8 +23,53 @@ const randomPadding = ():string => { return result; }; +/** + * Convert from uDenom to the human readable equivalent as BigNumber type + */ +const convertCoinFromUDenom = ( + amount: number | string | BigNumber, + decimals:number, +) => { + BigNumber.config({ DECIMAL_PLACES: 18 }); + return BigNumber( + amount, + ).dividedBy(BigNumber(10).pow(decimals)); +}; + +/** + * Convert BigNumber to the uDenom string type + */ +const convertCoinToUDenom = ( + amount: BigNumber | number | string, + decimals:number, +) => { + if (typeof amount === 'string' || typeof amount === 'number') { + return BigNumber(amount).multipliedBy(BigNumber(10).pow(decimals)).toFixed(0); + } + return amount.multipliedBy(BigNumber(10).pow(decimals)).toFixed(0); +}; + +function getTokenDecimalsByTokenConfig(tokenContractAddress: string, tokens: TokensConfig) { + const tokenConfigArr = tokens.filter( + (token) => token.tokenContractAddress === tokenContractAddress, + ); + + if (tokenConfigArr.length === 0) { + throw new Error(`token ${tokenContractAddress} not available`); + } + + if (tokenConfigArr.length > 1) { + throw new Error(`Duplicate ${tokenContractAddress} tokens found`); + } + // at this point we have determined there is a single match + return tokenConfigArr[0].decimals; +} + export { encodeJsonToB64, decodeB64ToJson, randomPadding, + convertCoinFromUDenom, + convertCoinToUDenom, + getTokenDecimalsByTokenConfig, }; diff --git a/src/test/mocks/swap/batchPairsInfoParsed.ts b/src/test/mocks/swap/batchPairsInfoParsed.ts index 469f34a..27750ff 100644 --- a/src/test/mocks/swap/batchPairsInfoParsed.ts +++ b/src/test/mocks/swap/batchPairsInfoParsed.ts @@ -23,12 +23,9 @@ const pairsInfoParsed = [ token0Amount: '4211390490855', token1Amount: '370196629477', lpTokenAmount: '487393298891', - priceRatio: null, pairSettings: { lpFee: 0.0029, daoFee: 0.0001, - stableLpFee: 0.000483, - stableDaoFee: 0.000017, stableParams: null, }, contractVersion: 1, @@ -58,12 +55,9 @@ const pairsInfoParsed = [ token0Amount: '93237038002', token1Amount: '385657573', lpTokenAmount: '5708789507', - priceRatio: null, pairSettings: { lpFee: 0.0029, daoFee: 0.0001, - stableLpFee: 0.000483, - stableDaoFee: 0.000017, stableParams: null, }, contractVersion: 1, diff --git a/src/test/mocks/swap/pairInfoParsed.ts b/src/test/mocks/swap/pairInfoParsed.ts index 6696507..90ec843 100644 --- a/src/test/mocks/swap/pairInfoParsed.ts +++ b/src/test/mocks/swap/pairInfoParsed.ts @@ -22,13 +22,11 @@ const pairInfoParsed: PairInfo = { token0Amount: '3218142110921700343525', token1Amount: '6366867216411002795778', lpTokenAmount: '4783477681443035000237', - priceRatio: '1.08921896906564985', pairSettings: { lpFee: 0.0005, daoFee: 0.0005, - stableLpFee: 0.0005, - stableDaoFee: 0.0005, stableParams: { + priceRatio: '1.08921896906564985', alpha: '150', gamma1: '6', gamma2: '50', diff --git a/src/test/mocks/swap/router.ts b/src/test/mocks/swap/router.ts new file mode 100644 index 0000000..aacd769 --- /dev/null +++ b/src/test/mocks/swap/router.ts @@ -0,0 +1,1274 @@ +import { BatchPairsInfo } from '~/types/contracts/swap/model'; +import { TokensConfig } from '~/types/shared'; + +const batchPairsInfoMock: BatchPairsInfo = [ + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_1', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_1', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_1', + }, + token0Contract: { + address: 'TOKEN_A_CONTRACT_ADDRESS', + codeHash: 'TOKEN_A_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_B_CONTRACT_ADDRESS', + codeHash: 'TOKEN_B_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_1', + isStable: false, + token0Amount: '111111111000000', + token1Amount: '222222222000000', + pairSettings: { + lpFee: 0.02, + daoFee: 0.01, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_2', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_2', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_2', + }, + token0Contract: { + address: 'TOKEN_C_CONTRACT_ADDRESS', + codeHash: 'TOKEN_C_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_B_CONTRACT_ADDRESS', + codeHash: 'TOKEN_B_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_2', + isStable: false, + token0Amount: '333333333000000', + token1Amount: '4444444444000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_3', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_3', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_3', + }, + token0Contract: { + address: 'TOKEN_C_CONTRACT_ADDRESS', + codeHash: 'TOKEN_C_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_D_CONTRACT_ADDRESS', + codeHash: 'TOKEN_D_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_3', + isStable: false, + token0Amount: '5555555555000000', + token1Amount: '66666666000000', + pairSettings: { + lpFee: 0.02, + daoFee: 0.02, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_4', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_4', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_4', + }, + token0Contract: { + address: 'TOKEN_E_CONTRACT_ADDRESS', + codeHash: 'TOKEN_E_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_F_CONTRACT_ADDRESS', + codeHash: 'TOKEN_F_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_4', + isStable: true, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.01, + daoFee: 0.02, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_4', + codeHash: 'ORACLE_CODE_HASH_PAIR_4', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_5', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_5', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_5', + }, + token0Contract: { + address: 'TOKEN_G_CONTRACT_ADDRESS', + codeHash: 'TOKEN_G_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_F_CONTRACT_ADDRESS', + codeHash: 'TOKEN_F_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_5', + isStable: true, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_5', + codeHash: 'ORACLE_CODE_HASH_PAIR_5', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_6', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_6', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_6', + }, + token0Contract: { + address: 'TOKEN_G_CONTRACT_ADDRESS', + codeHash: 'TOKEN_G_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_H_CONTRACT_ADDRESS', + codeHash: 'TOKEN_H_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_6', + isStable: true, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_6', + codeHash: 'ORACLE_CODE_HASH_PAIR_6', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_7', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_7', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_7', + }, + token0Contract: { + address: 'TOKEN_F_CONTRACT_ADDRESS', + codeHash: 'TOKEN_F_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_I_CONTRACT_ADDRESS', + codeHash: 'TOKEN_I_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_7', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_8', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_8', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_8', + }, + token0Contract: { + address: 'TOKEN_I_CONTRACT_ADDRESS', + codeHash: 'TOKEN_I_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_H_CONTRACT_ADDRESS', + codeHash: 'TOKEN_H_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_8', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_9', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_8', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_8', + }, + token0Contract: { + address: 'TOKEN_H_CONTRACT_ADDRESS', + codeHash: 'TOKEN_H_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_J_CONTRACT_ADDRESS', + codeHash: 'TOKEN_J_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_8', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_10', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_10', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_10', + }, + token0Contract: { + address: 'TOKEN_K_CONTRACT_ADDRESS', + codeHash: 'TOKEN_K_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_L_CONTRACT_ADDRESS', + codeHash: 'TOKEN_L_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_10', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_10', + codeHash: 'ORACLE_CODE_HASH_PAIR_10', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_11', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_11', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_11', + }, + token0Contract: { + address: 'TOKEN_M_CONTRACT_ADDRESS', + codeHash: 'TOKEN_M_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_L_CONTRACT_ADDRESS', + codeHash: 'TOKEN_L_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_11', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_11', + codeHash: 'ORACLE_CODE_HASH_PAIR_11', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_12', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_12', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_12', + }, + token0Contract: { + address: 'TOKEN_M_CONTRACT_ADDRESS', + codeHash: 'TOKEN_M_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_N_CONTRACT_ADDRESS', + codeHash: 'TOKEN_N_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_12', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_12', + codeHash: 'ORACLE_CODE_HASH_PAIR_12', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_13', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_13', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_13', + }, + token0Contract: { + address: 'TOKEN_O_CONTRACT_ADDRESS', + codeHash: 'TOKEN_O_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_L_CONTRACT_ADDRESS', + codeHash: 'TOKEN_L_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_13', + isStable: false, + token0Amount: '111111111000000', + token1Amount: '222222222000000', + pairSettings: { + lpFee: 0.02, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_13', + codeHash: 'ORACLE_CODE_HASH_PAIR_13', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_14', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_14', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_14', + }, + token0Contract: { + address: 'TOKEN_M_CONTRACT_ADDRESS', + codeHash: 'TOKEN_M_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_P_CONTRACT_ADDRESS', + codeHash: 'TOKEN_P_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_14', + isStable: false, + token0Amount: '111111111000000', + token1Amount: '222222222000000', + pairSettings: { + lpFee: 0.02, + daoFee: 0.01, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_15', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_15', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_15', + }, + token0Contract: { + address: 'TOKEN_Q_CONTRACT_ADDRESS', + codeHash: 'TOKEN_Q_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_R_CONTRACT_ADDRESS', + codeHash: 'TOKEN_R_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_15', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_15', + codeHash: 'ORACLE_CODE_HASH_PAIR_15', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_16', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_16', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_16', + }, + token0Contract: { + address: 'TOKEN_S_CONTRACT_ADDRESS', + codeHash: 'TOKEN_S_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_R_CONTRACT_ADDRESS', + codeHash: 'TOKEN_R_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_16', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_16', + codeHash: 'ORACLE_CODE_HASH_PAIR_16', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_17', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_17', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_17', + }, + token0Contract: { + address: 'TOKEN_S_CONTRACT_ADDRESS', + codeHash: 'TOKEN_S_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_T_CONTRACT_ADDRESS', + codeHash: 'TOKEN_T_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_17', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_17', + codeHash: 'ORACLE_CODE_HASH_PAIR_17', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_18', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_18', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_18', + }, + token0Contract: { + address: 'TOKEN_S_CONTRACT_ADDRESS', + codeHash: 'TOKEN_S_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_Q_CONTRACT_ADDRESS', + codeHash: 'TOKEN_Q_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_18', + isStable: true, + token0Amount: '157485051000000', + token1Amount: '135613721000000', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_18', + codeHash: 'ORACLE_CODE_HASH_PAIR_18', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, +]; + +const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_1', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_1', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_1', + }, + token0Contract: { + address: 'TOKEN_A_CONTRACT_ADDRESS', + codeHash: 'TOKEN_A_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_F_CONTRACT_ADDRESS', + codeHash: 'TOKEN_F_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_1', + isStable: false, + token0Amount: '111111111', + token1Amount: '222222222', + pairSettings: { + lpFee: 0.01, + daoFee: 0.02, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_2', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_2', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_2', + }, + token0Contract: { + address: 'TOKEN_F_CONTRACT_ADDRESS', + codeHash: 'TOKEN_F_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_D_CONTRACT_ADDRESS', + codeHash: 'TOKEN_D_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_2', + isStable: false, + token0Amount: '333333333', + token1Amount: '4444444444', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_3', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_3', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_3', + }, + token0Contract: { + address: 'TOKEN_A_CONTRACT_ADDRESS', + codeHash: 'TOKEN_A_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_D_CONTRACT_ADDRESS', + codeHash: 'TOKEN_D_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_3', + isStable: false, + token0Amount: '5555555555', + token1Amount: '66666666', + pairSettings: { + lpFee: 0.02, + daoFee: 0.02, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_4', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_4', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_4', + }, + token0Contract: { + address: 'TOKEN_D_CONTRACT_ADDRESS', + codeHash: 'TOKEN_D_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_G_CONTRACT_ADDRESS', + codeHash: 'TOKEN_G_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_4', + isStable: true, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.01, + daoFee: 0.02, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_4', + codeHash: 'ORACLE_CODE_HASH_PAIR_4', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_5', + pairInfo: { + lpTokenAmount: '0', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_5', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_5', + }, + token0Contract: { + address: 'TOKEN_A_CONTRACT_ADDRESS', + codeHash: 'TOKEN_A_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_C_CONTRACT_ADDRESS', + codeHash: 'TOKEN_C_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_5', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_5', + codeHash: 'ORACLE_CODE_HASH_PAIR_5', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_6', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_6', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_6', + }, + token0Contract: { + address: 'TOKEN_D_CONTRACT_ADDRESS', + codeHash: 'TOKEN_D_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_C_CONTRACT_ADDRESS', + codeHash: 'TOKEN_C_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_6', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_6', + codeHash: 'ORACLE_CODE_HASH_PAIR_6', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_7', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_7', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_7', + }, + token0Contract: { + address: 'TOKEN_A_CONTRACT_ADDRESS', + codeHash: 'TOKEN_A_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_B_CONTRACT_ADDRESS', + codeHash: 'TOKEN_B_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_7', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_8', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_8', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_8', + }, + token0Contract: { + address: 'TOKEN_D_CONTRACT_ADDRESS', + codeHash: 'TOKEN_D_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_E_CONTRACT_ADDRESS', + codeHash: 'TOKEN_E_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_8', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_9', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_8', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_8', + }, + token0Contract: { + address: 'TOKEN_C_CONTRACT_ADDRESS', + codeHash: 'TOKEN_C_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_B_CONTRACT_ADDRESS', + codeHash: 'TOKEN_B_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_8', + isStable: false, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_10', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_10', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_10', + }, + token0Contract: { + address: 'TOKEN_C_CONTRACT_ADDRESS', + codeHash: 'TOKEN_C_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_E_CONTRACT_ADDRESS', + codeHash: 'TOKEN_E_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_10', + isStable: true, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_10', + codeHash: 'ORACLE_CODE_HASH_PAIR_10', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, + { + pairContractAddress: 'CONTRACT_ADDRESS_PAIR_11', + pairInfo: { + lpTokenAmount: '145080056', + lpTokenContract: { + address: 'MOCK_LP_TOKEN_CONTRACT_ADDRESS_PAIR_11', + codeHash: 'MOCK_LP_TOKEN_CODE_HASH_PAIR_11', + }, + token0Contract: { + address: 'TOKEN_B_CONTRACT_ADDRESS', + codeHash: 'TOKEN_B_CODE_HASH', + }, + token1Contract: { + address: 'TOKEN_E_CONTRACT_ADDRESS', + codeHash: 'TOKEN_E_CODE_HASH', + }, + factoryContract: null, + daoContractAddress: 'MOCK_DAO_CONTRACT_ADDRESS_PAIR_11', + isStable: true, + token0Amount: '157485051', + token1Amount: '135613721', + pairSettings: { + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_11', + codeHash: 'ORACLE_CODE_HASH_PAIR_11', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, + }, + }, + contractVersion: 1, + }, + }, +]; + +const tokenConfigMock:TokensConfig = [ + { + tokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_B_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_C_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_D_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_E_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_F_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_G_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_H_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_I_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_J_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_K_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_L_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_M_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_N_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_O_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_P_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_Q_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_R_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_S_CONTRACT_ADDRESS', + decimals: 6, + }, + { + tokenContractAddress: 'TOKEN_T_CONTRACT_ADDRESS', + decimals: 6, + }, +]; + +export { + tokenConfigMock, + batchPairsInfoMock, + batchPairsInfoMockForComplexRoute, +}; diff --git a/src/types/contracts/swap/model.ts b/src/types/contracts/swap/model.ts index 39ebc5d..78ab6c1 100644 --- a/src/types/contracts/swap/model.ts +++ b/src/types/contracts/swap/model.ts @@ -60,6 +60,7 @@ type StableTokenData = { } type StableParams = { + priceRatio: string, alpha: string, gamma1: string, gamma2: string, @@ -82,12 +83,9 @@ type PairInfo = { isStable: boolean, token0Amount: string, token1Amount: string, - priceRatio: string | null, pairSettings: { lpFee: number, daoFee: number, - stableLpFee: number, - stableDaoFee: number, stableParams: StableParams | null }, contractVersion: number, diff --git a/src/types/shared.ts b/src/types/shared.ts new file mode 100644 index 0000000..5a06303 --- /dev/null +++ b/src/types/shared.ts @@ -0,0 +1,10 @@ +type TokenConfig = { + tokenContractAddress: string, + decimals: number, +} + +type TokensConfig = TokenConfig[] + +export type { + TokensConfig, +}; diff --git a/src/types/swap/router.ts b/src/types/swap/router.ts new file mode 100644 index 0000000..9a3ba87 --- /dev/null +++ b/src/types/swap/router.ts @@ -0,0 +1,26 @@ +import BigNumber from 'bignumber.js'; + +// Gas Multipliers based on the swap type +enum GasMultiplier { + STABLE = 2.7, + CONSTANT_PRODUCT = 1, +} + +type Route = { + inputAmount: BigNumber, + quoteOutputAmount: BigNumber, + quoteShadeDaoFee: BigNumber, + quoteLPFee: BigNumber, + priceImpact: BigNumber, + inputTokenContractAddress: string, + outputTokenContractAddress: string, + path: string[], + gasMultiplier: number, +}; + +export { + GasMultiplier, +}; +export type { + Route, +}; From 3b4f7ea0d26a2d8d3713c985b0e05d3ef1c60945 Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 13 Nov 2023 22:05:22 -0600 Subject: [PATCH 3/6] chore: remove changesets test code --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 88beb27..bf7b563 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,4 @@ Docs will be available on a vitepress site. You can run the site locally with th ``` $ yarn docs:dev -``` - -this is a test pr change for changesets automation \ No newline at end of file +``` \ No newline at end of file From 7b430b4306c42692bafeacd7602467326151e0e8 Mon Sep 17 00:00:00 2001 From: Austin Date: Mon, 13 Nov 2023 22:12:43 -0600 Subject: [PATCH 4/6] docs: remove unused properties --- docs/queries/swap.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/queries/swap.md b/docs/queries/swap.md index b79affb..a65a75d 100644 --- a/docs/queries/swap.md +++ b/docs/queries/swap.md @@ -414,8 +414,6 @@ console.log(output) "pairSettings": { "lpFee": 0.0029, "daoFee": 0.0001, - "stableLpFee": 0.000483, - "stableDaoFee": 0.000017, "stableParams": null }, "contractVersion": 1 @@ -448,8 +446,6 @@ console.log(output) "pairSettings": { "lpFee": 0.0029, "daoFee": 0.0001, - "stableLpFee": 0.000483, - "stableDaoFee": 0.000017, "stableParams": null }, "contractVersion": 1 From 9dc9a23e1627c4c8d100ea944ecf07421a805ca3 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 14 Nov 2023 08:30:32 -0600 Subject: [PATCH 5/6] refactor: tweaks to pair info data model --- docs/queries/swap.md | 24 +- src/contracts/services/swap.ts | 61 +- src/lib/swap/router.ts | 24 +- src/test/mocks/swap/batchPairsInfoParsed.ts | 16 +- src/test/mocks/swap/pairInfoParsed.ts | 47 +- src/test/mocks/swap/router.ts | 841 +++++++++----------- src/types/contracts/swap/model.ts | 8 +- 7 files changed, 471 insertions(+), 550 deletions(-) diff --git a/docs/queries/swap.md b/docs/queries/swap.md index a65a75d..3f889c1 100644 --- a/docs/queries/swap.md +++ b/docs/queries/swap.md @@ -327,11 +327,9 @@ type PairInfo = { isStable: boolean, token0Amount: string, token1Amount: string, - pairSettings: { - lpFee: number, - daoFee: number, - stableParams: StableParams | null - }, + lpFee: number, + daoFee: number, + stableParams: StableParams | null contractVersion: number, } @@ -411,11 +409,9 @@ console.log(output) "token0Amount": "4268251730565", "token1Amount": "365239579269", "lpTokenAmount": "487393298891", - "pairSettings": { - "lpFee": 0.0029, - "daoFee": 0.0001, - "stableParams": null - }, + "lpFee": 0.0029, + "daoFee": 0.0001, + "stableParams": null "contractVersion": 1 } }, @@ -443,11 +439,9 @@ console.log(output) "token0Amount": "95199329571", "token1Amount": "377657768", "lpTokenAmount": "5708789507", - "pairSettings": { - "lpFee": 0.0029, - "daoFee": 0.0001, - "stableParams": null - }, + "lpFee": 0.0029, + "daoFee": 0.0001, + "stableParams": null "contractVersion": 1 } } diff --git a/src/contracts/services/swap.ts b/src/contracts/services/swap.ts index e9d3418..829a9a6 100644 --- a/src/contracts/services/swap.ts +++ b/src/contracts/services/swap.ts @@ -187,38 +187,37 @@ function parsePairInfo( token0Amount: pairInfo.amount_0, token1Amount: pairInfo.amount_1, lpTokenAmount: pairInfo.total_liquidity, - pairSettings: { - lpFee: pairInfo.pair[2] ? fees.stable_lp_fee.nom / fees.stable_lp_fee.denom - : fees.lp_fee.nom / fees.lp_fee.denom, - daoFee: pairInfo.pair[2] ? fees.stable_shade_dao_fee.nom / fees.stable_shade_dao_fee.denom - : fees.shade_dao_fee.nom / fees.shade_dao_fee.denom, - stableParams: stableInfo ? { - priceRatio: stableInfo.p!, // if stable params exist, we know price ratio will be available - alpha: stableInfo.stable_params.a, - gamma1: stableInfo.stable_params.gamma1, - gamma2: stableInfo.stable_params.gamma2, - oracle: { - address: stableInfo.stable_params.oracle.address, - codeHash: stableInfo.stable_params.oracle.code_hash, - }, - token0Data: { - oracleKey: stableInfo.stable_token0_data.oracle_key, - decimals: stableInfo.stable_token0_data.decimals, - }, - token1Data: { - oracleKey: stableInfo.stable_token1_data.oracle_key, - decimals: stableInfo.stable_token1_data.decimals, - }, - minTradeSizeXForY: stableInfo.stable_params.min_trade_size_x_for_y, - minTradeSizeYForX: stableInfo.stable_params.min_trade_size_y_for_x, - maxPriceImpactAllowed: stableInfo.stable_params.max_price_impact_allowed, - customIterationControls: stableInfo.stable_params.custom_iteration_controls ? { - epsilon: stableInfo.stable_params.custom_iteration_controls.epsilon, - maxIteratorNewton: stableInfo.stable_params.custom_iteration_controls.max_iter_newton, - maxIteratorBisect: stableInfo.stable_params.custom_iteration_controls.max_iter_bisect, - } : null, + lpFee: pairInfo.pair[2] ? fees.stable_lp_fee.nom / fees.stable_lp_fee.denom + : fees.lp_fee.nom / fees.lp_fee.denom, + daoFee: pairInfo.pair[2] ? fees.stable_shade_dao_fee.nom / fees.stable_shade_dao_fee.denom + : fees.shade_dao_fee.nom / fees.shade_dao_fee.denom, + stableParams: stableInfo ? { + priceRatio: stableInfo.p!, // if stable params exist, we know price ratio will be available + alpha: stableInfo.stable_params.a, + gamma1: stableInfo.stable_params.gamma1, + gamma2: stableInfo.stable_params.gamma2, + oracle: { + address: stableInfo.stable_params.oracle.address, + codeHash: stableInfo.stable_params.oracle.code_hash, + }, + token0Data: { + oracleKey: stableInfo.stable_token0_data.oracle_key, + decimals: stableInfo.stable_token0_data.decimals, + }, + token1Data: { + oracleKey: stableInfo.stable_token1_data.oracle_key, + decimals: stableInfo.stable_token1_data.decimals, + }, + minTradeSizeXForY: stableInfo.stable_params.min_trade_size_x_for_y, + minTradeSizeYForX: stableInfo.stable_params.min_trade_size_y_for_x, + maxPriceImpactAllowed: stableInfo.stable_params.max_price_impact_allowed, + customIterationControls: stableInfo.stable_params.custom_iteration_controls ? { + epsilon: stableInfo.stable_params.custom_iteration_controls.epsilon, + maxIteratorNewton: stableInfo.stable_params.custom_iteration_controls.max_iter_newton, + maxIteratorBisect: stableInfo.stable_params.custom_iteration_controls.max_iter_bisect, } : null, - }, + } : null, + contractVersion: pairInfo.contract_version, }; } diff --git a/src/lib/swap/router.ts b/src/lib/swap/router.ts index a352c90..e13fa1c 100644 --- a/src/lib/swap/router.ts +++ b/src/lib/swap/router.ts @@ -128,8 +128,6 @@ function forwardCalculateRoute({ let swapAmountOutput; let swapPriceImpact; let poolMultiplier; - let daoFee; - let lpFee; const pairArr = pairs.filter( (pair) => pair.pairContractAddress === poolContractAddress, @@ -151,8 +149,10 @@ function forwardCalculateRoute({ token1Contract, token0Amount, token1Amount, - pairSettings, + lpFee, + daoFee, isStable, + stableParams, }, } = pair; // Convert pool liquidity from human readable to raw number for @@ -203,7 +203,6 @@ function forwardCalculateRoute({ ); // Stable Pool calculations - const { stableParams } = pairSettings; if (isStable && stableParams) { poolMultiplier = GasMultiplier.STABLE; @@ -217,8 +216,8 @@ function forwardCalculateRoute({ alpha: BigNumber(stableParams.alpha), gamma1: BigNumber(stableParams.gamma1), gamma2: BigNumber(stableParams.gamma2), - liquidityProviderFee: BigNumber(pairSettings.lpFee), - daoFee: BigNumber(pairSettings.daoFee), + liquidityProviderFee: BigNumber(lpFee), + daoFee: BigNumber(daoFee), minTradeSizeToken0For1: BigNumber(stableParams.minTradeSizeXForY), minTradeSizeToken1For0: BigNumber(stableParams.minTradeSizeYForX), priceImpactLimit: BigNumber(stableParams.maxPriceImpactAllowed), @@ -241,8 +240,8 @@ function forwardCalculateRoute({ alpha: BigNumber(stableParams.alpha), gamma1: BigNumber(stableParams.gamma1), gamma2: BigNumber(stableParams.gamma2), - liquidityProviderFee: BigNumber(pairSettings.lpFee), - daoFee: BigNumber(pairSettings.daoFee), + liquidityProviderFee: BigNumber(lpFee), + daoFee: BigNumber(daoFee), minTradeSizeToken0For1: BigNumber(stableParams.minTradeSizeXForY), minTradeSizeToken1For0: BigNumber(stableParams.minTradeSizeYForX), priceImpactLimit: BigNumber(stableParams.maxPriceImpactAllowed), @@ -258,9 +257,6 @@ function forwardCalculateRoute({ } else { throw Error('stableswap parameter error'); } - // set fees - daoFee = BigNumber(pairSettings.daoFee); - lpFee = BigNumber(pairSettings.lpFee); } else { poolMultiplier = GasMultiplier.CONSTANT_PRODUCT; // non-stable pools using constant product rule math @@ -270,7 +266,7 @@ function forwardCalculateRoute({ token0LiquidityAmount: BigNumber(token0Amount), token1LiquidityAmount: BigNumber(token1Amount), token0InputAmount: inputAmount, - fee: BigNumber(pairSettings.lpFee).plus(pairSettings.daoFee), + fee: BigNumber(lpFee).plus(daoFee), }); swapPriceImpact = constantProductPriceImpactToken0for1({ @@ -285,7 +281,7 @@ function forwardCalculateRoute({ token0LiquidityAmount: BigNumber(token0Amount), token1LiquidityAmount: BigNumber(token1Amount), token1InputAmount: inputAmount, - fee: BigNumber(pairSettings.lpFee).plus(pairSettings.daoFee), + fee: BigNumber(lpFee).plus(daoFee), }); swapPriceImpact = constantProductPriceImpactToken1for0({ @@ -296,8 +292,6 @@ function forwardCalculateRoute({ } else { throw Error('constant product rule swap parameter error'); } - daoFee = BigNumber(pairSettings.daoFee); - lpFee = BigNumber(pairSettings.lpFee); } // output data for the reduce function diff --git a/src/test/mocks/swap/batchPairsInfoParsed.ts b/src/test/mocks/swap/batchPairsInfoParsed.ts index 27750ff..ee25486 100644 --- a/src/test/mocks/swap/batchPairsInfoParsed.ts +++ b/src/test/mocks/swap/batchPairsInfoParsed.ts @@ -23,11 +23,9 @@ const pairsInfoParsed = [ token0Amount: '4211390490855', token1Amount: '370196629477', lpTokenAmount: '487393298891', - pairSettings: { - lpFee: 0.0029, - daoFee: 0.0001, - stableParams: null, - }, + lpFee: 0.0029, + daoFee: 0.0001, + stableParams: null, contractVersion: 1, }, }, @@ -55,11 +53,9 @@ const pairsInfoParsed = [ token0Amount: '93237038002', token1Amount: '385657573', lpTokenAmount: '5708789507', - pairSettings: { - lpFee: 0.0029, - daoFee: 0.0001, - stableParams: null, - }, + lpFee: 0.0029, + daoFee: 0.0001, + stableParams: null, contractVersion: 1, }, }, diff --git a/src/test/mocks/swap/pairInfoParsed.ts b/src/test/mocks/swap/pairInfoParsed.ts index 90ec843..2ce1f83 100644 --- a/src/test/mocks/swap/pairInfoParsed.ts +++ b/src/test/mocks/swap/pairInfoParsed.ts @@ -22,32 +22,29 @@ const pairInfoParsed: PairInfo = { token0Amount: '3218142110921700343525', token1Amount: '6366867216411002795778', lpTokenAmount: '4783477681443035000237', - pairSettings: { - lpFee: 0.0005, - daoFee: 0.0005, - stableParams: { - priceRatio: '1.08921896906564985', - alpha: '150', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'secret10n2xl5jmez6r9umtdrth78k0vwmce0l5m9f5dm', - codeHash: '32c4710842b97a526c243a68511b15f58d6e72a388af38a7221ff3244c754e91', - }, - token0Data: { - oracleKey: 'Stableswap Rate Base', - decimals: 18, - }, - token1Data: { - oracleKey: 'Stride INJ Rate', - decimals: 18, - }, - minTradeSizeXForY: '0.000000001', - minTradeSizeYForX: '0.000000001', - maxPriceImpactAllowed: '1000', - customIterationControls: null, + lpFee: 0.0005, + daoFee: 0.0005, + stableParams: { + priceRatio: '1.08921896906564985', + alpha: '150', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'secret10n2xl5jmez6r9umtdrth78k0vwmce0l5m9f5dm', + codeHash: '32c4710842b97a526c243a68511b15f58d6e72a388af38a7221ff3244c754e91', }, - + token0Data: { + oracleKey: 'Stableswap Rate Base', + decimals: 18, + }, + token1Data: { + oracleKey: 'Stride INJ Rate', + decimals: 18, + }, + minTradeSizeXForY: '0.000000001', + minTradeSizeYForX: '0.000000001', + maxPriceImpactAllowed: '1000', + customIterationControls: null, }, contractVersion: 1, }; diff --git a/src/test/mocks/swap/router.ts b/src/test/mocks/swap/router.ts index aacd769..b47ee20 100644 --- a/src/test/mocks/swap/router.ts +++ b/src/test/mocks/swap/router.ts @@ -23,11 +23,9 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '111111111000000', token1Amount: '222222222000000', - pairSettings: { - lpFee: 0.02, - daoFee: 0.01, - stableParams: null, - }, + lpFee: 0.02, + daoFee: 0.01, + stableParams: null, contractVersion: 1, }, }, @@ -52,11 +50,9 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '333333333000000', token1Amount: '4444444444000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: null, - }, + lpFee: 0.01, + daoFee: 0.01, + stableParams: null, contractVersion: 1, }, }, @@ -81,11 +77,9 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '5555555555000000', token1Amount: '66666666000000', - pairSettings: { - lpFee: 0.02, - daoFee: 0.02, - stableParams: null, - }, + lpFee: 0.02, + daoFee: 0.02, + stableParams: null, contractVersion: 1, }, }, @@ -110,31 +104,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.01, - daoFee: 0.02, - stableParams: { - priceRatio: '1.1234567', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_4', - codeHash: 'ORACLE_CODE_HASH_PAIR_4', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.02, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_4', + codeHash: 'ORACLE_CODE_HASH_PAIR_4', }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -160,31 +152,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: { - priceRatio: '1.1234567', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_5', - codeHash: 'ORACLE_CODE_HASH_PAIR_5', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_5', + codeHash: 'ORACLE_CODE_HASH_PAIR_5', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -210,31 +200,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: { - priceRatio: '1.1234567', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_6', - codeHash: 'ORACLE_CODE_HASH_PAIR_6', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_6', + codeHash: 'ORACLE_CODE_HASH_PAIR_6', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -260,11 +248,9 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: null, - }, + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, contractVersion: 1, }, }, @@ -289,11 +275,9 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: null, - }, + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, contractVersion: 1, }, }, @@ -318,11 +302,9 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: null, - }, + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, contractVersion: 1, }, }, @@ -347,31 +329,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_10', - codeHash: 'ORACLE_CODE_HASH_PAIR_10', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_10', + codeHash: 'ORACLE_CODE_HASH_PAIR_10', }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -397,31 +377,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_11', - codeHash: 'ORACLE_CODE_HASH_PAIR_11', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_11', + codeHash: 'ORACLE_CODE_HASH_PAIR_11', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -447,31 +425,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_12', - codeHash: 'ORACLE_CODE_HASH_PAIR_12', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_12', + codeHash: 'ORACLE_CODE_HASH_PAIR_12', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -497,31 +473,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '111111111000000', token1Amount: '222222222000000', - pairSettings: { - lpFee: 0.02, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_13', - codeHash: 'ORACLE_CODE_HASH_PAIR_13', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.02, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_13', + codeHash: 'ORACLE_CODE_HASH_PAIR_13', }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -547,11 +521,10 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: false, token0Amount: '111111111000000', token1Amount: '222222222000000', - pairSettings: { - lpFee: 0.02, - daoFee: 0.01, - stableParams: null, - }, + lpFee: 0.02, + daoFee: 0.01, + stableParams: null, + contractVersion: 1, }, }, @@ -576,31 +549,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_15', - codeHash: 'ORACLE_CODE_HASH_PAIR_15', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_15', + codeHash: 'ORACLE_CODE_HASH_PAIR_15', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -626,31 +597,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_16', - codeHash: 'ORACLE_CODE_HASH_PAIR_16', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_16', + codeHash: 'ORACLE_CODE_HASH_PAIR_16', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -676,31 +645,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_17', - codeHash: 'ORACLE_CODE_HASH_PAIR_17', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_17', + codeHash: 'ORACLE_CODE_HASH_PAIR_17', }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -726,31 +693,29 @@ const batchPairsInfoMock: BatchPairsInfo = [ isStable: true, token0Amount: '157485051000000', token1Amount: '135613721000000', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '10', - gamma1: '4', - gamma2: '5', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_18', - codeHash: 'ORACLE_CODE_HASH_PAIR_18', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '10', + gamma1: '4', + gamma2: '5', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_18', + codeHash: 'ORACLE_CODE_HASH_PAIR_18', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -779,11 +744,9 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '111111111', token1Amount: '222222222', - pairSettings: { - lpFee: 0.01, - daoFee: 0.02, - stableParams: null, - }, + lpFee: 0.01, + daoFee: 0.02, + stableParams: null, contractVersion: 1, }, }, @@ -808,11 +771,9 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '333333333', token1Amount: '4444444444', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: null, - }, + lpFee: 0.01, + daoFee: 0.01, + stableParams: null, contractVersion: 1, }, }, @@ -837,11 +798,9 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '5555555555', token1Amount: '66666666', - pairSettings: { - lpFee: 0.02, - daoFee: 0.02, - stableParams: null, - }, + lpFee: 0.02, + daoFee: 0.02, + stableParams: null, contractVersion: 1, }, }, @@ -866,31 +825,29 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: true, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.01, - daoFee: 0.02, - stableParams: { - priceRatio: '1.1234567', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_4', - codeHash: 'ORACLE_CODE_HASH_PAIR_4', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.02, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_4', + codeHash: 'ORACLE_CODE_HASH_PAIR_4', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -916,31 +873,29 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: { - priceRatio: '1.1234567', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_5', - codeHash: 'ORACLE_CODE_HASH_PAIR_5', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_5', + codeHash: 'ORACLE_CODE_HASH_PAIR_5', }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -966,31 +921,29 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: { - priceRatio: '1.1234567', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_6', - codeHash: 'ORACLE_CODE_HASH_PAIR_6', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.04, + daoFee: 0.16, + stableParams: { + priceRatio: '1.1234567', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_6', + codeHash: 'ORACLE_CODE_HASH_PAIR_6', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -1016,11 +969,9 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: null, - }, + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, contractVersion: 1, }, }, @@ -1045,11 +996,9 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: null, - }, + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, contractVersion: 1, }, }, @@ -1074,11 +1023,9 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: false, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.04, - daoFee: 0.16, - stableParams: null, - }, + lpFee: 0.04, + daoFee: 0.16, + stableParams: null, contractVersion: 1, }, }, @@ -1103,31 +1050,29 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: true, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_10', - codeHash: 'ORACLE_CODE_HASH_PAIR_10', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_10', + codeHash: 'ORACLE_CODE_HASH_PAIR_10', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, @@ -1153,31 +1098,29 @@ const batchPairsInfoMockForComplexRoute: BatchPairsInfo = [ isStable: true, token0Amount: '157485051', token1Amount: '135613721', - pairSettings: { - lpFee: 0.01, - daoFee: 0.01, - stableParams: { - priceRatio: '3', - alpha: '200', - gamma1: '6', - gamma2: '50', - oracle: { - address: 'ORACLE_CONTRACT_ADDRESS_PAIR_11', - codeHash: 'ORACLE_CODE_HASH_PAIR_11', - }, - token0Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - token1Data: { - oracleKey: 'ORACLE_KEY', - decimals: 5, - }, - minTradeSizeXForY: '1e-9', - minTradeSizeYForX: '1e-9', - maxPriceImpactAllowed: '500', - customIterationControls: null, + lpFee: 0.01, + daoFee: 0.01, + stableParams: { + priceRatio: '3', + alpha: '200', + gamma1: '6', + gamma2: '50', + oracle: { + address: 'ORACLE_CONTRACT_ADDRESS_PAIR_11', + codeHash: 'ORACLE_CODE_HASH_PAIR_11', + }, + token0Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, + }, + token1Data: { + oracleKey: 'ORACLE_KEY', + decimals: 5, }, + minTradeSizeXForY: '1e-9', + minTradeSizeYForX: '1e-9', + maxPriceImpactAllowed: '500', + customIterationControls: null, }, contractVersion: 1, }, diff --git a/src/types/contracts/swap/model.ts b/src/types/contracts/swap/model.ts index 78ab6c1..7885e56 100644 --- a/src/types/contracts/swap/model.ts +++ b/src/types/contracts/swap/model.ts @@ -83,11 +83,9 @@ type PairInfo = { isStable: boolean, token0Amount: string, token1Amount: string, - pairSettings: { - lpFee: number, - daoFee: number, - stableParams: StableParams | null - }, + lpFee: number, + daoFee: number, + stableParams: StableParams | null contractVersion: number, } From 78208849eb4ab092626d6c7b573d91a5c19787bc Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 14 Nov 2023 09:59:07 -0600 Subject: [PATCH 6/6] chore: misc cleanup and router docs --- docs/calculations/routing.md | 103 ++++++++++++++++++++++- docs/calculations/swap.md | 7 +- docs/queries/batch-query.md | 4 +- src/config.ts | 2 +- src/contracts/definitions/index.ts | 4 + src/contracts/definitions/snip20.test.ts | 4 +- src/contracts/definitions/snip20.ts | 11 +-- src/contracts/definitions/swap.test.ts | 2 +- src/contracts/definitions/swap.ts | 4 +- src/contracts/index.ts | 2 + src/contracts/services/index.ts | 4 + src/index.ts | 94 ++------------------- src/lib/swap/index.ts | 2 + src/lib/swap/router.test.ts | 28 +++--- src/lib/swap/router.ts | 6 +- src/lib/utils.test.ts | 8 +- src/lib/utils.ts | 8 +- 17 files changed, 169 insertions(+), 124 deletions(-) create mode 100644 src/contracts/definitions/index.ts create mode 100644 src/contracts/index.ts create mode 100644 src/contracts/services/index.ts create mode 100644 src/lib/swap/index.ts diff --git a/docs/calculations/routing.md b/docs/calculations/routing.md index 7419981..9220f57 100644 --- a/docs/calculations/routing.md +++ b/docs/calculations/routing.md @@ -1,3 +1,102 @@ -# ShadeSwap multi-hop routing +# ShadeSwap Multi-Hop Routing + +This page contains an example router that determines the optimal path for maximizing the users output tokens received + +## Router + +### Determine Possible Paths +Returns possible paths through one or multiple pools to complete a trade of two tokens. +```ts +function getPossiblePaths({ + inputTokenContractAddress, + outputTokenContractAddress, + maxHops, + pairs, +}:{ + inputTokenContractAddress:string, + outputTokenContractAddress:string + maxHops: number // max number of pairs used + pairs: BatchPairsInfo +}): string[][] +``` +See [Batch Pairs Query](../queries/swap.html#pairs-info) for input type BatchPairsInfo. + +::: warning +Increasing the max hops too much can cause decreased performance due to the large amount of computations required to calculate all routes. The current recommendation is 4 max based on the route paths available, but this is subject to change as more pairs are supported over time. +::: + +### Calculate Route +Calculates the output amount received for a given path + +```ts +function calculateRoute({ + inputTokenAmount, + inputTokenContractAddress, + path, + pairs, + tokens, +}:{ + inputTokenAmount: BigNumber, + inputTokenContractAddress: string, + path: string[], // path determined by getPossiblePaths + pairs: BatchPairsInfo, + tokens: TokensConfig, // list of all possible swap tokens +}): Route +``` + +::: tip +We pass in a list of all possible tokens (TokensConfig) so that we have access to their decimals for uDenom conversions. This is not the most elegant solution as it may be preferrable to reference your own data store for token data. In that case, you can create your own route calculator and use the ShadeJS one as a guide. +::: +```ts +type TokenConfig = { + tokenContractAddress: string, + decimals: number, +} + +type TokensConfig = TokenConfig[] +``` +**output** + +```ts +type Route = { + inputAmount: BigNumber, + quoteOutputAmount: BigNumber, + quoteShadeDaoFee: BigNumber, + quoteLPFee: BigNumber, + priceImpact: BigNumber, + inputTokenContractAddress: string, + outputTokenContractAddress: string, + path: string[], + gasMultiplier: number, // multiplier which is to be applied + // to the base gas cost of a swap +}; +``` + + +### Calculate All Possible Routes +Retrieves all potential route options and the outputs of each route. +Returns an array of routes in the order that will give the highest quoted +output amount. This function utilizes both getPossiblePaths and calculateRoute. + +```ts +function getRoutes({ + inputTokenAmount, + inputTokenContractAddress, + outputTokenContractAddress, + maxHops, + pairs, + tokens, +}: { + inputTokenAmount: BigNumber, + inputTokenContractAddress: string, + outputTokenContractAddress: string, + maxHops: number, + pairs: BatchPairsInfo, + tokens: TokensConfig, +}): Route[] +``` + +::: warning +This function optimizes for maximizing the output token amount only. It does NOT factor in the value of the gas for the extra hops (i.e. gas multiplier) relative to the value of tokens received. This will especially impact small trades where there is perceived arbitrage opportunities through certain paths, without factoring in the gas cost to perform the arbitrage. It is recommended that you create your own route calculator to handle token values and use the one provided here as a guide. +::: -Coming Soon... diff --git a/docs/calculations/swap.md b/docs/calculations/swap.md index e9f496d..8edf1a9 100644 --- a/docs/calculations/swap.md +++ b/docs/calculations/swap.md @@ -2,6 +2,9 @@ This page demonstrates how to calculate outputs of a single pair swap on ShadeSwap +## BigNumber.js +bignumber.js is used on all computations to prevent loss of precision that normally happens with standard javascript math + ## Constant Product (CPMM) ### Forward Swap @@ -47,7 +50,7 @@ function constantProductSwapToken1for0({ ``` ### Reverse Swap -Backwards calcuation for determining a token input amount for a given output amount. +Backwards calculation for determining a token input amount for a given output amount. ```ts /** * returns input of a simulated swap from token0 to token1 using the constant @@ -162,7 +165,7 @@ function stableSwapToken1for0({ ``` ### Reverse Swap -Backwards calcuation for determining a token input amount for a given output amount. +Backwards calculation for determining a token input amount for a given output amount. ```ts /** * returns input of a simulated swap of token0 for diff --git a/docs/queries/batch-query.md b/docs/queries/batch-query.md index 286cae2..64a54cb 100644 --- a/docs/queries/batch-query.md +++ b/docs/queries/batch-query.md @@ -2,7 +2,7 @@ This page demonstrates how to query using a smart contract batch query router. The purposes of a query router is to combine multiple queries to one or more contracts into a single http request. This reduces load on the node infrastructure and is faster for retrieving data than would otherwise be obtained by individual contract queries. -The batch query function is generalized to work with any contract queries. Miscellaneous ShadeJS services already implement the batch query router, for example the Pairs Info Query +The batch query function is generalized to work with any contract queries. Miscellaneous ShadeJS services already implement the batch query router, for example the Pairs Info Query ## Performance @@ -10,7 +10,7 @@ All of the following results are run with 500 total queries | Batch Size | RPC Queries | Time | Success | |------------|-------------|-------|---------| -| N/A | 500 | 5.56s | 26.6% | +| 1 | 500 | 5.56s | 26.6% | | 5 | 100 | 6.51s | 100% | | 10 | 50 | 9.24s | 100% | | 25 | 20 | 7.27s | 100% | diff --git a/src/config.ts b/src/config.ts index 62a764f..01e4f9b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,5 +1,5 @@ // default endpoint to be used when alternative endpoint is not provided -// this is a public endpoint and not guarantees can be provided about the performance +// this is a public endpoint and no guarantees can be provided about the performance const DEFAULT_SECRET_LCD_ENDPOINT = 'https://lcd.secret.express/'; const SECRET_MAINNET_CHAIN_ID = 'secret-4'; diff --git a/src/contracts/definitions/index.ts b/src/contracts/definitions/index.ts new file mode 100644 index 0000000..69c2f37 --- /dev/null +++ b/src/contracts/definitions/index.ts @@ -0,0 +1,4 @@ +export * from './batchQuery'; +export * from './oracle'; +export * from './snip20'; +export * from './swap'; diff --git a/src/contracts/definitions/snip20.test.ts b/src/contracts/definitions/snip20.test.ts index a12968e..b9daae9 100644 --- a/src/contracts/definitions/snip20.test.ts +++ b/src/contracts/definitions/snip20.test.ts @@ -136,13 +136,15 @@ test('it checks the shape of the snip20 increase allowance', () => { test('it checks the shape of the snip20 viewing', () => { const viewingKey = 'MOCK_VIEWING_KEY'; + const padding = 'PADDING'; const output = { msg: { set_viewing_key: { key: viewingKey, + padding, }, }, }; - expect(snip20.messages.createViewingKey(viewingKey)).toStrictEqual(output); + expect(snip20.messages.createViewingKey(viewingKey, padding)).toStrictEqual(output); }); diff --git a/src/contracts/definitions/snip20.ts b/src/contracts/definitions/snip20.ts index a86aea5..a491b3f 100644 --- a/src/contracts/definitions/snip20.ts +++ b/src/contracts/definitions/snip20.ts @@ -29,7 +29,7 @@ const snip20 = { recipientCodeHash?: string, amount: string, handleMsg: any, - padding: string, + padding?: string, }): Snip20MessageRequest { const msg = { send: { @@ -52,7 +52,7 @@ const snip20 = { }: { recipient: string, amount: string, - padding: string, + padding?: string, }): Snip20MessageRequest { const msg = { transfer: { @@ -85,7 +85,7 @@ const snip20 = { }:{ amount: string, denom: string, - padding: string, + padding?: string, }): Snip20MessageRequest { const msg = { redeem: { @@ -108,7 +108,7 @@ const snip20 = { spender: string, amount: string, expiration?: number, - padding: string, + padding?: string, }): Snip20MessageRequest { const msg = { increase_allowance: { @@ -123,10 +123,11 @@ const snip20 = { }; }, - createViewingKey(viewingKey: string): Snip20MessageRequest { + createViewingKey(viewingKey: string, padding?: string): Snip20MessageRequest { const msg = { set_viewing_key: { key: viewingKey, + padding, }, }; return { diff --git a/src/contracts/definitions/swap.test.ts b/src/contracts/definitions/swap.test.ts index 6cf83d8..69ae7e0 100644 --- a/src/contracts/definitions/swap.test.ts +++ b/src/contracts/definitions/swap.test.ts @@ -23,7 +23,7 @@ vi.mock('~/contracts/definitions/snip20', () => ({ })); vi.mock('~/lib/utils', () => ({ - randomPadding: vi.fn(() => 'RANDOM_PADDING'), + generatePadding: vi.fn(() => 'RANDOM_PADDING'), })); test('it tests the form of the query factory config msg', () => { diff --git a/src/contracts/definitions/swap.ts b/src/contracts/definitions/swap.ts index 2e8914f..d003eba 100644 --- a/src/contracts/definitions/swap.ts +++ b/src/contracts/definitions/swap.ts @@ -3,7 +3,7 @@ import { Path, Paths, } from '~/types/contracts/swap/model'; -import { randomPadding } from '~/lib/utils'; +import { generatePadding } from '~/lib/utils'; import { snip20 } from './snip20'; /** @@ -75,7 +75,7 @@ function msgSwap({ recipientCodeHash: routerCodeHash, amount: sendAmount, handleMsg: swapParamsMessage, - padding: randomPadding(), + padding: generatePadding(), }).msg; } diff --git a/src/contracts/index.ts b/src/contracts/index.ts new file mode 100644 index 0000000..09899e4 --- /dev/null +++ b/src/contracts/index.ts @@ -0,0 +1,2 @@ +export * from './definitions'; +export * from './services'; diff --git a/src/contracts/services/index.ts b/src/contracts/services/index.ts new file mode 100644 index 0000000..69c2f37 --- /dev/null +++ b/src/contracts/services/index.ts @@ -0,0 +1,4 @@ +export * from './batchQuery'; +export * from './oracle'; +export * from './snip20'; +export * from './swap'; diff --git a/src/index.ts b/src/index.ts index 7c7e43d..eb1d5c4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,88 +1,12 @@ import '~/polyfills/index'; -import { - getSecretNetworkClient$, - getActiveQueryClient$, -} from '~/client'; -import { - queryPrice$, - queryPrices$, - queryPrice, - queryPrices, -} from '~/contracts/services/oracle'; -import { - batchQuery$, - batchQuery, -} from '~/contracts/services/batchQuery'; -import { - queryFactoryConfig$, - queryFactoryPairs$, - queryPairConfig$, - batchQueryPairsInfo$, - batchQueryStakingInfo$, - queryFactoryConfig, - queryFactoryPairs, - queryPairConfig, - batchQueryPairsInfo, - batchQueryStakingInfo, - parseSwapResponse, -} from '~/contracts/services/swap'; -import { - querySnip20TokenInfo$, - querySnip20TokenInfo, - querySnip20Balance, - querySnip20Balance$, -} from '~/contracts/services/snip20'; -import { msgSwap } from '~/contracts/definitions/swap'; -import { - constantProductSwapToken0for1, - constantProductSwapToken1for0, - stableSwapToken0for1, - stableSwapToken1for0, - constantProductPriceImpactToken0for1, - constantProductPriceImpactToken1for0, - stableSwapPriceImpactToken0For1, - stableSwapPriceImpactToken1For0, - constantProductReverseSwapToken0for1, - constantProductReverseSwapToken1for0, - stableReverseSwapToken0for1, - stableReverseSwapToken1for0, -} from '~/lib/swap/swapCalculations'; +export * from '~/contracts'; +export * from '~/client'; +export * from '~/lib/swap'; export { - getSecretNetworkClient$, - getActiveQueryClient$, - queryPrice$, - queryPrices$, - queryPrice, - queryPrices, - batchQuery$, - batchQuery, - queryFactoryConfig$, - queryFactoryPairs$, - queryPairConfig$, - batchQueryPairsInfo$, - batchQueryStakingInfo$, - queryFactoryConfig, - queryFactoryPairs, - queryPairConfig, - batchQueryPairsInfo, - batchQueryStakingInfo, - querySnip20TokenInfo$, - querySnip20TokenInfo, - querySnip20Balance, - querySnip20Balance$, - msgSwap, - parseSwapResponse, - constantProductSwapToken0for1, - constantProductSwapToken1for0, - stableSwapToken0for1, - stableSwapToken1for0, - constantProductPriceImpactToken0for1, - constantProductPriceImpactToken1for0, - stableSwapPriceImpactToken0For1, - stableSwapPriceImpactToken1For0, - constantProductReverseSwapToken0for1, - constantProductReverseSwapToken1for0, - stableReverseSwapToken0for1, - stableReverseSwapToken1for0, -}; + encodeJsonToB64, + decodeB64ToJson, + generatePadding, + convertCoinFromUDenom, + convertCoinToUDenom, +} from '~/lib/utils'; diff --git a/src/lib/swap/index.ts b/src/lib/swap/index.ts new file mode 100644 index 0000000..94eb50c --- /dev/null +++ b/src/lib/swap/index.ts @@ -0,0 +1,2 @@ +export * from './swapCalculations'; +export * from './router'; diff --git a/src/lib/swap/router.test.ts b/src/lib/swap/router.test.ts index 71b2fdf..660f406 100644 --- a/src/lib/swap/router.test.ts +++ b/src/lib/swap/router.test.ts @@ -4,7 +4,7 @@ import { } from 'vitest'; import { getPossiblePaths, - forwardCalculateRoute, + calculateRoute, getRoutes, } from '~/lib/swap/router'; import BigNumber from 'bignumber.js'; @@ -213,7 +213,7 @@ test('it can calculate the output of a single pool swap route', () => { path: ['CONTRACT_ADDRESS_PAIR_1'], gasMultiplier: GasMultiplier.CONSTANT_PRODUCT, }; - expect(forwardCalculateRoute({ + expect(calculateRoute({ inputTokenAmount: BigNumber('1000000000'), inputTokenContractAddress: output.inputTokenContractAddress, path: ['CONTRACT_ADDRESS_PAIR_1'], @@ -248,7 +248,7 @@ test('it can calculate the output of a multi-hop constant product swap route', ( // liquidity provider Fee: 0.02 // Pool A-B - const constantProductSwap1Output = forwardCalculateRoute({ + const constantProductSwap1Output = calculateRoute({ inputTokenAmount: BigNumber('1000000000'), inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_1'], @@ -257,7 +257,7 @@ test('it can calculate the output of a multi-hop constant product swap route', ( }).quoteOutputAmount; // pool C-B - const constantProductSwap2Output = forwardCalculateRoute({ + const constantProductSwap2Output = calculateRoute({ inputTokenAmount: constantProductSwap1Output, inputTokenContractAddress: 'TOKEN_B_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_2'], @@ -266,7 +266,7 @@ test('it can calculate the output of a multi-hop constant product swap route', ( }).quoteOutputAmount; // pool C-D - const constantProductSwap3Output = forwardCalculateRoute({ + const constantProductSwap3Output = calculateRoute({ inputTokenAmount: constantProductSwap2Output, inputTokenContractAddress: 'TOKEN_C_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_3'], @@ -275,7 +275,7 @@ test('it can calculate the output of a multi-hop constant product swap route', ( }).quoteOutputAmount; // combine into multi-hop routing (FORWARD) - const calulatedRouteResult = forwardCalculateRoute({ + const calulatedRouteResult = calculateRoute({ inputTokenAmount: BigNumber('1000000000'), inputTokenContractAddress: 'TOKEN_A_CONTRACT_ADDRESS', path: [ @@ -350,7 +350,7 @@ test('it can calculate the output of a multi-hop stable swap route', () => { // First simulate indidual swaps using outputs as inputs of the following // Pool K-L - const stableSwap1Output = forwardCalculateRoute({ + const stableSwap1Output = calculateRoute({ inputTokenAmount: BigNumber('100000000'), inputTokenContractAddress: 'TOKEN_K_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_10'], @@ -359,7 +359,7 @@ test('it can calculate the output of a multi-hop stable swap route', () => { }).quoteOutputAmount; // pool M-L - const stableSwap2Output = forwardCalculateRoute({ + const stableSwap2Output = calculateRoute({ inputTokenAmount: stableSwap1Output, inputTokenContractAddress: 'TOKEN_L_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_11'], @@ -368,7 +368,7 @@ test('it can calculate the output of a multi-hop stable swap route', () => { }).quoteOutputAmount; // pool M-N - const stableSwap3Output = forwardCalculateRoute({ + const stableSwap3Output = calculateRoute({ inputTokenAmount: stableSwap2Output, inputTokenContractAddress: 'TOKEN_M_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_12'], @@ -377,7 +377,7 @@ test('it can calculate the output of a multi-hop stable swap route', () => { }).quoteOutputAmount; // combine into multi-hop routing - const calulatedStableRouteResult = forwardCalculateRoute({ + const calulatedStableRouteResult = calculateRoute({ inputTokenAmount: BigNumber('100000000'), inputTokenContractAddress: 'TOKEN_K_CONTRACT_ADDRESS', path: [ @@ -443,7 +443,7 @@ test('it can calculate the output of a multi-hop mixed swap route', () => { // First simulate indidual swaps using outputs as inputs of the following // Pool O-L - const mixedSwapConstantProduct1Output = forwardCalculateRoute({ + const mixedSwapConstantProduct1Output = calculateRoute({ inputTokenAmount: BigNumber('100000000'), inputTokenContractAddress: 'TOKEN_O_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_13'], @@ -452,7 +452,7 @@ test('it can calculate the output of a multi-hop mixed swap route', () => { }).quoteOutputAmount; // pool M-L - const mixedSwapStableSwapOutput = forwardCalculateRoute({ + const mixedSwapStableSwapOutput = calculateRoute({ inputTokenAmount: mixedSwapConstantProduct1Output, inputTokenContractAddress: 'TOKEN_L_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_11'], @@ -461,7 +461,7 @@ test('it can calculate the output of a multi-hop mixed swap route', () => { }).quoteOutputAmount; // pool M-P - const mixedSwapConstantProduct2Output = forwardCalculateRoute({ + const mixedSwapConstantProduct2Output = calculateRoute({ inputTokenAmount: mixedSwapStableSwapOutput, inputTokenContractAddress: 'TOKEN_M_CONTRACT_ADDRESS', path: ['CONTRACT_ADDRESS_PAIR_14'], @@ -470,7 +470,7 @@ test('it can calculate the output of a multi-hop mixed swap route', () => { }).quoteOutputAmount; // combined multi-hop - const mixedMultiHopResult = forwardCalculateRoute({ + const mixedMultiHopResult = calculateRoute({ inputTokenAmount: BigNumber('100000000'), inputTokenContractAddress: 'TOKEN_O_CONTRACT_ADDRESS', path: [ diff --git a/src/lib/swap/router.ts b/src/lib/swap/router.ts index e13fa1c..15de5fb 100644 --- a/src/lib/swap/router.ts +++ b/src/lib/swap/router.ts @@ -100,7 +100,7 @@ function getPossiblePaths({ * calculates the estimated output of swapping through a route given an input token amount * and also transforms the data collected in each pool into the Route data model */ -function forwardCalculateRoute({ +function calculateRoute({ inputTokenAmount, inputTokenContractAddress, path, @@ -371,7 +371,7 @@ function getRoutes({ const routes = possiblePaths.reduce((prev, path) => { try { - const newRoute = forwardCalculateRoute({ + const newRoute = calculateRoute({ inputTokenAmount, inputTokenContractAddress, path, @@ -401,6 +401,6 @@ function getRoutes({ } export { getPossiblePaths, - forwardCalculateRoute, + calculateRoute, getRoutes, }; diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index 450871e..7a258ee 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -7,7 +7,7 @@ import { import { encodeJsonToB64, decodeB64ToJson, - randomPadding, + generatePadding, convertCoinFromUDenom, convertCoinToUDenom, } from './utils'; @@ -31,15 +31,15 @@ test('It decodes a base64 string into JSON', () => { test('Generates random padding of length 8-15', () => { // checks midpoint vi.spyOn(global.Math, 'random').mockReturnValue(0.44351455); - expect(randomPadding()).toBe('bbbbbbbbbbb'); + expect(generatePadding()).toBe('bbbbbbbbbbb'); // checks upper bound vi.spyOn(global.Math, 'random').mockReturnValue(0.99999999); - expect(randomPadding()).toBe('999999999999999'); + expect(generatePadding()).toBe('999999999999999'); // checks lower bound vi.spyOn(global.Math, 'random').mockReturnValue(0); - expect(randomPadding()).toBe('AAAAAAAA'); + expect(generatePadding()).toBe('AAAAAAAA'); }); test('It converts token from U denom V2', () => { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index aa17360..150e551 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -8,7 +8,7 @@ const decodeB64ToJson = (encodedData: string) => JSON.parse(Buffer.from(encodedD /** * Generates random string of characters, used to add entropy to TX data * */ -const randomPadding = ():string => { +const generatePadding = ():string => { enum length { MAX = 15, MIN = 8 @@ -49,6 +49,10 @@ const convertCoinToUDenom = ( return amount.multipliedBy(BigNumber(10).pow(decimals)).toFixed(0); }; +/** + * function used to determine the decimals of a token given the contract address and a list + * of token configs + */ function getTokenDecimalsByTokenConfig(tokenContractAddress: string, tokens: TokensConfig) { const tokenConfigArr = tokens.filter( (token) => token.tokenContractAddress === tokenContractAddress, @@ -68,7 +72,7 @@ function getTokenDecimalsByTokenConfig(tokenContractAddress: string, tokens: Tok export { encodeJsonToB64, decodeB64ToJson, - randomPadding, + generatePadding, convertCoinFromUDenom, convertCoinToUDenom, getTokenDecimalsByTokenConfig,