@paraswap/dex-lib 2.42.27 → 2.42.29-wombat.2

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