@paraswap/dex-lib 2.42.24 → 2.42.25-wombat.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 (255) hide show
  1. package/.vscode/launch.json +39 -0
  2. package/.vscode/settings.json +2 -0
  3. package/.vscode/tasks.json +15 -0
  4. package/build/abi/wombat/asset.json +769 -0
  5. package/build/abi/wombat/bmw.json +1247 -0
  6. package/build/abi/wombat/pool.json +1364 -0
  7. package/build/config.js +1 -1
  8. package/build/config.js.map +1 -1
  9. package/build/dex/index.js +2 -0
  10. package/build/dex/index.js.map +1 -1
  11. package/build/dex/{woo-fi → wombat}/config.d.ts +1 -1
  12. package/build/dex/wombat/config.js +77 -0
  13. package/build/dex/wombat/config.js.map +1 -0
  14. package/build/dex/wombat/types.d.ts +33 -0
  15. package/build/dex/{woo-fi → wombat}/types.js.map +1 -1
  16. package/build/dex/wombat/utils.d.ts +9 -0
  17. package/build/dex/wombat/utils.js +66 -0
  18. package/build/dex/wombat/utils.js.map +1 -0
  19. package/build/dex/wombat/wombat-bmw.d.ts +40 -0
  20. package/build/dex/wombat/wombat-bmw.js +147 -0
  21. package/build/dex/wombat/wombat-bmw.js.map +1 -0
  22. package/build/dex/wombat/wombat-pool.d.ts +22 -0
  23. package/build/dex/wombat/wombat-pool.js +161 -0
  24. package/build/dex/wombat/wombat-pool.js.map +1 -0
  25. package/build/dex/wombat/wombat-quoter.d.ts +16 -0
  26. package/build/dex/wombat/wombat-quoter.js +176 -0
  27. package/build/dex/wombat/wombat-quoter.js.map +1 -0
  28. package/build/dex/wombat/wombat.d.ts +55 -0
  29. package/build/dex/wombat/wombat.js +290 -0
  30. package/build/dex/wombat/wombat.js.map +1 -0
  31. package/package.json +1 -1
  32. package/src/abi/wombat/asset.json +769 -0
  33. package/src/abi/wombat/bmw.json +1247 -0
  34. package/{build/abi/wBETH.json → src/abi/wombat/pool.json} +574 -737
  35. package/src/config.ts +1 -2
  36. package/src/dex/index.ts +2 -0
  37. package/src/dex/wombat/config.ts +77 -0
  38. package/src/dex/wombat/types.ts +55 -0
  39. package/src/dex/wombat/utils.ts +62 -0
  40. package/src/dex/wombat/wombat-bmw.ts +209 -0
  41. package/src/dex/wombat/wombat-e2e.test.ts +264 -0
  42. package/src/dex/wombat/wombat-integration.test.ts +258 -0
  43. package/src/dex/wombat/wombat-pool.ts +231 -0
  44. package/src/dex/wombat/wombat-quoter.ts +269 -0
  45. package/src/dex/wombat/wombat.ts +426 -0
  46. package/tests/constants-e2e.ts +19 -4
  47. package/tests/utils-e2e.ts +2 -1
  48. package/.idea/aws.xml +0 -17
  49. package/.idea/codeStyles/Project.xml +0 -19
  50. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  51. package/.idea/misc.xml +0 -6
  52. package/.idea/modules.xml +0 -8
  53. package/.idea/paraswap-dex-lib.iml +0 -9
  54. package/.idea/prettier.xml +0 -7
  55. package/.idea/vcs.xml +0 -6
  56. package/build/abi/AugustusV6.abi.json +0 -395
  57. package/build/abi/algebra/AlgebraPool.abi.json +0 -727
  58. package/build/abi/curve-v1/StableSwapFRXETH.json +0 -889
  59. package/build/abi/curve-v1/StableSwapWBETH.json +0 -1223
  60. package/build/abi/sushiswap-v3/QuoterV2.json +0 -267
  61. package/build/abi/sushiswap-v3/RouterProcessor3.json +0 -289
  62. package/build/abi/uniswap-v3/UniswapV3Quoter.abi.json +0 -193
  63. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3QuoterV2.abi.json +0 -285
  64. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3Router.abi.json +0 -583
  65. package/build/abi/woo-fi/WooFeeManager.abi.json +0 -318
  66. package/build/abi/woo-fi/WooPP.abi.json +0 -548
  67. package/build/abi/woo-fi/Wooracle.abi.json +0 -260
  68. package/build/dex/aave-v3/tokens/arbitrum.json +0 -50
  69. package/build/dex/aave-v3/tokens/avalanche.json +0 -74
  70. package/build/dex/aave-v3/tokens/fantom.json +0 -62
  71. package/build/dex/aave-v3/tokens/optimism.json +0 -50
  72. package/build/dex/aave-v3/tokens/polygon.json +0 -116
  73. package/build/dex/algebra/algebra-pool.d.ts +0 -114
  74. package/build/dex/algebra/algebra-pool.js +0 -448
  75. package/build/dex/algebra/algebra-pool.js.map +0 -1
  76. package/build/dex/balancer-v2/Gyro3Pool.d.ts +0 -43
  77. package/build/dex/balancer-v2/Gyro3Pool.js +0 -160
  78. package/build/dex/balancer-v2/Gyro3Pool.js.map +0 -1
  79. package/build/dex/balancer-v2/LinearMath.d.ts +0 -88
  80. package/build/dex/balancer-v2/LinearMath.js +0 -285
  81. package/build/dex/balancer-v2/LinearMath.js.map +0 -1
  82. package/build/dex/balancer-v2/LinearPool.d.ts +0 -81
  83. package/build/dex/balancer-v2/LinearPool.js +0 -444
  84. package/build/dex/balancer-v2/LinearPool.js.map +0 -1
  85. package/build/dex/balancer-v2/PhantomStablePool.d.ts +0 -90
  86. package/build/dex/balancer-v2/PhantomStablePool.js +0 -418
  87. package/build/dex/balancer-v2/PhantomStablePool.js.map +0 -1
  88. package/build/dex/balancer-v2/StableMath.d.ts +0 -9
  89. package/build/dex/balancer-v2/StableMath.js +0 -272
  90. package/build/dex/balancer-v2/StableMath.js.map +0 -1
  91. package/build/dex/balancer-v2/balancer-v2-pool.d.ts +0 -140
  92. package/build/dex/balancer-v2/balancer-v2-pool.js +0 -647
  93. package/build/dex/balancer-v2/balancer-v2-pool.js.map +0 -1
  94. package/build/dex/balancer-v2/pools/gyro/Gyro3Pool.d.ts +0 -33
  95. package/build/dex/balancer-v2/pools/gyro/Gyro3Pool.js +0 -128
  96. package/build/dex/balancer-v2/pools/gyro/Gyro3Pool.js.map +0 -1
  97. package/build/dex/balancer-v2/pools/gyro/GyroEPool.d.ts +0 -34
  98. package/build/dex/balancer-v2/pools/gyro/GyroEPool.js +0 -151
  99. package/build/dex/balancer-v2/pools/gyro/GyroEPool.js.map +0 -1
  100. package/build/dex/curve-v1/pools/frxETHpool.d.ts +0 -7
  101. package/build/dex/curve-v1/pools/frxETHpool.js +0 -27
  102. package/build/dex/curve-v1/pools/frxETHpool.js.map +0 -1
  103. package/build/dex/curve-v1/pools/wbETHpool.d.ts +0 -29
  104. package/build/dex/curve-v1/pools/wbETHpool.js +0 -408
  105. package/build/dex/curve-v1/pools/wbETHpool.js.map +0 -1
  106. package/build/dex/lighter-v1/abi/erc20.json +0 -222
  107. package/build/dex/lighter-v1/abi/factory.json +0 -291
  108. package/build/dex/lighter-v1/abi/order_book.json +0 -594
  109. package/build/dex/lighter-v1/abi/order_book_helper.json +0 -176
  110. package/build/dex/lighter-v1/abi/router.json +0 -488
  111. package/build/dex/lighter-v1/config.d.ts +0 -4
  112. package/build/dex/lighter-v1/config.js +0 -17
  113. package/build/dex/lighter-v1/config.js.map +0 -1
  114. package/build/dex/lighter-v1/constants.d.ts +0 -2
  115. package/build/dex/lighter-v1/constants.js +0 -13
  116. package/build/dex/lighter-v1/constants.js.map +0 -1
  117. package/build/dex/lighter-v1/lighter-v1-pool.d.ts +0 -57
  118. package/build/dex/lighter-v1/lighter-v1-pool.js +0 -310
  119. package/build/dex/lighter-v1/lighter-v1-pool.js.map +0 -1
  120. package/build/dex/lighter-v1/lighter-v1.d.ts +0 -45
  121. package/build/dex/lighter-v1/lighter-v1.js +0 -331
  122. package/build/dex/lighter-v1/lighter-v1.js.map +0 -1
  123. package/build/dex/lighter-v1/types.d.ts +0 -40
  124. package/build/dex/lighter-v1/types.js.map +0 -1
  125. package/build/dex/pancakeswap-v3/types.d.ts +0 -14
  126. package/build/dex/pancakeswap-v3/types.js +0 -3
  127. package/build/dex/pancakeswap-v3/types.js.map +0 -1
  128. package/build/dex/quickswap/camelot-v3.d.ts +0 -6
  129. package/build/dex/quickswap/camelot-v3.js +0 -19
  130. package/build/dex/quickswap/camelot-v3.js.map +0 -1
  131. package/build/dex/quickswap/zyberswap-v3.d.ts +0 -6
  132. package/build/dex/quickswap/zyberswap-v3.js +0 -19
  133. package/build/dex/quickswap/zyberswap-v3.js.map +0 -1
  134. package/build/dex/quickswap-v3.d.ts +0 -21
  135. package/build/dex/quickswap-v3.js +0 -40
  136. package/build/dex/quickswap-v3.js.map +0 -1
  137. package/build/dex/ramses-v2/config.d.ts +0 -4
  138. package/build/dex/ramses-v2/config.js +0 -28
  139. package/build/dex/ramses-v2/config.js.map +0 -1
  140. package/build/dex/ramses-v2/constants.d.ts +0 -28
  141. package/build/dex/ramses-v2/constants.js +0 -35
  142. package/build/dex/ramses-v2/constants.js.map +0 -1
  143. package/build/dex/ramses-v2/contract-math/BitMath.d.ts +0 -4
  144. package/build/dex/ramses-v2/contract-math/BitMath.js +0 -93
  145. package/build/dex/ramses-v2/contract-math/BitMath.js.map +0 -1
  146. package/build/dex/ramses-v2/contract-math/FixedPoint128.d.ts +0 -3
  147. package/build/dex/ramses-v2/contract-math/FixedPoint128.js +0 -8
  148. package/build/dex/ramses-v2/contract-math/FixedPoint128.js.map +0 -1
  149. package/build/dex/ramses-v2/contract-math/FixedPoint96.d.ts +0 -4
  150. package/build/dex/ramses-v2/contract-math/FixedPoint96.js +0 -9
  151. package/build/dex/ramses-v2/contract-math/FixedPoint96.js.map +0 -1
  152. package/build/dex/ramses-v2/contract-math/FullMath.d.ts +0 -4
  153. package/build/dex/ramses-v2/contract-math/FullMath.js +0 -19
  154. package/build/dex/ramses-v2/contract-math/FullMath.js.map +0 -1
  155. package/build/dex/ramses-v2/contract-math/LiquidityMath.d.ts +0 -3
  156. package/build/dex/ramses-v2/contract-math/LiquidityMath.js +0 -22
  157. package/build/dex/ramses-v2/contract-math/LiquidityMath.js.map +0 -1
  158. package/build/dex/ramses-v2/contract-math/Oracle.d.ts +0 -10
  159. package/build/dex/ramses-v2/contract-math/Oracle.js +0 -133
  160. package/build/dex/ramses-v2/contract-math/Oracle.js.map +0 -1
  161. package/build/dex/ramses-v2/contract-math/SqrtPriceMath.d.ts +0 -10
  162. package/build/dex/ramses-v2/contract-math/SqrtPriceMath.js +0 -91
  163. package/build/dex/ramses-v2/contract-math/SqrtPriceMath.js.map +0 -1
  164. package/build/dex/ramses-v2/contract-math/SwapMath.d.ts +0 -8
  165. package/build/dex/ramses-v2/contract-math/SwapMath.js +0 -70
  166. package/build/dex/ramses-v2/contract-math/SwapMath.js.map +0 -1
  167. package/build/dex/ramses-v2/contract-math/Tick.d.ts +0 -7
  168. package/build/dex/ramses-v2/contract-math/Tick.js +0 -45
  169. package/build/dex/ramses-v2/contract-math/Tick.js.map +0 -1
  170. package/build/dex/ramses-v2/contract-math/TickBitMap.d.ts +0 -8
  171. package/build/dex/ramses-v2/contract-math/TickBitMap.js +0 -87
  172. package/build/dex/ramses-v2/contract-math/TickBitMap.js.map +0 -1
  173. package/build/dex/ramses-v2/contract-math/TickMath.d.ts +0 -8
  174. package/build/dex/ramses-v2/contract-math/TickMath.js +0 -162
  175. package/build/dex/ramses-v2/contract-math/TickMath.js.map +0 -1
  176. package/build/dex/ramses-v2/contract-math/UnsafeMath.d.ts +0 -3
  177. package/build/dex/ramses-v2/contract-math/UnsafeMath.js +0 -10
  178. package/build/dex/ramses-v2/contract-math/UnsafeMath.js.map +0 -1
  179. package/build/dex/ramses-v2/contract-math/uniswap-v3-math.d.ts +0 -18
  180. package/build/dex/ramses-v2/contract-math/uniswap-v3-math.js +0 -392
  181. package/build/dex/ramses-v2/contract-math/uniswap-v3-math.js.map +0 -1
  182. package/build/dex/ramses-v2/contract-math/utils.d.ts +0 -3
  183. package/build/dex/ramses-v2/contract-math/utils.js +0 -16
  184. package/build/dex/ramses-v2/contract-math/utils.js.map +0 -1
  185. package/build/dex/ramses-v2/ramses-v2-pool.d.ts +0 -42
  186. package/build/dex/ramses-v2/ramses-v2-pool.js +0 -307
  187. package/build/dex/ramses-v2/ramses-v2-pool.js.map +0 -1
  188. package/build/dex/ramses-v2/ramses-v2.d.ts +0 -61
  189. package/build/dex/ramses-v2/ramses-v2.js +0 -690
  190. package/build/dex/ramses-v2/ramses-v2.js.map +0 -1
  191. package/build/dex/ramses-v2/types.d.ts +0 -154
  192. package/build/dex/ramses-v2/types.js +0 -9
  193. package/build/dex/ramses-v2/types.js.map +0 -1
  194. package/build/dex/ramses-v2/utils.d.ts +0 -6
  195. package/build/dex/ramses-v2/utils.js +0 -71
  196. package/build/dex/ramses-v2/utils.js.map +0 -1
  197. package/build/dex/solidly/forks-override/fvm.d.ts +0 -20
  198. package/build/dex/solidly/forks-override/fvm.js +0 -42
  199. package/build/dex/solidly/forks-override/fvm.js.map +0 -1
  200. package/build/dex/sushiswap-v3/config.d.ts +0 -4
  201. package/build/dex/sushiswap-v3/config.js +0 -132
  202. package/build/dex/sushiswap-v3/config.js.map +0 -1
  203. package/build/dex/sushiswap-v3/constants.d.ts +0 -4
  204. package/build/dex/sushiswap-v3/constants.js +0 -32
  205. package/build/dex/sushiswap-v3/constants.js.map +0 -1
  206. package/build/dex/sushiswap-v3/sushiswap-v3-original.d.ts +0 -56
  207. package/build/dex/sushiswap-v3/sushiswap-v3-original.js +0 -598
  208. package/build/dex/sushiswap-v3/sushiswap-v3-original.js.map +0 -1
  209. package/build/dex/sushiswap-v3/sushiswap-v3-pool.d.ts +0 -1
  210. package/build/dex/sushiswap-v3/sushiswap-v3-pool.js +0 -6
  211. package/build/dex/sushiswap-v3/sushiswap-v3-pool.js.map +0 -1
  212. package/build/dex/sushiswap-v3/sushiswap-v3.d.ts +0 -21
  213. package/build/dex/sushiswap-v3/sushiswap-v3.js +0 -58
  214. package/build/dex/sushiswap-v3/sushiswap-v3.js.map +0 -1
  215. package/build/dex/sushiswap-v3/token.d.ts +0 -6
  216. package/build/dex/sushiswap-v3/token.js +0 -23
  217. package/build/dex/sushiswap-v3/token.js.map +0 -1
  218. package/build/dex/sushiswap-v3/types.d.ts +0 -15
  219. package/build/dex/sushiswap-v3/types.js +0 -18
  220. package/build/dex/sushiswap-v3/types.js.map +0 -1
  221. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.d.ts +0 -12
  222. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js +0 -23
  223. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js.map +0 -1
  224. package/build/dex/woo-fi/config.js +0 -141
  225. package/build/dex/woo-fi/config.js.map +0 -1
  226. package/build/dex/woo-fi/constants.d.ts +0 -5
  227. package/build/dex/woo-fi/constants.js +0 -20
  228. package/build/dex/woo-fi/constants.js.map +0 -1
  229. package/build/dex/woo-fi/types.d.ts +0 -48
  230. package/build/dex/woo-fi/types.js +0 -3
  231. package/build/dex/woo-fi/woo-fi-decimal-math.d.ts +0 -14
  232. package/build/dex/woo-fi/woo-fi-decimal-math.js +0 -42
  233. package/build/dex/woo-fi/woo-fi-decimal-math.js.map +0 -1
  234. package/build/dex/woo-fi/woo-fi-math.d.ts +0 -31
  235. package/build/dex/woo-fi/woo-fi-math.js +0 -300
  236. package/build/dex/woo-fi/woo-fi-math.js.map +0 -1
  237. package/build/dex/woo-fi/woo-fi.d.ts +0 -65
  238. package/build/dex/woo-fi/woo-fi.js +0 -480
  239. package/build/dex/woo-fi/woo-fi.js.map +0 -1
  240. package/build/executor/Executor01BytecodeBuilder.d.ts +0 -77
  241. package/build/executor/Executor01BytecodeBuilder.js +0 -359
  242. package/build/executor/Executor01BytecodeBuilder.js.map +0 -1
  243. package/build/executor/Executor02BytecodeBuilder.d.ts +0 -12
  244. package/build/executor/Executor02BytecodeBuilder.js +0 -14
  245. package/build/executor/Executor02BytecodeBuilder.js.map +0 -1
  246. package/build/executor/ExecutorDetector.d.ts +0 -28
  247. package/build/executor/ExecutorDetector.js +0 -89
  248. package/build/executor/ExecutorDetector.js.map +0 -1
  249. package/build/executor/IExecutorBytecodeBuilder.d.ts +0 -6
  250. package/build/executor/IExecutorBytecodeBuilder.js +0 -3
  251. package/build/executor/IExecutorBytecodeBuilder.js.map +0 -1
  252. package/build/generic-swap-transaction-builder.d.ts +0 -39
  253. package/build/generic-swap-transaction-builder.js +0 -156
  254. package/build/generic-swap-transaction-builder.js.map +0 -1
  255. /package/build/dex/{lighter-v1 → wombat}/types.js +0 -0
