@paraswap/dex-lib 2.14.0 → 2.14.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 (107) hide show
  1. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  2. package/.idea/misc.xml +6 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/.vscode/launch.json +21 -0
  6. package/build/config.js +23 -5
  7. package/build/config.js.map +1 -1
  8. package/build/dex/aave-v3/tokens/arbitrum.json +50 -0
  9. package/build/dex/aave-v3/tokens/avalanche.json +50 -0
  10. package/build/dex/aave-v3/tokens/fantom.json +62 -0
  11. package/build/dex/aave-v3/tokens/mainnet.json +44 -0
  12. package/build/dex/aave-v3/tokens/optimism.json +50 -0
  13. package/build/dex/aave-v3/tokens/polygon.json +98 -0
  14. package/build/dex/balancer-v2/VirtualBoostedPool.d.ts +79 -0
  15. package/build/dex/balancer-v2/VirtualBoostedPool.js +382 -0
  16. package/build/dex/balancer-v2/VirtualBoostedPool.js.map +1 -0
  17. package/build/dex/generic-rfq/e2e-test-config.d.ts +9 -0
  18. package/build/dex/generic-rfq/e2e-test-config.js +33 -0
  19. package/build/dex/generic-rfq/e2e-test-config.js.map +1 -0
  20. package/build/dex/generic-rfq/rate-fetcher.js +2 -0
  21. package/build/dex/generic-rfq/rate-fetcher.js.map +1 -1
  22. package/build/dex/generic-rfq/validators.d.ts +1 -1
  23. package/build/dex/generic-rfq/validators.js +36 -26
  24. package/build/dex/generic-rfq/validators.js.map +1 -1
  25. package/build/dex/index.js +2 -2
  26. package/build/dex/index.js.map +1 -1
  27. package/build/dex/simple-exchange.d.ts +1 -0
  28. package/build/dex/simple-exchange.js +2 -0
  29. package/build/dex/simple-exchange.js.map +1 -1
  30. package/build/dex/test-aave-v3/config.d.ts +4 -0
  31. package/build/dex/test-aave-v3/config.js +15 -0
  32. package/build/dex/test-aave-v3/config.js.map +1 -0
  33. package/build/dex/test-aave-v3/test-aave-v3-pool.d.ts +39 -0
  34. package/build/dex/test-aave-v3/test-aave-v3-pool.js +63 -0
  35. package/build/dex/test-aave-v3/test-aave-v3-pool.js.map +1 -0
  36. package/build/dex/test-aave-v3/test-aave-v3.d.ts +37 -0
  37. package/build/dex/test-aave-v3/test-aave-v3.js +126 -0
  38. package/build/dex/test-aave-v3/test-aave-v3.js.map +1 -0
  39. package/build/dex/test-aave-v3/types.d.ts +6 -0
  40. package/build/dex/test-aave-v3/types.js +3 -0
  41. package/build/dex/test-aave-v3/types.js.map +1 -0
  42. package/build/lib/decoders.d.ts +2 -1
  43. package/build/lib/decoders.js +8 -1
  44. package/build/lib/decoders.js.map +1 -1
  45. package/build/lib/fetcher/fetcher.js +3 -0
  46. package/build/lib/fetcher/fetcher.js.map +1 -1
  47. package/build/lib/multi-wrapper.d.ts +2 -1
  48. package/build/lib/multi-wrapper.js.map +1 -1
  49. package/build/lib/tokens/balancer-fetcher.js +4 -5
  50. package/build/lib/tokens/balancer-fetcher.js.map +1 -1
  51. package/build/lib/tokens/utils.d.ts +2 -2
  52. package/build/lib/tokens/utils.js +1 -1
  53. package/build/lib/tokens/utils.js.map +1 -1
  54. package/build/types.d.ts +3 -0
  55. package/dex-template/__DexName__-e2e.test.ts.template +1 -0
  56. package/dex-template/__DexName__-events.test.ts.template +1 -0
  57. package/dex-template/__DexName__-integration.test.ts.template +1 -0
  58. package/dex-template/__DexName__-pool.ts.template +8 -5
  59. package/package.json +1 -1
  60. package/scripts/generate-bytecode.ts +2 -0
  61. package/src/abi/woo-fi-v2/IntegrationHelper.abi.json +116 -0
  62. package/src/abi/{woo-fi/Wooracle.abi.json → woo-fi-v2/WooOracleV2.abi.json} +148 -50
  63. package/src/abi/{woo-fi/WooPP.abi.json → woo-fi-v2/WooPPV2.abi.json} +201 -169
  64. package/src/config.ts +27 -5
  65. package/src/dex/balancer-v2/balancer-v2-e2e.test.ts +0 -1
  66. package/src/dex/generic-rfq/e2e-test-config.ts +37 -0
  67. package/src/dex/generic-rfq/generic-rfq-e2e.test.ts +63 -258
  68. package/src/dex/generic-rfq/generic-rfq-local-e2e.test.ts +121 -0
  69. package/src/dex/generic-rfq/rate-fetcher.ts +2 -0
  70. package/src/dex/generic-rfq/validators.test.ts +6 -32
  71. package/src/dex/generic-rfq/validators.ts +57 -32
  72. package/src/dex/index.ts +2 -2
  73. package/src/dex/simple-exchange.ts +3 -0
  74. package/src/dex/woo-fi-v2/config.ts +87 -0
  75. package/src/dex/woo-fi-v2/constants.ts +22 -0
  76. package/src/dex/woo-fi-v2/decoders.ts +45 -0
  77. package/src/dex/woo-fi-v2/types.ts +63 -0
  78. package/src/dex/woo-fi-v2/utils.ts +19 -0
  79. package/src/dex/woo-fi-v2/woo-fi-v2-e2e.test.ts +216 -0
  80. package/src/dex/woo-fi-v2/woo-fi-v2-integration.test.ts +495 -0
  81. package/src/dex/woo-fi-v2/woo-fi-v2-math.ts +195 -0
  82. package/src/dex/woo-fi-v2/woo-fi-v2-pool.ts +112 -0
  83. package/src/dex/woo-fi-v2/woo-fi-v2.ts +487 -0
  84. package/src/lib/decoders.ts +12 -1
  85. package/src/lib/fetcher/fetcher.ts +6 -0
  86. package/src/lib/log-messages-suppressor.ts +173 -0
  87. package/src/lib/multi-wrapper.ts +2 -1
  88. package/src/lib/stateful-rpc-poller/state-polling-manager.ts +320 -0
  89. package/src/lib/stateful-rpc-poller/stateful-rpc-poller.ts +604 -0
  90. package/src/lib/stateful-rpc-poller/types.ts +66 -0
  91. package/src/lib/stateful-rpc-poller/utils.ts +23 -0
  92. package/src/lib/tokens/balancer-fetcher.ts +5 -6
  93. package/src/lib/tokens/utils.ts +5 -3
  94. package/src/types.ts +4 -0
  95. package/tests/constants-e2e.ts +10 -3
  96. package/tests/tenderly-simulation.ts +1 -1
  97. package/tests/utils-e2e.ts +61 -48
  98. package/tests/utils.ts +2 -0
  99. package/src/abi/woo-fi/WooFeeManager.abi.json +0 -318
  100. package/src/dex/woo-fi/config.ts +0 -141
  101. package/src/dex/woo-fi/constants.ts +0 -21
  102. package/src/dex/woo-fi/types.ts +0 -55
  103. package/src/dex/woo-fi/woo-fi-decimal-math.ts +0 -45
  104. package/src/dex/woo-fi/woo-fi-e2e.test.ts +0 -183
  105. package/src/dex/woo-fi/woo-fi-integration.test.ts +0 -416
  106. package/src/dex/woo-fi/woo-fi-math.ts +0 -527
  107. package/src/dex/woo-fi/woo-fi.ts +0 -693
