@paraswap/dex-lib 2.42.28 → 2.42.29-wombat.3

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 (172) hide show
  1. package/build/abi/smardex/smardex-factory.json +185 -0
  2. package/build/abi/smardex/smardex-pool.json +578 -0
  3. package/build/abi/smardex/smardex-router.json +648 -0
  4. package/build/abi/{algebra/AlgebraPool.abi.json → solidly-v3/SolidlyV3Pool.abi.json} +293 -282
  5. package/build/abi/solidly-v3/SolidlyV3StateMulticall.abi.json +375 -0
  6. package/build/abi/trader-joe-v2_1/FactoryABI.json +0 -0
  7. package/build/abi/trader-joe-v2_1/PairABI.json +1493 -0
  8. package/build/abi/trader-joe-v2_1/RouterABI.json +1489 -0
  9. package/build/abi/wombat/pool-v2.json +1289 -0
  10. package/build/abi/wombat/pool-v3.json +2013 -0
  11. package/build/config.js +2 -2
  12. package/build/dex/index.js +4 -2
  13. package/build/dex/index.js.map +1 -1
  14. package/build/dex/smardex/subgraph-queries.d.ts +1 -0
  15. package/build/dex/smardex/subgraph-queries.js +17 -0
  16. package/build/dex/smardex/subgraph-queries.js.map +1 -0
  17. package/build/dex/smardex/usd-reserves.d.ts +23 -0
  18. package/build/dex/smardex/usd-reserves.js +86 -0
  19. package/build/dex/smardex/usd-reserves.js.map +1 -0
  20. package/build/dex/solidly-v3/config.d.ts +9 -0
  21. package/build/dex/solidly-v3/config.js +58 -0
  22. package/build/dex/solidly-v3/config.js.map +1 -0
  23. package/build/dex/solidly-v3/constants.d.ts +27 -0
  24. package/build/dex/solidly-v3/constants.js +34 -0
  25. package/build/dex/solidly-v3/constants.js.map +1 -0
  26. package/build/dex/solidly-v3/contract-math/BitMath.d.ts +4 -0
  27. package/build/dex/solidly-v3/contract-math/BitMath.js +93 -0
  28. package/build/dex/solidly-v3/contract-math/BitMath.js.map +1 -0
  29. package/build/dex/solidly-v3/contract-math/FixedPoint128.d.ts +3 -0
  30. package/build/dex/solidly-v3/contract-math/FixedPoint128.js +8 -0
  31. package/build/dex/solidly-v3/contract-math/FixedPoint128.js.map +1 -0
  32. package/build/dex/solidly-v3/contract-math/FixedPoint96.d.ts +4 -0
  33. package/build/dex/solidly-v3/contract-math/FixedPoint96.js +9 -0
  34. package/build/dex/solidly-v3/contract-math/FixedPoint96.js.map +1 -0
  35. package/build/dex/solidly-v3/contract-math/FullMath.d.ts +4 -0
  36. package/build/dex/solidly-v3/contract-math/FullMath.js +19 -0
  37. package/build/dex/solidly-v3/contract-math/FullMath.js.map +1 -0
  38. package/build/dex/solidly-v3/contract-math/LiquidityMath.d.ts +3 -0
  39. package/build/dex/solidly-v3/contract-math/LiquidityMath.js +22 -0
  40. package/build/dex/solidly-v3/contract-math/LiquidityMath.js.map +1 -0
  41. package/build/dex/solidly-v3/contract-math/SqrtPriceMath.d.ts +10 -0
  42. package/build/dex/solidly-v3/contract-math/SqrtPriceMath.js +91 -0
  43. package/build/dex/solidly-v3/contract-math/SqrtPriceMath.js.map +1 -0
  44. package/build/dex/solidly-v3/contract-math/SwapMath.d.ts +8 -0
  45. package/build/dex/solidly-v3/contract-math/SwapMath.js +70 -0
  46. package/build/dex/solidly-v3/contract-math/SwapMath.js.map +1 -0
  47. package/build/dex/solidly-v3/contract-math/Tick.d.ts +7 -0
  48. package/build/dex/solidly-v3/contract-math/Tick.js +36 -0
  49. package/build/dex/solidly-v3/contract-math/Tick.js.map +1 -0
  50. package/build/dex/solidly-v3/contract-math/TickBitMap.d.ts +7 -0
  51. package/build/dex/solidly-v3/contract-math/TickBitMap.js +84 -0
  52. package/build/dex/solidly-v3/contract-math/TickBitMap.js.map +1 -0
  53. package/build/dex/solidly-v3/contract-math/TickMath.d.ts +8 -0
  54. package/build/dex/solidly-v3/contract-math/TickMath.js +162 -0
  55. package/build/dex/solidly-v3/contract-math/TickMath.js.map +1 -0
  56. package/build/dex/solidly-v3/contract-math/UnsafeMath.d.ts +3 -0
  57. package/build/dex/solidly-v3/contract-math/UnsafeMath.js +10 -0
  58. package/build/dex/solidly-v3/contract-math/UnsafeMath.js.map +1 -0
  59. package/build/dex/solidly-v3/contract-math/uniswap-v3-math.d.ts +31 -0
  60. package/build/dex/solidly-v3/contract-math/uniswap-v3-math.js +363 -0
  61. package/build/dex/solidly-v3/contract-math/uniswap-v3-math.js.map +1 -0
  62. package/build/dex/solidly-v3/contract-math/utils.d.ts +7 -0
  63. package/build/dex/solidly-v3/contract-math/utils.js +39 -0
  64. package/build/dex/solidly-v3/contract-math/utils.js.map +1 -0
  65. package/build/dex/solidly-v3/solidly-v3-factory.d.ts +26 -0
  66. package/build/dex/solidly-v3/solidly-v3-factory.js +44 -0
  67. package/build/dex/solidly-v3/solidly-v3-factory.js.map +1 -0
  68. package/build/dex/{algebra/algebra-pool.d.ts → solidly-v3/solidly-v3-pool.d.ts} +14 -16
  69. package/build/dex/{algebra/algebra-pool.js → solidly-v3/solidly-v3-pool.js} +127 -165
  70. package/build/dex/solidly-v3/solidly-v3-pool.js.map +1 -0
  71. package/build/dex/solidly-v3/solidly-v3.d.ts +67 -0
  72. package/build/dex/solidly-v3/solidly-v3.js +590 -0
  73. package/build/dex/solidly-v3/solidly-v3.js.map +1 -0
  74. package/build/dex/solidly-v3/types.d.ts +132 -0
  75. package/build/dex/solidly-v3/types.js +9 -0
  76. package/build/dex/solidly-v3/types.js.map +1 -0
  77. package/build/dex/solidly-v3/utils.d.ts +6 -0
  78. package/build/dex/solidly-v3/utils.js +53 -0
  79. package/build/dex/solidly-v3/utils.js.map +1 -0
  80. package/build/dex/trader-joe-v2-1-2/config.d.ts +4 -0
  81. package/build/dex/trader-joe-v2-1-2/config.js +43 -0
  82. package/build/dex/trader-joe-v2-1-2/config.js.map +1 -0
  83. package/build/dex/trader-joe-v2-1-2/constants.d.ts +17 -0
  84. package/build/dex/trader-joe-v2-1-2/constants.js +19 -0
  85. package/build/dex/trader-joe-v2-1-2/constants.js.map +1 -0
  86. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2-pool.d.ts +60 -0
  87. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2-pool.js +199 -0
  88. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2-pool.js.map +1 -0
  89. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2.d.ts +49 -0
  90. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2.js +269 -0
  91. package/build/dex/trader-joe-v2-1-2/trader-joe-v2-1-2.js.map +1 -0
  92. package/build/dex/trader-joe-v2-1-2/types.d.ts +81 -0
  93. package/build/dex/trader-joe-v2-1-2/types.js +9 -0
  94. package/build/dex/trader-joe-v2-1-2/types.js.map +1 -0
  95. package/build/dex/trader-joe-v2_1/config.d.ts +4 -0
  96. package/build/dex/trader-joe-v2_1/config.js +43 -0
  97. package/build/dex/trader-joe-v2_1/config.js.map +1 -0
  98. package/build/dex/trader-joe-v2_1/constants.d.ts +16 -0
  99. package/build/dex/trader-joe-v2_1/constants.js +18 -0
  100. package/build/dex/trader-joe-v2_1/constants.js.map +1 -0
  101. package/build/dex/trader-joe-v2_1/trader-joe-v2.1.d.ts +0 -0
  102. package/build/dex/trader-joe-v2_1/trader-joe-v2.1.js +384 -0
  103. package/build/dex/trader-joe-v2_1/trader-joe-v2.1.js.map +1 -0
  104. package/build/dex/trader-joe-v2_1/types.d.ts +39 -0
  105. package/build/dex/trader-joe-v2_1/types.js +3 -0
  106. package/build/dex/trader-joe-v2_1/types.js.map +1 -0
  107. package/build/dex/uniswap-v2/uniswap-v2-factory.d.ts +25 -0
  108. package/build/dex/uniswap-v2/uniswap-v2-factory.js +43 -0
  109. package/build/dex/uniswap-v2/uniswap-v2-factory.js.map +1 -0
  110. package/build/dex/wombat/utils.d.ts +1 -0
  111. package/build/dex/wombat/utils.js +14 -1
  112. package/build/dex/wombat/utils.js.map +1 -1
  113. package/build/dex/wombat/wombat-bmw.d.ts +2 -2
  114. package/build/dex/wombat/wombat-bmw.js +8 -25
  115. package/build/dex/wombat/wombat-bmw.js.map +1 -1
  116. package/build/dex/wombat/wombat-pool-poller.d.ts +22 -0
  117. package/build/dex/wombat/wombat-pool-poller.js +164 -0
  118. package/build/dex/wombat/wombat-pool-poller.js.map +1 -0
  119. package/build/dex/wombat/wombat-pool.d.ts +51 -17
  120. package/build/dex/wombat/wombat-pool.js +398 -112
  121. package/build/dex/wombat/wombat-pool.js.map +1 -1
  122. package/build/dex/wombat/wombat.d.ts +1 -1
  123. package/build/dex/wombat/wombat.js +12 -18
  124. package/build/dex/wombat/wombat.js.map +1 -1
  125. package/package.json +1 -1
  126. package/src/abi/solidly-v3/SolidlyV3Pool.abi.json +738 -0
  127. package/src/abi/solidly-v3/SolidlyV3StateMulticall.abi.json +375 -0
  128. package/src/abi/wombat/pool-v3.json +2013 -0
  129. package/src/config.ts +2 -2
  130. package/src/dex/index.ts +4 -2
  131. package/src/dex/solidly-v3/config.ts +64 -0
  132. package/src/dex/solidly-v3/constants.ts +42 -0
  133. package/src/dex/solidly-v3/contract-math/BitMath.ts +90 -0
  134. package/src/dex/solidly-v3/contract-math/FixedPoint128.ts +3 -0
  135. package/src/dex/solidly-v3/contract-math/FixedPoint96.ts +4 -0
  136. package/src/dex/solidly-v3/contract-math/FullMath.ts +30 -0
  137. package/src/dex/solidly-v3/contract-math/LiquidityMath.ts +17 -0
  138. package/src/dex/solidly-v3/contract-math/SqrtPriceMath.ts +226 -0
  139. package/src/dex/solidly-v3/contract-math/SwapMath.ts +139 -0
  140. package/src/dex/solidly-v3/contract-math/Tick.ts +66 -0
  141. package/src/dex/solidly-v3/contract-math/TickBitMap.ts +123 -0
  142. package/src/dex/solidly-v3/contract-math/TickMath.ts +211 -0
  143. package/src/dex/solidly-v3/contract-math/UnsafeMath.ts +5 -0
  144. package/src/dex/solidly-v3/contract-math/uniswap-v3-math.ts +570 -0
  145. package/src/dex/solidly-v3/contract-math/utils.ts +50 -0
  146. package/src/dex/solidly-v3/solidly-v3-e2e.test.ts +124 -0
  147. package/src/dex/solidly-v3/solidly-v3-events.test.ts +144 -0
  148. package/src/dex/solidly-v3/solidly-v3-factory.ts +73 -0
  149. package/src/dex/solidly-v3/solidly-v3-integration.test.ts +358 -0
  150. package/src/dex/solidly-v3/solidly-v3-pool.ts +494 -0
  151. package/src/dex/solidly-v3/solidly-v3.ts +988 -0
  152. package/src/dex/solidly-v3/types.ts +158 -0
  153. package/src/dex/solidly-v3/utils.ts +71 -0
  154. package/src/dex/uniswap-v3/uniswap-v3-events.test.ts +3 -0
  155. package/src/dex/wombat/utils.ts +20 -0
  156. package/src/dex/wombat/wombat-bmw.ts +8 -31
  157. package/src/dex/wombat/wombat-e2e.test.ts +13 -1
  158. package/src/dex/wombat/wombat-events.test.ts +147 -0
  159. package/src/dex/wombat/wombat-integration.test.ts +70 -111
  160. package/src/dex/wombat/wombat-pool.ts +628 -171
  161. package/src/dex/wombat/wombat.ts +13 -23
  162. package/tests/constants-e2e.ts +11 -1
  163. package/build/abi/uniswap-v3/UniswapV3Quoter.abi.json +0 -193
  164. package/build/dex/algebra/algebra-pool.js.map +0 -1
  165. package/build/dex/quickswap/camelot-v3.d.ts +0 -6
  166. package/build/dex/quickswap/camelot-v3.js +0 -19
  167. package/build/dex/quickswap/camelot-v3.js.map +0 -1
  168. package/build/dex/quickswap/zyberswap-v3.d.ts +0 -6
  169. package/build/dex/quickswap/zyberswap-v3.js +0 -19
  170. package/build/dex/quickswap/zyberswap-v3.js.map +0 -1
  171. package/build/dex/uniswap-v2/rebase-tokens.json +0 -7
  172. /package/src/abi/wombat/{pool.json → pool-v2.json} +0 -0
