@paraswap/dex-lib 3.8.36 → 3.8.38

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 (58) hide show
  1. package/build/abi/cables/CablesMainnetRFQ.json +1073 -0
  2. package/build/abi/sdai/SavingsUSDS.abi.json +720 -0
  3. package/build/dex/cables/cables.d.ts +64 -0
  4. package/build/dex/cables/cables.js +445 -0
  5. package/build/dex/cables/cables.js.map +1 -0
  6. package/build/dex/cables/config.d.ts +4 -0
  7. package/build/dex/cables/config.js +15 -0
  8. package/build/dex/cables/config.js.map +1 -0
  9. package/build/dex/cables/constants.d.ts +19 -0
  10. package/build/dex/cables/constants.js +26 -0
  11. package/build/dex/cables/constants.js.map +1 -0
  12. package/build/dex/cables/rate-fetcher.d.ts +34 -0
  13. package/build/dex/cables/rate-fetcher.js +117 -0
  14. package/build/dex/cables/rate-fetcher.js.map +1 -0
  15. package/build/dex/cables/types.d.ts +106 -0
  16. package/build/dex/cables/types.js +12 -0
  17. package/build/dex/cables/types.js.map +1 -0
  18. package/build/dex/cables/validators.d.ts +5 -0
  19. package/build/dex/cables/validators.js +49 -0
  20. package/build/dex/cables/validators.js.map +1 -0
  21. package/build/dex/index.js +2 -0
  22. package/build/dex/index.js.map +1 -1
  23. package/build/dex/spark/config.js +25 -0
  24. package/build/dex/spark/config.js.map +1 -1
  25. package/build/dex/spark/scripts/validate-state.js +1 -1
  26. package/build/dex/spark/scripts/validate-state.js.map +1 -1
  27. package/build/dex/spark/spark-sdai-pool.d.ts +7 -3
  28. package/build/dex/spark/spark-sdai-pool.js +24 -28
  29. package/build/dex/spark/spark-sdai-pool.js.map +1 -1
  30. package/build/dex/spark/spark.d.ts +10 -5
  31. package/build/dex/spark/spark.js +46 -31
  32. package/build/dex/spark/spark.js.map +1 -1
  33. package/build/dex/spark/types.d.ts +6 -0
  34. package/build/dex/spark/types.js.map +1 -1
  35. package/build/dex/spark/utils.d.ts +3 -1
  36. package/build/dex/spark/utils.js +43 -7
  37. package/build/dex/spark/utils.js.map +1 -1
  38. package/build/dex/usual-bond/usual-bond.js +7 -9
  39. package/build/dex/usual-bond/usual-bond.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/abi/sdai/SavingsUSDS.abi.json +720 -0
  42. package/src/abi/usual-bond/usd0pp.abi.json +867 -0
  43. package/src/dex/index.ts +2 -0
  44. package/src/dex/spark/config.ts +24 -0
  45. package/src/dex/spark/scripts/validate-state.ts +1 -0
  46. package/src/dex/spark/spark-e2e.test.ts +25 -21
  47. package/src/dex/spark/spark-events.test.ts +77 -62
  48. package/src/dex/spark/spark-integration.test.ts +290 -7
  49. package/src/dex/spark/spark-sdai-pool.ts +22 -19
  50. package/src/dex/spark/spark.ts +62 -36
  51. package/src/dex/spark/types.ts +6 -0
  52. package/src/dex/spark/utils.ts +83 -19
  53. package/src/dex/usual-bond/config.ts +12 -0
  54. package/src/dex/usual-bond/types.ts +10 -0
  55. package/src/dex/usual-bond/usual-bond-e2e.test.ts +80 -0
  56. package/src/dex/usual-bond/usual-bond-integration.test.ts +144 -0
  57. package/src/dex/usual-bond/usual-bond.ts +208 -0
  58. package/tests/constants-e2e.ts +17 -0
