@paraswap/dex-lib 3.8.24 → 3.8.26-aave-gsm
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/Aave_GSM.json +751 -0
- package/build/dex/aave-gsm/aave-gsm.d.ts +33 -0
- package/build/dex/aave-gsm/aave-gsm.js +278 -0
- package/build/dex/aave-gsm/aave-gsm.js.map +1 -0
- package/build/dex/aave-gsm/config.d.ts +3 -0
- package/build/dex/aave-gsm/config.js +17 -0
- package/build/dex/aave-gsm/config.js.map +1 -0
- package/build/dex/aave-gsm/types.d.ts +11 -0
- package/build/dex/aave-gsm/types.js +3 -0
- package/build/dex/aave-gsm/types.js.map +1 -0
- package/build/dex/generic-rfq/rate-fetcher.js +1 -1
- package/build/dex/generic-rfq/rate-fetcher.js.map +1 -1
- package/build/dex/inception/inception-event-pool.d.ts +6 -4
- package/build/dex/inception/inception-event-pool.js +31 -8
- package/build/dex/inception/inception-event-pool.js.map +1 -1
- package/build/dex/inception/inception.js +16 -1
- package/build/dex/inception/inception.js.map +1 -1
- package/build/dex/index.js +4 -0
- package/build/dex/index.js.map +1 -1
- package/build/dex/oswap/oswap-pool.js +8 -8
- package/build/dex/oswap/oswap-pool.js.map +1 -1
- package/build/dex/oswap/oswap.d.ts +3 -3
- package/build/dex/oswap/oswap.js +21 -12
- package/build/dex/oswap/oswap.js.map +1 -1
- package/build/dex/oswap/types.d.ts +4 -4
- package/package.json +1 -1
- package/src/abi/Aave_GSM.json +751 -0
- package/src/abi/oswap/oswap.abi.json +452 -0
- package/src/dex/aave-gsm/aave-gsm-e2e.test.ts +109 -0
- package/src/dex/aave-gsm/aave-gsm-integration.test.ts +318 -0
- package/src/dex/aave-gsm/aave-gsm.ts +359 -0
- package/src/dex/aave-gsm/config.ts +16 -0
- package/src/dex/aave-gsm/types.ts +15 -0
- package/src/dex/generic-rfq/rate-fetcher.ts +6 -5
- package/src/dex/index.ts +4 -0
- package/src/dex/oswap/config.ts +32 -0
- package/src/dex/oswap/oswap-e2e.test.ts +91 -0
- package/src/dex/oswap/oswap-events.test.ts +88 -0
- package/src/dex/oswap/oswap-integration.test.ts +291 -0
- package/src/dex/oswap/oswap-pool.ts +190 -0
- package/src/dex/oswap/oswap.ts +414 -0
- package/src/dex/oswap/types.ts +29 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
dotenv.config();
|
|
4
|
+
|
|
5
|
+
import { Interface, Result } 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 { AaveGsm } from './aave-gsm';
|
|
10
|
+
import {
|
|
11
|
+
checkPoolPrices,
|
|
12
|
+
checkPoolsLiquidity,
|
|
13
|
+
checkConstantPoolPrices,
|
|
14
|
+
} from '../../../tests/utils';
|
|
15
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
16
|
+
import GSM_ABI from '../../abi/Aave_GSM.json';
|
|
17
|
+
|
|
18
|
+
function getReaderCalldata(
|
|
19
|
+
exchangeAddress: string,
|
|
20
|
+
readerIface: Interface,
|
|
21
|
+
amounts: bigint[],
|
|
22
|
+
funcName: string,
|
|
23
|
+
) {
|
|
24
|
+
return amounts.map(amount => ({
|
|
25
|
+
target: exchangeAddress,
|
|
26
|
+
callData: readerIface.encodeFunctionData(funcName, [amount]),
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function decodeReaderResult(
|
|
31
|
+
results: Result,
|
|
32
|
+
readerIface: Interface,
|
|
33
|
+
funcName: string,
|
|
34
|
+
index: number,
|
|
35
|
+
) {
|
|
36
|
+
return results.map(result => {
|
|
37
|
+
const parsed = readerIface.decodeFunctionResult(funcName, result);
|
|
38
|
+
return BigInt(parsed[index]._hex);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function checkOnChainPricing(
|
|
43
|
+
aaveGsm: AaveGsm,
|
|
44
|
+
funcName: string,
|
|
45
|
+
blockNumber: number,
|
|
46
|
+
prices: bigint[],
|
|
47
|
+
amounts: bigint[],
|
|
48
|
+
) {
|
|
49
|
+
const exchangeAddress = '0x686F8D21520f4ecEc7ba577be08354F4d1EB8262'; // TODO: Put here the real exchange address
|
|
50
|
+
const readerIface = new Interface(GSM_ABI);
|
|
51
|
+
|
|
52
|
+
const readerCallData = getReaderCalldata(
|
|
53
|
+
exchangeAddress,
|
|
54
|
+
readerIface,
|
|
55
|
+
amounts.slice(1),
|
|
56
|
+
funcName,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const readerResult = (
|
|
60
|
+
await aaveGsm.dexHelper.multiContract.methods
|
|
61
|
+
.aggregate(readerCallData)
|
|
62
|
+
.call({}, blockNumber)
|
|
63
|
+
).returnData;
|
|
64
|
+
|
|
65
|
+
const expectedPrices = [0n].concat(
|
|
66
|
+
decodeReaderResult(
|
|
67
|
+
readerResult,
|
|
68
|
+
readerIface,
|
|
69
|
+
funcName,
|
|
70
|
+
funcName.indexOf('getGho') == 0 ? 1 : 0,
|
|
71
|
+
),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
expect(prices).toEqual(expectedPrices);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function testPricingOnNetwork(
|
|
78
|
+
aaveGsm: AaveGsm,
|
|
79
|
+
network: Network,
|
|
80
|
+
dexKey: string,
|
|
81
|
+
blockNumber: number,
|
|
82
|
+
srcTokenSymbol: string,
|
|
83
|
+
destTokenSymbol: string,
|
|
84
|
+
side: SwapSide,
|
|
85
|
+
amounts: bigint[],
|
|
86
|
+
funcNameToCheck: string,
|
|
87
|
+
) {
|
|
88
|
+
const networkTokens = Tokens[network];
|
|
89
|
+
|
|
90
|
+
const pools = await aaveGsm.getPoolIdentifiers(
|
|
91
|
+
networkTokens[srcTokenSymbol],
|
|
92
|
+
networkTokens[destTokenSymbol],
|
|
93
|
+
side,
|
|
94
|
+
blockNumber,
|
|
95
|
+
);
|
|
96
|
+
console.log(
|
|
97
|
+
`${srcTokenSymbol} <> ${destTokenSymbol} Pool Identifiers: `,
|
|
98
|
+
pools,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
expect(pools.length).toBeGreaterThan(0);
|
|
102
|
+
|
|
103
|
+
const poolPrices = await aaveGsm.getPricesVolume(
|
|
104
|
+
networkTokens[srcTokenSymbol],
|
|
105
|
+
networkTokens[destTokenSymbol],
|
|
106
|
+
amounts,
|
|
107
|
+
side,
|
|
108
|
+
blockNumber,
|
|
109
|
+
pools,
|
|
110
|
+
);
|
|
111
|
+
console.log(
|
|
112
|
+
`${srcTokenSymbol} <> ${destTokenSymbol} Pool Prices: `,
|
|
113
|
+
poolPrices,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(poolPrices).not.toBeNull();
|
|
117
|
+
if (aaveGsm.hasConstantPriceLargeAmounts) {
|
|
118
|
+
checkConstantPoolPrices(poolPrices!, amounts, dexKey);
|
|
119
|
+
} else {
|
|
120
|
+
checkPoolPrices(poolPrices!, amounts, side, dexKey);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check if onchain pricing equals to calculated ones
|
|
124
|
+
await checkOnChainPricing(
|
|
125
|
+
aaveGsm,
|
|
126
|
+
funcNameToCheck,
|
|
127
|
+
blockNumber,
|
|
128
|
+
poolPrices![0].prices,
|
|
129
|
+
amounts,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
describe('AaveGsm', function () {
|
|
134
|
+
const dexKey = 'AaveGsm';
|
|
135
|
+
let blockNumber: number;
|
|
136
|
+
let aaveGsm: AaveGsm;
|
|
137
|
+
|
|
138
|
+
describe('Mainnet GSM_USDT', () => {
|
|
139
|
+
const network = Network.MAINNET;
|
|
140
|
+
const dexHelper = new DummyDexHelper(network);
|
|
141
|
+
|
|
142
|
+
const tokens = Tokens[network];
|
|
143
|
+
|
|
144
|
+
const srcTokenSymbol = 'USDT';
|
|
145
|
+
const destTokenSymbol = 'GHO';
|
|
146
|
+
|
|
147
|
+
const amountsForSell = [
|
|
148
|
+
0n,
|
|
149
|
+
1n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
150
|
+
2n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
151
|
+
3n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
152
|
+
4n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
153
|
+
5n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
154
|
+
6n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
155
|
+
7n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
156
|
+
8n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
157
|
+
9n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
158
|
+
10n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
const amountsForBuy = [
|
|
162
|
+
0n,
|
|
163
|
+
1n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
164
|
+
2n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
165
|
+
3n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
166
|
+
4n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
167
|
+
5n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
168
|
+
6n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
169
|
+
7n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
170
|
+
8n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
171
|
+
9n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
172
|
+
10n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
beforeAll(async () => {
|
|
176
|
+
blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
|
|
177
|
+
aaveGsm = new AaveGsm(network, dexKey, dexHelper);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('getPoolIdentifiers and getPricesVolume SELL', async function () {
|
|
181
|
+
await testPricingOnNetwork(
|
|
182
|
+
aaveGsm,
|
|
183
|
+
network,
|
|
184
|
+
dexKey,
|
|
185
|
+
blockNumber,
|
|
186
|
+
srcTokenSymbol,
|
|
187
|
+
destTokenSymbol,
|
|
188
|
+
SwapSide.SELL,
|
|
189
|
+
amountsForSell,
|
|
190
|
+
'getGhoAmountForSellAsset',
|
|
191
|
+
);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('getPoolIdentifiers and getPricesVolume BUY', async function () {
|
|
195
|
+
await testPricingOnNetwork(
|
|
196
|
+
aaveGsm,
|
|
197
|
+
network,
|
|
198
|
+
dexKey,
|
|
199
|
+
blockNumber,
|
|
200
|
+
srcTokenSymbol,
|
|
201
|
+
destTokenSymbol,
|
|
202
|
+
SwapSide.BUY,
|
|
203
|
+
amountsForBuy,
|
|
204
|
+
'getAssetAmountForSellAsset',
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('getTopPoolsForToken', async function () {
|
|
209
|
+
// We have to check without calling initializePricing, because
|
|
210
|
+
// pool-tracker is not calling that function
|
|
211
|
+
const newAaveGsm = new AaveGsm(network, dexKey, dexHelper);
|
|
212
|
+
const poolLiquidity = await newAaveGsm.getTopPoolsForToken(
|
|
213
|
+
tokens[srcTokenSymbol].address,
|
|
214
|
+
10,
|
|
215
|
+
);
|
|
216
|
+
console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity);
|
|
217
|
+
|
|
218
|
+
if (!newAaveGsm.hasConstantPriceLargeAmounts) {
|
|
219
|
+
checkPoolsLiquidity(
|
|
220
|
+
poolLiquidity,
|
|
221
|
+
Tokens[network][srcTokenSymbol].address,
|
|
222
|
+
dexKey,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('Mainnet GSM_USDC', () => {
|
|
229
|
+
const network = Network.MAINNET;
|
|
230
|
+
const dexHelper = new DummyDexHelper(network);
|
|
231
|
+
|
|
232
|
+
const tokens = Tokens[network];
|
|
233
|
+
|
|
234
|
+
// Don't forget to update relevant tokens in constant-e2e.ts
|
|
235
|
+
const srcTokenSymbol = 'USDC';
|
|
236
|
+
const destTokenSymbol = 'GHO';
|
|
237
|
+
|
|
238
|
+
const amountsForSell = [
|
|
239
|
+
0n,
|
|
240
|
+
1n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
241
|
+
2n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
242
|
+
3n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
243
|
+
4n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
244
|
+
5n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
245
|
+
6n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
246
|
+
7n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
247
|
+
8n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
248
|
+
9n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
249
|
+
10n * BI_POWS[tokens[srcTokenSymbol].decimals],
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
const amountsForBuy = [
|
|
253
|
+
0n,
|
|
254
|
+
1n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
255
|
+
2n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
256
|
+
3n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
257
|
+
4n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
258
|
+
5n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
259
|
+
6n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
260
|
+
7n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
261
|
+
8n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
262
|
+
9n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
263
|
+
10n * BI_POWS[tokens[destTokenSymbol].decimals],
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
beforeAll(async () => {
|
|
267
|
+
blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
|
|
268
|
+
aaveGsm = new AaveGsm(network, dexKey, dexHelper);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('getPoolIdentifiers and getPricesVolume SELL', async function () {
|
|
272
|
+
await testPricingOnNetwork(
|
|
273
|
+
aaveGsm,
|
|
274
|
+
network,
|
|
275
|
+
dexKey,
|
|
276
|
+
blockNumber,
|
|
277
|
+
srcTokenSymbol,
|
|
278
|
+
destTokenSymbol,
|
|
279
|
+
SwapSide.SELL,
|
|
280
|
+
amountsForSell,
|
|
281
|
+
'getGhoAmountForSellAsset',
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('getPoolIdentifiers and getPricesVolume BUY', async function () {
|
|
286
|
+
await testPricingOnNetwork(
|
|
287
|
+
aaveGsm,
|
|
288
|
+
network,
|
|
289
|
+
dexKey,
|
|
290
|
+
blockNumber,
|
|
291
|
+
srcTokenSymbol,
|
|
292
|
+
destTokenSymbol,
|
|
293
|
+
SwapSide.BUY,
|
|
294
|
+
amountsForBuy,
|
|
295
|
+
'getAssetAmountForSellAsset',
|
|
296
|
+
);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('getTopPoolsForToken', async function () {
|
|
300
|
+
// We have to check without calling initializePricing, because
|
|
301
|
+
// pool-tracker is not calling that function
|
|
302
|
+
const newAaveGsm = new AaveGsm(network, dexKey, dexHelper);
|
|
303
|
+
const poolLiquidity = await newAaveGsm.getTopPoolsForToken(
|
|
304
|
+
tokens[srcTokenSymbol].address,
|
|
305
|
+
10,
|
|
306
|
+
);
|
|
307
|
+
console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity);
|
|
308
|
+
|
|
309
|
+
if (!newAaveGsm.hasConstantPriceLargeAmounts) {
|
|
310
|
+
checkPoolsLiquidity(
|
|
311
|
+
poolLiquidity,
|
|
312
|
+
Tokens[network][srcTokenSymbol].address,
|
|
313
|
+
dexKey,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Token,
|
|
3
|
+
Address,
|
|
4
|
+
ExchangePrices,
|
|
5
|
+
PoolPrices,
|
|
6
|
+
AdapterExchangeParam,
|
|
7
|
+
PoolLiquidity,
|
|
8
|
+
Logger,
|
|
9
|
+
NumberAsString,
|
|
10
|
+
DexExchangeParam,
|
|
11
|
+
} from '../../types';
|
|
12
|
+
import { SwapSide, Network } from '../../constants';
|
|
13
|
+
import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
|
|
14
|
+
import { getDexKeysWithNetwork } from '../../utils';
|
|
15
|
+
import { IDex } from '../../dex/idex';
|
|
16
|
+
import { IDexHelper } from '../../dex-helper/idex-helper';
|
|
17
|
+
import { AaveGsmData, DexParams } from './types';
|
|
18
|
+
import { SimpleExchange } from '../simple-exchange';
|
|
19
|
+
import { AaveGsmConfig } from './config';
|
|
20
|
+
|
|
21
|
+
import GSM_ABI from '../../abi/Aave_GSM.json';
|
|
22
|
+
import { Interface } from '@ethersproject/abi';
|
|
23
|
+
import { MultiResult } from '../../lib/multi-wrapper';
|
|
24
|
+
import { BytesLike } from 'ethers';
|
|
25
|
+
import { generalDecoder } from '../../lib/decoders';
|
|
26
|
+
import { parseUnits } from 'ethers/lib/utils';
|
|
27
|
+
|
|
28
|
+
export class AaveGsm extends SimpleExchange implements IDex<AaveGsmData> {
|
|
29
|
+
static readonly gsmInterface = new Interface(GSM_ABI);
|
|
30
|
+
|
|
31
|
+
protected config: DexParams;
|
|
32
|
+
|
|
33
|
+
readonly hasConstantPriceLargeAmounts = false;
|
|
34
|
+
readonly needWrapNative = false;
|
|
35
|
+
|
|
36
|
+
readonly isFeeOnTransferSupported = false;
|
|
37
|
+
|
|
38
|
+
public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
|
|
39
|
+
getDexKeysWithNetwork(AaveGsmConfig);
|
|
40
|
+
|
|
41
|
+
logger: Logger;
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
readonly network: Network,
|
|
45
|
+
readonly dexKey: string,
|
|
46
|
+
readonly dexHelper: IDexHelper,
|
|
47
|
+
) {
|
|
48
|
+
super(dexHelper, dexKey);
|
|
49
|
+
const config = AaveGsmConfig[dexKey][network];
|
|
50
|
+
this.config = {
|
|
51
|
+
GSM_USDT: config.GSM_USDT.toLowerCase(),
|
|
52
|
+
GSM_USDC: config.GSM_USDC.toLowerCase(),
|
|
53
|
+
USDT: config.USDT.toLowerCase(),
|
|
54
|
+
USDC: config.USDC.toLowerCase(),
|
|
55
|
+
GHO: config.GHO.toLowerCase(),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
this.logger = dexHelper.getLogger(dexKey);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getAdapters(side: SwapSide): { name: string; index: number }[] | null {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async getPoolIdentifiers(
|
|
66
|
+
srcToken: Token,
|
|
67
|
+
destToken: Token,
|
|
68
|
+
side: SwapSide,
|
|
69
|
+
blockNumber: number,
|
|
70
|
+
): Promise<string[]> {
|
|
71
|
+
const srcTokenAddress = srcToken.address.toLowerCase();
|
|
72
|
+
const destTokenAddress = destToken.address.toLowerCase();
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
(srcTokenAddress === this.config.GHO &&
|
|
76
|
+
destTokenAddress === this.config.USDT) ||
|
|
77
|
+
(srcTokenAddress === this.config.USDT &&
|
|
78
|
+
destTokenAddress === this.config.GHO)
|
|
79
|
+
) {
|
|
80
|
+
return [`${this.dexKey}_${this.config.GSM_USDT}`];
|
|
81
|
+
} else if (
|
|
82
|
+
(srcTokenAddress === this.config.GHO &&
|
|
83
|
+
destTokenAddress === this.config.USDC) ||
|
|
84
|
+
(srcTokenAddress === this.config.USDC &&
|
|
85
|
+
destTokenAddress === this.config.GHO)
|
|
86
|
+
) {
|
|
87
|
+
return [`${this.dexKey}_${this.config.GSM_USDC}`];
|
|
88
|
+
} else {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Returns pool prices for amounts.
|
|
94
|
+
// If limitPools is defined only pools in limitPools
|
|
95
|
+
// should be used. If limitPools is undefined then
|
|
96
|
+
// any pools can be used.
|
|
97
|
+
async getPricesVolume(
|
|
98
|
+
srcToken: Token,
|
|
99
|
+
destToken: Token,
|
|
100
|
+
amounts: bigint[],
|
|
101
|
+
side: SwapSide,
|
|
102
|
+
blockNumber: number,
|
|
103
|
+
limitPools?: string[],
|
|
104
|
+
): Promise<null | ExchangePrices<AaveGsmData>> {
|
|
105
|
+
const srcTokenAddress = srcToken.address.toLowerCase();
|
|
106
|
+
const destTokenAddress = destToken.address.toLowerCase();
|
|
107
|
+
|
|
108
|
+
if (
|
|
109
|
+
!(
|
|
110
|
+
(srcTokenAddress == this.config.GHO &&
|
|
111
|
+
(destTokenAddress == this.config.USDC ||
|
|
112
|
+
destTokenAddress == this.config.USDT)) ||
|
|
113
|
+
(destTokenAddress == this.config.GHO &&
|
|
114
|
+
(srcTokenAddress == this.config.USDC ||
|
|
115
|
+
srcTokenAddress == this.config.USDT))
|
|
116
|
+
)
|
|
117
|
+
) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let endpoint: string;
|
|
122
|
+
let target: string;
|
|
123
|
+
let resultIsGho: boolean;
|
|
124
|
+
if (srcTokenAddress == this.config.GHO && side == SwapSide.BUY) {
|
|
125
|
+
endpoint = 'getGhoAmountForBuyAsset';
|
|
126
|
+
resultIsGho = true;
|
|
127
|
+
} else if (srcTokenAddress == this.config.GHO && side == SwapSide.SELL) {
|
|
128
|
+
endpoint = 'getAssetAmountForBuyAsset';
|
|
129
|
+
resultIsGho = false;
|
|
130
|
+
} else if (destTokenAddress == this.config.GHO && side == SwapSide.SELL) {
|
|
131
|
+
endpoint = 'getGhoAmountForSellAsset';
|
|
132
|
+
resultIsGho = true;
|
|
133
|
+
} else {
|
|
134
|
+
endpoint = 'getAssetAmountForSellAsset';
|
|
135
|
+
resultIsGho = false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
srcTokenAddress == this.config.USDT ||
|
|
140
|
+
destTokenAddress == this.config.USDT
|
|
141
|
+
) {
|
|
142
|
+
target = this.config.GSM_USDT;
|
|
143
|
+
} else {
|
|
144
|
+
target = this.config.GSM_USDC;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const unit = parseUnits(
|
|
148
|
+
'1',
|
|
149
|
+
side == SwapSide.SELL ? srcToken.decimals : destToken.decimals,
|
|
150
|
+
).toBigInt();
|
|
151
|
+
|
|
152
|
+
const amountsWithUnit = [...amounts, unit];
|
|
153
|
+
|
|
154
|
+
const calls = amountsWithUnit.map(amount => ({
|
|
155
|
+
target,
|
|
156
|
+
callData: AaveGsm.gsmInterface.encodeFunctionData(endpoint, [amount]),
|
|
157
|
+
decodeFunction: (
|
|
158
|
+
result: MultiResult<BytesLike> | BytesLike,
|
|
159
|
+
): { underlying: bigint; gho: bigint } => {
|
|
160
|
+
return generalDecoder(
|
|
161
|
+
result,
|
|
162
|
+
['uint256', 'uint256', 'uint256', 'uint256'],
|
|
163
|
+
{
|
|
164
|
+
underlying: 0n,
|
|
165
|
+
gho: 0n,
|
|
166
|
+
},
|
|
167
|
+
value => ({
|
|
168
|
+
underlying: value[0].toBigInt(),
|
|
169
|
+
gho: value[1].toBigInt(),
|
|
170
|
+
}),
|
|
171
|
+
);
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
|
|
175
|
+
let results = await this.dexHelper.multiWrapper.tryAggregate<{
|
|
176
|
+
underlying: bigint;
|
|
177
|
+
gho: bigint;
|
|
178
|
+
}>(true, calls, blockNumber);
|
|
179
|
+
|
|
180
|
+
const unitPriceResult = results.pop()!;
|
|
181
|
+
|
|
182
|
+
return [
|
|
183
|
+
{
|
|
184
|
+
unit: resultIsGho
|
|
185
|
+
? unitPriceResult.returnData.gho
|
|
186
|
+
: unitPriceResult.returnData.underlying,
|
|
187
|
+
prices: results.map(result =>
|
|
188
|
+
resultIsGho ? result.returnData.gho : result.returnData.underlying,
|
|
189
|
+
),
|
|
190
|
+
data: {
|
|
191
|
+
exchange: this.dexKey,
|
|
192
|
+
},
|
|
193
|
+
poolAddresses: [target],
|
|
194
|
+
exchange: this.dexKey,
|
|
195
|
+
gasCost: endpoint.indexOf('BuyAsset') > 0 ? 80000 : 74000,
|
|
196
|
+
poolIdentifier: `${this.dexKey}_${target}`,
|
|
197
|
+
},
|
|
198
|
+
];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Returns estimated gas cost of calldata for this DEX in multiSwap
|
|
202
|
+
getCalldataGasCost(poolPrices: PoolPrices<AaveGsmData>): number | number[] {
|
|
203
|
+
return CALLDATA_GAS_COST.DEX_NO_PAYLOAD;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
getAdapterParam(
|
|
207
|
+
srcToken: string,
|
|
208
|
+
destToken: string,
|
|
209
|
+
srcAmount: string,
|
|
210
|
+
destAmount: string,
|
|
211
|
+
data: AaveGsmData,
|
|
212
|
+
side: SwapSide,
|
|
213
|
+
): AdapterExchangeParam {
|
|
214
|
+
const { exchange } = data;
|
|
215
|
+
|
|
216
|
+
const payload = '';
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
targetExchange: exchange,
|
|
220
|
+
payload,
|
|
221
|
+
networkFee: '0',
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async getDexParam(
|
|
226
|
+
srcToken: Address,
|
|
227
|
+
destToken: Address,
|
|
228
|
+
srcAmount: NumberAsString,
|
|
229
|
+
destAmount: NumberAsString,
|
|
230
|
+
recipient: Address,
|
|
231
|
+
data: AaveGsmData,
|
|
232
|
+
side: SwapSide,
|
|
233
|
+
): Promise<DexExchangeParam> {
|
|
234
|
+
const isSrcGho = srcToken.toLowerCase() === this.config.GHO;
|
|
235
|
+
const swapFunction = isSrcGho ? 'buyAsset' : 'sellAsset';
|
|
236
|
+
const ghoAmount = isSrcGho ? srcAmount : destAmount;
|
|
237
|
+
let assetAmount = isSrcGho ? destAmount : srcAmount;
|
|
238
|
+
const targetExchange =
|
|
239
|
+
srcToken.toLowerCase() === this.config.USDT ||
|
|
240
|
+
destToken.toLowerCase() === this.config.USDT
|
|
241
|
+
? this.config.GSM_USDT
|
|
242
|
+
: this.config.GSM_USDC;
|
|
243
|
+
|
|
244
|
+
if (BigInt(assetAmount) == 1n) {
|
|
245
|
+
const endpoint = isSrcGho
|
|
246
|
+
? 'getAssetAmountForBuyAsset'
|
|
247
|
+
: 'getAssetAmountForSellAsset';
|
|
248
|
+
|
|
249
|
+
const calldata = {
|
|
250
|
+
target: targetExchange,
|
|
251
|
+
callData: AaveGsm.gsmInterface.encodeFunctionData(endpoint, [
|
|
252
|
+
ghoAmount,
|
|
253
|
+
]),
|
|
254
|
+
decodeFunction: (
|
|
255
|
+
result: MultiResult<BytesLike> | BytesLike,
|
|
256
|
+
): { underlying: bigint; gho: bigint } => {
|
|
257
|
+
return generalDecoder(
|
|
258
|
+
result,
|
|
259
|
+
['uint256', 'uint256', 'uint256', 'uint256'],
|
|
260
|
+
{
|
|
261
|
+
underlying: 0n,
|
|
262
|
+
gho: 0n,
|
|
263
|
+
},
|
|
264
|
+
value => ({
|
|
265
|
+
underlying: value[0].toBigInt(),
|
|
266
|
+
gho: value[1].toBigInt(),
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const result = await this.dexHelper.multiWrapper.tryAggregate<{
|
|
273
|
+
underlying: bigint;
|
|
274
|
+
gho: bigint;
|
|
275
|
+
}>(true, [calldata]);
|
|
276
|
+
|
|
277
|
+
assetAmount = result[0].returnData.underlying.toString();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const exchangeData = AaveGsm.gsmInterface.encodeFunctionData(swapFunction, [
|
|
281
|
+
assetAmount,
|
|
282
|
+
recipient,
|
|
283
|
+
]);
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
needWrapNative: this.needWrapNative,
|
|
287
|
+
dexFuncHasRecipient: true,
|
|
288
|
+
exchangeData,
|
|
289
|
+
targetExchange,
|
|
290
|
+
returnAmountPos: isSrcGho ? 1 : 0,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Returns list of top pools based on liquidity. Max
|
|
295
|
+
// limit number pools should be returned.
|
|
296
|
+
async getTopPoolsForToken(
|
|
297
|
+
tokenAddress: Address,
|
|
298
|
+
limit: number,
|
|
299
|
+
): Promise<PoolLiquidity[]> {
|
|
300
|
+
tokenAddress = tokenAddress.toLowerCase();
|
|
301
|
+
|
|
302
|
+
if (tokenAddress == this.config.GHO) {
|
|
303
|
+
return [
|
|
304
|
+
{
|
|
305
|
+
exchange: this.dexKey,
|
|
306
|
+
address: this.config.GSM_USDC,
|
|
307
|
+
connectorTokens: [
|
|
308
|
+
{
|
|
309
|
+
decimals: 6,
|
|
310
|
+
address: this.config.USDC,
|
|
311
|
+
},
|
|
312
|
+
],
|
|
313
|
+
liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
exchange: this.dexKey,
|
|
317
|
+
address: this.config.GSM_USDT,
|
|
318
|
+
connectorTokens: [
|
|
319
|
+
{
|
|
320
|
+
decimals: 6,
|
|
321
|
+
address: this.config.USDT,
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred
|
|
325
|
+
},
|
|
326
|
+
];
|
|
327
|
+
} else if (tokenAddress == this.config.USDC) {
|
|
328
|
+
return [
|
|
329
|
+
{
|
|
330
|
+
exchange: this.dexKey,
|
|
331
|
+
address: this.config.GSM_USDC,
|
|
332
|
+
connectorTokens: [
|
|
333
|
+
{
|
|
334
|
+
decimals: 18,
|
|
335
|
+
address: this.config.GHO,
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred
|
|
339
|
+
},
|
|
340
|
+
];
|
|
341
|
+
} else if (tokenAddress == this.config.USDT) {
|
|
342
|
+
return [
|
|
343
|
+
{
|
|
344
|
+
exchange: this.dexKey,
|
|
345
|
+
address: this.config.GSM_USDT,
|
|
346
|
+
connectorTokens: [
|
|
347
|
+
{
|
|
348
|
+
decimals: 18,
|
|
349
|
+
address: this.config.GHO,
|
|
350
|
+
},
|
|
351
|
+
],
|
|
352
|
+
liquidityUSD: 1000000000, // Just returning a big number so this DEX will be preferred
|
|
353
|
+
},
|
|
354
|
+
];
|
|
355
|
+
} else {
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DexParams } from './types';
|
|
2
|
+
import { DexConfigMap, AdapterMappings } from '../../types';
|
|
3
|
+
import { Network, SwapSide } from '../../constants';
|
|
4
|
+
import { AaveV3Ethereum, MiscEthereum } from '@bgd-labs/aave-address-book';
|
|
5
|
+
|
|
6
|
+
export const AaveGsmConfig: DexConfigMap<DexParams> = {
|
|
7
|
+
AaveGsm: {
|
|
8
|
+
[Network.MAINNET]: {
|
|
9
|
+
GSM_USDT: MiscEthereum.GSM_USDT,
|
|
10
|
+
GSM_USDC: MiscEthereum.GSM_USDC,
|
|
11
|
+
USDT: AaveV3Ethereum.ASSETS.USDT.UNDERLYING,
|
|
12
|
+
USDC: AaveV3Ethereum.ASSETS.USDC.UNDERLYING,
|
|
13
|
+
GHO: AaveV3Ethereum.ASSETS.GHO.UNDERLYING,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Address } from '../../types';
|
|
2
|
+
|
|
3
|
+
export type AaveGsmData = {
|
|
4
|
+
// returned by the API that can be used for
|
|
5
|
+
// tx building. The data structure should be minimal.
|
|
6
|
+
exchange: Address;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type DexParams = {
|
|
10
|
+
GSM_USDT: string;
|
|
11
|
+
GSM_USDC: string;
|
|
12
|
+
USDT: string;
|
|
13
|
+
USDC: string;
|
|
14
|
+
GHO: string;
|
|
15
|
+
};
|