@@ -1,152 +1,266 @@
1
1
  import { Interface } from '@ethersproject/abi';
2
- import { Address } from '@paraswap/core';
3
- import _ from 'lodash';
4
-
5
- import { MultiCallParams, MultiResult } from '../../lib/multi-wrapper';
6
- import { IDexHelper } from '../../dex-helper';
7
- import { StatefulRpcPoller } from '../../lib/stateful-rpc-poller/stateful-rpc-poller';
8
- import { StatePollingManager } from '../../lib/stateful-rpc-poller/state-polling-manager';
9
- import { ObjWithUpdateInfo } from '../../lib/stateful-rpc-poller/types';
10
- import { pollingManagerCbExtractor } from '../../lib/stateful-rpc-poller/utils';
2
+ import { AsyncOrSync, DeepReadonly } from 'ts-essentials';
3
+ import {
4
+ Address,
5
+ Log,
6
+ Logger,
7
+ MultiCallInput,
8
+ MultiCallOutput,
9
+ } from '../../types';
10
+ import { catchParseLogError } from '../../utils';
11
11
  import {
12
- addressArrayDecode,
13
- booleanDecode,
14
- uint256ToBigInt,
15
- uint8ToNumber,
16
- } from '../../lib/decoders';
17
- import PoolABI from '../../abi/wombat/pool.json';
12
+ InitializeStateOptions,
13
+ StatefulEventSubscriber,
14
+ } from '../../stateful-event-subscriber';
15
+ import { IDexHelper } from '../../dex-helper';
16
+ import PoolV2ABI from '../../abi/wombat/pool-v2.json';
17
+ import PoolV3ABI from '../../abi/wombat/pool-v3.json';
18
18
  import AssetABI from '../../abi/wombat/asset.json';