package/src/dex/index.ts CHANGED
@@ -88,6 +88,7 @@ import { ConcentratorArusd } from './concentrator-arusd/concentrator-arusd';
88
88
  import { FxProtocolRusd } from './fx-protocol-rusd/fx-protocol-rusd';
89
89
  import { AaveGsm } from './aave-gsm/aave-gsm';
90
90
  import { LitePsm } from './lite-psm/lite-psm';
91
+ import { UsualBond } from './usual-bond/usual-bond';
91
92
  import { StkGHO } from './stkgho/stkgho';
92
93
  import { SkyConverter } from './sky-converter/sky-converter';
93
94
 
@@ -173,6 +174,7 @@ const Dexes = [
173
174
  FxProtocolRusd,
174
175
  AaveGsm,
175
176
  LitePsm,
177
+ UsualBond,
176
178
  StkGHO,
177
179
  SkyConverter,
178
180
  ];
@@ -2,6 +2,9 @@ import { SparkParams } from './types';
2
2
  import { DexConfigMap } from '../../types';
3
3
  import { Network } from '../../constants';
4
4
  import { SwapSide } from '@paraswap/core';
5
+ import PotAbi from '../../abi/maker-psm/pot.json';
6
+ import SavingsUSDSAbi from '../../abi/sdai/SavingsUSDS.abi.json';
7
+ import { Interface } from '@ethersproject/abi';
5
8
 
6
9
  export const SDaiConfig: DexConfigMap<SparkParams> = {
7
10
  Spark: {
@@ -9,6 +12,27 @@ export const SDaiConfig: DexConfigMap<SparkParams> = {
9
12
  sdaiAddress: '0x83F20F44975D03b1b09e64809B757c47f942BEeA',
10
13
  daiAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
11
14
  potAddress: '0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7',
15
+ savingsRate: {
16
+ symbol: 'dsr',
17
+ // bytes32 repr of "dsr" string
18
+ topic:
19
+ '0x6473720000000000000000000000000000000000000000000000000000000000',
20
+ },
21
+ poolInterface: new Interface(PotAbi),
22
+ },
23
+ },
24
+ sUSDS: {
25
+ [Network.MAINNET]: {
26
+ sdaiAddress: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD', // sUSDS
27
+ daiAddress: '0xdC035D45d973E3EC169d2276DDab16f1e407384F', // USDS
28
+ potAddress: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD', // no separate pot, sUSDS is the pot
29
+ savingsRate: {
30
+ symbol: 'ssr',
31
+ // bytes32 repr of "ssr" string
32
+ topic:
33
+ '0x7373720000000000000000000000000000000000000000000000000000000000',
34
+ },
35
+ poolInterface: new Interface(SavingsUSDSAbi),
12
36
  },
13
37
  },
14
38
  };
@@ -72,6 +72,7 @@ async function isPoolStateEqualToReal(
72
72
  dexHelper.multiContract,
73
73
  potAddress,
74
74
  new Interface(PotAbi),
75
+ 'dsr',
75
76
  blockNumber,
76
77
  );
77
78
 
