@paraswap/dex-lib 3.8.35-usds-psm → 3.8.36-susds
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.
- package/build/abi/sdai/SavingsUSDS.abi.json +720 -0
- package/build/dex/spark/config.js +25 -0
- package/build/dex/spark/config.js.map +1 -1
- package/build/dex/spark/scripts/validate-state.js +1 -1
- package/build/dex/spark/scripts/validate-state.js.map +1 -1
- package/build/dex/spark/spark-sdai-pool.d.ts +4 -1
- package/build/dex/spark/spark-sdai-pool.js +6 -7
- package/build/dex/spark/spark-sdai-pool.js.map +1 -1
- package/build/dex/spark/spark.d.ts +3 -3
- package/build/dex/spark/spark.js +4 -4
- package/build/dex/spark/spark.js.map +1 -1
- package/build/dex/spark/types.d.ts +6 -0
- package/build/dex/spark/types.js.map +1 -1
- package/build/dex/spark/utils.d.ts +3 -1
- package/build/dex/spark/utils.js +43 -7
- package/build/dex/spark/utils.js.map +1 -1
- package/build/dex/usual-bond/usual-bond.js +5 -11
- package/build/dex/usual-bond/usual-bond.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/sdai/SavingsUSDS.abi.json +720 -0
- package/src/dex/spark/config.ts +24 -0
- package/src/dex/spark/scripts/validate-state.ts +1 -0
- package/src/dex/spark/spark-e2e.test.ts +28 -9
- package/src/dex/spark/spark-events.test.ts +77 -62
- package/src/dex/spark/spark-integration.test.ts +141 -7
- package/src/dex/spark/spark-sdai-pool.ts +10 -5
- package/src/dex/spark/spark.ts +6 -2
- package/src/dex/spark/types.ts +6 -0
- package/src/dex/spark/utils.ts +83 -19
- package/tests/constants-e2e.ts +5 -0
package/src/dex/spark/config.ts
CHANGED
|
@@ -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
|
};
|
|
@@ -26,17 +26,17 @@ function testForNetwork(
|
|
|
26
26
|
[
|
|
27
27
|
SwapSide.SELL,
|
|
28
28
|
[
|
|
29
|
-
ContractMethod.simpleSwap,
|
|
30
|
-
ContractMethod.multiSwap,
|
|
31
|
-
ContractMethod.megaSwap,
|
|
29
|
+
// ContractMethod.simpleSwap,
|
|
30
|
+
// ContractMethod.multiSwap,
|
|
31
|
+
// ContractMethod.megaSwap,
|
|
32
32
|
ContractMethod.swapExactAmountIn,
|
|
33
33
|
],
|
|
34
34
|
],
|
|
35
35
|
[
|
|
36
36
|
SwapSide.BUY,
|
|
37
37
|
[
|
|
38
|
-
ContractMethod.simpleBuy,
|
|
39
|
-
ContractMethod.buy,
|
|
38
|
+
// ContractMethod.simpleBuy,
|
|
39
|
+
// ContractMethod.buy,
|
|
40
40
|
ContractMethod.swapExactAmountOut,
|
|
41
41
|
],
|
|
42
42
|
],
|
|
@@ -80,10 +80,9 @@ function testForNetwork(
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
describe('
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
describe('Mainnet', () => {
|
|
83
|
+
describe('Spark E2E', () => {
|
|
84
|
+
describe('sDai', () => {
|
|
85
|
+
const dexKey = 'Spark';
|
|
87
86
|
const network = Network.MAINNET;
|
|
88
87
|
|
|
89
88
|
const tokenASymbol: string = 'DAI';
|
|
@@ -101,4 +100,24 @@ describe('sDAI E2E', () => {
|
|
|
101
100
|
tokenBAmount,
|
|
102
101
|
);
|
|
103
102
|
});
|
|
103
|
+
|
|
104
|
+
describe('sUSDS', () => {
|
|
105
|
+
const dexKey = 'sUSDS';
|
|
106
|
+
const network = Network.MAINNET;
|
|
107
|
+
|
|
108
|
+
const tokenASymbol: string = 'USDS';
|
|
109
|
+
const tokenBSymbol: string = 'sUSDS';
|
|
110
|
+
|
|
111
|
+
const tokenAAmount: string = '1000000000000000000';
|
|
112
|
+
const tokenBAmount: string = '1000000000000000000';
|
|
113
|
+
|
|
114
|
+
testForNetwork(
|
|
115
|
+
network,
|
|
116
|
+
dexKey,
|
|
117
|
+
tokenASymbol,
|
|
118
|
+
tokenBSymbol,
|
|
119
|
+
tokenAAmount,
|
|
120
|
+
tokenBAmount,
|
|
121
|
+
);
|
|
122
|
+
});
|
|
104
123
|
});
|
|
@@ -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
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
});
|
|
@@ -10,20 +10,20 @@ import { Spark } from './spark';
|
|
|
10
10
|
|
|
11
11
|
const network = Network.MAINNET;
|
|
12
12
|
|
|
13
|
-
const SDaiSymbol = 'sDAI';
|
|
14
|
-
const SDaiToken = Tokens[network][SDaiSymbol];
|
|
15
|
-
|
|
16
|
-
const DaiSymbol = 'DAI';
|
|
17
|
-
const DaiToken = Tokens[network][DaiSymbol];
|
|
18
|
-
|
|
19
13
|
const amounts = [0n, BI_POWS[18], 2000000000000000000n];
|
|
20
14
|
|
|
21
|
-
const dexKey = 'Spark';
|
|
22
15
|
const dexHelper = new DummyDexHelper(network);
|
|
23
16
|
let blocknumber: number;
|
|
24
17
|
let spark: Spark;
|
|
25
18
|
|
|
26
19
|
describe('Spark', function () {
|
|
20
|
+
const dexKey = 'Spark';
|
|
21
|
+
const SDaiSymbol = 'sDAI';
|
|
22
|
+
const SDaiToken = Tokens[network][SDaiSymbol];
|
|
23
|
+
|
|
24
|
+
const DaiSymbol = 'DAI';
|
|
25
|
+
const DaiToken = Tokens[network][DaiSymbol];
|
|
26
|
+
|
|
27
27
|
beforeAll(async () => {
|
|
28
28
|
blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
|
|
29
29
|
spark = new Spark(network, dexKey, dexHelper);
|
|
@@ -149,3 +149,137 @@ describe('Spark', function () {
|
|
|
149
149
|
checkPoolsLiquidity(poolLiquidity, SDaiToken.address, dexKey);
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
|
+
|
|
153
|
+
describe('sUSDS', function () {
|
|
154
|
+
const dexKey = 'sUSDS';
|
|
155
|
+
const SDaiSymbol = 'USDS';
|
|
156
|
+
const SDaiToken = Tokens[network][SDaiSymbol];
|
|
157
|
+
|
|
158
|
+
const DaiSymbol = 'sUSDS';
|
|
159
|
+
const DaiToken = Tokens[network][DaiSymbol];
|
|
160
|
+
|
|
161
|
+
beforeAll(async () => {
|
|
162
|
+
blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
|
|
163
|
+
spark = new Spark(network, dexKey, dexHelper);
|
|
164
|
+
if (spark.initializePricing) {
|
|
165
|
+
await spark.initializePricing(blocknumber);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('getPoolIdentifiers and getPricesVolume USDS -> sUSDS SELL', async function () {
|
|
170
|
+
const pools = await spark.getPoolIdentifiers(
|
|
171
|
+
DaiToken,
|
|
172
|
+
SDaiToken,
|
|
173
|
+
SwapSide.SELL,
|
|
174
|
+
blocknumber,
|
|
175
|
+
);
|
|
176
|
+
console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Identifiers: `, pools);
|
|
177
|
+
|
|
178
|
+
expect(pools.length).toBeGreaterThan(0);
|
|
179
|
+
|
|
180
|
+
const poolPrices = await spark.getPricesVolume(
|
|
181
|
+
DaiToken,
|
|
182
|
+
SDaiToken,
|
|
183
|
+
amounts,
|
|
184
|
+
SwapSide.SELL,
|
|
185
|
+
blocknumber,
|
|
186
|
+
pools,
|
|
187
|
+
);
|
|
188
|
+
console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Prices: `, poolPrices);
|
|
189
|
+
|
|
190
|
+
expect(poolPrices).not.toBeNull();
|
|
191
|
+
checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('getPoolIdentifiers and getPricesVolume sUSDS -> USDS SELL', async function () {
|
|
195
|
+
const pools = await spark.getPoolIdentifiers(
|
|
196
|
+
SDaiToken,
|
|
197
|
+
DaiToken,
|
|
198
|
+
SwapSide.SELL,
|
|
199
|
+
blocknumber,
|
|
200
|
+
);
|
|
201
|
+
console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Identifiers: `, pools);
|
|
202
|
+
|
|
203
|
+
expect(pools.length).toBeGreaterThan(0);
|
|
204
|
+
|
|
205
|
+
const poolPrices = await spark.getPricesVolume(
|
|
206
|
+
SDaiToken,
|
|
207
|
+
DaiToken,
|
|
208
|
+
amounts,
|
|
209
|
+
SwapSide.SELL,
|
|
210
|
+
blocknumber,
|
|
211
|
+
pools,
|
|
212
|
+
);
|
|
213
|
+
console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Prices: `, poolPrices);
|
|
214
|
+
|
|
215
|
+
expect(poolPrices).not.toBeNull();
|
|
216
|
+
checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('getPoolIdentifiers and getPricesVolume USDS -> sUSDS BUY', async function () {
|
|
220
|
+
const pools = await spark.getPoolIdentifiers(
|
|
221
|
+
DaiToken,
|
|
222
|
+
SDaiToken,
|
|
223
|
+
SwapSide.BUY,
|
|
224
|
+
blocknumber,
|
|
225
|
+
);
|
|
226
|
+
console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Identifiers: `, pools);
|
|
227
|
+
|
|
228
|
+
expect(pools.length).toBeGreaterThan(0);
|
|
229
|
+
|
|
230
|
+
const poolPrices = await spark.getPricesVolume(
|
|
231
|
+
DaiToken,
|
|
232
|
+
SDaiToken,
|
|
233
|
+
amounts,
|
|
234
|
+
SwapSide.BUY,
|
|
235
|
+
blocknumber,
|
|
236
|
+
pools,
|
|
237
|
+
);
|
|
238
|
+
console.log(`${DaiSymbol} <> ${SDaiSymbol} Pool Prices: `, poolPrices);
|
|
239
|
+
|
|
240
|
+
expect(poolPrices).not.toBeNull();
|
|
241
|
+
checkPoolPrices(poolPrices!, amounts, SwapSide.BUY, dexKey);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('getPoolIdentifiers and getPricesVolume sUSDS -> USDS BUY', async function () {
|
|
245
|
+
const pools = await spark.getPoolIdentifiers(
|
|
246
|
+
SDaiToken,
|
|
247
|
+
DaiToken,
|
|
248
|
+
SwapSide.BUY,
|
|
249
|
+
blocknumber,
|
|
250
|
+
);
|
|
251
|
+
console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Identifiers: `, pools);
|
|
252
|
+
|
|
253
|
+
expect(pools.length).toBeGreaterThan(0);
|
|
254
|
+
|
|
255
|
+
const poolPrices = await spark.getPricesVolume(
|
|
256
|
+
SDaiToken,
|
|
257
|
+
DaiToken,
|
|
258
|
+
amounts,
|
|
259
|
+
SwapSide.BUY,
|
|
260
|
+
blocknumber,
|
|
261
|
+
pools,
|
|
262
|
+
);
|
|
263
|
+
console.log(`${SDaiSymbol} <> ${DaiSymbol} Pool Prices: `, poolPrices);
|
|
264
|
+
|
|
265
|
+
expect(poolPrices).not.toBeNull();
|
|
266
|
+
checkPoolPrices(poolPrices!, amounts, SwapSide.BUY, dexKey);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('USDS getTopPoolsForToken', async function () {
|
|
270
|
+
const poolLiquidity = await spark.getTopPoolsForToken(DaiToken.address, 10);
|
|
271
|
+
console.log(`${DaiSymbol} Top Pools:`, poolLiquidity);
|
|
272
|
+
|
|
273
|
+
checkPoolsLiquidity(poolLiquidity, DaiToken.address, dexKey);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('sUSDS getTopPoolsForToken', async function () {
|
|
277
|
+
const poolLiquidity = await spark.getTopPoolsForToken(
|
|
278
|
+
SDaiToken.address,
|
|
279
|
+
10,
|
|
280
|
+
);
|
|
281
|
+
console.log(`${SDaiSymbol} Top Pools:`, poolLiquidity);
|
|
282
|
+
|
|
283
|
+
checkPoolsLiquidity(poolLiquidity, SDaiToken.address, dexKey);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
@@ -7,6 +7,8 @@ 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
13
|
const RAY = BI_POWS[27];
|
|
12
14
|
const ZERO = BigInt(0);
|
|
@@ -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;
|
|
@@ -54,11 +52,14 @@ const calcChi = (state: SparkSDaiPoolState, currentTimestamp?: number) => {
|
|
|
54
52
|
export class SparkSDaiEventPool extends StatefulEventSubscriber<SparkSDaiPoolState> {
|
|
55
53
|
constructor(
|
|
56
54
|
parentName: string,
|
|
55
|
+
network: Network,
|
|
57
56
|
poolName: string,
|
|
58
57
|
protected dexHelper: IDexHelper,
|
|
59
58
|
private potAddress: Address,
|
|
60
59
|
private potInterface: Interface,
|
|
61
60
|
logger: Logger,
|
|
61
|
+
private savingsRateTopic: string,
|
|
62
|
+
private savingsRateSymbol: 'ssr' | 'dsr',
|
|
62
63
|
) {
|
|
63
64
|
super(parentName, poolName, dexHelper, logger);
|
|
64
65
|
this.addressesSubscribed = [potAddress];
|
|
@@ -69,7 +70,10 @@ export class SparkSDaiEventPool extends StatefulEventSubscriber<SparkSDaiPoolSta
|
|
|
69
70
|
log: Readonly<Log>,
|
|
70
71
|
blockHeader: Readonly<BlockHeader>,
|
|
71
72
|
): AsyncOrSync<DeepReadonly<SparkSDaiPoolState> | null> {
|
|
72
|
-
if (
|
|
73
|
+
if (
|
|
74
|
+
log.topics[0] === FILE_TOPICHASH &&
|
|
75
|
+
log.topics[2] === this.savingsRateTopic
|
|
76
|
+
) {
|
|
73
77
|
return {
|
|
74
78
|
...state,
|
|
75
79
|
dsr: BigInt(log.topics[3]).toString(),
|
|
@@ -94,6 +98,7 @@ export class SparkSDaiEventPool extends StatefulEventSubscriber<SparkSDaiPoolSta
|
|
|
94
98
|
this.dexHelper.multiContract,
|
|
95
99
|
this.potAddress,
|
|
96
100
|
this.potInterface,
|
|
101
|
+
this.savingsRateSymbol,
|
|
97
102
|
blockNumber,
|
|
98
103
|
);
|
|
99
104
|
}
|
package/src/dex/spark/spark.ts
CHANGED
|
@@ -47,20 +47,24 @@ export class Spark
|
|
|
47
47
|
readonly daiAddress: string = SDaiConfig[dexKey][network].daiAddress,
|
|
48
48
|
readonly sdaiAddress: string = SDaiConfig[dexKey][network].sdaiAddress,
|
|
49
49
|
readonly potAddress: string = SDaiConfig[dexKey][network].potAddress,
|
|
50
|
+
readonly abiInterface: Interface = SDaiConfig[dexKey][network]
|
|
51
|
+
.poolInterface,
|
|
50
52
|
|
|
51
53
|
protected adapters = Adapters[network] || {},
|
|
52
54
|
protected sdaiInterface = new Interface(SavingsDaiAbi),
|
|
53
|
-
protected potInterface = new Interface(PotAbi),
|
|
54
55
|
) {
|
|
55
56
|
super(dexHelper, dexKey);
|
|
56
57
|
this.logger = dexHelper.getLogger(dexKey);
|
|
57
58
|
this.eventPool = new SparkSDaiEventPool(
|
|
58
59
|
this.dexKey,
|
|
60
|
+
this.network,
|
|
59
61
|
`${this.daiAddress}_${this.sdaiAddress}`,
|
|
60
62
|
dexHelper,
|
|
61
63
|
this.potAddress,
|
|
62
|
-
this.
|
|
64
|
+
this.abiInterface,
|
|
63
65
|
this.logger,
|
|
66
|
+
SDaiConfig[dexKey][network].savingsRate.topic,
|
|
67
|
+
SDaiConfig[dexKey][network].savingsRate.symbol,
|
|
64
68
|
);
|
|
65
69
|
}
|
|
66
70
|
|
package/src/dex/spark/types.ts
CHANGED
|
@@ -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 {
|
package/src/dex/spark/utils.ts
CHANGED
|
@@ -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
|
+
}
|
package/tests/constants-e2e.ts
CHANGED
|
@@ -19,6 +19,10 @@ export const Tokens: {
|
|
|
19
19
|
[network: number]: { [symbol: string]: SmartTokenParams };
|
|
20
20
|
} = {
|
|
21
21
|
[Network.MAINNET]: {
|
|
22
|
+
sUSDS: {
|
|
23
|
+
address: '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD',
|
|
24
|
+
decimals: 18,
|
|
25
|
+
},
|
|
22
26
|
USDS: {
|
|
23
27
|
address: '0xdC035D45d973E3EC169d2276DDab16f1e407384F',
|
|
24
28
|
decimals: 18,
|
|
@@ -1501,6 +1505,7 @@ export const Holders: {
|
|
|
1501
1505
|
} = {
|
|
1502
1506
|
[Network.MAINNET]: {
|
|
1503
1507
|
USDS: '0xB1796E8f1eEcF23027c1E3C00fE303629A189d10',
|
|
1508
|
+
sUSDS: '0xd564B3aE673CAa49D054Bf185bD72a6853763eE7',
|
|
1504
1509
|
SKY: '0x0ddda327A6614130CCb20bc0097313A282176A01',
|
|
1505
1510
|
MKR: '0xe9aAA7A9DDc0877626C1779AbC29993aD89A6c1f',
|
|
1506
1511
|
// Idle tokens
|