@paraswap/dex-lib 4.1.7-pub-sub.2 → 4.1.7-pub-sub.4
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/dex/angle-staked-stable/angle-staked-stable.js +2 -1
- package/build/dex/angle-staked-stable/angle-staked-stable.js.map +1 -1
- package/build/dex/angle-transmuter/angle-transmuter.js.map +1 -1
- package/build/dex/balancer-v1/config.js +2 -1
- package/build/dex/balancer-v1/config.js.map +1 -1
- package/build/dex/dexalot/dexalot.d.ts +2 -9
- package/build/dex/dexalot/dexalot.js +18 -62
- package/build/dex/dexalot/dexalot.js.map +1 -1
- package/build/dex/dexalot/rate-fetcher.d.ts +19 -4
- package/build/dex/dexalot/rate-fetcher.js +112 -8
- package/build/dex/dexalot/rate-fetcher.js.map +1 -1
- package/build/dex/dexalot/types.d.ts +0 -1
- package/build/dex/generic-rfq/rate-fetcher.js +0 -12
- package/build/dex/generic-rfq/rate-fetcher.js.map +1 -1
- package/build/dex/hashflow/constants.d.ts +2 -2
- package/build/dex/hashflow/constants.js +2 -2
- package/build/dex/hashflow/hashflow.d.ts +1 -6
- package/build/dex/hashflow/hashflow.js +9 -34
- package/build/dex/hashflow/hashflow.js.map +1 -1
- package/build/dex/hashflow/rate-fetcher.d.ts +12 -2
- package/build/dex/hashflow/rate-fetcher.js +54 -6
- package/build/dex/hashflow/rate-fetcher.js.map +1 -1
- package/build/dex/hashflow/types.d.ts +0 -1
- package/build/dex/weth/weth.js +2 -1
- package/build/dex/weth/weth.js.map +1 -1
- package/build/lib/pub-sub.d.ts +0 -2
- package/build/lib/pub-sub.js +0 -12
- package/build/lib/pub-sub.js.map +1 -1
- package/build/pricing-helper.d.ts +1 -1
- package/build/pricing-helper.js +13 -9
- package/build/pricing-helper.js.map +1 -1
- package/build/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/dex/aave-gsm/aave-gsm-gas-estimation.test.ts +32 -0
- package/src/dex/aave-v2/aave-v2-gas-estimation.test.ts +28 -0
- package/src/dex/aave-v3/aave-v3-gas-estimation.test.ts +66 -0
- package/src/dex/aave-v3-stata/aave-v3-stata-gas-estimation.test.ts +41 -0
- package/src/dex/aave-v3-stata-v2/aave-v3-stata-v2-gas-estimation.test.ts +41 -0
- package/src/dex/angle-staked-stable/angle-staked-stable-gas-estimation.test.ts +29 -0
- package/src/dex/angle-staked-stable/angle-staked-stable.ts +2 -1
- package/src/dex/angle-transmuter/angle-transmuter-gas-estimation.test.ts +41 -0
- package/src/dex/angle-transmuter/angle-transmuter.ts +0 -1
- package/src/dex/balancer-v1/balancer-v1-gas-estimation.test.ts +29 -0
- package/src/dex/balancer-v1/config.ts +2 -1
- package/src/dex/balancer-v2/balancer-v2-gas-estimation.test.ts +98 -0
- package/src/dex/balancer-v3/balancer-v3-gas-estimation.test.ts +30 -0
- package/src/dex/bancor/bancor-gas-estimation.test.ts +30 -0
- package/src/dex/bebop/bebop-gas-estimation.test.ts +30 -0
- package/src/dex/concentrator-arusd/concentrator-arusd-gas-estimation.test.ts +29 -0
- package/src/dex/curve-v1/curve-v1-gas-estimation.test.ts +29 -0
- package/src/dex/curve-v2/curve-v2-gas-estimation.test.ts +29 -0
- package/src/dex/dexalot/dexalot.ts +27 -127
- package/src/dex/dexalot/rate-fetcher.ts +219 -9
- package/src/dex/dexalot/types.ts +0 -1
- package/src/dex/fluid-dex/fluid-dex-gas-estimation.test.ts +29 -0
- package/src/dex/fx-protocol-rusd/fx-protocol-rusd-gas-estimation.test.ts +29 -0
- package/src/dex/generic-rfq/rate-fetcher.ts +0 -30
- package/src/dex/hashflow/constants.ts +2 -2
- package/src/dex/hashflow/hashflow-gas-estimation.test.ts +30 -0
- package/src/dex/hashflow/hashflow.ts +11 -67
- package/src/dex/hashflow/rate-fetcher.ts +106 -8
- package/src/dex/hashflow/types.ts +0 -1
- package/src/dex/idle-dao/idle-dao--gas-estimation.test.ts +30 -0
- package/src/dex/lido/lido-gas-estimation.test.ts +29 -0
- package/src/dex/lite-psm/lite-psm-gas-estimation.test.ts +34 -0
- package/src/dex/maker-psm/maker-psm-gas-estimation.test.ts +34 -0
- package/src/dex/maverick-v1/maverick-v1-gas-estimation.test.ts +29 -0
- package/src/dex/maverick-v2/maverick-v2-gas-estimation.test.ts +29 -0
- package/src/dex/pancakeswap-v3/pancakeswap-v3-gas-estimation.test.ts +29 -0
- package/src/dex/polygon-migrator/polygon-migrator-gas-estimation.test.ts +41 -0
- package/src/dex/sky-converter/sky-converter-gas-estimation.test.ts +78 -0
- package/src/dex/solidly/solidly-gas-estimation.test.ts +29 -0
- package/src/dex/solidly-v3/solidly-v3-gas-estimation.test.ts +29 -0
- package/src/dex/spark/spark-gas-estimation.test.ts +29 -0
- package/src/dex/stader/stader-gas-estimation.test.ts +29 -0
- package/src/dex/stkgho/stkgho-gas-estimation.test.ts +29 -0
- package/src/dex/swaap-v2/swaap-v2-estimation.test.ts +29 -0
- package/src/dex/swell/swell-estimation.test.ts +29 -0
- package/src/dex/trader-joe-v2.1/trader-joe-v2.1-gas-estimation.test.ts +29 -0
- package/src/dex/uniswap-v2/uniswap-v2-gas-estimation.test.ts +98 -0
- package/src/dex/uniswap-v3/uniswap-v3-gas-estimation.test.ts +98 -0
- package/src/dex/usual/usual-gas-estimation.test.ts +54 -0
- package/src/dex/usual-pp/usual-pp-gas-estimation.test.ts +29 -0
- package/src/dex/weth/weth-gas-estimation.test.ts +42 -0
- package/src/dex/weth/weth.ts +3 -1
- package/src/dex/wombat/wombat-gas-estimation.test.ts +29 -0
- package/src/dex/wsteth/wsteth-gas-estimation.test.ts +41 -0
- package/src/dex/wusdm/wusdm-gas-estimation.test.ts +41 -0
- package/src/lib/pub-sub.ts +0 -27
- package/src/pricing-helper.ts +19 -11
- package/src/types.ts +1 -0
- package/tests/constants-e2e.ts +8 -0
- package/tests/tenderly-simulation-new.test.ts +151 -0
- package/tests/tenderly-simulation-new.ts +698 -0
- package/tests/token-storage-slots.json +532 -0
- package/tests/utils-e2e.ts +137 -1
|
@@ -46,7 +46,6 @@ export const reversePrice = (price: PriceAndAmountBigNumber) =>
|
|
|
46
46
|
price[1].times(price[0]),
|
|
47
47
|
] as PriceAndAmountBigNumber;
|
|
48
48
|
|
|
49
|
-
const logPrefix = 'RateFetched[pub_sub]';
|
|
50
49
|
export class RateFetcher {
|
|
51
50
|
private tokensFetcher: Fetcher<TokensResponse>;
|
|
52
51
|
private pairsFetcher: Fetcher<PairsResponse>;
|
|
@@ -168,7 +167,6 @@ export class RateFetcher {
|
|
|
168
167
|
}
|
|
169
168
|
|
|
170
169
|
async initialize() {
|
|
171
|
-
this.logger.info(`${logPrefix} Initializing rate fetcher`);
|
|
172
170
|
const isContract = await isContractAddress(
|
|
173
171
|
this.dexHelper.web3Provider,
|
|
174
172
|
this.config.maker,
|
|
@@ -181,10 +179,8 @@ export class RateFetcher {
|
|
|
181
179
|
}
|
|
182
180
|
|
|
183
181
|
if (this.dexHelper.config.isSlave) {
|
|
184
|
-
this.logger.info(`${logPrefix} Subscribing to prices pubsub`);
|
|
185
182
|
this.pricesPubSub.subscribe();
|
|
186
183
|
if (this.blacklistPubSub) {
|
|
187
|
-
this.logger.info(`${logPrefix} Subscribing to blacklist pubsub`);
|
|
188
184
|
const initSet = await this.dexHelper.cache.smembers(
|
|
189
185
|
this.blackListCacheKey,
|
|
190
186
|
);
|
|
@@ -194,7 +190,6 @@ export class RateFetcher {
|
|
|
194
190
|
}
|
|
195
191
|
|
|
196
192
|
start() {
|
|
197
|
-
this.logger.info(`${logPrefix} Starting rate fetcher`);
|
|
198
193
|
this.tokensFetcher.startPolling();
|
|
199
194
|
this.rateFetcher.startPolling();
|
|
200
195
|
this.pairsFetcher.startPolling();
|
|
@@ -204,7 +199,6 @@ export class RateFetcher {
|
|
|
204
199
|
}
|
|
205
200
|
|
|
206
201
|
stop() {
|
|
207
|
-
this.logger.info(`${logPrefix} Stopping rate fetcher`);
|
|
208
202
|
this.tokensFetcher.stopPolling();
|
|
209
203
|
this.pairsFetcher.stopPolling();
|
|
210
204
|
this.rateFetcher.stopPolling();
|
|
@@ -215,10 +209,6 @@ export class RateFetcher {
|
|
|
215
209
|
}
|
|
216
210
|
|
|
217
211
|
private handleTokensResponse(data: TokensResponse) {
|
|
218
|
-
this.logger.info(
|
|
219
|
-
`${logPrefix} Handling tokens response, tokens: `,
|
|
220
|
-
Object.keys(data.tokens).length,
|
|
221
|
-
);
|
|
222
212
|
for (const tokenName of Object.keys(data.tokens)) {
|
|
223
213
|
const token = data.tokens[tokenName];
|
|
224
214
|
token.address = token.address.toLowerCase();
|
|
@@ -236,10 +226,6 @@ export class RateFetcher {
|
|
|
236
226
|
}
|
|
237
227
|
|
|
238
228
|
private handlePairsResponse(resp: PairsResponse) {
|
|
239
|
-
this.logger.info(
|
|
240
|
-
`${logPrefix} Handling pairs response, pairs: `,
|
|
241
|
-
Object.keys(resp.pairs).length,
|
|
242
|
-
);
|
|
243
229
|
this.pairs = {};
|
|
244
230
|
|
|
245
231
|
const pairs: PairMap = {};
|
|
@@ -251,19 +237,11 @@ export class RateFetcher {
|
|
|
251
237
|
}
|
|
252
238
|
|
|
253
239
|
private handleBlackListResponse(resp: BlackListResponse) {
|
|
254
|
-
this.logger.info(
|
|
255
|
-
`${logPrefix} Handling blacklist response, blacklist length: `,
|
|
256
|
-
resp.blacklist.length,
|
|
257
|
-
);
|
|
258
240
|
for (const address of resp.blacklist) {
|
|
259
241
|
this.dexHelper.cache.sadd(this.blackListCacheKey, address.toLowerCase());
|
|
260
242
|
}
|
|
261
243
|
|
|
262
244
|
if (this.blacklistPubSub) {
|
|
263
|
-
this.logger.info(
|
|
264
|
-
`${logPrefix} Publishing blacklist to pubsub, blacklist length: `,
|
|
265
|
-
resp.blacklist.length,
|
|
266
|
-
);
|
|
267
245
|
this.blacklistPubSub.publish(resp.blacklist);
|
|
268
246
|
}
|
|
269
247
|
}
|
|
@@ -276,10 +254,6 @@ export class RateFetcher {
|
|
|
276
254
|
}
|
|
277
255
|
|
|
278
256
|
private handleRatesResponse(resp: RatesResponse) {
|
|
279
|
-
this.logger.info(
|
|
280
|
-
`${logPrefix} Handling rates response, prices length: `,
|
|
281
|
-
Object.keys(resp.prices).length,
|
|
282
|
-
);
|
|
283
257
|
const pubSubData: Record<string, unknown> = {};
|
|
284
258
|
const ttl = this.config.rateConfig.dataTTLS;
|
|
285
259
|
const pairs = this.pairs;
|
|
@@ -395,10 +369,6 @@ export class RateFetcher {
|
|
|
395
369
|
|
|
396
370
|
public async getAvailablePairs(): Promise<string[]> {
|
|
397
371
|
const pairs = await this.pricesPubSub.getAndCache<string[]>(`pairs`);
|
|
398
|
-
this.logger.info(
|
|
399
|
-
`${logPrefix} Getting available pairs, pairs: `,
|
|
400
|
-
pairs?.length,
|
|
401
|
-
);
|
|
402
372
|
if (!pairs) {
|
|
403
373
|
return [];
|
|
404
374
|
}
|
|
@@ -4,11 +4,11 @@ export const HASHFLOW_BLACKLIST_TTL_S = 60 * 60 * 24 * 7; // 7 days
|
|
|
4
4
|
|
|
5
5
|
export const HASHFLOW_MM_RESTRICT_TTL_S = 60 * 60;
|
|
6
6
|
|
|
7
|
-
export const HASHFLOW_PRICES_CACHES_TTL_S =
|
|
7
|
+
export const HASHFLOW_PRICES_CACHES_TTL_S = 5;
|
|
8
8
|
|
|
9
9
|
export const HASHFLOW_MARKET_MAKERS_CACHES_TTL_S = 30;
|
|
10
10
|
|
|
11
|
-
export const HASHFLOW_API_PRICES_POLLING_INTERVAL_MS =
|
|
11
|
+
export const HASHFLOW_API_PRICES_POLLING_INTERVAL_MS = 2000;
|
|
12
12
|
|
|
13
13
|
export const HASHFLOW_API_MARKET_MAKERS_POLLING_INTERVAL_MS = 28 * 1000; // 28 secs
|
|
14
14
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
describe('Hashflow Gas Estimation', () => {
|
|
9
|
+
const dexKey = 'Hashflow';
|
|
10
|
+
const network = Network.MAINNET;
|
|
11
|
+
|
|
12
|
+
describe('swapExactAmountIn', () => {
|
|
13
|
+
const USDT = Tokens[network]['USDT'];
|
|
14
|
+
const USDC = Tokens[network]['USDC'];
|
|
15
|
+
const amount = 100000000n;
|
|
16
|
+
|
|
17
|
+
// todo: fix tx build
|
|
18
|
+
it('tradeRFQT', async () => {
|
|
19
|
+
await testGasEstimation(
|
|
20
|
+
network,
|
|
21
|
+
USDT,
|
|
22
|
+
USDC,
|
|
23
|
+
amount,
|
|
24
|
+
SwapSide.SELL,
|
|
25
|
+
dexKey,
|
|
26
|
+
ContractMethodV6.swapExactAmountIn,
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { ChainId } from '@hashflow/sdk';
|
|
2
2
|
import { Chain, ChainType, HashflowApi } from '@hashflow/taker-js';
|
|
3
|
-
import {
|
|
4
|
-
MarketMakersResponse,
|
|
5
|
-
PriceLevelsResponse,
|
|
6
|
-
RfqResponse,
|
|
7
|
-
} from '@hashflow/taker-js/dist/types/rest';
|
|
3
|
+
import { RfqResponse } from '@hashflow/taker-js/dist/types/rest';
|
|
8
4
|
import BigNumber from 'bignumber.js';
|
|
9
5
|
import { Interface } from 'ethers/lib/utils';
|
|
10
6
|
import { assert } from 'ts-essentials';
|
|
@@ -145,7 +141,6 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
145
141
|
},
|
|
146
142
|
headers: { Authorization: this.hashFlowAuthToken },
|
|
147
143
|
},
|
|
148
|
-
getCachedMarketMakers: this.getCachedMarketMakers.bind(this),
|
|
149
144
|
filterMarketMakers: this.getFilteredMarketMakers.bind(this),
|
|
150
145
|
pricesCacheKey: this.pricesCacheKey,
|
|
151
146
|
pricesCacheTTLSecs: HASHFLOW_PRICES_CACHES_TTL_S,
|
|
@@ -157,9 +152,7 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
157
152
|
}
|
|
158
153
|
|
|
159
154
|
async initializePricing(blockNumber: number): Promise<void> {
|
|
160
|
-
|
|
161
|
-
this.rateFetcher.start();
|
|
162
|
-
}
|
|
155
|
+
this.rateFetcher.start();
|
|
163
156
|
|
|
164
157
|
return;
|
|
165
158
|
}
|
|
@@ -198,7 +191,7 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
198
191
|
return [];
|
|
199
192
|
}
|
|
200
193
|
|
|
201
|
-
const levels = (await this.getCachedLevels()) || {};
|
|
194
|
+
const levels = (await this.rateFetcher.getCachedLevels()) || {};
|
|
202
195
|
const makers = Object.keys(levels);
|
|
203
196
|
|
|
204
197
|
return makers
|
|
@@ -381,32 +374,6 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
381
374
|
return undefined;
|
|
382
375
|
}
|
|
383
376
|
|
|
384
|
-
async getCachedMarketMakers(): Promise<
|
|
385
|
-
MarketMakersResponse['marketMakers'] | null
|
|
386
|
-
> {
|
|
387
|
-
const cachedMarketMakers = await this.dexHelper.cache.rawget(
|
|
388
|
-
this.marketMakersCacheKey,
|
|
389
|
-
);
|
|
390
|
-
|
|
391
|
-
if (cachedMarketMakers) {
|
|
392
|
-
return JSON.parse(
|
|
393
|
-
cachedMarketMakers,
|
|
394
|
-
) as MarketMakersResponse['marketMakers'];
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return null;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async getCachedLevels(): Promise<PriceLevelsResponse['levels'] | null> {
|
|
401
|
-
const cachedLevels = await this.dexHelper.cache.rawget(this.pricesCacheKey);
|
|
402
|
-
|
|
403
|
-
if (cachedLevels) {
|
|
404
|
-
return JSON.parse(cachedLevels) as PriceLevelsResponse['levels'];
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
377
|
async getPricesVolume(
|
|
411
378
|
srcToken: Token,
|
|
412
379
|
destToken: Token,
|
|
@@ -434,7 +401,7 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
434
401
|
|
|
435
402
|
const marketMakersToUse = pools.map(p => p.split(`${prefix}_`).pop());
|
|
436
403
|
|
|
437
|
-
const levelsMap = (await this.getCachedLevels()) || {};
|
|
404
|
+
const levelsMap = (await this.rateFetcher.getCachedLevels()) || {};
|
|
438
405
|
|
|
439
406
|
Object.keys(levelsMap).forEach(mmKey => {
|
|
440
407
|
if (!marketMakersToUse.includes(mmKey)) {
|
|
@@ -715,7 +682,7 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
715
682
|
this.logger.warn(
|
|
716
683
|
`${this.dexKey}-${this.network}: Encountered restricted user=${options.userAddress}. Adding to local blacklist cache`,
|
|
717
684
|
);
|
|
718
|
-
await this.setBlacklist(options.userAddress);
|
|
685
|
+
await this.rateFetcher.setBlacklist(options.userAddress);
|
|
719
686
|
} else {
|
|
720
687
|
if (e instanceof TooStrictSlippageCheckError) {
|
|
721
688
|
this.logger.warn(
|
|
@@ -911,33 +878,6 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
911
878
|
};
|
|
912
879
|
}
|
|
913
880
|
|
|
914
|
-
getBlackListKey(address: Address) {
|
|
915
|
-
return `blacklist_${address}`.toLowerCase();
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
async isBlacklisted(txOrigin: Address): Promise<boolean> {
|
|
919
|
-
const result = await this.dexHelper.cache.get(
|
|
920
|
-
this.dexKey,
|
|
921
|
-
this.network,
|
|
922
|
-
this.getBlackListKey(txOrigin),
|
|
923
|
-
);
|
|
924
|
-
return result === 'blacklisted';
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
async setBlacklist(
|
|
928
|
-
txOrigin: Address,
|
|
929
|
-
ttl: number = HASHFLOW_BLACKLIST_TTL_S,
|
|
930
|
-
) {
|
|
931
|
-
await this.dexHelper.cache.setex(
|
|
932
|
-
this.dexKey,
|
|
933
|
-
this.network,
|
|
934
|
-
this.getBlackListKey(txOrigin),
|
|
935
|
-
ttl,
|
|
936
|
-
'blacklisted',
|
|
937
|
-
);
|
|
938
|
-
return true;
|
|
939
|
-
}
|
|
940
|
-
|
|
941
881
|
async getSimpleParam(
|
|
942
882
|
srcToken: string,
|
|
943
883
|
destToken: string,
|
|
@@ -1058,9 +998,9 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
1058
998
|
.wrapETH(tokenAddress)
|
|
1059
999
|
.toLowerCase();
|
|
1060
1000
|
|
|
1061
|
-
const makers = (await this.getCachedMarketMakers()) || [];
|
|
1001
|
+
const makers = (await this.rateFetcher.getCachedMarketMakers()) || [];
|
|
1062
1002
|
const filteredMakers = await this.getFilteredMarketMakers(makers);
|
|
1063
|
-
const pLevels = (await this.getCachedLevels()) || {};
|
|
1003
|
+
const pLevels = (await this.rateFetcher.getCachedLevels()) || {};
|
|
1064
1004
|
|
|
1065
1005
|
let baseToken: Token | undefined = undefined;
|
|
1066
1006
|
// TODO: Improve efficiency of this part. Quite inefficient way to determine
|
|
@@ -1120,4 +1060,8 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
1120
1060
|
this.rateFetcher.stop();
|
|
1121
1061
|
}
|
|
1122
1062
|
}
|
|
1063
|
+
|
|
1064
|
+
async isBlacklisted(txOrigin: Address): Promise<boolean> {
|
|
1065
|
+
return this.rateFetcher.isBlacklisted(txOrigin);
|
|
1066
|
+
}
|
|
1123
1067
|
}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MarketMakersResponse,
|
|
3
|
+
PriceLevelsResponse,
|
|
4
|
+
} from '@hashflow/taker-js/dist/types/rest';
|
|
1
5
|
import { Network } from '../../constants';
|
|
2
6
|
import { IDexHelper } from '../../dex-helper';
|
|
3
7
|
import { Fetcher, SkippingRequest } from '../../lib/fetcher/fetcher';
|
|
4
8
|
import { validateAndCast } from '../../lib/validators';
|
|
5
|
-
import { Logger } from '../../types';
|
|
9
|
+
import { Address, Logger } from '../../types';
|
|
6
10
|
import {
|
|
7
11
|
HashflowMarketMakersResponse,
|
|
8
12
|
HashflowRateFetcherConfig,
|
|
9
13
|
HashflowRatesResponse,
|
|
10
14
|
} from './types';
|
|
11
15
|
import { marketMakersValidator, pricesResponseValidator } from './validators';
|
|
16
|
+
import { HASHFLOW_BLACKLIST_TTL_S } from './constants';
|
|
17
|
+
import { ExpKeyValuePubSub, NonExpSetPubSub } from '../../lib/pub-sub';
|
|
12
18
|
|
|
13
19
|
export class RateFetcher {
|
|
14
20
|
private rateFetcher: Fetcher<HashflowRatesResponse>;
|
|
21
|
+
private ratePubSub: ExpKeyValuePubSub;
|
|
15
22
|
private pricesCacheKey: string;
|
|
16
23
|
private pricesCacheTTL: number;
|
|
17
24
|
|
|
@@ -19,6 +26,8 @@ export class RateFetcher {
|
|
|
19
26
|
private marketMakersCacheKey: string;
|
|
20
27
|
private marketMakersCacheTTL: number;
|
|
21
28
|
|
|
29
|
+
private blacklistedPubSub: NonExpSetPubSub;
|
|
30
|
+
|
|
22
31
|
constructor(
|
|
23
32
|
private dexHelper: IDexHelper,
|
|
24
33
|
private dexKey: string,
|
|
@@ -48,16 +57,18 @@ export class RateFetcher {
|
|
|
48
57
|
logger,
|
|
49
58
|
);
|
|
50
59
|
|
|
60
|
+
this.ratePubSub = new ExpKeyValuePubSub(dexHelper, dexKey, 'rates');
|
|
61
|
+
|
|
51
62
|
this.rateFetcher = new Fetcher<HashflowRatesResponse>(
|
|
52
63
|
dexHelper.httpRequest,
|
|
53
64
|
{
|
|
54
65
|
info: {
|
|
55
66
|
requestOptions: config.rateConfig.pricesReqParams,
|
|
56
67
|
requestFunc: async options => {
|
|
57
|
-
const { filterMarketMakers
|
|
58
|
-
config.rateConfig;
|
|
68
|
+
const { filterMarketMakers } = config.rateConfig;
|
|
59
69
|
|
|
60
|
-
const cachedMarketMakers =
|
|
70
|
+
const cachedMarketMakers =
|
|
71
|
+
(await this.getCachedMarketMakers()) || [];
|
|
61
72
|
const filteredMarketMakers = await filterMarketMakers(
|
|
62
73
|
cachedMarketMakers,
|
|
63
74
|
);
|
|
@@ -86,11 +97,24 @@ export class RateFetcher {
|
|
|
86
97
|
config.rateConfig.pricesIntervalMs,
|
|
87
98
|
logger,
|
|
88
99
|
);
|
|
100
|
+
|
|
101
|
+
this.blacklistedPubSub = new NonExpSetPubSub(
|
|
102
|
+
dexHelper,
|
|
103
|
+
dexKey,
|
|
104
|
+
'blacklisted',
|
|
105
|
+
);
|
|
89
106
|
}
|
|
90
107
|
|
|
91
|
-
start() {
|
|
92
|
-
this.
|
|
93
|
-
|
|
108
|
+
async start() {
|
|
109
|
+
if (!this.dexHelper.config.isSlave) {
|
|
110
|
+
this.marketMakersFetcher.startPolling();
|
|
111
|
+
this.rateFetcher.startPolling();
|
|
112
|
+
} else {
|
|
113
|
+
this.ratePubSub.subscribe();
|
|
114
|
+
|
|
115
|
+
const allBlacklisted = await this.getAllBlacklisted();
|
|
116
|
+
this.blacklistedPubSub.initializeAndSubscribe(allBlacklisted);
|
|
117
|
+
}
|
|
94
118
|
}
|
|
95
119
|
|
|
96
120
|
stop() {
|
|
@@ -109,10 +133,84 @@ export class RateFetcher {
|
|
|
109
133
|
|
|
110
134
|
private handleRatesResponse(resp: HashflowRatesResponse): void {
|
|
111
135
|
const { levels } = resp;
|
|
112
|
-
this.dexHelper.cache.
|
|
136
|
+
this.dexHelper.cache.setex(
|
|
137
|
+
this.dexKey,
|
|
138
|
+
this.network,
|
|
113
139
|
this.pricesCacheKey,
|
|
140
|
+
this.pricesCacheTTL,
|
|
114
141
|
JSON.stringify(levels),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
this.ratePubSub.publish(
|
|
145
|
+
{ [this.pricesCacheKey]: levels },
|
|
115
146
|
this.pricesCacheTTL,
|
|
116
147
|
);
|
|
117
148
|
}
|
|
149
|
+
|
|
150
|
+
async getCachedMarketMakers(): Promise<
|
|
151
|
+
MarketMakersResponse['marketMakers'] | null
|
|
152
|
+
> {
|
|
153
|
+
const cachedMarketMakers = await this.dexHelper.cache.rawget(
|
|
154
|
+
this.marketMakersCacheKey,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (cachedMarketMakers) {
|
|
158
|
+
return JSON.parse(
|
|
159
|
+
cachedMarketMakers,
|
|
160
|
+
) as MarketMakersResponse['marketMakers'];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async getCachedLevels(): Promise<PriceLevelsResponse['levels'] | null> {
|
|
167
|
+
const cachedLevels = await this.ratePubSub.getAndCache(this.pricesCacheKey);
|
|
168
|
+
|
|
169
|
+
if (cachedLevels) {
|
|
170
|
+
return cachedLevels as PriceLevelsResponse['levels'];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async isBlacklisted(txOrigin: Address): Promise<boolean> {
|
|
177
|
+
return this.blacklistedPubSub.has(txOrigin.toLowerCase());
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async setBlacklist(
|
|
181
|
+
txOrigin: Address,
|
|
182
|
+
ttl: number = HASHFLOW_BLACKLIST_TTL_S,
|
|
183
|
+
) {
|
|
184
|
+
await this.dexHelper.cache.setex(
|
|
185
|
+
this.dexKey,
|
|
186
|
+
this.network,
|
|
187
|
+
this.getBlackListKey(txOrigin),
|
|
188
|
+
ttl,
|
|
189
|
+
'blacklisted',
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
this.blacklistedPubSub.publish([txOrigin.toLowerCase()]);
|
|
193
|
+
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async getAllBlacklisted(): Promise<Address[]> {
|
|
198
|
+
const defaultKey = this.getBlackListKey('');
|
|
199
|
+
const pattern = `${defaultKey}*`;
|
|
200
|
+
const allBlacklisted = await this.dexHelper.cache.keys(
|
|
201
|
+
this.dexKey,
|
|
202
|
+
this.network,
|
|
203
|
+
pattern,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
return allBlacklisted.map(t => this.getAddressFromBlackListKey(t));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
getBlackListKey(address: Address) {
|
|
210
|
+
return `blacklist_${address}`.toLowerCase();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getAddressFromBlackListKey(key: Address) {
|
|
214
|
+
return (key.split('blacklist_')[1] ?? '').toLowerCase();
|
|
215
|
+
}
|
|
118
216
|
}
|
|
@@ -64,7 +64,6 @@ export type HashflowRateFetcherConfig = {
|
|
|
64
64
|
};
|
|
65
65
|
pricesIntervalMs: number;
|
|
66
66
|
markerMakersIntervalMs: number;
|
|
67
|
-
getCachedMarketMakers: () => Promise<string[] | null>;
|
|
68
67
|
filterMarketMakers: (makers: string[]) => Promise<string[]>;
|
|
69
68
|
pricesCacheKey: string;
|
|
70
69
|
marketMakersCacheKey: string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
describe('IdleDao Gas Estimation', () => {
|
|
9
|
+
const dexKey = 'IdleDao';
|
|
10
|
+
const network = Network.MAINNET;
|
|
11
|
+
|
|
12
|
+
describe('swapExactAmountIn', () => {
|
|
13
|
+
const STETH = Tokens[network]['STETH'];
|
|
14
|
+
const AA_wstETH = Tokens[network]['AA_wstETH'];
|
|
15
|
+
const amount = 1000000000000000000n;
|
|
16
|
+
|
|
17
|
+
// todo: uncomment? (the dex doesn't seem to be working)
|
|
18
|
+
// it('deposit', async () => {
|
|
19
|
+
// await testGasEstimation(
|
|
20
|
+
// network,
|
|
21
|
+
// STETH,
|
|
22
|
+
// AA_wstETH,
|
|
23
|
+
// amount,
|
|
24
|
+
// SwapSide.SELL,
|
|
25
|
+
// dexKey,
|
|
26
|
+
// ContractMethodV6.swapExactAmountIn,
|
|
27
|
+
// );
|
|
28
|
+
// });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
describe('Lido Gas Estimation', () => {
|
|
9
|
+
const dexKey = 'Lido';
|
|
10
|
+
const network = Network.MAINNET;
|
|
11
|
+
|
|
12
|
+
describe('swapExactAmountIn', () => {
|
|
13
|
+
const STETH = Tokens[network]['STETH'];
|
|
14
|
+
const ETH = Tokens[network]['ETH'];
|
|
15
|
+
const amount = 100000000000000000000n;
|
|
16
|
+
|
|
17
|
+
it('submit', async () => {
|
|
18
|
+
await testGasEstimation(
|
|
19
|
+
network,
|
|
20
|
+
ETH,
|
|
21
|
+
STETH,
|
|
22
|
+
amount,
|
|
23
|
+
SwapSide.SELL,
|
|
24
|
+
dexKey,
|
|
25
|
+
ContractMethodV6.swapExactAmountIn,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
dotenv.config();
|
|
9
|
+
|
|
10
|
+
describe('LitePsm Gas Estimation', () => {
|
|
11
|
+
const dexKey = 'LitePsm';
|
|
12
|
+
const network = Network.MAINNET;
|
|
13
|
+
const srcToken = Tokens[network]['USDC'];
|
|
14
|
+
const destToken = Tokens[network]['DAI'];
|
|
15
|
+
const methods: ContractMethodV6[] = [
|
|
16
|
+
ContractMethodV6.swapExactAmountInOutOnMakerPSM,
|
|
17
|
+
ContractMethodV6.swapExactAmountIn,
|
|
18
|
+
];
|
|
19
|
+
const amount = 10000000n;
|
|
20
|
+
|
|
21
|
+
methods.forEach(async method => {
|
|
22
|
+
it(method, async () => {
|
|
23
|
+
await testGasEstimation(
|
|
24
|
+
network,
|
|
25
|
+
srcToken,
|
|
26
|
+
destToken,
|
|
27
|
+
amount,
|
|
28
|
+
SwapSide.SELL,
|
|
29
|
+
dexKey,
|
|
30
|
+
method,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
dotenv.config();
|
|
9
|
+
|
|
10
|
+
describe('MakerPsm Gas Estimation', () => {
|
|
11
|
+
const dexKey = 'MakerPsm';
|
|
12
|
+
const network = Network.MAINNET;
|
|
13
|
+
const srcToken = Tokens[network]['USDC'];
|
|
14
|
+
const destToken = Tokens[network]['DAI'];
|
|
15
|
+
const methods: ContractMethodV6[] = [
|
|
16
|
+
ContractMethodV6.swapExactAmountInOutOnMakerPSM,
|
|
17
|
+
ContractMethodV6.swapExactAmountIn,
|
|
18
|
+
];
|
|
19
|
+
const amount = 10000000n;
|
|
20
|
+
|
|
21
|
+
methods.forEach(async method => {
|
|
22
|
+
it(method, async () => {
|
|
23
|
+
await testGasEstimation(
|
|
24
|
+
network,
|
|
25
|
+
srcToken,
|
|
26
|
+
destToken,
|
|
27
|
+
amount,
|
|
28
|
+
SwapSide.SELL,
|
|
29
|
+
dexKey,
|
|
30
|
+
method,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
describe('MaverickV1 Gas Estimation', () => {
|
|
9
|
+
const dexKey = 'MaverickV1';
|
|
10
|
+
const network = Network.MAINNET;
|
|
11
|
+
|
|
12
|
+
describe('swapExactAmountIn', () => {
|
|
13
|
+
const USDT = Tokens[network]['USDT'];
|
|
14
|
+
const USDC = Tokens[network]['USDC'];
|
|
15
|
+
const amount = 1000000n;
|
|
16
|
+
|
|
17
|
+
it('exactInputSingle', async () => {
|
|
18
|
+
await testGasEstimation(
|
|
19
|
+
network,
|
|
20
|
+
USDT,
|
|
21
|
+
USDC,
|
|
22
|
+
amount,
|
|
23
|
+
SwapSide.SELL,
|
|
24
|
+
dexKey,
|
|
25
|
+
ContractMethodV6.swapExactAmountIn,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
describe('MaverickV2 Gas Estimation', () => {
|
|
9
|
+
const dexKey = 'MaverickV2';
|
|
10
|
+
const network = Network.MAINNET;
|
|
11
|
+
|
|
12
|
+
describe('swapExactAmountIn', () => {
|
|
13
|
+
const USDT = Tokens[network]['USDT'];
|
|
14
|
+
const USDC = Tokens[network]['USDC'];
|
|
15
|
+
const amount = 100000000n;
|
|
16
|
+
|
|
17
|
+
it('swap', async () => {
|
|
18
|
+
await testGasEstimation(
|
|
19
|
+
network,
|
|
20
|
+
USDT,
|
|
21
|
+
USDC,
|
|
22
|
+
amount,
|
|
23
|
+
SwapSide.SELL,
|
|
24
|
+
dexKey,
|
|
25
|
+
ContractMethodV6.swapExactAmountIn,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import { testGasEstimation } from '../../../tests/utils-e2e';
|
|
4
|
+
import { Tokens } from '../../../tests/constants-e2e';
|
|
5
|
+
import { Network, SwapSide } from '../../constants';
|
|
6
|
+
import { ContractMethodV6 } from '@paraswap/core';
|
|
7
|
+
|
|
8
|
+
describe('PancakeswapV3 Gas Estimation', () => {
|
|
9
|
+
const dexKey = 'PancakeswapV3';
|
|
10
|
+
const network = Network.MAINNET;
|
|
11
|
+
|
|
12
|
+
describe('swapExactAmountIn', () => {
|
|
13
|
+
const USDT = Tokens[network]['USDT'];
|
|
14
|
+
const USDC = Tokens[network]['USDC'];
|
|
15
|
+
const amount = 100000000n;
|
|
16
|
+
|
|
17
|
+
it('exactInput', async () => {
|
|
18
|
+
await testGasEstimation(
|
|
19
|
+
network,
|
|
20
|
+
USDT,
|
|
21
|
+
USDC,
|
|
22
|
+
amount,
|
|
23
|
+
SwapSide.SELL,
|
|
24
|
+
dexKey,
|
|
25
|
+
ContractMethodV6.swapExactAmountIn,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|