@@ -23,23 +23,8 @@ function testForNetwork(
23
23
  const holders = Holders[network];
24
24
 
25
25
  const sideToContractMethods = new Map([
26
- [
27
- SwapSide.SELL,
28
- [
29
- ContractMethod.simpleSwap,
30
- ContractMethod.multiSwap,
31
- ContractMethod.megaSwap,
32
- ContractMethod.swapExactAmountIn,
33
- ],
34
- ],
35
- [
36
- SwapSide.BUY,
37
- [
38
- ContractMethod.simpleBuy,
39
- ContractMethod.buy,
40
- ContractMethod.swapExactAmountOut,
41
- ],
42
- ],
26
+ [SwapSide.SELL, [ContractMethod.swapExactAmountIn]],
27
+ [SwapSide.BUY, [ContractMethod.swapExactAmountOut]],
43
28
  ]);
44
29
 
45
30
  describe(`${network}`, () => {
@@ -80,10 +65,9 @@ function testForNetwork(
80
65
  });
81
66
  }
82
67
 
83
- describe('sDAI E2E', () => {
84
- const dexKey = 'Spark';
85
-
86
- describe('Mainnet', () => {
68
+ describe('Spark E2E', () => {
69
+ describe('sDai', () => {
70
+ const dexKey = 'Spark';
87
71
  const network = Network.MAINNET;
88
72
 
89
73
  const tokenASymbol: string = 'DAI';
@@ -101,4 +85,24 @@ describe('sDAI E2E', () => {
101
85
  tokenBAmount,
102
86
  );
103
87
  });
88
+
89
+ describe('sUSDS', () => {
90
+ const dexKey = 'sUSDS';
91
+ const network = Network.MAINNET;
92
+
93
+ const tokenASymbol: string = 'USDS';
94
+ const tokenBSymbol: string = 'sUSDS';
95
+
96
+ const tokenAAmount: string = '1000000000000000000';
97
+ const tokenBAmount: string = '1000000000000000000';
98
+
99
+ testForNetwork(
100
+ network,
101
+ dexKey,
102
+ tokenASymbol,
103
+ tokenBSymbol,
104
+ tokenAAmount,
105
+ tokenBAmount,
106
+ );
107
+ });
104
108
  });
@@ -12,41 +12,7 @@ import PotAbi from '../../abi/maker-psm/pot.json';
12
12
  import { Interface } from '@ethersproject/abi';
13
13
  import _ from 'lodash';
14
14
 
15
- /*
16
- README
17
- ======
18
-
19
- This test script adds unit tests for SDai event based
20
- system. This is done by fetching the state on-chain before the
21
- event block, manually pushing the block logs to the event-subscriber,
22
- comparing the local state with on-chain state.
23
-
24
- Most of the logic for testing is abstracted by `testEventSubscriber`.
25
- You need to do two things to make the tests work:
26
-
27
- 1. Fetch the block numbers where certain events were released. You
28
- can modify the `./scripts/fetch-event-blocknumber.ts` to get the
29
- block numbers for different events. Make sure to get sufficient
30
- number of blockNumbers to cover all possible cases for the event
31
- mutations.
32
-
33
- 2. Complete the implementation for fetchPoolState function. The
34
- function should fetch the on-chain state of the event subscriber
35
- using just the blocknumber.
36
-
37
- The template tests only include the test for a single event
38
- subscriber. There can be cases where multiple event subscribers
39
- exist for a single DEX. In such cases additional tests should be
40
- added.
41
-
42
- You can run this individual test script by running:
43
- `npx jest src/dex/<dex-name>/<dex-name>-events.test.ts`
44
-
45
- (This comment should be removed from the final implementation)
46
- */
47
-
48
15
  jest.setTimeout(50 * 1000);
49
- const dexKey = 'Spark';
50
16
  const network = Network.MAINNET;
51
17
 
52
18
  async function fetchPoolState(
@@ -56,7 +22,8 @@ async function fetchPoolState(
56
22
  return sdaiPool.generateState(blockNumber);
57
23
  }
58
24
 
59
- describe('SDai Event', function () {
25
+ describe('SDai', function () {
26
+ const dexKey = 'Spark';
60
27
  const blockNumbers: { [eventName: string]: number[] } = {
61
28
  drip: [19827559, 19827524, 19827163, 19827124, 19827000, 19826892],
62
29
  // TODO: no matching logs, you have to manually call "file"
@@ -69,33 +36,81 @@ describe('SDai Event', function () {
69
36
  potAddress: SDaiConfig[dexKey][network].potAddress,
70
37
  };
71
38
 
72
- describe('SDaiPool', function () {
73
- Object.keys(blockNumbers).forEach((event: string) => {
74
- blockNumbers[event].forEach((blockNumber: number) => {
75
- it(`Should return the correct state after the ${blockNumber}:${event}`, async function () {
76
- const dexHelper = new DummyDexHelper(network);
77
- const logger = dexHelper.getLogger(dexKey);
78
-
79
- const sdaiPool = new SparkSDaiEventPool(
80
- dexKey,
81
- `dai-sdai-pool`,
82
- dexHelper,
83
- addresses.potAddress,
84
- new Interface(PotAbi),
85
- logger,
86
- );
87
-
88
- await sdaiPool.initialize(blockNumber);
89
-
90
- await testEventSubscriber(
91
- sdaiPool,
92
- sdaiPool.addressesSubscribed,
93
- (_blockNumber: number) => fetchPoolState(sdaiPool, _blockNumber),
94
- blockNumber,
95
- `${dexKey}_${sdaiPool}`,
96
- dexHelper.provider,
97
- );
98
- });
39
+ const potIface = SDaiConfig[dexKey][network].poolInterface;
40
+
41
+ Object.keys(blockNumbers).forEach((event: string) => {
42
+ blockNumbers[event].forEach((blockNumber: number) => {
43
+ it(`Should return the correct state after the ${blockNumber}:${event}`, async function () {
44
+ const dexHelper = new DummyDexHelper(network);
45
+ const logger = dexHelper.getLogger(dexKey);
46
+
47
+ const sdaiPool = new SparkSDaiEventPool(
48
+ dexKey,
49
+ network,
50
+ `dai-sdai-pool`,
51
+ dexHelper,
52
+ addresses.potAddress,
53
+ potIface,
54
+ logger,
55
+ '0x6473720000000000000000000000000000000000000000000000000000000000',
56
+ 'dsr',
57
+ );
58
+
59
+ await sdaiPool.initialize(blockNumber);
60
+
61
+ await testEventSubscriber(
62
+ sdaiPool,
63
+ sdaiPool.addressesSubscribed,
64
+ (_blockNumber: number) => fetchPoolState(sdaiPool, _blockNumber),
65
+ blockNumber,
66
+ `${dexKey}_${sdaiPool}`,
67
+ dexHelper.provider,
68
+ );
69
+ });
70
+ });
71
+ });
72
+ });
73
+
74
+ describe('sUSDS', function () {
75
+ const dexKey = 'sUSDS';
76
+ const blockNumbers: { [eventName: string]: number[] } = {
77
+ drip: [20812786, 20812797, 20813343, 20813668, 20814065, 20814418],
78
+ };
79
+
80
+ const addresses: { [contract: string]: string } = {
81
+ potAddress: SDaiConfig[dexKey][network].potAddress,
82
+ };
83
+
84
+ const potIface = SDaiConfig[dexKey][network].poolInterface;
85
+
86
+ Object.keys(blockNumbers).forEach((event: string) => {
87
+ blockNumbers[event].forEach((blockNumber: number) => {
88
+ it(`Should return the correct state after the ${blockNumber}:${event}`, async function () {
89
+ const dexHelper = new DummyDexHelper(network);
90
+ const logger = dexHelper.getLogger(dexKey);
91
+
92
+ const sUSDSPool = new SparkSDaiEventPool(
93
+ dexKey,
94
+ network,
95
+ `usds-susds-pool`,
96
+ dexHelper,
97
+ addresses.potAddress,
98
+ potIface,
99
+ logger,
100
+ '0x7373720000000000000000000000000000000000000000000000000000000000',
101
+ 'ssr',
102
+ );
103
+
104
+ await sUSDSPool.initialize(blockNumber);
105
+
106
+ await testEventSubscriber(
107
+ sUSDSPool,
108
+ sUSDSPool.addressesSubscribed,
109
+ (_blockNumber: number) => fetchPoolState(sUSDSPool, _blockNumber),
110
+ blockNumber,
111
+ `${dexKey}_${sUSDSPool}`,
112
+ dexHelper.provider,
113
+ );
99
114
  });
100
115
  });
101
116
  });
@@ -7,23 +7,25 @@ import { checkPoolPrices, checkPoolsLiquidity } from '../../../tests/utils';
7
7
  import { Tokens } from '../../../tests/constants-e2e';
8
8
  import { BI_POWS } from '../../bigint-constants';
9
9
  import { Spark } from './spark';
10
+ import { MultiCallParams } from '../../lib/multi-wrapper';
11
+ import { uint256ToBigInt } from '../../lib/decoders';
10
12
 
11
13
  const network = Network.MAINNET;
12
14
 
13
- const SDaiSymbol = 'sDAI';
14
- const SDaiToken = Tokens[network][SDaiSymbol];
15
-
16
- const DaiSymbol = 'DAI';
17
- const DaiToken = Tokens[network][DaiSymbol];
18
-
19
15
  const amounts = [0n, BI_POWS[18], 2000000000000000000n];
20
16
 
21
- const dexKey = 'Spark';
22
17
  const dexHelper = new DummyDexHelper(network);
23
18
  let blocknumber: number;
24
19
  let spark: Spark;
25
20
 
26
21
  describe('Spark', function () {
22
+ const dexKey = 'Spark';
23
+ const SDaiSymbol = 'sDAI';
24
+ const SDaiToken = Tokens[network][SDaiSymbol];
25
+
26
+ const DaiSymbol = 'DAI';
27
+ const DaiToken = Tokens[network][DaiSymbol];
28
+
27
29
  beforeAll(async () => {
28
30
  blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
29
31
  spark = new Spark(network, dexKey, dexHelper);
@@ -149,3 +151,284 @@ describe('Spark', function () {
149
151
  checkPoolsLiquidity(poolLiquidity, SDaiToken.address, dexKey);
150
152
  });
151
153
  });
154
+
155
+ describe('sUSDS', function () {
156
+ const dexKey = 'sUSDS';
157
+ const SDaiSymbol = 'sUSDS';
158
+ const SDaiToken = Tokens[network][SDaiSymbol];
159
+
160
+ const DaiSymbol = 'USDS';
161
+ const DaiToken = Tokens[network][DaiSymbol];
162
+
163
+ beforeAll(async () => {
164
+ blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
165
+ spark = new Spark(network, dexKey, dexHelper);
166
+ if (spark.initializePricing) {
167
+ await spark.initializePricing(blocknumber);
168
+ }
169
+ });
170
+
171
+ it('getPoolIdentifiers and getPricesVolume USDS -> sUSDS SELL', async function () {
172
+ const pools = await spark.getPoolIdentifiers(
173
+ DaiToken,
174
+ SDaiToken,
175
+ SwapSide.SELL,
176
+ blocknumber,
177
+ );
178
+ console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Identifiers: `, pools);
179
+
180
+ expect(pools.length).toBeGreaterThan(0);
181
+
182
+ const poolPrices = await spark.getPricesVolume(
183
+ DaiToken,
184
+ SDaiToken,
185
+ amounts,
186
+ SwapSide.SELL,
187
+ blocknumber,
188
+ pools,
189
+ );
190
+ console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Prices: `, poolPrices);
191
+
192
+ const onChainPrices = await Promise.all(
193
+ amounts.map(async amount => {
194
+ const callData: MultiCallParams<bigint>[] = [
195
+ {
196
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
197
+ callData: spark.abiInterface.encodeFunctionData('previewDeposit', [
198
+ amount,
199
+ ]),
200
+ decodeFunction: uint256ToBigInt,
201
+ },
202
+ ];
203
+
204
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
205
+ callData,
206
+ blocknumber,
207
+ );
208
+ return results[0];
209
+ }),
210
+ );
211
+
212
+ console.log('On-chain price:', onChainPrices);
213
+
214
+ const chiCalldata: MultiCallParams<bigint>[] = [
215
+ {
216
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
217
+ callData: spark.abiInterface.encodeFunctionData('chi', []),
218
+ decodeFunction: uint256ToBigInt,
219
+ },
220
+ ];
221
+
222
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
223
+ chiCalldata,
224
+ blocknumber,
225
+ );
226
+ console.log(`ON_CHAIN_CHI at block=${blocknumber}`, results[0]);
227
+
228
+ expect(poolPrices).not.toBeNull();
229
+ expect(poolPrices?.[0].prices).toEqual(onChainPrices);
230
+ checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);
231
+ });
232
+
233
+ it('getPoolIdentifiers and getPricesVolume sUSDS -> USDS SELL', async function () {
234
+ const pools = await spark.getPoolIdentifiers(
235
+ SDaiToken,
236
+ DaiToken,
237
+ SwapSide.SELL,
238
+ blocknumber,
239
+ );
240
+ console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Identifiers: `, pools);
241
+
242
+ expect(pools.length).toBeGreaterThan(0);
243
+
244
+ const poolPrices = await spark.getPricesVolume(
245
+ SDaiToken,
246
+ DaiToken,
247
+ amounts,
248
+ SwapSide.SELL,
249
+ blocknumber,
250
+ pools,
251
+ );
252
+ console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Prices: `, poolPrices);
253
+
254
+ const onChainPrices = await Promise.all(
255
+ amounts.map(async amount => {
256
+ const callData: MultiCallParams<bigint>[] = [
257
+ {
258
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
259
+ callData: spark.abiInterface.encodeFunctionData('previewRedeem', [
260
+ amount,
261
+ ]),
262
+ decodeFunction: uint256ToBigInt,
263
+ },
264
+ ];
265
+
266
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
267
+ callData,
268
+ blocknumber,
269
+ );
270
+ return results[0];
271
+ }),
272
+ );
273
+
274
+ console.log('On-chain price:', onChainPrices);
275
+
276
+ const chiCalldata: MultiCallParams<bigint>[] = [
277
+ {
278
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
279
+ callData: spark.abiInterface.encodeFunctionData('chi', []),
280
+ decodeFunction: uint256ToBigInt,
281
+ },
282
+ ];
283
+
284
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
285
+ chiCalldata,
286
+ blocknumber,
287
+ );
288
+ console.log('ON_CHAIN_CHI:', results[0]);
289
+
290
+ expect(poolPrices).not.toBeNull();
291
+ expect(poolPrices?.[0].prices).toEqual(onChainPrices);
292
+ checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);
293
+ });
294
+
295
+ it('getPoolIdentifiers and getPricesVolume USDS -> sUSDS BUY', async function () {
296
+ const pools = await spark.getPoolIdentifiers(
297
+ DaiToken,
298
+ SDaiToken,
299
+ SwapSide.BUY,
300
+ blocknumber,
301
+ );
302
+ console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Identifiers: `, pools);
303
+
304
+ expect(pools.length).toBeGreaterThan(0);
305
+
306
+ const poolPrices = await spark.getPricesVolume(
307
+ DaiToken,
308
+ SDaiToken,
309
+ amounts,
310
+ SwapSide.BUY,
311
+ blocknumber,
312
+ pools,
313
+ );
314
+ console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Prices: `, poolPrices);
315
+
316
+ const onChainPrices = await Promise.all(
317
+ amounts.map(async amount => {
318
+ const callData: MultiCallParams<bigint>[] = [
319
+ {
320
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
321
+ callData: spark.abiInterface.encodeFunctionData('previewMint', [
322
+ amount,
323
+ ]),
324
+ decodeFunction: uint256ToBigInt,
325
+ },
326
+ ];
327
+
328
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
329
+ callData,
330
+ blocknumber,
331
+ );
332
+ return results[0];
333
+ }),
334
+ );
335
+
336
+ console.log('On-chain price:', onChainPrices);
337
+
338
+ const chiCalldata: MultiCallParams<bigint>[] = [
339
+ {
340
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
341
+ callData: spark.abiInterface.encodeFunctionData('chi', []),
342
+ decodeFunction: uint256ToBigInt,
343
+ },
344
+ ];
345
+
346
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
347
+ chiCalldata,
348
+ blocknumber,
349
+ );
350
+ console.log('ON_CHAIN_CHI:', results[0]);
351
+ expect(poolPrices).not.toBeNull();
352
+ expect(poolPrices?.[0].prices).toEqual(onChainPrices);
353
+ checkPoolPrices(poolPrices!, amounts, SwapSide.BUY, dexKey);
354
+ });
355
+
356
+ it('getPoolIdentifiers and getPricesVolume sUSDS -> USDS BUY', async function () {
357
+ const pools = await spark.getPoolIdentifiers(
358
+ SDaiToken,
359
+ DaiToken,
360
+ SwapSide.BUY,
361
+ blocknumber,
362
+ );
363
+ console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Identifiers: `, pools);
364
+
365
+ expect(pools.length).toBeGreaterThan(0);
366
+
367
+ const poolPrices = await spark.getPricesVolume(
368
+ SDaiToken,
369
+ DaiToken,
370
+ amounts,
371
+ SwapSide.BUY,
372
+ blocknumber,
373
+ pools,
374
+ );
375
+ console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Prices: `, poolPrices);
376
+
377
+ const onChainPrices = await Promise.all(
378
+ amounts.map(async amount => {
379
+ const callData: MultiCallParams<bigint>[] = [
380
+ {
381
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
382
+ callData: spark.abiInterface.encodeFunctionData('previewWithdraw', [
383
+ amount,
384
+ ]),
385
+ decodeFunction: uint256ToBigInt,
386
+ },
387
+ ];
388
+
389
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
390
+ callData,
391
+ blocknumber,
392
+ );
393
+ return results[0];
394
+ }),
395
+ );
396
+
397
+ console.log('On-chain price:', onChainPrices);
398
+
399
+ const chiCalldata: MultiCallParams<bigint>[] = [
400
+ {
401
+ target: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
402
+ callData: spark.abiInterface.encodeFunctionData('chi', []),
403
+ decodeFunction: uint256ToBigInt,
404
+ },
405
+ ];
406
+
407
+ const results = await spark.dexHelper.multiWrapper.aggregate<bigint>(
408
+ chiCalldata,
409
+ blocknumber,
410
+ );
411
+ console.log('ON_CHAIN_CHI:', results[0]);
412
+
413
+ expect(poolPrices).not.toBeNull();
414
+ expect(poolPrices?.[0].prices).toEqual(onChainPrices);
415
+ checkPoolPrices(poolPrices!, amounts, SwapSide.BUY, dexKey);
416
+ });
417
+
418
+ it('USDS getTopPoolsForToken', async function () {
419
+ const poolLiquidity = await spark.getTopPoolsForToken(DaiToken.address, 10);
420
+ console.log(`${DaiSymbol} Top Pools:`, poolLiquidity);
421
+
422
+ checkPoolsLiquidity(poolLiquidity, DaiToken.address, dexKey);
423
+ });
424
+
425
+ it('sUSDS getTopPoolsForToken', async function () {
426
+ const poolLiquidity = await spark.getTopPoolsForToken(
427
+ SDaiToken.address,
428
+ 10,
429
+ );
430
+ console.log(`${SDaiSymbol} Top Pools:`, poolLiquidity);
431
+
432
+ checkPoolsLiquidity(poolLiquidity, SDaiToken.address, dexKey);
433
+ });
434
+ });
@@ -7,8 +7,10 @@ import type { AsyncOrSync, DeepReadonly } from 'ts-essentials';
7
7
  import type { Address, BlockHeader, Log, Logger } from '../../types';
8
8
  import type { SparkSDaiPoolState } from './types';
9
9
  import { getOnChainState } from './utils';
10
+ import { SDaiConfig } from './config';
11
+ import { Network } from '../../constants';
10
12
 
11
- const RAY = BI_POWS[27];
13
+ export const RAY = BI_POWS[27];
12
14
  const ZERO = BigInt(0);
13
15
  const TWO = BigInt(2);
14
16
  const HALF = RAY / TWO;
@@ -17,10 +19,6 @@ const HALF = RAY / TWO;
17
19
  const FILE_TOPICHASH = `0x29ae811400000000000000000000000000000000000000000000000000000000`;
18
20
  // function drip()
19
21
  const DRIP_TOPICHASH = `0x9f678cca00000000000000000000000000000000000000000000000000000000`;
20
- // function cage()
21
- const CAGE_TOPICHASH = `0x6924500900000000000000000000000000000000000000000000000000000000`;
22
- // bytes32 repr of "dsr" string
23
- const DSR_TOPIC = `0x6473720000000000000000000000000000000000000000000000000000000000`;
24
22
 
25
23
  const rpow = (x: bigint, n: bigint): bigint => {
26
24
  if (!x && !n) return RAY;
@@ -38,7 +36,10 @@ const rpow = (x: bigint, n: bigint): bigint => {
38
36
  return z;
39
37
  };
40
38
 
41
- const calcChi = (state: SparkSDaiPoolState, currentTimestamp?: number) => {
39
+ export const calcChi = (
40
+ state: SparkSDaiPoolState,
41
+ currentTimestamp?: number,
42
+ ) => {
42
43
  currentTimestamp ||= Math.floor(Date.now() / 1000);
43
44
  if (!state.live) return RAY;
44
45
 
@@ -54,11 +55,14 @@ const calcChi = (state: SparkSDaiPoolState, currentTimestamp?: number) => {
54
55
  export class SparkSDaiEventPool extends StatefulEventSubscriber<SparkSDaiPoolState> {
55
56
  constructor(
56
57
  parentName: string,
58
+ network: Network,
57
59
  poolName: string,
58
60
  protected dexHelper: IDexHelper,
59
61
  private potAddress: Address,
60
62
  private potInterface: Interface,
61
63
  logger: Logger,
64
+ private savingsRateTopic: string,
65
+ private savingsRateSymbol: 'ssr' | 'dsr',
62
66
  ) {
63
67
  super(parentName, poolName, dexHelper, logger);
64
68
  this.addressesSubscribed = [potAddress];
@@ -69,7 +73,10 @@ export class SparkSDaiEventPool extends StatefulEventSubscriber<SparkSDaiPoolSta
69
73
  log: Readonly<Log>,
70
74
  blockHeader: Readonly<BlockHeader>,
71
75
  ): AsyncOrSync<DeepReadonly<SparkSDaiPoolState> | null> {
72
- if (log.topics[0] === FILE_TOPICHASH && log.topics[2] === DSR_TOPIC) {
76
+ if (
77
+ log.topics[0] === FILE_TOPICHASH &&
78
+ log.topics[2] === this.savingsRateTopic
79
+ ) {
73
80
  return {
74
81
  ...state,
75
82
  dsr: BigInt(log.topics[3]).toString(),
@@ -94,21 +101,17 @@ export class SparkSDaiEventPool extends StatefulEventSubscriber<SparkSDaiPoolSta
94
101
  this.dexHelper.multiContract,
95
102
  this.potAddress,
96
103
  this.potInterface,
104
+ this.savingsRateSymbol,
97
105
  blockNumber,
98
106
  );
99
107
  }
100
108
 
101
- convertToSDai(daiAmount: bigint, blockNumber: number): bigint {
102
- const state = this.getState(blockNumber);
103
- if (!state) throw new Error(`SDai state at ${blockNumber} does not exists`);
104
-
105
- return (daiAmount * RAY) / calcChi(state);
106
- }
107
-
108
- convertToDai(sdaiAmount: bigint, blockNumber: number): bigint {
109
- const state = this.getState(blockNumber);
110
- if (!state) throw new Error(`SDai state at ${blockNumber} does not exists`);
111
-
112
- return (sdaiAmount * calcChi(state)) / RAY;
109
+ async getOrGenerateState(blockNumber: number): Promise<SparkSDaiPoolState> {
110
+ let state = this.getState(blockNumber);
111
+ if (!state) {
112
+ state = await this.generateState(blockNumber);
113
+ this.setState(state, blockNumber);
114
+ }
115
+ return state;
113
116
  }
114
117
  }