19
- import { uint120ToBigInt } from './utils';
20
- import { AssetState, MulticallResultOutputs, PoolState } from './types';
21
-
22
- export class WombatPool extends StatefulRpcPoller<
23
- PoolState,
24
- MulticallResultOutputs
25
- > {
26
- static readonly poolInterface = new Interface(PoolABI);
19
+ import { convertUint256ToInt256, toWad, WAD, wdiv, wmul } from './utils';
20
+ import { BlockHeader } from 'web3-eth';
21
+ import { AssetState, PoolState } from './types';
22
+
23
+ const CLEAR_RPC_CALL_COUNT_INTERVAL = 1000 * 60 * 5; // 5 minutes
24
+
25
+ export class WombatPool extends StatefulEventSubscriber<PoolState> {
26
+ static readonly poolV2Interface = new Interface(PoolV2ABI);
27
+ static readonly poolV3Interface = new Interface(PoolV3ABI);
27
28
  static readonly assetInterface = new Interface(AssetABI);
28
29
 
30
+ private rpcCallCount = 0;
31
+
32
+ private handlers: {
33
+ [event: string]: (
34
+ event: any,
35
+ state: DeepReadonly<PoolState>,
36
+ log: Readonly<Log>,
37
+ ) => AsyncOrSync<DeepReadonly<PoolState> | null>;
38
+ } = {};
39
+ private poolInterface: Interface = WombatPool.poolV2Interface;
40
+ private eventRefetched: string[];
41
+
42
+ blankState: PoolState = {
43
+ asset: {},
44
+ underlyingAddresses: [],
45
+ params: {
46
+ paused: false,
47
+ ampFactor: 0n,
48
+ haircutRate: 0n,
49
+ startCovRatio: 0n,
50
+ endCovRatio: 0n,
51
+ },
52
+ };
53
+
29
54
  constructor(
30
55
  dexKey: string,
31
- poolIdentifier: string,
32
- dexHelper: IDexHelper,
56
+ name: string,
57
+ protected network: number,
58
+ protected dexHelper: IDexHelper,
59
+ logger: Logger,
33
60
  protected poolAddress: Address,
34
- protected asset2TokenMap: Map<Address, Address>,
35
61
  ) {
36
- const callbacks = pollingManagerCbExtractor(
37
- StatePollingManager.getInstance(dexHelper),
62
+ super(
63
+ `${dexKey}_${name}`,
64
+ `${dexKey}_${network}_${name}`,
65
+ dexHelper,
66
+ logger,
38
67
  );
39
68
 
40
- super(dexKey, poolIdentifier, dexHelper, 0, 0, false, callbacks);
69
+ this.addressesSubscribed = [this.poolAddress];
70
+
71
+ // users-actions handlers
72
+ this.handlers['Swap'] = this.handleSwap.bind(this);
73
+ this.handlers['SwapV2'] = this.handleSwapV2.bind(this);
74
+
75
+ // admin-actions handlers
76
+ this.handlers['SetAmpFactor'] = this.handleSetAmpFactor.bind(this);
77
+ this.handlers['SetHaircutRate'] = this.handleSetHaircutRate.bind(this);
78
+ this.handlers['AssetAdded'] = this.handleAssetAdded.bind(this);
79
+ this.handlers['AssetRemoved'] = this.handleAssetRemoved.bind(this);
80
+ this.handlers['FillPool'] = this.handleFillPool.bind(this);
81
+ this.handlers['Paused'] = this.handlePaused.bind(this);
82
+ this.handlers['Unpaused'] = this.handleUnpaused.bind(this);
83
+ this.handlers['PausedAsset'] = this.handlePausedAsset.bind(this);
84
+ this.handlers['UnpausedAsset'] = this.handleUnpausedAsset.bind(this);
85
+
86
+ this.eventRefetched = ['Deposit', 'Withdraw'];
87
+
88
+ setInterval(() => {
89
+ this.rpcCallCount = 0;
90
+ }, CLEAR_RPC_CALL_COUNT_INTERVAL);
91
+ }
92
+
93
+ async initialize(
94
+ blockNumber: number,
95
+ options?: InitializeStateOptions<PoolState>,
96
+ ) {
97
+ const poolContract = new this.dexHelper.web3Provider.eth.Contract(
98
+ PoolV3ABI as any,
99
+ this.poolAddress,
100
+ );
101
+ try {
102
+ await poolContract.methods.withdrawalHaircutRate().call({}, blockNumber);
103
+ this.poolInterface = WombatPool.poolV3Interface;
104
+ } catch (e) {
105
+ this.logger.info(
106
+ `no public variable withdrawalHaircutRate in pool ${this.poolAddress}, this is v2 pool`,
107
+ );
108
+ }
109
+ await super.initialize(blockNumber, options);
110
+ }
111
+
112
+ protected async processBlockLogs(
113
+ state: DeepReadonly<PoolState>,
114
+ logs: Readonly<Log>[],
115
+ blockHeader: Readonly<BlockHeader>,
116
+ ): Promise<DeepReadonly<PoolState> | null> {
117
+ let nextState: DeepReadonly<PoolState> | null = null;
118
+ for (const log of logs) {
119
+ try {
120
+ const event = this.poolInterface.parseLog(log);
121
+ if (this.eventRefetched.includes(event.name)) {
122
+ // if the state is refetched, no need to deal with the left logs in the block
123
+ return await this.generateState(log.blockNumber);
124
+ }
125
+ } catch (e) {
126
+ catchParseLogError(e, this.logger);
127
+ }
128
+
129
+ const retState: DeepReadonly<PoolState> | null = await this.processLog(
130
+ nextState || state,
131
+ log,
132
+ blockHeader,
133
+ );
134
+
135
+ if (retState) {
136
+ nextState = retState;
137
+ }
138
+ }
139
+ return nextState;
41
140
  }
42
141
 
43
- protected _getFetchStateMultiCalls(): MultiCallParams<MulticallResultOutputs>[] {
44
- const params: MultiCallParams<MulticallResultOutputs>[] = [];
142
+ /**
143
+ * The function is called every time any of the subscribed
144
+ * addresses release log. The function accepts the current
145
+ * state, updates the state according to the log, and returns
146
+ * the updated state.
147
+ * @param state - Current state of event subscriber
148
+ * @param log - Log released by one of the subscribed addresses
149
+ * @param blockHeader
150
+ * @returns Updates state of the event subscriber after the log
151
+ */
152
+ protected async processLog(
153
+ state: DeepReadonly<PoolState>,
154
+ log: Readonly<Log>,
155
+ blockHeader: Readonly<BlockHeader>,
156
+ ): Promise<DeepReadonly<PoolState> | null> {
157
+ try {
158
+ const event = this.poolInterface.parseLog(log);
159
+ if (event.name in this.handlers) {
160
+ return await this.handlers[event.name](event, state, log);
161
+ }
162
+ } catch (e) {
163
+ catchParseLogError(e, this.logger);
164
+ }
45
165
 
46
- params.push({
166
+ return null;
167
+ }
168
+
169
+ /**
170
+ * The function generates state using on-chain calls. This
171
+ * function is called to regenerate state if the event based
172
+ * system fails to fetch events and the local state is no
173
+ * more correct.
174
+ * @param blockNumber - Blocknumber for which the state should
175
+ * should be generated
176
+ * @returns state of the event subscriber at blocknumber
177
+ */
178
+ async generateState(blockNumber: number): Promise<DeepReadonly<PoolState>> {
179
+ this.rpcCallCount++;
180
+
181
+ if (this.rpcCallCount > 1) {
182
+ this.logger.warn(
183
+ `WombatPool generateState excessive RPC call. Name: ${
184
+ this.name
185
+ }; pool: ${this.poolAddress}. Called ${
186
+ this.rpcCallCount + 1
187
+ } times during ${CLEAR_RPC_CALL_COUNT_INTERVAL / 1000} s interval`,
188
+ );
189
+ }
190
+ let multiCallInputs: MultiCallInput[] = [];
191
+
192
+ // 1.A generate pool params requests
193
+ // paused
194
+ multiCallInputs.push({
47
195
  target: this.poolAddress,
48
- callData: WombatPool.poolInterface.encodeFunctionData('paused'),
49
- decodeFunction: booleanDecode,
196
+ callData: this.poolInterface.encodeFunctionData('paused'),
50
197
  });
51
- params.push({
198
+ // ampFactor
199
+ multiCallInputs.push({
52
200
  target: this.poolAddress,
53
- callData: WombatPool.poolInterface.encodeFunctionData('ampFactor'),
54
- decodeFunction: uint256ToBigInt,
201
+ callData: this.poolInterface.encodeFunctionData('ampFactor'),
55
202
  });
56
- params.push({
203
+ // haircutRate
204
+ multiCallInputs.push({
57
205
  target: this.poolAddress,
58
- callData: WombatPool.poolInterface.encodeFunctionData('haircutRate'),
59
- decodeFunction: uint256ToBigInt,
206
+ callData: this.poolInterface.encodeFunctionData('haircutRate'),
60
207
  });
61
- params.push({
208
+ // startCovRatio
209
+ multiCallInputs.push({
62
210
  target: this.poolAddress,
63
- callData: WombatPool.poolInterface.encodeFunctionData('startCovRatio'),
64
- decodeFunction: uint256ToBigInt,
211
+ callData: this.poolInterface.encodeFunctionData('startCovRatio'),
65
212
  });
66
- params.push({
213
+ // endCovRatio
214
+ multiCallInputs.push({
67
215
  target: this.poolAddress,
68
- callData: WombatPool.poolInterface.encodeFunctionData('endCovRatio'),
69
- decodeFunction: uint256ToBigInt,
216
+ callData: this.poolInterface.encodeFunctionData('endCovRatio'),
70
217
  });
71
- params.push({
218
+ // tokens
219
+ multiCallInputs.push({
72
220
  target: this.poolAddress,
73
- callData: WombatPool.poolInterface.encodeFunctionData('getTokens'),
74
- decodeFunction: addressArrayDecode,
221
+ callData: this.poolInterface.encodeFunctionData('getTokens'),
75
222
  });
76
223
 
77
- this.asset2TokenMap.forEach((token, asset) => {
78
- params.push({
79
- target: this.poolAddress,
80
- callData: WombatPool.poolInterface.encodeFunctionData('isPaused', [
81
- token,
82
- ]),
83
- decodeFunction: booleanDecode,
84
- });
85
- params.push({
86
- target: asset,
87
- callData: WombatPool.assetInterface.encodeFunctionData('cash'),
88
- decodeFunction: uint120ToBigInt,
89
- });
90
- params.push({
91
- target: asset,
92
- callData: WombatPool.assetInterface.encodeFunctionData('liability'),
93
- decodeFunction: uint120ToBigInt,
94
- });
95
- params.push({
96
- target: asset,
97
- callData: WombatPool.assetInterface.encodeFunctionData(
98
- 'underlyingTokenDecimals',
99
- ),
100
- decodeFunction: uint8ToNumber,
101
- });
102
- params.push({
103
- target: asset,
104
- callData:
105
- WombatPool.assetInterface.encodeFunctionData('getRelativePrice'),
106
- decodeFunction: uint256ToBigInt,
107
- });
108
- });
109
-
110
- return params;
111
- }
224
+ // 1.B. invoke multicall
225
+ let returnData: MultiCallOutput[] = [];
226
+ if (multiCallInputs.length) {
227
+ returnData = (
228
+ await this.dexHelper.multiContract.methods
229
+ .aggregate(multiCallInputs)
230
+ .call({}, blockNumber)
231
+ ).returnData;
232
+ }
112
233
 
113
- protected _parseStateFromMultiResults(
114
- multiOutputs: MulticallResultOutputs[],
115
- ): PoolState {
116
- const [
117
- paused,
118
- ampFactor,
119
- haircutRate,
120
- startCovRatio,
121
- endCovRatio,
122
- tokens,
123
- ...remained
124
- ] = multiOutputs as [
125
- boolean,
126
- bigint,
127
- bigint,
128
- bigint,
129
- bigint,
130
- Address[],
131
- ...MulticallResultOutputs[],
132
- ];
234
+ let i = 0;
235
+ // 1.C. decode pool params
236
+ const paused = Boolean(
237
+ this.poolInterface.decodeFunctionResult('paused', returnData[i++])[0],
238
+ );
239
+ const ampFactor = BigInt(
240
+ this.poolInterface.decodeFunctionResult('ampFactor', returnData[i++])[0],
241
+ );
242
+ const haircutRate = BigInt(
243
+ this.poolInterface.decodeFunctionResult(
244
+ 'haircutRate',
245
+ returnData[i++],
246
+ )[0],
247
+ );
248
+ const startCovRatio = BigInt(
249
+ this.poolInterface.decodeFunctionResult(
250
+ 'startCovRatio',
251
+ returnData[i++],
252
+ )[0],
253
+ );
254
+ const endCovRatio = BigInt(
255
+ this.poolInterface.decodeFunctionResult(
256
+ 'endCovRatio',
257
+ returnData[i++],
258
+ )[0],
259
+ );
133
260
 
134
- const assetTokenArray = Array.from(this.asset2TokenMap.entries());
135
- const token2AssetStates = new Map<Address, AssetState>();
136
- _.chunk(remained, 5).forEach((chunk, i) => {
137
- const [paused, cash, liability, underlyingTokenDecimals, relativePrice] =
138
- chunk as [boolean, bigint, bigint, number, bigint | undefined];
139
-
140
- const [asset, token] = assetTokenArray[i];
141
- token2AssetStates.set(token, {
142
- address: asset,
143
- paused,
144
- cash,
145
- liability,
146
- underlyingTokenDecimals,
147
- relativePrice,
148
- });
149
- });
261
+ const tokens = this.poolInterface
262
+ .decodeFunctionResult('getTokens', returnData[i++])[0]
263
+ .map((tokenAddress: Address) => tokenAddress.toLowerCase());
150
264
 
151
265
  const poolState: PoolState = {
152
266
  params: {
@@ -160,77 +274,420 @@ export class WombatPool extends StatefulRpcPoller<
160
274
  asset: {},
161
275
  };
162
276
 
277
+ // 2.A. generate requests for getting asset addresses
278
+ multiCallInputs = tokens.map((tokenAddress: Address) => ({
279
+ target: this.poolAddress,
280
+ callData: this.poolInterface.encodeFunctionData('addressOfAsset', [
281
+ tokenAddress,
282
+ ]),
283
+ }));
284
+
285
+ // 2.B. invoke multicall
286
+ returnData = (
287
+ await this.dexHelper.multiContract.methods
288
+ .aggregate(multiCallInputs)
289
+ .call({}, blockNumber)
290
+ ).returnData;
291
+
292
+ // 2.C. decode asset addresses
293
+ const assets: Address[] = returnData.map(data => {
294
+ return this.poolInterface.decodeFunctionResult('addressOfAsset', data)[0];
295
+ });
296
+
297
+ // 3. get asset states
298
+ const assetState = await this.getAssetState(
299
+ this.poolAddress,
300
+ assets.map(asset => asset.toLowerCase()),
301
+ tokens,
302
+ blockNumber,
303
+ );
163
304
  const isMainPool =
164
- Array.from(token2AssetStates.values()).filter(
165
- assetState => assetState.relativePrice === undefined,
166
- ).length > 0;
167
- for (const token of poolState.underlyingAddresses) {
168
- if (!token2AssetStates.has(token)) {
169
- // this happens when asset has been added to pool but is not added to BMW yet
170
- continue;
171
- }
172
- poolState.asset[token] = token2AssetStates.get(token)!;
305
+ assetState.filter(asset => asset.relativePrice === undefined).length > 0;
306
+ for (let j = 0; j < tokens.length; j++) {
173
307
  if (isMainPool) {
174
- poolState.asset[token].relativePrice = undefined;
308
+ assetState[j].relativePrice = undefined;
175
309
  }
310
+ poolState.asset[tokens[j]] = assetState[j];
176
311
  }
177
312
 
178
313
  return poolState;
179
314
  }
180
315
 
181
- public async fetchLatestStateFromRpc(): Promise<ObjWithUpdateInfo<PoolState> | null> {
182
- const multiCalls = this.getFetchStateWithBlockInfoMultiCalls();
183
- try {
184
- const lastUpdatedAtMs = Date.now();
185
- const aggregatedResults = (await this.dexHelper.multiWrapper.tryAggregate<
186
- number | MulticallResultOutputs
187
- >(
188
- false,
189
- multiCalls as MultiCallParams<MulticallResultOutputs | number>[],
190
- undefined,
191
- undefined,
192
- // multiCalls includes calls asset.isPaused, asset.getRelativePrice
193
- // some of the contracts don't have these methods, so prevent logging errors
194
- false,
195
- )) as [MultiResult<number>, ...MultiResult<MulticallResultOutputs>[]];
196
-
197
- return this.parseStateFromMultiResultsWithBlockInfo(
198
- aggregatedResults,
199
- lastUpdatedAtMs,
316
+ handleSwap(
317
+ event: any,
318
+ state: DeepReadonly<PoolState>,
319
+ log: Readonly<Log>,
320
+ ): AsyncOrSync<DeepReadonly<PoolState> | null> {
321
+ const fromTokenAddress = event.args.fromToken.toString().toLowerCase();
322
+ const fromAmount = BigInt(event.args.fromAmount.toString());
323
+ const toTokenAddress = event.args.toToken.toString().toLowerCase();
324
+ const toAmount = BigInt(event.args.toAmount.toString());
325
+
326
+ if (
327
+ !state.underlyingAddresses.includes(fromTokenAddress) ||
328
+ !state.underlyingAddresses.includes(toTokenAddress)
329
+ ) {
330
+ return null;
331
+ }
332
+
333
+ let idealToAmount;
334
+ const fromAmountInt256 = convertUint256ToInt256(fromAmount);
335
+ if (fromAmountInt256 > 0) {
336
+ idealToAmount = wdiv(toAmount, WAD - state.params.haircutRate);
337
+ } else {
338
+ this.logger.warn(
339
+ `pool ${this.poolAddress} swap from a negative amount ${fromAmountInt256} at block ${log.blockNumber} should not happen`,
200
340
  );
201
- } catch (e) {
202
- this._logMessageWithSuppression('ERROR_FETCHING_STATE_FROM_RPC', e);
341
+ const haircut = wmul(-fromAmount, state.params.haircutRate);
342
+ idealToAmount = toAmount + haircut;
203
343
  }
204
344
 
205
- return null;
345
+ const fromAmountInWad = toWad(
346
+ fromAmount,
347
+ BigInt(state.asset[fromTokenAddress].underlyingTokenDecimals),
348
+ );
349
+ const toAmountInWad = toWad(
350
+ idealToAmount,
351
+ BigInt(state.asset[toTokenAddress].underlyingTokenDecimals),
352
+ );
353
+
354
+ return {
355
+ ...state,
356
+ asset: {
357
+ ...state.asset,
358
+ [fromTokenAddress]: {
359
+ ...state.asset[fromTokenAddress],
360
+ cash: state.asset[fromTokenAddress].cash + fromAmountInWad,
361
+ },
362
+ [toTokenAddress]: {
363
+ ...state.asset[toTokenAddress],
364
+ cash: state.asset[toTokenAddress].cash - toAmountInWad,
365
+ },
366
+ },
367
+ };
368
+ }
369
+
370
+ handleSwapV2(
371
+ event: any,
372
+ state: DeepReadonly<PoolState>,
373
+ _log: Readonly<Log>,
374
+ ): AsyncOrSync<DeepReadonly<PoolState> | null> {
375
+ const fromTokenAddress = event.args.fromToken.toString().toLowerCase();
376
+ const fromAmount = BigInt(event.args.fromAmount.toString());
377
+ const toTokenAddress = event.args.toToken.toString().toLowerCase();
378
+ const toAmount = BigInt(event.args.toAmount.toString());
379
+ const toTokenFee = BigInt(event.args.toTokenFee.toString());
380
+
381
+ if (
382
+ !state.underlyingAddresses.includes(fromTokenAddress) ||
383
+ !state.underlyingAddresses.includes(toTokenAddress)
384
+ ) {
385
+ return null;
386
+ }
387
+
388
+ const fromAmountInWad = toWad(
389
+ fromAmount,
390
+ BigInt(state.asset[fromTokenAddress].underlyingTokenDecimals),
391
+ );
392
+ const toAmountInWad = toWad(
393
+ toAmount + toTokenFee,
394
+ BigInt(state.asset[toTokenAddress].underlyingTokenDecimals),
395
+ );
396
+
397
+ return {
398
+ ...state,
399
+ asset: {
400
+ ...state.asset,
401
+ [fromTokenAddress]: {
402
+ ...state.asset[fromTokenAddress],
403
+ cash: state.asset[fromTokenAddress].cash + fromAmountInWad,
404
+ },
405
+ [toTokenAddress]: {
406
+ ...state.asset[toTokenAddress],
407
+ cash: state.asset[toTokenAddress].cash - toAmountInWad,
408
+ },
409
+ },
410
+ };
206
411
  }
207
412
 
208
- public parseStateFromMultiResultsWithBlockInfo(
209
- multiOutputs: [
210
- MultiResult<number>,
211
- ...MultiResult<MulticallResultOutputs>[],
212
- ],
213
- lastUpdatedAtMs: number,
214
- ): ObjWithUpdateInfo<PoolState> {
215
- const [blockNumber, ...outputsForAbstract] = multiOutputs.map((m, i) => {
216
- return m.returnData;
217
- }) as [number, ...MulticallResultOutputs[]];
413
+ handleSetAmpFactor(
414
+ event: any,
415
+ state: DeepReadonly<PoolState>,
416
+ _log: Readonly<Log>,
417
+ ): AsyncOrSync<DeepReadonly<PoolState> | null> {
418
+ const ampFactor = BigInt(event.args.value.toString());
218
419
 
219
420
  return {
220
- value: this._parseStateFromMultiResults(outputsForAbstract),
221
- blockNumber,
222
- lastUpdatedAtMs,
421
+ ...state,
422
+ params: {
423
+ ...state.params,
424
+ ampFactor,
425
+ },
223
426
  };
224
427
  }
225
428
 
226
- public addAssets(asset2TokenMap: Map<Address, Address>) {
227
- for (const [asset, token] of asset2TokenMap) {
228
- if (this.asset2TokenMap.has(asset)) {
229
- continue;
429
+ handleSetHaircutRate(
430
+ event: any,
431
+ state: DeepReadonly<PoolState>,
432
+ _log: Readonly<Log>,
433
+ ): AsyncOrSync<DeepReadonly<PoolState> | null> {
434
+ const haircutRate = BigInt(event.args.value.toString());
435
+
436
+ return {
437
+ ...state,
438
+ params: {
439
+ ...state.params,
440
+ haircutRate,
441
+ },
442
+ };
443
+ }
444
+
445
+ async handleAssetAdded(
446
+ event: any,
447
+ state: DeepReadonly<PoolState>,
448
+ log: Readonly<Log>,
449
+ ): Promise<DeepReadonly<PoolState> | null> {
450
+ const token: Address = event.args.token.toString().toLowerCase();
451
+ const asset: Address = event.args.asset.toString().toLowerCase();
452
+ if (state.underlyingAddresses.includes(token)) {
453
+ return null;
454
+ }
455
+
456
+ const assetState = await this.getAssetState(
457
+ this.poolAddress,
458
+ [asset],
459
+ [token],
460
+ log.blockNumber,
461
+ );
462
+ const poolState = {
463
+ ...state,
464
+ underlyingAddresses: [...state.underlyingAddresses, token],
465
+ asset: {
466
+ ...state.asset,
467
+ [token]: assetState[0],
468
+ },
469
+ };
470
+
471
+ const isMainPool =
472
+ Object.values(poolState.asset).filter(
473
+ asset => asset.relativePrice === undefined,
474
+ ).length > 0;
475
+ if (isMainPool) {
476
+ for (const underlyingAddress of poolState.underlyingAddresses) {
477
+ poolState.asset[underlyingAddress] = {
478
+ ...poolState.asset[underlyingAddress],
479
+ relativePrice: undefined,
480
+ };
230
481
  }
482
+ }
483
+ return poolState;
484
+ }
231
485
 
232
- this.asset2TokenMap.set(asset, token);
233
- this._cachedMultiCallData = undefined;
486
+ async handleAssetRemoved(
487
+ event: any,
488
+ state: DeepReadonly<PoolState>,
489
+ _log: Readonly<Log>,
490
+ ): Promise<DeepReadonly<PoolState> | null> {
491
+ const token = event.args.token.toString().toLowerCase();
492
+ if (!state.underlyingAddresses.includes(token)) {
493
+ return null;
234
494
  }
495
+
496
+ return {
497
+ ...state,
498
+ underlyingAddresses: state.underlyingAddresses.filter(
499
+ underlyingAddress => underlyingAddress !== token,
500
+ ),
501
+ asset: {
502
+ ...state.asset,
503
+ [token]: undefined,
504
+ },
505
+ };
506
+ }
507
+
508
+ async handleFillPool(
509
+ event: any,
510
+ state: DeepReadonly<PoolState>,
511
+ _log: Readonly<Log>,
512
+ ): Promise<DeepReadonly<PoolState> | null> {
513
+ const token = event.args.token.toString().toLowerCase();
514
+ const amount = BigInt(event.args.amount.toString());
515
+ if (!state.underlyingAddresses.includes(token)) {
516
+ return null;
517
+ }
518
+
519
+ return {
520
+ ...state,
521
+ asset: {
522
+ ...state.asset,
523
+ [token]: {
524
+ ...state.asset[token],
525
+ cash: state.asset[token].cash + amount,
526
+ },
527
+ },
528
+ };
529
+ }
530
+
531
+ async handlePaused(
532
+ event: any,
533
+ state: DeepReadonly<PoolState>,
534
+ _log: Readonly<Log>,
535
+ ): Promise<DeepReadonly<PoolState> | null> {
536
+ return {
537
+ ...state,
538
+ params: {
539
+ ...state.params,
540
+ paused: true,
541
+ },
542
+ };
543
+ }
544
+
545
+ async handleUnpaused(
546
+ event: any,
547
+ state: DeepReadonly<PoolState>,
548
+ _log: Readonly<Log>,
549
+ ): Promise<DeepReadonly<PoolState> | null> {
550
+ return {
551
+ ...state,
552
+ params: {
553
+ ...state.params,
554
+ paused: false,
555
+ },
556
+ };
557
+ }
558
+
559
+ async handlePausedAsset(
560
+ event: any,
561
+ state: DeepReadonly<PoolState>,
562
+ _log: Readonly<Log>,
563
+ ): Promise<DeepReadonly<PoolState> | null> {
564
+ const token = event.args.token.toString();
565
+ if (!state.underlyingAddresses.includes(token)) {
566
+ return null;
567
+ }
568
+
569
+ return {
570
+ ...state,
571
+ asset: {
572
+ ...state.asset,
573
+ [token]: {
574
+ ...state.asset[token],
575
+ paused: true,
576
+ },
577
+ },
578
+ };
579
+ }
580
+
581
+ async handleUnpausedAsset(
582
+ event: any,
583
+ state: DeepReadonly<PoolState>,
584
+ _log: Readonly<Log>,
585
+ ): Promise<DeepReadonly<PoolState> | null> {
586
+ const token = event.args.token.toString();
587
+ if (!state.underlyingAddresses.includes(token)) {
588
+ return null;
589
+ }
590
+
591
+ return {
592
+ ...state,
593
+ asset: {
594
+ ...state.asset,
595
+ [token]: {
596
+ ...state.asset[token],
597
+ paused: true,
598
+ },
599
+ },
600
+ };
601
+ }
602
+
603
+ private async getAssetState(
604
+ pool: Address,
605
+ assets: Address[],
606
+ tokens: Address[],
607
+ blockNumber: number,
608
+ ): Promise<AssetState[]> {
609
+ const assetStates: AssetState[] = [];
610
+ const multiCallInputs: MultiCallInput[] = [];
611
+
612
+ const methods = [
613
+ 'cash',
614
+ 'liability',
615
+ 'underlyingTokenDecimals',
616
+ 'getRelativePrice',
617
+ ];
618
+
619
+ for (let i = 0; i < assets.length; i++) {
620
+ const asset = assets[i];
621
+ const token = tokens[i];
622
+
623
+ multiCallInputs.push({
624
+ target: pool,
625
+ callData: this.poolInterface.encodeFunctionData('isPaused', [token]),
626
+ });
627
+
628
+ for (const method of methods) {
629
+ multiCallInputs.push({
630
+ target: asset,
631
+ callData: WombatPool.assetInterface.encodeFunctionData(method),
632
+ });
633
+ }
634
+ }
635
+
636
+ const returnData = await this.dexHelper.multiContract.methods
637
+ .tryAggregate(false, multiCallInputs)
638
+ .call({}, blockNumber);
639
+
640
+ for (
641
+ let i = 0;
642
+ i < assets.length * (methods.length + 1);
643
+ i += methods.length + 1
644
+ ) {
645
+ const paused = returnData[i].success
646
+ ? Boolean(
647
+ this.poolInterface.decodeFunctionResult(
648
+ 'isPaused',
649
+ returnData[i].returnData,
650
+ )[0],
651
+ )
652
+ : false;
653
+ const cash = BigInt(
654
+ WombatPool.assetInterface.decodeFunctionResult(
655
+ methods[0],
656
+ returnData[i + 1].returnData,
657
+ )[0],
658
+ );
659
+ const liability = BigInt(
660
+ WombatPool.assetInterface.decodeFunctionResult(
661
+ methods[1],
662
+ returnData[i + 2].returnData,
663
+ )[0],
664
+ );
665
+ const underlyingTokenDecimals =
666
+ WombatPool.assetInterface.decodeFunctionResult(
667
+ methods[2],
668
+ returnData[i + 3].returnData,
669
+ )[0];
670
+
671
+ let relativePrice: bigint | undefined;
672
+ if (returnData[i + 4].success) {
673
+ relativePrice = BigInt(
674
+ WombatPool.assetInterface.decodeFunctionResult(
675
+ methods[3],
676
+ returnData[i + 4].returnData,
677
+ )[0],
678
+ );
679
+ }
680
+
681
+ assetStates.push({
682
+ address: assets[i / (methods.length + 1)],
683
+ paused,
684
+ cash,
685
+ liability,
686
+ underlyingTokenDecimals,
687
+ relativePrice,
688
+ });
689
+ }
690
+
691
+ return assetStates;
235
692
  }
236
693
  }