@@ -1,3 +1,4 @@
1
+ import { BytesLike } from 'ethers';
1
2
  import _ from 'lodash';
2
3
  import { Logger } from 'log4js';
3
4
  import { Contract } from 'web3-eth-contract';
@@ -10,7 +11,7 @@ export type MultiResult<T> = {
10
11
  export type MultiCallParams<T> = {
11
12
  target: string;
12
13
  callData: string;
13
- decodeFunction: (str: MultiResult<string> | string) => T;
14
+ decodeFunction: (str: MultiResult<BytesLike> | BytesLike) => T;
14
15
  cb?: (data: T) => void;
15
16
  };
16
17
 
@@ -0,0 +1,320 @@
1
+ import _ from 'lodash';
2
+ import { assert } from 'console';
3
+ import { IDexHelper } from '../../dex-helper';
4
+ import { Logger } from '../../types';
5
+ import { MultiResult } from '../multi-wrapper';
6
+ import { IStatefulRpcPoller } from './types';
7
+
8
+ export class StatePollingManager {
9
+ // This is for update pool states function. If we see state for new block and
10
+ // the diff is bigger than this number, than something might be wrong and
11
+ // we warn about this
12
+ static readonly DEFAULT_BLOCK_NUMBER_DIFFERENCE_TO_ALERT = 10;
13
+
14
+ private static __instances: Record<string, StatePollingManager> = {};
15
+
16
+ static getInstance(dexHelper: IDexHelper): StatePollingManager {
17
+ const network = dexHelper.config.data.network;
18
+ if (StatePollingManager.__instances[network] === undefined) {
19
+ StatePollingManager.__instances[network] = new StatePollingManager(
20
+ dexHelper,
21
+ );
22
+ }
23
+ return StatePollingManager.__instances[network];
24
+ }
25
+
26
+ private _lastProcessedBlockNumber = 0;
27
+
28
+ private logger: Logger;
29
+
30
+ private _registeredPendingPools: IStatefulRpcPoller<any, any>[] = [];
31
+
32
+ // ALl registered instances from identifier to instance
33
+ private _poolsToInstances: Record<string, IStatefulRpcPoller<any, any>> = {};
34
+
35
+ // This pools will be updated if we see new block and the time has come
36
+ private _poolsToBeUpdated: Set<string> = new Set();
37
+
38
+ // This pools wont be updated before we change _isStateToBeUpdated to true
39
+ private _idlePools: Set<string> = new Set();
40
+
41
+ private constructor(protected dexHelper: IDexHelper) {
42
+ this.logger = this.dexHelper.getLogger(
43
+ `${this.constructor.name}-${dexHelper.config.data.network}`,
44
+ );
45
+ }
46
+
47
+ get isMaster() {
48
+ return !this.dexHelper.config.isSlave;
49
+ }
50
+
51
+ enableStateTracking(identifierKey: string) {
52
+ assert(
53
+ this._poolsToInstances[identifierKey] !== undefined,
54
+ `enableTracking: pool with identifierKey=${identifierKey} is not initialized`,
55
+ );
56
+ this._poolsToBeUpdated.add(identifierKey);
57
+ this._idlePools.delete(identifierKey);
58
+ }
59
+
60
+ disableStateTracking(identifierKey: string) {
61
+ assert(
62
+ this._poolsToInstances[identifierKey] !== undefined,
63
+ `disableStateTracking: pool with identifierKey=${identifierKey} is not initialized`,
64
+ );
65
+ this._poolsToBeUpdated.delete(identifierKey);
66
+ this._idlePools.add(identifierKey);
67
+ }
68
+
69
+ async onBlockNumber(blockNumber: number): Promise<void> {
70
+ if (!this.isMaster) {
71
+ return;
72
+ }
73
+
74
+ // Events-client calls several times for the same blockNumber sometimes
75
+ // I want to filter them. The only condition, that matters is that blockNumbers are the same
76
+ if (this._lastProcessedBlockNumber === blockNumber) {
77
+ return;
78
+ }
79
+ this._lastProcessedBlockNumber = blockNumber;
80
+
81
+ const poolsToBeUpdated: IStatefulRpcPoller<any, any>[] = [];
82
+
83
+ Array.from(this._poolsToBeUpdated).forEach(p => {
84
+ const pool = this._keyToPoolInstance(p);
85
+
86
+ // We always expect pools in _poolsToBeUpdated to participate in updates
87
+ assert(
88
+ pool.isPoolParticipateInUpdates,
89
+ `onBlockNumber: pool=${p} from ${pool.dexKey} is not participate in updates`,
90
+ );
91
+
92
+ if (
93
+ !pool.isPoolInTheMiddleOfUpdate &&
94
+ pool.isTimeToTriggerUpdate(blockNumber)
95
+ ) {
96
+ pool.isPoolInTheMiddleOfUpdate = true;
97
+ poolsToBeUpdated.push(pool);
98
+ }
99
+ });
100
+
101
+ if (poolsToBeUpdated.length === 0) {
102
+ this.logger.debug(
103
+ `onBlockNumber=${blockNumber} no pools to be updated. Skipping`,
104
+ );
105
+ return;
106
+ }
107
+
108
+ this._updatePoolStates(poolsToBeUpdated)
109
+ .then(receivedBlockNumber => {
110
+ // There is no guarantee that we receive latest state. This is our best effort
111
+ if (
112
+ Math.abs(blockNumber - receivedBlockNumber) >
113
+ StatePollingManager.DEFAULT_BLOCK_NUMBER_DIFFERENCE_TO_ALERT
114
+ ) {
115
+ this.logger.warn(
116
+ `onBlockNumber=${blockNumber} at least for some pools receivedBlockNumber=${receivedBlockNumber} is lower than expected`,
117
+ );
118
+ }
119
+ this.logger.info(
120
+ `onBlockNumber=${blockNumber} updated ${
121
+ poolsToBeUpdated.length
122
+ } pools: ${poolsToBeUpdated
123
+ .map(p => p.identifierKey)
124
+ .slice(0, 10)
125
+ .join(',')} (sample)`,
126
+ );
127
+ })
128
+ .catch(e =>
129
+ this.logger.error(
130
+ `onBlockNumber=${blockNumber} error while updating pools: ${e}`,
131
+ ),
132
+ )
133
+ .finally(() => {
134
+ poolsToBeUpdated.forEach(pool => {
135
+ pool.isPoolInTheMiddleOfUpdate = false;
136
+ });
137
+ });
138
+ }
139
+
140
+ protected async _updatePoolStates(
141
+ poolsToBeUpdated: IStatefulRpcPoller<any, any>[],
142
+ blockNumber: number | 'latest' = 'latest',
143
+ numberOfChunks?: number,
144
+ ): Promise<number> {
145
+ const indexDividers: number[] = [];
146
+
147
+ const multiCalls = poolsToBeUpdated
148
+ .map((p, i) => {
149
+ const callData = p.getFetchStateWithBlockInfoMultiCalls();
150
+ indexDividers.push(callData.length);
151
+ return callData;
152
+ })
153
+ .flat();
154
+
155
+ assert(
156
+ indexDividers.length === poolsToBeUpdated.length,
157
+ 'indexDividers.length === poolsToBeUpdated.length',
158
+ );
159
+
160
+ const results = (await this.dexHelper.multiWrapper.tryAggregate(
161
+ false,
162
+ multiCalls,
163
+ blockNumber,
164
+ numberOfChunks,
165
+ )) as [MultiResult<number>, ...MultiResult<any>[]];
166
+
167
+ let minBlockNumber = 0;
168
+ const lastUpdatedAtMs = Date.now();
169
+
170
+ // Let's pack each result into relevant pools
171
+ const unFlattenedResults: [MultiResult<number>, ...MultiResult<any>[]][] =
172
+ [];
173
+
174
+ let accumulatedStart = 0;
175
+ indexDividers.forEach(divider => {
176
+ unFlattenedResults.push(
177
+ results.slice(accumulatedStart, accumulatedStart + divider) as [
178
+ MultiResult<number>,
179
+ ...MultiResult<any>[],
180
+ ],
181
+ );
182
+ accumulatedStart += divider;
183
+ });
184
+
185
+ assert(
186
+ unFlattenedResults.length === poolsToBeUpdated.length,
187
+ 'unFlattenedResults.length === poolsToBeUpdated.length',
188
+ );
189
+
190
+ await Promise.all(
191
+ unFlattenedResults.map(async (result, index) => {
192
+ const pool = poolsToBeUpdated[index];
193
+ try {
194
+ const parsedStateResult =
195
+ pool.parseStateFromMultiResultsWithBlockInfo(
196
+ result,
197
+ lastUpdatedAtMs,
198
+ );
199
+
200
+ minBlockNumber =
201
+ minBlockNumber === 0
202
+ ? parsedStateResult.blockNumber
203
+ : Math.min(parsedStateResult.blockNumber, minBlockNumber);
204
+
205
+ await pool.setState(
206
+ parsedStateResult.value,
207
+ parsedStateResult.blockNumber,
208
+ parsedStateResult.lastUpdatedAtMs,
209
+ );
210
+ } catch (e) {
211
+ this.logger.error(
212
+ `onBlockNumber=${blockNumber} error while parsing state from multicall for pool=${pool.identifierKey} from ${pool.dexKey}: ${e}`,
213
+ );
214
+ }
215
+ }),
216
+ );
217
+
218
+ return minBlockNumber;
219
+ }
220
+
221
+ // When this method is called, we expect that all pools are initialized
222
+ private _keyToPoolInstance(
223
+ identifierKey: string,
224
+ ): IStatefulRpcPoller<any, any> {
225
+ const pool = this._poolsToInstances[identifierKey];
226
+ assert(
227
+ pool !== undefined,
228
+ `keyToPoolInstance: pool=${identifierKey} is undefined`,
229
+ );
230
+ return pool;
231
+ }
232
+
233
+ // Once you instantiated all your pools, you should trigger at the end of initializing this method
234
+ // So all state will be initialized. It is not part of constructor, because and that time we don't have
235
+ // all classes built
236
+ initializeAllPendingPools() {
237
+ if (this._registeredPendingPools.length === 0) {
238
+ return;
239
+ }
240
+
241
+ this._registeredPendingPools.forEach(p => {
242
+ this.initializePool(p);
243
+ });
244
+
245
+ this._registeredPendingPools = [];
246
+ }
247
+
248
+ registerPendingPool<T, M>(statefulRpcPoller: IStatefulRpcPoller<T, M>) {
249
+ if (this._poolsToInstances[statefulRpcPoller.identifierKey]) {
250
+ this.logger.error(
251
+ `Attempt to register initialized pool=${statefulRpcPoller.identifierKey}`,
252
+ );
253
+ return;
254
+ }
255
+
256
+ const alreadyRegisteredAsPending = this._registeredPendingPools.some(
257
+ p => p.identifierKey === statefulRpcPoller.identifierKey,
258
+ );
259
+ if (alreadyRegisteredAsPending) {
260
+ this.logger.error(
261
+ `Attempt to register pool=${statefulRpcPoller.identifierKey} twice`,
262
+ );
263
+ return;
264
+ }
265
+ this._registeredPendingPools.push(statefulRpcPoller);
266
+ }
267
+
268
+ async initializePool<T, M>(statefulRpcPoller: IStatefulRpcPoller<T, M>) {
269
+ const { identifierKey } = statefulRpcPoller;
270
+
271
+ if (
272
+ this._idlePools.has(identifierKey) ||
273
+ this._poolsToBeUpdated.has(identifierKey) ||
274
+ this._poolsToInstances.hasOwnProperty(identifierKey)
275
+ ) {
276
+ this.logger.warn(
277
+ `Attempt to reinitialize existing poolIdentifier=` +
278
+ `${identifierKey}. Maybe there is memory leak`,
279
+ );
280
+ } else {
281
+ this._poolsToInstances[identifierKey] = statefulRpcPoller;
282
+ statefulRpcPoller.isPoolParticipateInUpdates
283
+ ? this._poolsToBeUpdated.add(identifierKey)
284
+ : this._idlePools.add(identifierKey);
285
+
286
+ let currentBlockNumber: number | undefined;
287
+ // This complication is only for pool tracker. We don't have block manager there and
288
+ // this is workaround to get current block number
289
+ if (
290
+ this.dexHelper.blockManager &&
291
+ this.dexHelper.blockManager.getActiveChainHead
292
+ ) {
293
+ currentBlockNumber =
294
+ this.dexHelper.blockManager.getActiveChainHead()?.number;
295
+ }
296
+
297
+ if (currentBlockNumber === undefined) {
298
+ currentBlockNumber =
299
+ await this.dexHelper.web3Provider.eth.getBlockNumber();
300
+ }
301
+
302
+ assert(
303
+ currentBlockNumber !== undefined,
304
+ 'currentBlockNumber !== undefined',
305
+ );
306
+
307
+ statefulRpcPoller
308
+ .initializeState()
309
+ .then(() => {
310
+ this.logger.info(`Successfully initialized pool=${identifierKey}`);
311
+ })
312
+ .catch(e => {
313
+ // Must never happen
314
+ this.logger.error(
315
+ `initializePool: pool=${identifierKey} from ${statefulRpcPoller.dexKey} error while initializing state: ${e}`,
316
+ );
317
+ });
318
+ }
319
+ }
320
+ }