@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
@@ -1,6 +1,11 @@
1
1
  import { SimpleExchange } from '../simple-exchange';
2
2
  import { Context, IDex } from '../idex';
3
- import { SparkParams, SparkData, SparkSDaiFunctions } from './types';
3
+ import {
4
+ SparkParams,
5
+ SparkData,
6
+ SparkSDaiFunctions,
7
+ SparkSDaiPoolState,
8
+ } from './types';
4
9
  import { Network, SwapSide } from '../../constants';
5
10
  import { getDexKeysWithNetwork } from '../../utils';
6
11
  import { Adapters, SDaiConfig } from './config';
@@ -21,7 +26,7 @@ import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
21
26
  import PotAbi from '../../abi/maker-psm/pot.json';
22
27
  import SavingsDaiAbi from '../../abi/sdai/SavingsDai.abi.json';
23
28
  import { Interface } from 'ethers/lib/utils';
24
- import { SparkSDaiEventPool } from './spark-sdai-pool';
29
+ import { calcChi, RAY, SparkSDaiEventPool } from './spark-sdai-pool';
25
30
  import { BI_POWS } from '../../bigint-constants';
26
31
  import { SDAI_DEPOSIT_GAS_COST, SDAI_REDEEM_GAS_COST } from './constants';
27
32
  import { extractReturnAmountPosition } from '../../executor/utils';
@@ -42,25 +47,29 @@ export class Spark
42
47
  constructor(
43
48
  protected network: Network,
44
49
  dexKey: string,
45
- protected dexHelper: IDexHelper,
50
+ readonly dexHelper: IDexHelper,
46
51
 
47
52
  readonly daiAddress: string = SDaiConfig[dexKey][network].daiAddress,
48
53
  readonly sdaiAddress: string = SDaiConfig[dexKey][network].sdaiAddress,
49
54
  readonly potAddress: string = SDaiConfig[dexKey][network].potAddress,
55
+ readonly abiInterface: Interface = SDaiConfig[dexKey][network]
56
+ .poolInterface,
50
57
 
51
58
  protected adapters = Adapters[network] || {},
52
59
  protected sdaiInterface = new Interface(SavingsDaiAbi),
53
- protected potInterface = new Interface(PotAbi),
54
60
  ) {
55
61
  super(dexHelper, dexKey);
56
62
  this.logger = dexHelper.getLogger(dexKey);
57
63
  this.eventPool = new SparkSDaiEventPool(
58
64
  this.dexKey,
65
+ this.network,
59
66
  `${this.daiAddress}_${this.sdaiAddress}`,
60
67
  dexHelper,
61
68
  this.potAddress,
62
- this.potInterface,
69
+ this.abiInterface,
63
70
  this.logger,
71
+ SDaiConfig[dexKey][network].savingsRate.topic,
72
+ SDaiConfig[dexKey][network].savingsRate.symbol,
64
73
  );
65
74
  }
66
75
 
@@ -107,41 +116,38 @@ export class Spark
107
116
  limitPools?: string[],
