@marko00/routing-finder-mare 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/.idea/copilot.data.migration.agent.xml +6 -0
  2. package/.idea/copilot.data.migration.ask.xml +6 -0
  3. package/.idea/copilot.data.migration.ask2agent.xml +6 -0
  4. package/.idea/copilot.data.migration.edit.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/php.xml +19 -0
  7. package/.idea/ratex-sdk.iml +8 -0
  8. package/.idea/vcs.xml +6 -0
  9. package/LICENSE-MIT +21 -0
  10. package/README.md +209 -0
  11. package/contracts/abi/BalancerHelperAbi.ts +1 -0
  12. package/contracts/abi/CamelotHelperAbi.ts +1 -0
  13. package/contracts/abi/RateXAbi.ts +482 -0
  14. package/contracts/abi/SushiSwapHelperAbi.ts +1 -0
  15. package/contracts/abi/UniswapHelperAbi.ts +1 -0
  16. package/contracts/abi/UniswapV2HelperAbi.ts +1 -0
  17. package/contracts/addresses-arbitrum.ts +8 -0
  18. package/contracts/addresses-mainnet.ts +7 -0
  19. package/contracts/addresses-polkadot.ts +9 -0
  20. package/contracts/addresses-sei.ts +9 -0
  21. package/contracts/rateX/BalancerHelper.ts +13 -0
  22. package/contracts/rateX/CamelotHelper.ts +13 -0
  23. package/contracts/rateX/SushiSwapHelper.ts +13 -0
  24. package/contracts/rateX/UniswapHelper.ts +19 -0
  25. package/contracts/rateX/UniswapV2Helper.ts +19 -0
  26. package/dexes/dexIdsList.ts +9 -0
  27. package/dexes/graph_queries/BalancerV2.ts +150 -0
  28. package/dexes/graph_queries/CamelotV2.ts +202 -0
  29. package/dexes/graph_queries/SushiSwapV2.ts +283 -0
  30. package/dexes/graph_queries/UniswapV2.ts +252 -0
  31. package/dexes/graph_queries/UniswapV3.ts +229 -0
  32. package/dexes/graph_queries/graphQueryFilters.ts +41 -0
  33. package/dexes/graph_queries/x_template.ts +67 -0
  34. package/dexes/pools/Balancer/BalancerState.ts +34 -0
  35. package/dexes/pools/Balancer/BalancerWeightedPool.ts +96 -0
  36. package/dexes/pools/Camelot.ts +164 -0
  37. package/dexes/pools/SushiSwapV2.ts +35 -0
  38. package/dexes/pools/UniswapV2.ts +36 -0
  39. package/dexes/pools/uniswap/UniswapV3.ts +40 -0
  40. package/dexes/pools/uniswap/testUniswapOffchainQuoter.ts +169 -0
  41. package/dexes/pools/uniswap/types.ts +174 -0
  42. package/dexes/pools/uniswap/uniswapOffchainQuoter.ts +173 -0
  43. package/dexes/pools/uniswap/uniswapState.ts +56 -0
  44. package/dexes/pools/uniswap/utils.ts +71 -0
  45. package/dist/contracts/abi/BalancerHelperAbi.d.ts +25 -0
  46. package/dist/contracts/abi/BalancerHelperAbi.js +4 -0
  47. package/dist/contracts/abi/CamelotHelperAbi.d.ts +45 -0
  48. package/dist/contracts/abi/CamelotHelperAbi.js +4 -0
  49. package/dist/contracts/abi/RateXAbi.d.ts +71 -0
  50. package/dist/contracts/abi/RateXAbi.js +485 -0
  51. package/dist/contracts/abi/SushiSwapHelperAbi.d.ts +45 -0
  52. package/dist/contracts/abi/SushiSwapHelperAbi.js +4 -0
  53. package/dist/contracts/abi/UniswapHelperAbi.d.ts +39 -0
  54. package/dist/contracts/abi/UniswapHelperAbi.js +4 -0
  55. package/dist/contracts/abi/UniswapV2HelperAbi.d.ts +45 -0
  56. package/dist/contracts/abi/UniswapV2HelperAbi.js +4 -0
  57. package/dist/contracts/addresses-arbitrum.d.ts +6 -0
  58. package/dist/contracts/addresses-arbitrum.js +10 -0
  59. package/dist/contracts/addresses-mainnet.d.ts +6 -0
  60. package/dist/contracts/addresses-mainnet.js +10 -0
  61. package/dist/contracts/addresses-polkadot.d.ts +6 -0
  62. package/dist/contracts/addresses-polkadot.js +10 -0
  63. package/dist/contracts/addresses-sei.d.ts +6 -0
  64. package/dist/contracts/addresses-sei.js +10 -0
  65. package/dist/contracts/rateX/BalancerHelper.d.ts +26 -0
  66. package/dist/contracts/rateX/BalancerHelper.js +14 -0
  67. package/dist/contracts/rateX/CamelotHelper.d.ts +46 -0
  68. package/dist/contracts/rateX/CamelotHelper.js +14 -0
  69. package/dist/contracts/rateX/SushiSwapHelper.d.ts +46 -0
  70. package/dist/contracts/rateX/SushiSwapHelper.js +14 -0
  71. package/dist/contracts/rateX/UniswapHelper.d.ts +40 -0
  72. package/dist/contracts/rateX/UniswapHelper.js +22 -0
  73. package/dist/contracts/rateX/UniswapV2Helper.d.ts +46 -0
  74. package/dist/contracts/rateX/UniswapV2Helper.js +22 -0
  75. package/dist/dexes/dexIdsList.d.ts +9 -0
  76. package/dist/dexes/dexIdsList.js +12 -0
  77. package/dist/dexes/graph_queries/BalancerV2.d.ts +14 -0
  78. package/dist/dexes/graph_queries/BalancerV2.js +141 -0
  79. package/dist/dexes/graph_queries/CamelotV2.d.ts +14 -0
  80. package/dist/dexes/graph_queries/CamelotV2.js +183 -0
  81. package/dist/dexes/graph_queries/SushiSwapV2.d.ts +14 -0
  82. package/dist/dexes/graph_queries/SushiSwapV2.js +263 -0
  83. package/dist/dexes/graph_queries/UniswapV2.d.ts +14 -0
  84. package/dist/dexes/graph_queries/UniswapV2.js +217 -0
  85. package/dist/dexes/graph_queries/UniswapV3.d.ts +14 -0
  86. package/dist/dexes/graph_queries/UniswapV3.js +198 -0
  87. package/dist/dexes/graph_queries/graphQueryFilters.d.ts +19 -0
  88. package/dist/dexes/graph_queries/graphQueryFilters.js +40 -0
  89. package/dist/dexes/graph_queries/x_template.d.ts +12 -0
  90. package/dist/dexes/graph_queries/x_template.js +57 -0
  91. package/dist/dexes/pools/Balancer/BalancerState.d.ts +6 -0
  92. package/dist/dexes/pools/Balancer/BalancerState.js +32 -0
  93. package/dist/dexes/pools/Balancer/BalancerWeightedPool.d.ts +12 -0
  94. package/dist/dexes/pools/Balancer/BalancerWeightedPool.js +109 -0
  95. package/dist/dexes/pools/Camelot.d.ts +12 -0
  96. package/dist/dexes/pools/Camelot.js +135 -0
  97. package/dist/dexes/pools/SushiSwapV2.d.ts +9 -0
  98. package/dist/dexes/pools/SushiSwapV2.js +34 -0
  99. package/dist/dexes/pools/UniswapV2.d.ts +9 -0
  100. package/dist/dexes/pools/UniswapV2.js +34 -0
  101. package/dist/dexes/pools/uniswap/UniswapV3.d.ts +7 -0
  102. package/dist/dexes/pools/uniswap/UniswapV3.js +36 -0
  103. package/dist/dexes/pools/uniswap/types.d.ts +76 -0
  104. package/dist/dexes/pools/uniswap/types.js +111 -0
  105. package/dist/dexes/pools/uniswap/uniswapOffchainQuoter.d.ts +13 -0
  106. package/dist/dexes/pools/uniswap/uniswapOffchainQuoter.js +121 -0
  107. package/dist/dexes/pools/uniswap/uniswapState.d.ts +14 -0
  108. package/dist/dexes/pools/uniswap/uniswapState.js +51 -0
  109. package/dist/dexes/pools/uniswap/utils.d.ts +3 -0
  110. package/dist/dexes/pools/uniswap/utils.js +41 -0
  111. package/dist/index.d.ts +26 -0
  112. package/dist/index.js +41 -0
  113. package/dist/routes.d.ts +1 -0
  114. package/dist/routes.js +20 -0
  115. package/dist/routing/iterative_spliting/main.d.ts +3 -0
  116. package/dist/routing/iterative_spliting/main.js +104 -0
  117. package/dist/routing/iterative_spliting/multiHopSwap.d.ts +4 -0
  118. package/dist/routing/iterative_spliting/multiHopSwap.js +83 -0
  119. package/dist/routing/main.d.ts +2 -0
  120. package/dist/routing/main.js +22 -0
  121. package/dist/routing/uni_like_algo/algo_config.d.ts +2 -0
  122. package/dist/routing/uni_like_algo/algo_config.js +8 -0
  123. package/dist/routing/uni_like_algo/amount_distribution.d.ts +2 -0
  124. package/dist/routing/uni_like_algo/amount_distribution.js +17 -0
  125. package/dist/routing/uni_like_algo/compute_routes_backtrack.d.ts +3 -0
  126. package/dist/routing/uni_like_algo/compute_routes_backtrack.js +44 -0
  127. package/dist/routing/uni_like_algo/main.d.ts +2 -0
  128. package/dist/routing/uni_like_algo/main.js +49 -0
  129. package/dist/routing/uni_like_algo/routes_quoter.d.ts +21 -0
  130. package/dist/routing/uni_like_algo/routes_quoter.js +53 -0
  131. package/dist/routing/uni_like_algo/swap_finder.d.ts +25 -0
  132. package/dist/routing/uni_like_algo/swap_finder.js +154 -0
  133. package/dist/routing/uni_like_algo/types.d.ts +40 -0
  134. package/dist/routing/uni_like_algo/types.js +12 -0
  135. package/dist/swap/graph_communication.d.ts +5 -0
  136. package/dist/swap/graph_communication.js +187 -0
  137. package/dist/swap/my_local_storage.d.ts +8 -0
  138. package/dist/swap/my_local_storage.js +16 -0
  139. package/dist/utils/addresses.d.ts +24 -0
  140. package/dist/utils/addresses.js +60 -0
  141. package/dist/utils/math/fixed-points.d.ts +14 -0
  142. package/dist/utils/math/fixed-points.js +123 -0
  143. package/dist/utils/math/log-exp.d.ts +5 -0
  144. package/dist/utils/math/log-exp.js +385 -0
  145. package/dist/utils/math/math.d.ts +12 -0
  146. package/dist/utils/math/math.js +50 -0
  147. package/dist/utils/types/types.d.ts +51 -0
  148. package/dist/utils/types/types.js +25 -0
  149. package/dist/utils/utils.d.ts +20 -0
  150. package/dist/utils/utils.js +72 -0
  151. package/images/decenter_logo.png +0 -0
  152. package/index.ts +50 -0
  153. package/package.json +39 -0
  154. package/routes.ts +27 -0
  155. package/routing/iterative_spliting/main.ts +131 -0
  156. package/routing/iterative_spliting/multiHopSwap.ts +98 -0
  157. package/routing/main.ts +22 -0
  158. package/routing/uni_like_algo/algo_config.ts +7 -0
  159. package/routing/uni_like_algo/amount_distribution.ts +16 -0
  160. package/routing/uni_like_algo/compute_routes_backtrack.ts +81 -0
  161. package/routing/uni_like_algo/main.ts +65 -0
  162. package/routing/uni_like_algo/routes_quoter.ts +63 -0
  163. package/routing/uni_like_algo/swap_finder.ts +185 -0
  164. package/routing/uni_like_algo/types.ts +54 -0
  165. package/swap/graph_communication.ts +212 -0
  166. package/swap/my_local_storage.ts +27 -0
  167. package/tsconfig.json +26 -0
  168. package/utils/addresses.ts +64 -0
  169. package/utils/math/fixed-points.ts +88 -0
  170. package/utils/math/log-exp.ts +469 -0
  171. package/utils/math/math.ts +46 -0
  172. package/utils/types/types.ts +100 -0
  173. package/utils/utils.ts +125 -0