@@ -0,0 +1,269 @@
1
+ import { AssetState, PoolParams } from './types';
2
+ import { fromWad, sqrt, toWad, WAD, wdiv, wmul } from './utils';
3
+
4
+ export class WombatQuoter {
5
+ private readonly ampFactor: bigint;
6
+ private readonly haircutRate: bigint;
7
+ private readonly startCovRatio: bigint;
8
+ private readonly endCovRatio: bigint;
9
+
10
+ constructor(poolParams: PoolParams) {
11
+ this.ampFactor = poolParams.ampFactor;
12
+ this.haircutRate = poolParams.haircutRate;
13
+ this.startCovRatio = poolParams.startCovRatio;
14
+ this.endCovRatio = poolParams.endCovRatio;
15
+ }
16
+
17
+ public getQuote(
18
+ fromAsset: AssetState,
19
+ toAsset: AssetState,
20
+ fromAmount: bigint,
21
+ ): bigint {
22
+ if (fromAmount === 0n || fromAsset.paused) {
23
+ return 0n;
24
+ }
25
+
26
+ fromAmount = toWad(fromAmount, BigInt(fromAsset.underlyingTokenDecimals));
27
+
28
+ try {
29
+ const { actualToAmount, haircut } = this._highCovRatioPoolQuoteFrom(
30
+ fromAsset,
31
+ toAsset,
32
+ fromAmount,
33
+ );
34
+ const toCash = toAsset.cash - actualToAmount - haircut;
35
+
36
+ if (wdiv(toCash, toAsset.liability) < WAD / 100n) {
37
+ return 0n;
38
+ }
39
+
40
+ return fromWad(actualToAmount, BigInt(toAsset.underlyingTokenDecimals));
41
+ } catch (e) {
42
+ return 0n;
43
+ }
44
+ }
45
+
46
+ private _highCovRatioPoolQuoteFrom(
47
+ fromAsset: AssetState,
48
+ toAsset: AssetState,
49
+ fromAmount: bigint,
50
+ ): { actualToAmount: bigint; haircut: bigint } {
51
+ let { actualToAmount, haircut } = this._quoteFrom(
52
+ fromAsset,
53
+ toAsset,
54
+ fromAmount,
55
+ );
56
+
57
+ if (fromAmount > 0n) {
58
+ const fromCash = fromAsset.cash;
59
+ const fromLiability = fromAsset.liability;
60
+
61
+ const finalFromAssetCovRatio = wdiv(fromCash + fromAmount, fromLiability);
62
+ if (finalFromAssetCovRatio > this.startCovRatio) {
63
+ // charge high cov ratio fee
64
+ const highCovRatioFee = wmul(
65
+ this._highCovRatioFee(
66
+ wdiv(fromCash, fromLiability),
67
+ finalFromAssetCovRatio,
68
+ ),
69
+ actualToAmount,
70
+ );
71
+
72
+ actualToAmount -= highCovRatioFee;
73
+ haircut += highCovRatioFee;
74
+ }
75
+ } else {
76
+ // reverse quote
77
+ const toCash = toAsset.cash;
78
+ const toLiability = toAsset.liability;
79
+
80
+ const finalToAssetCovRatio = wdiv(toCash + actualToAmount, toLiability);
81
+ if (finalToAssetCovRatio <= this.startCovRatio) {
82
+ // happy path: no high cov ratio fee is charged
83
+ return { actualToAmount, haircut };
84
+ } else if (wdiv(toCash, toLiability) >= this.endCovRatio) {
85
+ // the to-asset exceeds it's cov ratio limit, further swap to increase cov ratio is impossible
86
+ throw new Error('WOMBAT_COV_RATIO_LIMIT_EXCEEDED');
87
+ }
88
+
89
+ // reverse quote: cov ratio of the to-asset exceed endCovRatio. direct reverse quote is not supported
90
+ // we binary search for a upper bound
91
+ actualToAmount = this._findUpperBound(toAsset, fromAsset, -fromAmount);
92
+ const result = this._highCovRatioPoolQuoteFrom(
93
+ toAsset,
94
+ fromAsset,
95
+ actualToAmount,
96
+ );
97
+ haircut = result.haircut;
98
+ }
99
+
100
+ return { actualToAmount, haircut };
101
+ }
102
+
103
+ private _highCovRatioFee(
104
+ initCovRatio: bigint,
105
+ finalCovRatio: bigint,
106
+ ): bigint {
107
+ const startCovRatio = this.startCovRatio!;
108
+ const endCovRatio = this.endCovRatio!;
109
+ if (finalCovRatio > endCovRatio) {
110
+ // invalid swap
111
+ throw new Error('WOMBAT_COV_RATIO_LIMIT_EXCEEDED');
112
+ } else if (
113
+ finalCovRatio <= startCovRatio ||
114
+ finalCovRatio <= initCovRatio
115
+ ) {
116
+ return 0n;
117
+ }
118
+
119
+ // 1. Calculate the area of fee(r) = (r - startCovRatio) / (endCovRatio - startCovRatio)
120
+ // when r increase from initCovRatio to finalCovRatio
121
+ // 2. Then multiply it by (endCovRatio - startCovRatio) / (finalCovRatio - initCovRatio)
122
+ // to get the average fee over the range
123
+ const a =
124
+ initCovRatio <= startCovRatio
125
+ ? 0n
126
+ : (initCovRatio - startCovRatio) * (initCovRatio - startCovRatio);
127
+ const b = (finalCovRatio - startCovRatio) * (finalCovRatio - startCovRatio);
128
+ return wdiv(
129
+ (b - a) / (finalCovRatio - initCovRatio) / BigInt(2),
130
+ endCovRatio - startCovRatio,
131
+ );
132
+ }
133
+
134
+ private _quoteFrom(
135
+ fromAsset: AssetState,
136
+ toAsset: AssetState,
137
+ fromAmount: bigint,
138
+ ): { actualToAmount: bigint; haircut: bigint } {
139
+ if (fromAmount < 0n) {
140
+ fromAmount = wdiv(fromAmount, WAD - this.haircutRate);
141
+ }
142
+
143
+ let fromCash = fromAsset.cash;
144
+ const toCash = toAsset.cash;
145
+ let fromLiability = fromAsset.liability;
146
+ const toLiability = toAsset.liability;
147
+
148
+ const scaleFactor = this._quoteFactor(fromAsset, toAsset);
149
+ if (scaleFactor !== WAD) {
150
+ fromCash = (fromCash * scaleFactor) / WAD;
151
+ fromLiability = (fromLiability * scaleFactor) / WAD;
152
+ fromAmount = (fromAmount * scaleFactor) / WAD;
153
+ }
154
+
155
+ const idealToAmount = WombatQuoter.swapQuoteFunc(
156
+ fromCash,
157
+ toCash,
158
+ fromLiability,
159
+ toLiability,
160
+ fromAmount,
161
+ this.ampFactor,
162
+ );
163
+ if (
164
+ (fromAmount > 0n && toCash < idealToAmount) ||
165
+ (fromAmount < 0n && fromCash < -fromAmount)
166
+ ) {
167
+ throw new Error('WOMBAT_CASH_NOT_ENOUGH');
168
+ }
169
+
170
+ let actualToAmount, haircut;
171
+ if (fromAmount > 0) {
172
+ haircut = wmul(idealToAmount, this.haircutRate);
173
+ actualToAmount = idealToAmount - haircut;
174
+ } else {
175
+ actualToAmount = idealToAmount;
176
+ haircut = wmul(-fromAmount, this.haircutRate);
177
+ }
178
+
179
+ return { actualToAmount, haircut };
180
+ }
181
+
182
+ private _findUpperBound(
183
+ fromAsset: AssetState,
184
+ toAsset: AssetState,
185
+ toAmount: bigint,
186
+ ): bigint {
187
+ const decimals = BigInt(fromAsset.underlyingTokenDecimals);
188
+ const toWadFactor = toWad(1n, decimals);
189
+ // the search value uses the same number of digits as the token
190
+ let high = fromWad(
191
+ wmul(fromAsset.liability, this.endCovRatio!) - fromAsset.cash,
192
+ decimals,
193
+ );
194
+ let low = 1n;
195
+
196
+ // verify `high` is a valid upper bound
197
+ const { actualToAmount: quote } = this._highCovRatioPoolQuoteFrom(
198
+ fromAsset,
199
+ toAsset,
200
+ high * toWadFactor,
201
+ );
202
+ if (quote < toAmount) {
203
+ throw new Error('WOMBAT_COV_RATIO_LIMIT_EXCEEDED');
204
+ }
205
+
206
+ // Note: we might limit the maximum number of rounds if the request is always rejected by the RPC server
207
+ while (low < high) {
208
+ const mid = (low + high) / BigInt(2);
209
+ const { actualToAmount: quote } = this._highCovRatioPoolQuoteFrom(
210
+ fromAsset,
211
+ toAsset,
212
+ mid * toWadFactor,
213
+ );
214
+ if (quote >= toAmount) {
215
+ high = mid;
216
+ } else {
217
+ low = mid + 1n;
218
+ }
219
+ }
220
+ return high * toWadFactor;
221
+ }
222
+
223
+ private _quoteFactor(fromAsset: AssetState, toAsset: AssetState): bigint {
224
+ if (!fromAsset.relativePrice || !toAsset.relativePrice) {
225
+ return WAD;
226
+ }
227
+ return (WAD * fromAsset.relativePrice) / toAsset.relativePrice;
228
+ }
229
+
230
+ static solveQuad(b: bigint, c: bigint): bigint {
231
+ return (sqrt(b * b + c * 4n * WAD, b) - b) / 2n;
232
+ }
233
+
234
+ static swapQuoteFunc(
235
+ aX: bigint,
236
+ aY: bigint,
237
+ lX: bigint,
238
+ lY: bigint,
239
+ dX: bigint,
240
+ a: bigint,
241
+ ): bigint {
242
+ if (lX == 0n || lY == 0n) {
243
+ // in case div of 0, CORE_UNDERFLOW
244
+ return 0n;
245
+ }
246
+
247
+ // int256 D = Ax + Ay - A.wmul((Lx * Lx) / Ax + (Ly * Ly) / Ay); // flattened _invariantFunc
248
+ const d = aX + aY - wmul(a, (lX * lX) / aX + (lY * lY) / aY);
249
+ // int256 rx_ = (Ax + Dx).wdiv(Lx);
250
+ const rX = wdiv(aX + dX, lX);
251
+ // int256 b = (Lx * (rx_ - A.wdiv(rx_))) / Ly - D.wdiv(Ly); // flattened _coefficientFunc
252
+ const b = (lX * (rX - wdiv(a, rX))) / lY - wdiv(d, lY);
253
+ // int256 ry_ = _solveQuad(b, A);
254
+ const rY = WombatQuoter.solveQuad(b, a);
255
+ // int256 Dy = Ly.wmul(ry_) - Ay;
256
+ const dY = wmul(lY, rY) - aY;
257
+
258
+ // if (Dy < 0) {
259
+ // quote = uint256(-Dy);
260
+ // } else {
261
+ // quote = uint256(Dy);
262
+ // }
263
+ if (dY < 0n) {
264
+ return -dY;
265
+ } else {
266
+ return dY;
267
+ }
268
+ }
269
+ }
@@ -0,0 +1,426 @@
1
+ import { AsyncOrSync, DeepReadonly } from 'ts-essentials';
2
+ import { Interface } from '@ethersproject/abi';
3
+ import { SwapSide } from '@paraswap/core';
4
+
5
+ import {
6
+ AdapterExchangeParam,
7
+ Address,
8
+ ExchangePrices,
9
+ Logger,
10
+ PoolLiquidity,
11
+ PoolPrices,
12
+ SimpleExchangeParam,
13
+ Token,
14
+ } from '../../types';
15
+ import { Network } from '../../constants';
16
+ import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
17
+ import { getBigIntPow, getDexKeysWithNetwork, isETHAddress } from '../../utils';
18
+ import { IDex } from '../idex';
19
+ import { IDexHelper } from '../../dex-helper';
20
+ import { DexParams, PoolState, WombatData } from './types';
21
+ import {
22
+ getLocalDeadlineAsFriendlyPlaceholder,
23
+ SimpleExchange,
24
+ } from '../simple-exchange';
25
+ import { Adapters, WombatConfig } from './config';
26
+ import PoolABI from '../../abi/wombat/pool.json';
27
+ import AssetABI from '../../abi/wombat/asset.json';
28
+ import ERC20ABI from '../../abi/erc20.json';
29
+ import { WombatQuoter } from './wombat-quoter';
30
+ import { WombatBmw } from './wombat-bmw';
31
+ import { fromWad } from './utils';
32
+ import { WombatPool } from './wombat-pool';
33
+
34
+ export class Wombat extends SimpleExchange implements IDex<WombatData> {
35
+ // export class Wombat implements IDex<WombatData> {
36
+ // contract interfaces
37
+ static readonly erc20Interface = new Interface(ERC20ABI);
38
+ static readonly poolInterface = new Interface(PoolABI);
39
+ static readonly assetInterface = new Interface(AssetABI);
40
+
41
+ protected config: DexParams;
42
+ protected poolLiquidityUSD?: { [poolAddress: string]: number };
43
+ public bmw: WombatBmw;
44
+ public pools: { [poolAddress: string]: WombatPool } = {};
45
+
46
+ readonly hasConstantPriceLargeAmounts = false;
47
+ readonly needWrapNative = true;
48
+
49
+ readonly isFeeOnTransferSupported = false;
50
+
51
+ public static dexKeysWithNetwork: {
52
+ key: string;
53
+ networks: Network[];
54
+ }[] = getDexKeysWithNetwork(WombatConfig);
55
+
56
+ logger: Logger;
57
+
58
+ constructor(
59
+ readonly network: Network,
60
+ readonly dexKey: string,
61
+ readonly dexHelper: IDexHelper,
62
+ protected adapters = Adapters[network] || {}, // TODO: add any additional optional params to support other fork DEXes
63
+ ) {
64
+ super(dexHelper, dexKey);
65
+ this.logger = dexHelper.getLogger(dexKey);
66
+ this.config = WombatConfig[dexKey][network];
67
+ this.bmw = new WombatBmw(
68
+ dexKey,
69
+ this.config.bmwAddress,
70
+ network,
71
+ dexHelper,
72
+ this.logger,
73
+ this.config.bmwAddress,
74
+ this.onAssetAdded.bind(this),
75
+ );
76
+ }
77
+
78
+ async init(blockNumber: number) {
79
+ if (!this.bmw.isInitialized) {
80
+ await this.bmw.initialize(blockNumber);
81
+ }
82
+ }
83
+
84
+ // Initialize pricing is called once in the start of
85
+ // pricing service. It is intended to setup the integration
86
+ // for pricing requests. It is optional for a DEX to
87
+ // implement this function
88
+ async initializePricing(blockNumber: number) {
89
+ await this.init(blockNumber);
90
+ const bmwState = this.bmw.getState(blockNumber);
91
+ if (!bmwState) {
92
+ throw new Error('initializePricing: bmwState still null after init');
93
+ }
94
+ }
95
+
96
+ onAssetAdded = async (
97
+ pool: Address,
98
+ asset2TokenMap: Map<Address, Address>,
99
+ blockNumber: number,
100
+ ): Promise<void> => {
101
+ if (!this.pools[pool]) {
102
+ this.pools[pool] = new WombatPool(
103
+ this.dexKey,
104
+ this.getPoolIdentifier(pool),
105
+ this.dexHelper,
106
+ pool,
107
+ asset2TokenMap,
108
+ );
109
+ await this.pools[pool].getState('latest', true);
110
+ } else {
111
+ this.pools[pool].addAssets(asset2TokenMap);
112
+ }
113
+ };
114
+
115
+ // Returns the list of contract adapters (name and index)
116
+ // for a buy/sell. Return null if there are no adapters.
117
+ getAdapters(side: SwapSide): { name: string; index: number }[] | null {
118
+ return this.adapters[side] ? this.adapters[side] : null;
119
+ }
120
+
121
+ // Returns list of pool identifiers that can be used
122
+ // for a given swap. poolIdentifiers must be unique
123
+ // across DEXes. It is recommended to use
124
+ // ${dexKey}_${poolAddress} as a poolIdentifier
125
+ async getPoolIdentifiers(
126
+ srcToken: Token,
127
+ destToken: Token,
128
+ side: SwapSide,
129
+ blockNumber: number,
130
+ ): Promise<string[]> {
131
+ await this.updatePoolState();
132
+ return (
133
+ await this.findPools(
134
+ this.dexHelper.config.wrapETH(srcToken).address.toLowerCase(),
135
+ this.dexHelper.config.wrapETH(destToken).address.toLowerCase(),
136
+ blockNumber,
137
+ )
138
+ ).map(p => this.getPoolIdentifier(p));
139
+ }
140
+
141
+ protected getPoolIdentifier(poolAddress: Address): string {
142
+ return `${this.dexKey}_${poolAddress}`;
143
+ }
144
+
145
+ // Returns pool prices for amounts.
146
+ // If limitPools is defined only pools in limitPools
147
+ // should be used. If limitPools is undefined then
148
+ // any pools can be used.
149
+ async getPricesVolume(
150
+ srcToken: Token,
151
+ destToken: Token,
152
+ amounts: bigint[],
153
+ side: SwapSide,
154
+ blockNumber: number,
155
+ limitPools?: string[],
156
+ ): Promise<null | ExchangePrices<WombatData>> {
157
+ if (!this.pools) {
158
+ this.logger.error(`Missing pools for ${this.dexKey} in getPricesVolume`);
159
+ return null;
160
+ }
161
+ const srcTokenAddress = this.dexHelper.config
162
+ .wrapETH(srcToken)
163
+ .address.toLowerCase();
164
+ const destTokenAddress = this.dexHelper.config
165
+ .wrapETH(destToken)
166
+ .address.toLowerCase();
167
+ if (srcTokenAddress === destTokenAddress) return null;
168
+
169
+ const pools = (
170
+ await this.findPools(srcTokenAddress, destTokenAddress, blockNumber)
171
+ ).filter(
172
+ poolAddress =>
173
+ !limitPools || limitPools.includes(this.getPoolIdentifier(poolAddress)),
174
+ );
175
+
176
+ const promises = [];
177
+ for (const poolAddress of pools) {
178
+ let state = await this.pools![poolAddress].getState(blockNumber);
179
+ if (!state) {
180
+ this.logger.warn(
181
+ `State of pool ${poolAddress} is null in getPricesVolume, skipping...`,
182
+ );
183
+ continue;
184
+ }
185
+ const [unit, ...prices] = this.computePrices(
186
+ srcTokenAddress,
187
+ destTokenAddress,
188
+ [getBigIntPow(srcToken.decimals), ...amounts],
189
+ side,
190
+ state.value,
191
+ );
192
+ promises.push({
193
+ prices,
194
+ unit,
195
+ data: {
196
+ exchange: poolAddress,
197
+ },
198
+ poolAddresses: [poolAddress],
199
+ exchange: this.dexKey,
200
+ /** @todo specify gas cost */
201
+ gasCost: 260 * 1000,
202
+ poolIdentifier: this.getPoolIdentifier(poolAddress),
203
+ });
204
+ }
205
+
206
+ return await Promise.all(promises);
207
+ }
208
+
209
+ // take PoolState to compute price
210
+ protected computePrices(
211
+ srcTokenAddress: Address,
212
+ destTokenAddress: Address,
213
+ amounts: bigint[],
214
+ side: SwapSide,
215
+ state: DeepReadonly<PoolState>,
216
+ ): bigint[] {
217
+ const srcAsset = state.asset[srcTokenAddress];
218
+ const destAsset = state.asset[destTokenAddress];
219
+ const quoter = new WombatQuoter(state.params);
220
+
221
+ return amounts.map(fromAmount => {
222
+ return side === SwapSide.SELL
223
+ ? quoter.getQuote(srcAsset, destAsset, fromAmount)
224
+ : quoter.getQuote(destAsset, srcAsset, -fromAmount);
225
+ });
226
+ }
227
+
228
+ protected async findPools(
229
+ srcTokenAddress: Address,
230
+ destTokenAddress: Address,
231
+ blockNumber: number,
232
+ ): Promise<Address[]> {
233
+ const pools: Address[] = [];
234
+ for (const [poolAddress, pool] of Object.entries(this.pools)) {
235
+ let stateOj = await pool.getState(blockNumber);
236
+ if (!stateOj) {
237
+ this.logger.warn(
238
+ `State of pool ${poolAddress} is null in findPools, skipping...`,
239
+ );
240
+ continue;
241
+ }
242
+
243
+ const state = stateOj.value;
244
+ if (
245
+ state &&
246
+ !state.params.paused &&
247
+ state.asset[srcTokenAddress] &&
248
+ state.asset[destTokenAddress]
249
+ ) {
250
+ pools.push(poolAddress);
251
+ }
252
+ }
253
+
254
+ return pools;
255
+ }
256
+
257
+ // Returns estimated gas cost of calldata for this DEX in multiSwap
258
+ getCalldataGasCost(poolPrices: PoolPrices<WombatData>): number | number[] {
259
+ // TODO: update if there is any payload in getAdapterParam
260
+ return CALLDATA_GAS_COST.DEX_NO_PAYLOAD;
261
+ }
262
+
263
+ getAdapterParam(
264
+ srcToken: string,
265
+ destToken: string,
266
+ srcAmount: string,
267
+ destAmount: string,
268
+ data: WombatData,
269
+ side: SwapSide,
270
+ ): AdapterExchangeParam {
271
+ const { exchange } = data;
272
+
273
+ return {
274
+ targetExchange: exchange,
275
+ payload: '0x',
276
+ networkFee: '0',
277
+ };
278
+ }
279
+
280
+ // Encode call data used by simpleSwap like routers
281
+ // Used for simpleSwap & simpleBuy
282
+ // Hint: this.buildSimpleParamWithoutWETHConversion
283
+ // could be useful
284
+ async getSimpleParam(
285
+ srcToken: string,
286
+ destToken: string,
287
+ srcAmount: string,
288
+ destAmount: string,
289
+ data: WombatData,
290
+ side: SwapSide,
291
+ ): Promise<SimpleExchangeParam> {
292
+ const { exchange } = data;
293
+
294
+ // Encode here the transaction arguments
295
+ const swapData = Wombat.poolInterface.encodeFunctionData('swap', [
296
+ srcToken,
297
+ destToken,
298
+ srcAmount,
299
+ destAmount,
300
+ this.augustusAddress,
301
+ getLocalDeadlineAsFriendlyPlaceholder(),
302
+ ]);
303
+
304
+ return this.buildSimpleParamWithoutWETHConversion(
305
+ srcToken,
306
+ srcAmount,
307
+ destToken,
308
+ destAmount,
309
+ swapData,
310
+ exchange,
311
+ );
312
+ }
313
+
314
+ // This is called once before getTopPoolsForToken is
315
+ // called for multiple tokens. This can be helpful to
316
+ // update common state required for calculating
317
+ // getTopPoolsForToken. For example, poolLiquidityUSD.
318
+ async updatePoolState(): Promise<void> {
319
+ const blockNumber = await this.dexHelper.provider.getBlockNumber();
320
+ await this.init(blockNumber);
321
+ const bmwState = this.bmw.getState(blockNumber);
322
+ if (!bmwState) {
323
+ throw new Error('updatePoolState: bmwState still null after init');
324
+ }
325
+
326
+ // All tokens are USD stablecoins so to estimate liquidity can just add
327
+ // the cash balances of all the tokens
328
+ const poolLiquidityUSD: { [poolAddress: string]: number } = {};
329
+ const usdPromises = [];
330
+ const poolStates: { [poolAddress: string]: DeepReadonly<PoolState> } = {};
331
+ const poolStateObjs = await Promise.all(
332
+ Object.values(this.pools).map(pool => pool.getState()),
333
+ );
334
+
335
+ for (const [poolAddress, pool] of Object.entries(this.pools)) {
336
+ const index = Object.keys(this.pools).indexOf(poolAddress);
337
+ let state = poolStateObjs[index];
338
+ if (!state) {
339
+ this.logger.warn(
340
+ `State of ${poolAddress} is null in updatePoolState, skipping...`,
341
+ );
342
+ continue;
343
+ }
344
+ poolStates[poolAddress] = state.value;
345
+ for (const [tokenAddress, assetState] of Object.entries(
346
+ state.value.asset,
347
+ )) {
348
+ usdPromises.push(
349
+ this.dexHelper.getTokenUSDPrice(
350
+ {
351
+ address: tokenAddress,
352
+ decimals: assetState.underlyingTokenDecimals,
353
+ },
354
+ fromWad(
355
+ assetState.cash,
356
+ BigInt(assetState.underlyingTokenDecimals),
357
+ ),
358
+ ),
359
+ );
360
+ }
361
+ }
362
+ const usdValues = await Promise.all(usdPromises);
363
+
364
+ for (const [poolAddress, poolState] of Object.entries(poolStates)) {
365
+ poolLiquidityUSD[poolAddress] = 0;
366
+ for (let i = 0; i < poolState.underlyingAddresses.length; i++) {
367
+ poolLiquidityUSD[poolAddress] += usdValues[i];
368
+ }
369
+ }
370
+
371
+ this.poolLiquidityUSD = poolLiquidityUSD;
372
+ }
373
+
374
+ // Returns list of top pools based on liquidity. Max
375
+ // limit number pools should be returned.
376
+ async getTopPoolsForToken(
377
+ tokenAddress: Address,
378
+ limit: number,
379
+ ): Promise<PoolLiquidity[]> {
380
+ if (!this.poolLiquidityUSD) await this.updatePoolState();
381
+ tokenAddress = (
382
+ isETHAddress(tokenAddress)
383
+ ? this.dexHelper.config.data.wrappedNativeTokenAddress
384
+ : tokenAddress
385
+ ).toLowerCase();
386
+ const pools: string[] = [];
387
+ const poolStates: { [poolAddress: string]: DeepReadonly<PoolState> } = {};
388
+ for (const [poolAddress, eventPool] of Object.entries(this.pools)) {
389
+ let state = await eventPool.getState();
390
+ if (!state) {
391
+ this.logger.warn(
392
+ `State of ${poolAddress} is null in getTopPoolsForToken, skipping...`,
393
+ );
394
+ continue;
395
+ }
396
+ if (
397
+ state.value.underlyingAddresses.includes(tokenAddress) &&
398
+ this.poolLiquidityUSD![poolAddress]
399
+ ) {
400
+ poolStates[poolAddress] = state.value;
401
+ pools.push(poolAddress);
402
+ }
403
+ }
404
+
405
+ // sort by liquidity
406
+ pools.sort((a, b) => this.poolLiquidityUSD![b] - this.poolLiquidityUSD![a]);
407
+ return pools.slice(0, limit).map(poolAddress => ({
408
+ exchange: this.dexKey,
409
+ address: poolAddress,
410
+ // other tokens in the same pool
411
+ connectorTokens: poolStates[poolAddress].underlyingAddresses
412
+ .filter(t => t !== tokenAddress)
413
+ .map(t => ({
414
+ decimals: poolStates[poolAddress].asset[t].underlyingTokenDecimals,
415
+ address: t,
416
+ })),
417
+ liquidityUSD: this.poolLiquidityUSD![poolAddress],
418
+ }));
419
+ }
420
+
421
+ // This is optional function in case if your implementation has acquired any resources
422
+ // you need to release for graceful shutdown. For example, it may be any interval timer
423
+ releaseResources(): AsyncOrSync<void> {
424
+ // TODO: complete me!
425
+ }
426
+ }