108
117
  ): Promise<null | ExchangePrices<SparkData>> {
109
118
  if (!this.isAppropriatePair(srcToken, destToken)) return null;
110
- if (!this.eventPool.getState(blockNumber)) return null;
119
+ const state = this.eventPool.getState(blockNumber);
120
+ if (!state) return null;
121
+
122
+ const isSrcAsset = this.isDai(srcToken.address);
123
+
124
+ let calcFunction: Function;
111
125
 
112
126
  if (side === SwapSide.SELL) {
113
- const calcSellFn = (blockNumber: number, amountIn: bigint) =>
114
- this.isDai(srcToken.address)
115
- ? this.eventPool.convertToSDai(amountIn, blockNumber)
116
- : this.eventPool.convertToDai(amountIn, blockNumber);
117
-
118
- return [
119
- {
120
- prices: amounts.map(amount => calcSellFn(blockNumber, amount)),
121
- unit: calcSellFn(blockNumber, BI_POWS[18]),
122
- gasCost: SDAI_DEPOSIT_GAS_COST,
123
- exchange: this.dexKey,
124
- data: { exchange: `${this.sdaiAddress}` },
125
- poolAddresses: [`${this.sdaiAddress}`],
126
- },
127
- ];
127
+ if (isSrcAsset) {
128
+ calcFunction = this.previewDeposit.bind(this);
129
+ } else {
130
+ calcFunction = this.previewRedeem.bind(this);
131
+ }
128
132
  } else {
129
- const calcBuyFn = (blockNumber: number, amountIn: bigint) =>
130
- this.isDai(srcToken.address)
131
- ? this.eventPool.convertToDai(amountIn, blockNumber)
132
- : this.eventPool.convertToSDai(amountIn, blockNumber);
133
-
134
- return [
135
- {
136
- prices: amounts.map(amount => calcBuyFn(blockNumber, amount)),
137
- unit: calcBuyFn(blockNumber, BI_POWS[18]),
138
- gasCost: SDAI_REDEEM_GAS_COST,
139
- exchange: this.dexKey,
140
- data: { exchange: `${this.sdaiAddress}` },
141
- poolAddresses: [`${this.sdaiAddress}`],
142
- },
143
- ];
133
+ if (isSrcAsset) {
134
+ calcFunction = this.previewMint.bind(this);
135
+ } else {
136
+ calcFunction = this.previewWithdraw.bind(this);
137
+ }
144
138
  }
139
+
140
+ return [
141
+ {
142
+ // cannot produce 1:1 price without making an rpc call for block.timestamp and using it for price calculation in `calcChi` function
143
+ prices: amounts.map(amount => calcFunction(amount, state)),
144
+ unit: BI_POWS[18],
145
+ gasCost: SDAI_DEPOSIT_GAS_COST,
146
+ exchange: this.dexKey,
147
+ data: { exchange: `${this.sdaiAddress}` },
148
+ poolAddresses: [`${this.sdaiAddress}`],
149
+ },
150
+ ];
145
151
  }
146
152
 
147
153
  // Returns estimated gas cost of calldata for this DEX in multiSwap
@@ -286,4 +292,24 @@ export class Spark
286
292
  networkFee: '0',
287
293
  };
288
294
  }
295
+
296
+ previewRedeem(shares: bigint, state: SparkSDaiPoolState) {
297
+ return (shares * calcChi(state)) / RAY;
298
+ }
299
+
300
+ previewMint(shares: bigint, state: SparkSDaiPoolState) {
301
+ return this.divUp(shares * calcChi(state), RAY);
302
+ }
303
+
304
+ previewWithdraw(assets: bigint, state: SparkSDaiPoolState) {
305
+ return this.divUp(assets * RAY, calcChi(state));
306
+ }
307
+
308
+ previewDeposit(assets: bigint, state: SparkSDaiPoolState) {
309
+ return (assets * RAY) / calcChi(state);
310
+ }
311
+
312
+ divUp(x: bigint, y: bigint): bigint {
313
+ return x !== 0n ? (x - 1n) / y + 1n : 0n;
314
+ }
289
315
  }
@@ -1,3 +1,4 @@
1
+ import { Interface } from '@ethersproject/abi';
1
2
  import { Address } from '../../types';
2
3
 
3
4
  export type SparkData = { exchange: Address };
@@ -6,6 +7,11 @@ export type SparkParams = {
6
7
  sdaiAddress: Address;
7
8
  daiAddress: Address;
8
9
  potAddress: Address;
10
+ savingsRate: {
11
+ symbol: 'dsr' | 'ssr';
12
+ topic: string;
13
+ };
14
+ poolInterface: Interface;
9
15
  };
10
16
 