@@ -0,0 +1,96 @@
1
+ // Ported from Solidity: https://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/pool-weighted/contracts/WeightedMath.sol
2
+
3
+ import { Token, Pool } from '../../../utils/types/types'
4
+ import BigNumber from 'bignumber.js'
5
+ import * as fp from '../../../utils/math/fixed-points'
6
+ import * as math from '../../../utils/math/math'
7
+
8
+ // Swap limits: amounts swapped may not be larger than this percentage of total balance of the token being swapped
9
+ // Example - if the pool has 100 WETH, we can swap a maximum od 30 WETH
10
+ const _MAX_IN_RATIO = new BigNumber(0.3e18)
11
+
12
+ export class BalancerWeightedPool extends Pool {
13
+ reserves: BigNumber[]
14
+ startingReserves: BigNumber[]
15
+ weights: BigNumber[]
16
+ swapFeePercentage: BigNumber
17
+
18
+ constructor(poolId: string, dexId: string, tokens: Token[], reserves: BigInt[], weights: BigInt[], swapFeePercentage: BigInt) {
19
+ super(poolId, dexId, tokens)
20
+ this.reserves = reserves.map((r: BigInt) => new BigNumber(r.toString()))
21
+ this.startingReserves = [...this.reserves]
22
+ this.weights = weights.map((r: BigInt) => new BigNumber(r.toString()))
23
+ this.swapFeePercentage = new BigNumber(swapFeePercentage.toString())
24
+ }
25
+
26
+ reset(): void {
27
+ this.reserves = [...this.startingReserves]
28
+ }
29
+
30
+ calculateExpectedOutputAmount(tokenIn: string, tokenOut: string, amountIn: bigint): bigint {
31
+ return calculateOutputAmount(this, tokenIn, tokenOut, BigNumber(amountIn.toString()))
32
+ }
33
+
34
+ update(tokenIn: string, tokenOut: string, amountIn: bigint, amountOut: bigint): void {
35
+ // CHECK ???
36
+ const i = this.tokens.findIndex((token) => token._address === tokenIn)
37
+ const j = this.tokens.findIndex((token) => token._address === tokenOut)
38
+
39
+ this.reserves[i] = fp.add(this.reserves[i], BigNumber(amountIn.toString()))
40
+ this.reserves[j] = fp.sub(this.reserves[j], BigNumber(amountOut.toString()))
41
+ }
42
+ }
43
+
44
+ function calculateOutputAmount(
45
+ pool: BalancerWeightedPool,
46
+ tokenA: string,
47
+ tokenB: string,
48
+ tokenAmountIn: BigNumber,
49
+ swapFeePercentage?: BigNumber
50
+ ): bigint {
51
+ // Subtract the fee from the amount in if requested
52
+ if (swapFeePercentage) tokenAmountIn = fp.sub(tokenAmountIn, fp.mulUp(tokenAmountIn, swapFeePercentage))
53
+
54
+ // Get the index of the token we are swapping from and to
55
+ const i = pool.tokens.findIndex((token) => token._address === tokenA)
56
+ const j = pool.tokens.findIndex((token) => token._address === tokenB)
57
+
58
+ try {
59
+ const res = _calcOutGivenIn(pool.reserves[i], pool.weights[i], pool.reserves[j], pool.weights[j], tokenAmountIn)
60
+ return BigInt(res.toFixed())
61
+ } catch (e) {
62
+ return BigInt(0)
63
+ }
64
+ }
65
+
66
+ /* Computes how many tokens can be taken out of a pool if `amountIn` are sent, given the current balances and weights.
67
+ Amount out, so we round down overall:
68
+ **********************************************************************************************
69
+ // outGivenIn //
70
+ // aO = amountOut //
71
+ // bO = balanceOut //
72
+ // bI = balanceIn / / bI \ (wI / wO) \ //
73
+ // aI = amountIn aO = bO * | 1 - | -------------------------- | ^ | //
74
+ // wI = weightIn \ \ ( bI + aI ) / / //
75
+ // wO = weightOut //
76
+ **********************************************************************************************
77
+ The multiplication rounds down, and the subtrahend (power) runds up (so the base rounds up too).
78
+ Because bI / (bI + aI) <= 1, the exponent rounds down. */
79
+ // Ovde puca!!!!!!!!!!!!!!
80
+ function _calcOutGivenIn(
81
+ balanceIn: BigNumber,
82
+ weightIn: BigNumber,
83
+ balanceOut: BigNumber,
84
+ weightOut: BigNumber,
85
+ amountIn: BigNumber
86
+ ): BigNumber {
87
+ // Cannot exceed maximum in ratio (30% of tokenIn balance)
88
+ if (amountIn.gte(fp.mulDown(balanceIn, _MAX_IN_RATIO))) throw new Error('MAX_IN_RATIO')
89
+
90
+ const denominator = math.add(balanceIn, amountIn)
91
+ const base = fp.divUp(balanceIn, denominator)
92
+ const exponent = fp.divDown(weightIn, weightOut)
93
+ const power = fp.powUp(base, exponent)
94
+
95
+ return fp.mulDown(balanceOut, fp.complement(power))
96
+ }
@@ -0,0 +1,164 @@
1
+ import { Pool, Token } from '../../utils/types/types'
2
+ import BigNumber from "bignumber.js"
3
+
4
+ // Camelot V2 pools have 2 tokens in the pool, and a fee
5
+ // Example contracts of one Camelot V2 pool: https://arbiscan.io/address/0xa6c5c7d189fa4eb5af8ba34e63dcdd3a635d433f#readContract
6
+
7
+ const feeDenominator = new BigNumber(100000)
8
+
9
+ export class CamelotPool extends Pool {
10
+
11
+ fees: BigNumber[]
12
+ reserves: BigNumber[]
13
+ startingReserves: BigNumber[]
14
+ stableSwap: boolean
15
+
16
+ constructor(poolId: string, dexId: string, tokens: Token[], reserves: bigint[], fees: bigint[], stableSwap: boolean) {
17
+ super(poolId, dexId, tokens)
18
+ this.reserves = reserves.map((r) => BigNumber(r.toString()))
19
+ this.startingReserves = [...this.reserves]
20
+ this.fees = fees.map((f) => BigNumber(f.toString()))
21
+ this.stableSwap = stableSwap
22
+ }
23
+
24
+ reset(): void {
25
+ this.reserves = [...this.startingReserves]
26
+ }
27
+
28
+ // function getAmountOut on Camelot V2 pools smart contracts
29
+ calculateExpectedOutputAmount(tokenIn: string, tokenOut: string, amountIn: bigint): bigint {
30
+ // this function will be called by our routing algorithm which uses bigint values
31
+ const amountInBN = new BigNumber(amountIn.toString())
32
+
33
+ if (this.stableSwap)
34
+ return calculateStableSwap(this, tokenIn, tokenOut, amountInBN)
35
+ else
36
+ return calculateRegularSwap(this, tokenIn, tokenOut, amountInBN)
37
+ }
38
+
39
+ update(tokenIn: string, tokenOut: string, amountIn: bigint, amountOut: bigint): void {
40
+ const i = this.tokens.findIndex((token) => token._address === tokenIn)
41
+ const j = this.tokens.findIndex((token) => token._address === tokenOut)
42
+
43
+ this.reserves[i] = this.reserves[i].plus(BigNumber(amountIn.toString()))
44
+ this.reserves[j] = this.reserves[j].minus(BigNumber(amountOut.toString()))
45
+ }
46
+ }
47
+
48
+ function calculateStableSwap(pool: CamelotPool, tokenIn: string, tokenOut: string, amountIn: BigNumber): bigint {
49
+
50
+ const feePercent = tokenIn.toLowerCase() === pool.tokens[0]._address.toLowerCase() ? pool.fees[0] : pool.fees[1];
51
+
52
+ let reserve0 = pool.reserves[0]
53
+ let reserve1 = pool.reserves[1]
54
+ const precisionMultiplier0 = new BigNumber(10 ** pool.tokens[0].decimals)
55
+ const precisionMultiplier1 = new BigNumber(10 ** pool.tokens[1].decimals)
56
+
57
+ amountIn = amountIn.minus(amountIn.times(feePercent).div(feeDenominator)) // remove fee from amount received
58
+ const xy: BigNumber = _k(pool);
59
+ reserve0 = reserve0.times(1e18).div(precisionMultiplier0)
60
+ reserve1 = reserve1.times(1e18).div(precisionMultiplier1)
61
+
62
+ const [reserveA, reserveB] = tokenIn.toLowerCase() === pool.tokens[0]._address.toLowerCase()
63
+ ? [reserve0, reserve1]
64
+ : [reserve1, reserve0];
65
+
66
+ // amountIn = tokenIn == token0 ? amountIn * 1e18 / precisionMultiplier0 : amountIn * 1e18 / precisionMultiplier1;
67
+ amountIn = tokenIn.toLowerCase() === pool.tokens[0]._address.toLowerCase()
68
+ ? amountIn.times(1e18).div(precisionMultiplier0)
69
+ : amountIn.times(1e18).div(precisionMultiplier1);
70
+
71
+ // uint y = reserveB - _get_y(amountIn + reserveA, xy, reserveB);
72
+ const y = reserveB.minus(_get_y(amountIn.plus(reserveA), xy, reserveB))
73
+
74
+ // return y * (tokenIn == token0 ? precisionMultiplier1 : precisionMultiplier0) / 1e18;
75
+ let result = tokenIn.toLowerCase() === pool.tokens[0]._address.toLowerCase()
76
+ ? y.times(precisionMultiplier1).div(1e18)
77
+ : y.times(precisionMultiplier0).div(1e18)
78
+
79
+ result = floor(result)
80
+ return BigInt(result.toFixed())
81
+ }
82
+
83
+ // named the same as in Camelot V2 pools smart contracts
84
+ function _k(pool: CamelotPool): BigNumber {
85
+
86
+ // for simplicity extract values
87
+ let reserve0 = pool.reserves[0]
88
+ let reserve1 = pool.reserves[1]
89
+
90
+ if (pool.stableSwap) {
91
+ const precisionMultiplier0 = new BigNumber(10 ** pool.tokens[0].decimals)
92
+ const precisionMultiplier1 = new BigNumber(10 ** pool.tokens[1].decimals)
93
+
94
+ const x = reserve0.times(1e18).div(precisionMultiplier0)
95
+ const y = reserve1.times(1e18).div(precisionMultiplier1)
96
+ const a = x.times(y).div(1e18)
97
+ const b = x.times(x).div(1e18).plus(y.times(y).div(1e18))
98
+ let res = a.times(b).div(1e18)
99
+ return floor(res) // x3y+y3x >= k
100
+ }
101
+ return reserve0.times(reserve1)
102
+ }
103
+
104
+ // named the same as in Camelot V2 pools smart contracts
105
+ function _get_y(x0: BigNumber, xy: BigNumber, y: BigNumber): BigNumber {
106
+
107
+ for (let i = 0; i < 255; i++) {
108
+ const y_prev = y
109
+ const k = _f(x0, y)
110
+ if (k.lt(xy)) {
111
+ let dy = xy.minus(k).times(1e18).dividedToIntegerBy(_d(x0, y))
112
+ y = y.plus(dy)
113
+ } else {
114
+ let dy = k.minus(xy).times(1e18).dividedToIntegerBy(_d(x0, y))
115
+ y = y.minus(dy)
116
+ }
117
+
118
+ const diff = y.minus(y_prev).abs()
119
+ if (diff.lte(1))
120
+ break
121
+ }
122
+ return floor(y)
123
+ }
124
+
125
+ function _f(x0: BigNumber, y: BigNumber): BigNumber {
126
+ // return x0 * (y * y / 1e18 * y / 1e18) / 1e18 + (x0 * x0 / 1e18 * x0 / 1e18) * y / 1e18;
127
+ const ySquared = y.times(y).dividedToIntegerBy(1e18)
128
+ const x0Squared = x0.times(x0).dividedToIntegerBy(1e18)
129
+ const term1 = x0.times((ySquared).times(y).dividedToIntegerBy(1e18)).dividedToIntegerBy(1e18)
130
+ const term2 = y.times(x0Squared.times(x0).dividedToIntegerBy(1e18)).dividedToIntegerBy(1e18)
131
+ return term1.plus(term2)
132
+ }
133
+
134
+ function _d(x0: BigNumber, y: BigNumber): BigNumber {
135
+ // return 3 * x0 * (y * y / 1e18) / 1e18 + (x0 * x0 / 1e18 * x0 / 1e18);
136
+ const ySquared = y.times(y).dividedToIntegerBy(1e18)
137
+ const x0Squared = x0.times(x0).dividedToIntegerBy(1e18)
138
+ const term1 = x0.times(ySquared).times(3).dividedToIntegerBy(1e18)
139
+ const term2 = x0Squared.times(x0).dividedToIntegerBy(1e18)
140
+ return term1.plus(term2)
141
+ }
142
+
143
+ function calculateRegularSwap(pool: CamelotPool, tokenIn: string, tokenOut: string, amountIn: BigNumber): bigint {
144
+
145
+ const feePercent = tokenIn.toLowerCase() === pool.tokens[0]._address.toLowerCase() ? pool.fees[0] : pool.fees[1];
146
+
147
+ const [reserveA, reserveB] = tokenIn.toLowerCase() === pool.tokens[0]._address.toLowerCase()
148
+ ? [pool.reserves[0], pool.reserves[1]]
149
+ : [pool.reserves[1], pool.reserves[0]];
150
+
151
+ amountIn = amountIn.times(feeDenominator.minus(feePercent))
152
+ const numerator = amountIn.times(reserveB)
153
+ const denominator = reserveA.times(feeDenominator).plus(amountIn)
154
+ const result = floor(numerator.div(denominator))
155
+ return BigInt(result.toFixed())
156
+ }
157
+
158
+ /* Custom floor function because BigNumber library does not implement it
159
+ @param num: the BigNumber number to be floored
160
+ */
161
+ function floor(num: BigNumber): BigNumber {
162
+ const whole = num.toFixed().toString().split('.')[0]
163
+ return new BigNumber(whole)
164
+ }
@@ -0,0 +1,35 @@
1
+ import { Pool, Token } from '../../utils/types/types'
2
+
3
+ export class SushiSwapV2Pool extends Pool {
4
+ reserves: bigint[]
5
+ startingReserves: bigint[]
6
+
7
+ constructor(poolId: string, dexId: string, tokens: Token[], reserves: bigint[]) {
8
+ super(poolId, dexId, tokens)
9
+ this.reserves = reserves.slice()
10
+ this.startingReserves = [...this.reserves]
11
+ }
12
+ reset(): void {
13
+ this.reserves = [...this.startingReserves]
14
+ }
15
+
16
+ calculateExpectedOutputAmount(tokenIn: string, tokenOut: string, amountIn: bigint): bigint {
17
+ let reserveIn: bigint = this.reserves[0]
18
+ let reserveOut: bigint = this.reserves[1]
19
+ if (tokenIn.toLowerCase() === this.tokens[1]._address.toLowerCase()) {
20
+ reserveIn = this.reserves[1]
21
+ reserveOut = this.reserves[0]
22
+ }
23
+ return (amountIn * BigInt(997) * reserveOut) / (reserveIn * BigInt(1000) + amountIn * BigInt(997))
24
+ }
25
+
26
+ update(tokenIn: string, tokenOut: string, amountIn: bigint, amountOut: bigint): void {
27
+ if (tokenIn.toLowerCase() === this.tokens[0]._address.toLowerCase()) {
28
+ this.reserves[0] += amountIn
29
+ this.reserves[1] -= amountOut
30
+ } else {
31
+ this.reserves[1] += amountIn
32
+ this.reserves[0] -= amountOut
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,36 @@
1
+ import { Pool, Token } from '../../utils/types/types'
2
+
3
+ export class UniswapV2Pool extends Pool {
4
+ reserves: bigint[]
5
+ startingReserves: bigint[]
6
+
7
+ constructor(poolId: string, dexId: string, tokens: Token[], reserves: bigint[]) {
8
+ super(poolId, dexId, tokens)
9
+ this.reserves = reserves.slice()
10
+ this.startingReserves = [...this.reserves]
11
+ }
12
+
13
+ reset(): void {
14
+ this.reserves = [...this.startingReserves]
15
+ }
16
+
17
+ calculateExpectedOutputAmount(tokenIn: string, tokenOut: string, amountIn: bigint): bigint {
18
+ let reserveIn: bigint = this.reserves[0]
19
+ let reserveOut: bigint = this.reserves[1]
20
+ if (tokenIn.toLowerCase() === this.tokens[1]._address.toLowerCase()) {
21
+ reserveIn = this.reserves[1]
22
+ reserveOut = this.reserves[0]
23
+ }
24
+ return (amountIn * BigInt(997) * reserveOut) / (reserveIn * BigInt(1000) + amountIn * BigInt(997))
25
+ }
26
+
27
+ update(tokenIn: string, tokenOut: string, amountIn: bigint, amountOut: bigint): void {
28
+ if (tokenIn.toLowerCase() === this.tokens[0]._address.toLowerCase()) {
29
+ this.reserves[0] += amountIn
30
+ this.reserves[1] -= amountOut
31
+ } else {
32
+ this.reserves[1] += amountIn
33
+ this.reserves[0] -= amountOut
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,40 @@
1
+ import { Pool, Token } from '../../../utils/types/types'
2
+ import { UniswapState } from './uniswapState'
3
+ import { PoolState } from './types'
4
+
5
+ export class UniswapV3Pool extends Pool {
6
+ public constructor(poolId: string, dexId: string, tokens: Token[]) {
7
+ super(poolId.toLowerCase(), dexId, tokens)
8
+ }
9
+
10
+ calculateExpectedOutputAmount(tokenIn: string, tokenOut: string, amountIn: bigint): bigint {
11
+ const poolData: PoolState | undefined = UniswapState.getPoolState(this.poolId)
12
+ if (!poolData) {
13
+ console.log('ERROR: Data for uni v3 pool: ' + this.poolId + ' not found')
14
+ return BigInt(0)
15
+ }
16
+
17
+ return UniswapState.quoter.quote(poolData, tokenIn, tokenOut, amountIn)[0]
18
+ }
19
+
20
+ reset(): void {
21
+ UniswapState.resetPoolState(this.poolId)
22
+ }
23
+
24
+ update(tokenIn: string, tokenOut: string, amountIn: bigint) {
25
+ const poolData: PoolState | undefined = UniswapState.getPoolState(this.poolId)
26
+ if (!poolData) {
27
+ console.log('ERROR: Data for uni v3 pool: ' + this.poolId + ' not found')
28
+ return BigInt(0)
29
+ }
30
+
31
+ // lastQuote will be stored each time we call quote
32
+ const lastQuote = poolData.lastQuote;
33
+ poolData.data.currentLiquidity = lastQuote.newLiquidity;
34
+ poolData.data.currentSqrtPriceX96 = lastQuote.newSqrtPriceX96;
35
+ poolData.data.currentTickIndex = lastQuote.newTickIndex;
36
+
37
+ // we don't need this, because we don't use amountIn anyway
38
+ return BigInt(0);
39
+ }
40
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * If you want to run this file separately, or any other in ts isolated environment
3
+ * ts-node --esm dexes/pools/uniswap/testUniswapOffchainQuoter.ts
4
+ *
5
+ * remove "type": "module" from sdk package.json
6
+ * And remove rpc function in RPC provider because window object is available only in browser
7
+ *
8
+ * Later if you want to run things in browser, add "type": "module" back to sdk package.json
9
+ *
10
+ * This examples assumes that you have localhost hardhat node running with deployed contracts
11
+ * */
12
+
13
+ import { TradeInfo } from './types'
14
+ import { Token } from '../../../types'
15
+ import { addresses } from '../../../utils/addresses'
16
+ import { UniswapState } from './uniswapState'
17
+ import { UniswapV3Pool } from './UniswapV3'
18
+ import Web3 from 'web3'
19
+ import { IQuoterV2_ABI } from '../../../../contracts/abi/common/IQuoterV2_ABI'
20
+ import { initLocalHardhatProvider } from '../../../../providers/RPCProvider'
21
+
22
+ const web3: Web3 = initLocalHardhatProvider()
23
+
24
+ const POOLS = [
25
+ addresses.univ3_wbtc_eth_pool_0_3,
26
+ addresses.gmx_usdc_pool_0_1,
27
+ addresses.uni_weth_pool,
28
+ addresses.weth_link_pool,
29
+ addresses.dai_usdce_pool_0_0_1,
30
+ ]
31
+ const quoterContract = new web3.eth.Contract(IQuoterV2_ABI, addresses.uniQuoterV2)
32
+
33
+ async function testQuote() {
34
+ const startTimestamp = Date.now()
35
+ await UniswapState.initializeFreshPoolsData(POOLS, 1, web3)
36
+ const endTimestamp = Date.now()
37
+
38
+ console.log('Time taken for initialization: ', endTimestamp - startTimestamp)
39
+
40
+ const trades: TradeInfo[] = getTestTrades()
41
+
42
+ for (let tradeInfo of trades) {
43
+ let params = {
44
+ tokenIn: tradeInfo.tokenIn,
45
+ tokenOut: tradeInfo.tokenOut,
46
+ amountIn: tradeInfo.amountIn,
47
+ fee: tradeInfo.fee,
48
+ sqrtPriceLimitX96: 0,
49
+ }
50
+ const tokenIn = { _address: tradeInfo.tokenIn } as Token
51
+ const tokenOut = { _address: tradeInfo.tokenOut } as Token
52
+ //@ts-ignore
53
+ let x: any[] = await quoterContract.methods.quoteExactInputSingle(params).call()
54
+
55
+ const uniV3Pool = new UniswapV3Pool(tradeInfo.pool, 'uniswap', [tokenIn, tokenOut])
56
+
57
+ let y = uniV3Pool.calculateExpectedOutputAmount(tradeInfo.tokenIn, tradeInfo.tokenOut, tradeInfo.amountIn)
58
+
59
+ console.log('-------')
60
+ console.log('Uniswap quote: ', x[0], x[2])
61
+ console.log('Offchain quote: ', y)
62
+ }
63
+ }
64
+
65
+ function getTestTrades(): TradeInfo[] {
66
+ let trades: TradeInfo[] = []
67
+
68
+ trades.push(
69
+ new TradeInfo(
70
+ addresses.univ3_wbtc_eth_pool_0_3,
71
+ addresses.wethToken,
72
+ addresses.wbtcToken,
73
+ BigInt('100000000000000000000'), // 100 WETH
74
+ BigInt(3000)
75
+ )
76
+ )
77
+ trades.push(
78
+ new TradeInfo(
79
+ addresses.gmx_usdc_pool_0_1,
80
+ addresses.gmxToken,
81
+ addresses.usdcToken,
82
+ BigInt('200000000000000000000'), // 200 GMX
83
+ BigInt(10000)
84
+ )
85
+ )
86
+ trades.push(
87
+ new TradeInfo(
88
+ addresses.uni_weth_pool,
89
+ addresses.wethToken,
90
+ addresses.uniToken,
91
+ BigInt('1000000000000000000'), // 1 WETH
92
+ BigInt(3000)
93
+ )
94
+ )
95
+ trades.push(
96
+ new TradeInfo(
97
+ addresses.weth_link_pool,
98
+ addresses.linkToken,
99
+ addresses.wethToken,
100
+ BigInt('3000000000000000000000'), // 3000 LINK
101
+ BigInt(3000)
102
+ )
103
+ )
104
+ trades.push(
105
+ new TradeInfo(
106
+ addresses.dai_usdce_pool_0_0_1,
107
+ addresses.usdceToken,
108
+ addresses.daiToken,
109
+ BigInt('10000000000'), // 10 000 usdc
110
+ BigInt(100)
111
+ )
112
+ )
113
+
114
+ // ZERO FOR ONE
115
+
116
+ trades.push(
117
+ new TradeInfo(
118
+ addresses.univ3_wbtc_eth_pool_0_3,
119
+ addresses.wbtcToken,
120
+ addresses.wethToken,
121
+ BigInt('1000000000'), // 10 WBTC
122
+ BigInt(3000)
123
+ )
124
+ )
125
+ trades.push(
126
+ new TradeInfo(
127
+ addresses.gmx_usdc_pool_0_1,
128
+ addresses.usdcToken,
129
+ addresses.gmxToken,
130
+ BigInt('1000000000'), // 1000 USDC
131
+ BigInt(10000)
132
+ )
133
+ )
134
+ trades.push(
135
+ new TradeInfo(
136
+ addresses.uni_weth_pool,
137
+ addresses.uniToken,
138
+ addresses.wethToken,
139
+ BigInt('1000000000000000000000'), // 1000 UNI
140
+ BigInt(3000)
141
+ )
142
+ )
143
+ trades.push(
144
+ new TradeInfo(
145
+ addresses.weth_link_pool,
146
+ addresses.wethToken,
147
+ addresses.linkToken,
148
+ BigInt('10000000000000000000'), // 10 WETH
149
+ BigInt(3000)
150
+ )
151
+ )
152
+ trades.push(
153
+ new TradeInfo(
154
+ addresses.dai_usdce_pool_0_0_1,
155
+ addresses.daiToken,
156
+ addresses.usdceToken,
157
+ BigInt('1000000000000000000000'), // 1000 DAI
158
+ BigInt(100)
159
+ )
160
+ )
161
+
162
+ return trades
163
+ }
164
+
165
+ async function main() {
166
+ await testQuote()
167
+ }
168
+
169
+ main()