11
17
  export enum SparkSDaiFunctions {
@@ -4,34 +4,60 @@ import { Interface, AbiCoder } from '@ethersproject/abi';
4
4
 
5
5
  const coder = new AbiCoder();
6
6
 
7
- // - `dsr`: the Dai Savings Rate
7
+ // - `dsr` || `ssr`: the Dai Savings Rate or USDS savings rate
8
8
  // - `chi`: the Rate Accumulator
9
9
  // - `rho`: time of last drip
10
10
  export async function getOnChainState(
11
11
  multiContract: Contract,
12
12
  potAddress: string,
13
13
  potInterface: Interface,
14
+ savingsRateSymbol: 'dsr' | 'ssr',
14
15
  blockNumber: number | 'latest',
15
16
  ): Promise<SparkSDaiPoolState> {
17
+ if (savingsRateSymbol === 'dsr') {
18
+ return getOnChainStateSDAI(
19
+ multiContract,
20
+ potAddress,
21
+ potInterface,
22
+ blockNumber,
23
+ );
24
+ }
25
+
26
+ return getOnChainStateUSDS(
27
+ multiContract,
28
+ potAddress,
29
+ potInterface,
30
+ blockNumber,
31
+ );
32
+ }
33
+
34
+ export async function getOnChainStateSDAI(
35
+ multiContract: Contract,
36
+ potAddress: string,
37
+ potInterface: Interface,
38
+ blockNumber: number | 'latest',
39
+ ): Promise<SparkSDaiPoolState> {
40
+ const calls = [
41
+ {
42
+ target: potAddress,
43
+ callData: potInterface.encodeFunctionData('dsr', []),
44
+ },
45
+ {
46
+ target: potAddress,
47
+ callData: potInterface.encodeFunctionData('chi', []),
48
+ },
49
+ {
50
+ target: potAddress,
51
+ callData: potInterface.encodeFunctionData('rho', []),
52
+ },
53
+ {
54
+ target: potAddress,
55
+ callData: potInterface.encodeFunctionData('live', []),
56
+ },
57
+ ];
58
+
16
59
  const data: { returnData: any[] } = await multiContract.methods
17
- .aggregate([
18
- {
19
- target: potAddress,
20
- callData: potInterface.encodeFunctionData('dsr', []),
21
- },
22
- {
23
- target: potAddress,
24
- callData: potInterface.encodeFunctionData('chi', []),
25
- },
26
- {
27
- target: potAddress,
28
- callData: potInterface.encodeFunctionData('rho', []),
29
- },
30
- {
31
- target: potAddress,
32
- callData: potInterface.encodeFunctionData('live', []),
33
- },
34
- ])
60
+ .aggregate(calls)
35
61
  .call({}, blockNumber);
36
62
 
37
63
  const [dsr, chi, rho, live] = data.returnData.map(item =>
@@ -45,3 +71,41 @@ export async function getOnChainState(
45
71
  rho,
46
72
  };
47
73
  }
74
+
75
+ export async function getOnChainStateUSDS(
76
+ multiContract: Contract,
77
+ potAddress: string,
78
+ potInterface: Interface,
79
+ blockNumber: number | 'latest',
80
+ ): Promise<SparkSDaiPoolState> {
81
+ const calls = [
82
+ {
83
+ target: potAddress,
84
+ callData: potInterface.encodeFunctionData('ssr', []),
85
+ },
86
+ {
87
+ target: potAddress,
88
+ callData: potInterface.encodeFunctionData('chi', []),
89
+ },
90
+ {
91
+ target: potAddress,
92
+ callData: potInterface.encodeFunctionData('rho', []),
93
+ },
94
+ ];
95
+
96
+ const data: { returnData: any[] } = await multiContract.methods
97
+ .aggregate(calls)
98
+ .call({}, blockNumber);
99
+
100
+ const [dsr, chi, rho] = data.returnData.map(item =>
101
+ coder.decode(['uint256'], item)[0].toString(),
102
+ );
103
+
104
+ return {
105
+ // 'hack' - sUSDS doesn't have global shutdown and no notion of `live`, so it's always `live`
106
+ live: true,
107
+ dsr,
108
+ chi,
109
+ rho,
110
+ };
111
+ }
@@ -0,0 +1,12 @@
1
+ import { DexParams } from './types';
2
+ import { DexConfigMap } from '../../types';
3
+ import { Network } from '../../constants';
4
+
5
+ export const UsualBondConfig: DexConfigMap<DexParams> = {
6
+ UsualBond: {
7
+ [Network.MAINNET]: {
8
+ usd0Address: '0x73A15FeD60Bf67631dC6cd7Bc5B6e8da8190aCF5',
9
+ usd0ppAddress: '0x35D8949372D46B7a3D5A56006AE77B215fc69bC0',
10
+ },
11
+ },
12
+ };
@@ -0,0 +1,10 @@
1
+ import { Address } from '../../types';
2
+
3
+ export type PoolState = {};
4
+
5
+ export type UsualBondData = {};
6
+
7
+ export type DexParams = {
8
+ usd0Address: Address;
9
+ usd0ppAddress: Address;
10
+ };
@@ -0,0 +1,80 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { testE2E } from '../../../tests/utils-e2e';
6
+ import {
7
+ Tokens,
8
+ Holders,
9
+ NativeTokenSymbols,
10
+ } from '../../../tests/constants-e2e';
11
+ import { Network, ContractMethod, SwapSide } from '../../constants';
12
+ import { StaticJsonRpcProvider } from '@ethersproject/providers';
13
+ import { generateConfig } from '../../config';
14
+
15
+ function testForNetwork(
16
+ network: Network,
17
+ dexKey: string,
18
+ tokenASymbol: string,
19
+ tokenBSymbol: string,
20
+ tokenAAmount: string,
21
+ tokenBAmount: string,
22
+ ) {
23
+ const provider = new StaticJsonRpcProvider(
24
+ generateConfig(network).privateHttpProvider,
25
+ network,
26
+ );
27
+ const tokens = Tokens[network];
28
+ const holders = Holders[network];
29
+
30
+ const sideToContractMethods = new Map([
31
+ [SwapSide.SELL, [ContractMethod.swapExactAmountIn]],
32
+ ]);
33
+
34
+ describe(`${network}`, () => {
35
+ sideToContractMethods.forEach((contractMethods, side) =>
36
+ describe(`${side}`, () => {
37
+ contractMethods.forEach((contractMethod: ContractMethod) => {
38
+ describe(`${contractMethod}`, () => {
39
+ it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => {
40
+ await testE2E(
41
+ tokens[tokenASymbol],
42
+ tokens[tokenBSymbol],
43
+ holders[tokenASymbol],
44
+ side === SwapSide.SELL ? tokenAAmount : tokenBAmount,
45
+ side,
46
+ dexKey,
47
+ contractMethod,
48
+ network,
49
+ provider,
50
+ );
51
+ });
52
+ });
53
+ });
54
+ }),
55
+ );
56
+ });
57
+ }
58
+
59
+ describe('UsualBond E2E', () => {
60
+ const dexKey = 'UsualBond';
61
+
62
+ describe('Mainnet', () => {
63
+ const network = Network.MAINNET;
64
+
65
+ const tokenASymbol: string = 'USD0';
66
+ const tokenBSymbol: string = 'USD0++';
67
+
68
+ const tokenAAmount: string = '100000';
69
+ const tokenBAmount: string = '100000';
70
+
71
+ testForNetwork(
72
+ network,
73
+ dexKey,
74
+ tokenASymbol,
75
+ tokenBSymbol,
76
+ tokenAAmount,
77
+ tokenBAmount,
78
+ );
79
+ });
80
+ });
@@ -0,0 +1,144 @@
1
+ /* eslint-disable no-console */
2
+ import dotenv from 'dotenv';
3
+ dotenv.config();
4
+
5
+ import { Interface } from '@ethersproject/abi';
6
+ import { DummyDexHelper } from '../../dex-helper/index';
7
+ import { Network, SwapSide } from '../../constants';
8
+ import { BI_POWS } from '../../bigint-constants';
9
+ import { UsualBond } from './usual-bond';
10
+ import {
11
+ checkPoolPrices,
12
+ checkConstantPoolPrices,
13
+ checkPoolsLiquidity,
14
+ } from '../../../tests/utils';
15
+ import { Tokens } from '../../../tests/constants-e2e';
16
+
17
+ async function testPricingOnNetwork(
18
+ usualBond: UsualBond,
19
+ network: Network,
20
+ dexKey: string,
21
+ blockNumber: number,
22
+ srcTokenAddress: string,
23
+ destTokenAddress: string,
24
+ side: SwapSide,
25
+ amounts: bigint[],
26
+ funcNameToCheck: string,
27
+ ) {
28
+ const networkTokens = Tokens[network];
29
+
30
+ console.log(amounts);
31
+
32
+ const pools = await usualBond.getPoolIdentifiers(
33
+ networkTokens['USD0'],
34
+ networkTokens['USD0++'],
35
+ side,
36
+ blockNumber,
37
+ );
38
+ console.log(`${'USD0'} <> ${'USD0++'} Pool Identifiers: `, pools);
39
+
40
+ expect(pools.length).toBeGreaterThan(0);
41
+
42
+ const poolPrices = await usualBond.getPricesVolume(
43
+ networkTokens['USD0'],
44
+ networkTokens['USD0++'],
45
+ amounts,
46
+ side,
47
+ blockNumber,
48
+ pools,
49
+ );
50
+ console.log(`${'USD0'} <> ${'USD0++'} Pool Prices: `, poolPrices);
51
+
52
+ expect(poolPrices).not.toBeNull();
53
+ if (usualBond.hasConstantPriceLargeAmounts) {
54
+ checkConstantPoolPrices(poolPrices!, amounts, dexKey);
55
+ } else {
56
+ checkPoolPrices(poolPrices!, amounts, side, dexKey);
57
+ }
58
+
59
+ // Check if onchain pricing equals to calculated ones
60
+ checkPoolPrices(poolPrices!, amounts, side, dexKey);
61
+ }
62
+
63
+ describe('UsualBond', function () {
64
+ const dexKey = 'UsualBond';
65
+ let blockNumber: number;
66
+ let usualBond: UsualBond;
67
+
68
+ describe('Mainnet', () => {
69
+ const network = Network.MAINNET;
70
+ const dexHelper = new DummyDexHelper(network);
71
+
72
+ // Don't forget to update relevant tokens in constant-e2e.ts
73
+
74
+ const amountsForSell = [
75
+ 0n,
76
+ 1n * BI_POWS[18],
77
+ 2n * BI_POWS[18],
78
+ 3n * BI_POWS[18],
79
+ 4n * BI_POWS[18],
80
+ 5n * BI_POWS[18],
81
+ 6n * BI_POWS[18],
82
+ 7n * BI_POWS[18],
83
+ 8n * BI_POWS[18],
84
+ 9n * BI_POWS[18],
85
+ 10n * BI_POWS[18],
86
+ ];
87
+
88
+ beforeAll(async () => {
89
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
90
+ usualBond = new UsualBond(network, dexKey, dexHelper);
91
+ if (usualBond.initializePricing) {
92
+ await usualBond.initializePricing(blockNumber);
93
+ }
94
+ });
95
+
96
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
97
+ await testPricingOnNetwork(
98
+ usualBond,
99
+ network,
100
+ dexKey,
101
+ blockNumber,
102
+ 'USD0',
103
+ 'USD0++',
104
+ SwapSide.SELL,
105
+ amountsForSell,
106
+ '',
107
+ );
108
+ });
109
+
110
+ it('getTopPoolsForToken: USD0', async function () {
111
+ const tokenA = Tokens[network]['USD0'];
112
+ const dexHelper = new DummyDexHelper(network);
113
+ const usualBond = new UsualBond(network, dexKey, dexHelper);
114
+
115
+ const poolLiquidity = await usualBond.getTopPoolsForToken(
116
+ tokenA.address,
117
+ 10,
118
+ );
119
+ console.log(
120
+ `${tokenA.symbol} Top Pools:`,
121
+ JSON.stringify(poolLiquidity, null, 2),
122
+ );
123
+
124
+ checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey);
125
+ });
126
+
127
+ it('getTopPoolsForToken: USD0++', async function () {
128
+ const tokenA = Tokens[network]['USD0++'];
129
+ const dexHelper = new DummyDexHelper(network);
130
+ const usualBond = new UsualBond(network, dexKey, dexHelper);
131
+
132
+ const poolLiquidity = await usualBond.getTopPoolsForToken(
133
+ tokenA.address,
134
+ 10,
135
+ );
136
+ console.log(
137
+ `${tokenA.symbol} Top Pools:`,
138
+ JSON.stringify(poolLiquidity, null, 2),
139
+ );
140
+
141
+ checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey);
142
+ });
143
+ });
144
+ });