@paraswap/dex-lib 2.14.6 → 2.14.7-hashflow-state-polling-dex
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/.idea/aws.xml +17 -0
- package/.idea/codeStyles/Project.xml +19 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/paraswap-dex-lib.iml +9 -0
- package/.idea/runConfigurations.xml +10 -0
- package/.idea/vcs.xml +6 -0
- package/build/dex/aave-v3/tokens/arbitrum.json +50 -0
- package/build/dex/aave-v3/tokens/avalanche.json +74 -0
- package/build/dex/aave-v3/tokens/fantom.json +62 -0
- package/build/dex/aave-v3/tokens/optimism.json +50 -0
- package/build/dex/aave-v3/tokens/polygon.json +116 -0
- package/build/dex/generic-rfq/fetch-mm-api.js +6 -5
- package/build/dex/generic-rfq/fetch-mm-api.js.map +1 -1
- package/build/dex/generic-rfq/rate-fetcher.js +7 -6
- package/build/dex/generic-rfq/rate-fetcher.js.map +1 -1
- package/build/dex/generic-rfq/validators.d.ts +0 -6
- package/build/dex/generic-rfq/validators.js +1 -24
- package/build/dex/generic-rfq/validators.js.map +1 -1
- package/build/dex/hashflow/constants.d.ts +5 -0
- package/build/dex/hashflow/constants.js +6 -1
- package/build/dex/hashflow/constants.js.map +1 -1
- package/build/dex/hashflow/hashflow.d.ts +8 -1
- package/build/dex/hashflow/hashflow.js +51 -15
- package/build/dex/hashflow/hashflow.js.map +1 -1
- package/build/dex/hashflow/rate-fetcher.d.ts +19 -0
- package/build/dex/hashflow/rate-fetcher.js +62 -0
- package/build/dex/hashflow/rate-fetcher.js.map +1 -0
- package/build/dex/hashflow/types.d.ts +34 -0
- package/build/dex/hashflow/types.js.map +1 -1
- package/build/dex/hashflow/validators.d.ts +4 -0
- package/build/dex/hashflow/validators.js +31 -0
- package/build/dex/hashflow/validators.js.map +1 -0
- package/build/lib/fetcher/fetcher.d.ts +2 -1
- package/build/lib/fetcher/fetcher.js +13 -4
- package/build/lib/fetcher/fetcher.js.map +1 -1
- package/build/lib/validators.d.ts +7 -0
- package/build/lib/validators.js +27 -0
- package/build/lib/validators.js.map +1 -0
- package/package.json +1 -1
- package/src/dex/generic-rfq/fetch-mm-api.ts +1 -1
- package/src/dex/generic-rfq/rate-fetcher.ts +3 -4
- package/src/dex/generic-rfq/validators.test.ts +1 -1
- package/src/dex/generic-rfq/validators.ts +0 -33
- package/src/dex/hashflow/constants.ts +10 -0
- package/src/dex/hashflow/hashflow.ts +76 -40
- package/src/dex/hashflow/rate-fetcher.ts +79 -0
- package/src/dex/hashflow/types.ts +38 -0
- package/src/dex/hashflow/validators.ts +27 -0
- package/src/lib/fetcher/fetcher.ts +15 -4
- package/src/lib/validators.ts +34 -0
- package/build/abi/maverick/pool.json +0 -913
- package/build/abi/maverick/router.json +0 -703
- package/build/dex/maverick/config.d.ts +0 -4
- package/build/dex/maverick/config.js +0 -20
- package/build/dex/maverick/config.js.map +0 -1
- package/build/dex/maverick/maverick-math/maverick-pool-math.d.ts +0 -67
- package/build/dex/maverick/maverick-math/maverick-pool-math.js +0 -406
- package/build/dex/maverick/maverick-math/maverick-pool-math.js.map +0 -1
- package/build/dex/maverick/maverick-math/maverick-sol-math.d.ts +0 -17
- package/build/dex/maverick/maverick-math/maverick-sol-math.js +0 -139
- package/build/dex/maverick/maverick-math/maverick-sol-math.js.map +0 -1
- package/build/dex/maverick/maverick-pool.d.ts +0 -41
- package/build/dex/maverick/maverick-pool.js +0 -130
- package/build/dex/maverick/maverick-pool.js.map +0 -1
- package/build/dex/maverick/maverick.d.ts +0 -42
- package/build/dex/maverick/maverick.js +0 -174
- package/build/dex/maverick/maverick.js.map +0 -1
- package/build/dex/maverick/subgraph-queries.d.ts +0 -4
- package/build/dex/maverick/subgraph-queries.js +0 -114
- package/build/dex/maverick/subgraph-queries.js.map +0 -1
- package/build/dex/maverick/types.d.ts +0 -46
- package/build/dex/maverick/types.js +0 -3
- package/build/dex/maverick/types.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../../src/lib/fetcher/fetcher.ts"],"names":[],"mappings":";;AAIA,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AACnC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../../src/lib/fetcher/fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
export declare class ValidationError extends Error {
|
|
3
|
+
readonly rawMessage: string;
|
|
4
|
+
readonly key?: string;
|
|
5
|
+
constructor(message: string, key?: string);
|
|
6
|
+
}
|
|
7
|
+
export declare const validateAndCast: <T>(value: unknown, schema: joi.Schema, name?: string | undefined) => T;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateAndCast = exports.ValidationError = void 0;
|
|
4
|
+
class ValidationError extends Error {
|
|
5
|
+
constructor(message, key) {
|
|
6
|
+
super(key !== undefined ? `'${key}': ${message}` : message);
|
|
7
|
+
this.rawMessage = message;
|
|
8
|
+
this.key = key;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.ValidationError = ValidationError;
|
|
12
|
+
const validateAndCast = (value, schema, name) => {
|
|
13
|
+
const { error, value: parsed } = schema.validate(value);
|
|
14
|
+
if (error !== undefined) {
|
|
15
|
+
let message;
|
|
16
|
+
if (name) {
|
|
17
|
+
message = `"${name}" ${error.message.slice(error.message.indexOf('must'))}`;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
message = error.message;
|
|
21
|
+
}
|
|
22
|
+
throw new ValidationError(message);
|
|
23
|
+
}
|
|
24
|
+
return parsed;
|
|
25
|
+
};
|
|
26
|
+
exports.validateAndCast = validateAndCast;
|
|
27
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/lib/validators.ts"],"names":[],"mappings":";;;AAEA,MAAa,eAAgB,SAAQ,KAAK;IAKxC,YAAY,OAAe,EAAE,GAAY;QACvC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC5D,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC;QAC1B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAVD,0CAUC;AAEM,MAAM,eAAe,GAAG,CAC7B,KAAc,EACd,MAAkB,EAClB,IAAa,EACV,EAAE;IACL,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExD,IAAI,KAAK,KAAK,SAAS,EAAE;QACvB,IAAI,OAAO,CAAC;QACZ,IAAI,IAAI,EAAE;YACR,OAAO,GAAG,IAAI,IAAI,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CACxC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAC9B,EAAE,CAAC;SACL;aAAM;YACL,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;SACzB;QACD,MAAM,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;KACpC;IACD,OAAO,MAAW,CAAC;AACrB,CAAC,CAAC;AAnBW,QAAA,eAAe,mBAmB1B"}
|
package/package.json
CHANGED
|
@@ -23,11 +23,11 @@ import {
|
|
|
23
23
|
pairsResponseValidator,
|
|
24
24
|
pricesResponse,
|
|
25
25
|
tokensResponseValidator,
|
|
26
|
-
validateAndCast,
|
|
27
26
|
} from './validators';
|
|
28
27
|
import MultiV2Abi from '../../abi/multi-v2.json';
|
|
29
28
|
import { AbiItem } from 'web3-utils';
|
|
30
29
|
import { checkOrder } from './utils';
|
|
30
|
+
import { validateAndCast } from '../../lib/validators';
|
|
31
31
|
|
|
32
32
|
const network = 1;
|
|
33
33
|
|
|
@@ -28,17 +28,16 @@ import {
|
|
|
28
28
|
pairsResponseValidator,
|
|
29
29
|
pricesResponse,
|
|
30
30
|
tokensResponseValidator,
|
|
31
|
-
validateAndCast,
|
|
32
31
|
} from './validators';
|
|
33
32
|
import { genericRFQAuthHttp } from './security';
|
|
34
|
-
|
|
35
|
-
const GET_FIRM_RATE_TIMEOUT_MS = 2000;
|
|
33
|
+
import { validateAndCast } from '../../lib/validators';
|
|
36
34
|
import {
|
|
37
35
|
createERC1271Contract,
|
|
38
36
|
ERC1271Contract,
|
|
39
37
|
} from '../../lib/erc1271-utils';
|
|
40
38
|
import { isContractAddress } from '../../utils';
|
|
41
39
|
|
|
40
|
+
const GET_FIRM_RATE_TIMEOUT_MS = 2000;
|
|
42
41
|
export const reversePrice = (price: PriceAndAmountBigNumber) =>
|
|
43
42
|
[
|
|
44
43
|
BN_1.dividedBy(price[0]),
|
|
@@ -60,7 +59,7 @@ export class RateFetcher {
|
|
|
60
59
|
public blackListCacheKey: string;
|
|
61
60
|
|
|
62
61
|
private authHttp: (
|
|
63
|
-
|
|
62
|
+
secret: RFQSecret,
|
|
64
63
|
) => (options: RequestConfig) => RequestConfig;
|
|
65
64
|
|
|
66
65
|
private verifierContract?: ERC1271Contract;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
validateAndCast,
|
|
3
2
|
tokensResponseValidator,
|
|
4
3
|
pairsResponseValidator,
|
|
5
4
|
pricesResponse,
|
|
6
5
|
blacklistResponseValidator,
|
|
7
6
|
firmRateResponseValidator,
|
|
8
7
|
} from './validators';
|
|
8
|
+
import { validateAndCast } from '../../lib/validators';
|
|
9
9
|
|
|
10
10
|
describe('GenericRFQ Validator test', () => {
|
|
11
11
|
describe('GenericRFQ Tokens Test', () => {
|
|
@@ -4,18 +4,6 @@ import * as ethers from 'ethers';
|
|
|
4
4
|
|
|
5
5
|
const tokensType = ['ERC20'];
|
|
6
6
|
|
|
7
|
-
export class ValidationError extends Error {
|
|
8
|
-
readonly rawMessage: string;
|
|
9
|
-
|
|
10
|
-
readonly key?: string;
|
|
11
|
-
|
|
12
|
-
constructor(message: string, key?: string) {
|
|
13
|
-
super(key !== undefined ? `'${key}': ${message}` : message);
|
|
14
|
-
this.rawMessage = message;
|
|
15
|
-
this.key = key;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
7
|
export const tokenValidator = joi.object({
|
|
20
8
|
symbol: joi.string().min(1).required(),
|
|
21
9
|
name: joi.string().min(1).required(),
|
|
@@ -120,27 +108,6 @@ export const pricesResponse = joi.object({
|
|
|
120
108
|
),
|
|
121
109
|
});
|
|
122
110
|
|
|
123
|
-
export const validateAndCast = <T>(
|
|
124
|
-
value: unknown,
|
|
125
|
-
schema: joi.Schema,
|
|
126
|
-
name?: string,
|
|
127
|
-
): T => {
|
|
128
|
-
const { error, value: parsed } = schema.validate(value);
|
|
129
|
-
|
|
130
|
-
if (error !== undefined) {
|
|
131
|
-
let message;
|
|
132
|
-
if (name) {
|
|
133
|
-
message = `"${name}" ${error.message.slice(
|
|
134
|
-
error.message.indexOf('must'),
|
|
135
|
-
)}`;
|
|
136
|
-
} else {
|
|
137
|
-
message = error.message;
|
|
138
|
-
}
|
|
139
|
-
throw new ValidationError(message);
|
|
140
|
-
}
|
|
141
|
-
return parsed as T;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
111
|
export const addressSchema = joi.string().custom((value, helpers) => {
|
|
145
112
|
if (ethers.utils.isAddress(value)) {
|
|
146
113
|
return value.toLowerCase();
|
|
@@ -4,3 +4,13 @@ export const PRICE_LEVELS_TTL_SECONDS = 1;
|
|
|
4
4
|
export const HASHFLOW_BLACKLIST_TTL_S = 60 * 60 * 24 * 7;
|
|
5
5
|
|
|
6
6
|
export const HASHFLOW_MM_RESTRICT_TTL_S = 60 * 60;
|
|
7
|
+
|
|
8
|
+
export const HASHFLOW_PRICES_CACHES_TTL_S = 2;
|
|
9
|
+
|
|
10
|
+
export const HASHFLOW_MARKET_MAKERS_CACHES_TTL_S = 2;
|
|
11
|
+
|
|
12
|
+
export const HASHFLOW_API_POLLING_INTERVAL_MS = 0;
|
|
13
|
+
|
|
14
|
+
export const HASHFLOW_API_URL = 'https://api.hashflow.com';
|
|
15
|
+
|
|
16
|
+
export const HASHFLOW_API_CLIENT_NAME = 'paraswap';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {
|
|
3
2
|
Token,
|
|
4
3
|
Address,
|
|
@@ -30,14 +29,19 @@ import {
|
|
|
30
29
|
SlippageCheckError,
|
|
31
30
|
} from './types';
|
|
32
31
|
import { SimpleExchange } from '../simple-exchange';
|
|
33
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
Adapters,
|
|
34
|
+
HashflowConfig
|
|
35
|
+
} from './config';
|
|
34
36
|
import { HashflowApi } from '@hashflow/taker-js';
|
|
37
|
+
import { RateFetcher } from './rate-fetcher';
|
|
35
38
|
import routerAbi from '../../abi/hashflow/HashflowRouter.abi.json';
|
|
36
39
|
import BigNumber from 'bignumber.js';
|
|
37
40
|
import { BN_0, BN_1, getBigNumberPow } from '../../bignumber-constants';
|
|
38
41
|
import { Interface } from 'ethers/lib/utils';
|
|
39
42
|
import { ChainId, ZERO_ADDRESS } from '@hashflow/sdk';
|
|
40
43
|
import {
|
|
44
|
+
MarketMakersResponse,
|
|
41
45
|
PriceLevelsResponse,
|
|
42
46
|
RfqResponse,
|
|
43
47
|
} from '@hashflow/taker-js/dist/types/rest';
|
|
@@ -45,22 +49,31 @@ import { assert } from 'ts-essentials';
|
|
|
45
49
|
import {
|
|
46
50
|
HASHFLOW_BLACKLIST_TTL_S,
|
|
47
51
|
HASHFLOW_MM_RESTRICT_TTL_S,
|
|
48
|
-
|
|
52
|
+
HASHFLOW_API_CLIENT_NAME,
|
|
53
|
+
HASHFLOW_API_URL,
|
|
54
|
+
HASHFLOW_API_POLLING_INTERVAL_MS,
|
|
55
|
+
HASHFLOW_PRICES_CACHES_TTL_S,
|
|
56
|
+
HASHFLOW_MARKET_MAKERS_CACHES_TTL_S,
|
|
49
57
|
} from './constants';
|
|
50
58
|
import { BI_MAX_UINT256 } from '../../bigint-constants';
|
|
51
59
|
|
|
52
60
|
const HASHFLOW_ASYNC_CALL_TIMEOUT = 150;
|
|
53
61
|
|
|
54
62
|
export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
63
|
+
readonly isStatePollingDex = true;
|
|
55
64
|
readonly hasConstantPriceLargeAmounts = false;
|
|
56
65
|
readonly needWrapNative = false;
|
|
57
66
|
readonly isFeeOnTransferSupported = false;
|
|
58
67
|
private api: HashflowApi;
|
|
68
|
+
private rateFetcher: RateFetcher | undefined;
|
|
59
69
|
|
|
60
70
|
private hashFlowAuthToken: string;
|
|
61
71
|
private disabledMMs: Set<string>;
|
|
62
72
|
private runtimeMMsRestrictHashMapKey: string;
|
|
63
73
|
|
|
74
|
+
private pricesCacheKey: string;
|
|
75
|
+
private marketMakersCacheKey: string;
|
|
76
|
+
|
|
64
77
|
public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
|
|
65
78
|
getDexKeysWithNetwork(HashflowConfig);
|
|
66
79
|
|
|
@@ -82,13 +95,46 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
82
95
|
token !== undefined,
|
|
83
96
|
'Hashflow auth token is not specified with env variable',
|
|
84
97
|
);
|
|
98
|
+
|
|
85
99
|
this.hashFlowAuthToken = token;
|
|
86
|
-
this.api = new HashflowApi('taker',
|
|
100
|
+
this.api = new HashflowApi('taker', HASHFLOW_API_CLIENT_NAME, this.hashFlowAuthToken);
|
|
101
|
+
|
|
102
|
+
this.pricesCacheKey = `${this.dexHelper.config.data.network}_${this.dexKey}_prices`;
|
|
103
|
+
this.marketMakersCacheKey = `${this.dexHelper.config.data.network}_${this.dexKey}_mms`;
|
|
104
|
+
|
|
87
105
|
this.disabledMMs = new Set(dexHelper.config.data.hashFlowDisabledMMs);
|
|
88
106
|
this.runtimeMMsRestrictHashMapKey =
|
|
89
107
|
`${CACHE_PREFIX}_${this.dexKey}_${this.network}_restricted_mms`.toLowerCase();
|
|
90
108
|
}
|
|
91
109
|
|
|
110
|
+
async initializePricing(blockNumber: number): Promise<void> {
|
|
111
|
+
if (!this.dexHelper.config.isSlave) {
|
|
112
|
+
this.rateFetcher = new RateFetcher(this.dexHelper, this.dexKey, this.logger, {
|
|
113
|
+
rateConfig: {
|
|
114
|
+
intervalMs: HASHFLOW_API_POLLING_INTERVAL_MS,
|
|
115
|
+
marketMakersReqParams: {
|
|
116
|
+
url: `${HASHFLOW_API_URL}/taker/v1/marketMakers`,
|
|
117
|
+
params: { networkId: this.network, source: HASHFLOW_API_CLIENT_NAME },
|
|
118
|
+
headers: { Authorization: this.hashFlowAuthToken },
|
|
119
|
+
},
|
|
120
|
+
pricesReqParams: {
|
|
121
|
+
url: `${HASHFLOW_API_URL}/taker/v2/price-levels`,
|
|
122
|
+
params: { networkId: this.network, source: HASHFLOW_API_CLIENT_NAME, marketMakers: [] },
|
|
123
|
+
headers: { Authorization: this.hashFlowAuthToken },
|
|
124
|
+
},
|
|
125
|
+
filterMarketMakers: this.getFilteredMarketMakers.bind(this),
|
|
126
|
+
pricesCacheKey: this.pricesCacheKey,
|
|
127
|
+
pricesCacheTTLSecs: HASHFLOW_PRICES_CACHES_TTL_S,
|
|
128
|
+
marketMakersCacheKey: this.marketMakersCacheKey,
|
|
129
|
+
marketMakersCacheTTLSecs: HASHFLOW_MARKET_MAKERS_CACHES_TTL_S,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
this.rateFetcher.start();
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
92
138
|
getAdapters(side: SwapSide): { name: string; index: number }[] | null {
|
|
93
139
|
return this.adapters[side] ? this.adapters[side] : null;
|
|
94
140
|
}
|
|
@@ -144,11 +190,8 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
144
190
|
);
|
|
145
191
|
}
|
|
146
192
|
|
|
147
|
-
private async getFilteredMarketMakers(
|
|
148
|
-
const
|
|
149
|
-
this.api.getMarketMakers(chainId),
|
|
150
|
-
this.dexHelper.cache.hgetAll(this.runtimeMMsRestrictHashMapKey),
|
|
151
|
-
]);
|
|
193
|
+
private async getFilteredMarketMakers(makers: string[]): Promise<string[]> {
|
|
194
|
+
const cachedRestrictionUnparsed = await this.dexHelper.cache.hgetAll(this.runtimeMMsRestrictHashMapKey);
|
|
152
195
|
|
|
153
196
|
const runtimeRestrictedMMs = this.parseCacheRestrictionAndExpiryIfNeeded(
|
|
154
197
|
cachedRestrictionUnparsed,
|
|
@@ -312,36 +355,24 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
312
355
|
return undefined;
|
|
313
356
|
}
|
|
314
357
|
|
|
315
|
-
async
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
);
|
|
321
|
-
if (cachedLevels) {
|
|
322
|
-
return JSON.parse(cachedLevels) as PriceLevelsResponse['levels'];
|
|
358
|
+
async getMarketMakers(): Promise<MarketMakersResponse['marketMakers']> {
|
|
359
|
+
const cachedMarketMakers = await this.dexHelper.cache.rawget(this.marketMakersCacheKey);
|
|
360
|
+
|
|
361
|
+
if(cachedMarketMakers) {
|
|
362
|
+
return JSON.parse(cachedMarketMakers) as MarketMakersResponse['marketMakers'];
|
|
323
363
|
}
|
|
324
364
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
HASHFLOW_ASYNC_CALL_TIMEOUT,
|
|
328
|
-
'Hashflow: getFilteredMarketMakers timeout',
|
|
329
|
-
);
|
|
330
|
-
const levels = await Utils.timeoutPromise(
|
|
331
|
-
this.api.getPriceLevels(this.network as ChainId, makers),
|
|
332
|
-
HASHFLOW_ASYNC_CALL_TIMEOUT,
|
|
333
|
-
'Hashflow: getPriceLevels timeout',
|
|
334
|
-
);
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
335
367
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
this.network as ChainId,
|
|
339
|
-
`levels`,
|
|
340
|
-
PRICE_LEVELS_TTL_SECONDS,
|
|
341
|
-
JSON.stringify(levels),
|
|
342
|
-
);
|
|
368
|
+
async getLevelsWithCache(): Promise<PriceLevelsResponse['levels']> {
|
|
369
|
+
const cachedLevels = await this.dexHelper.cache.rawget(this.pricesCacheKey);
|
|
343
370
|
|
|
344
|
-
|
|
371
|
+
if(cachedLevels) {
|
|
372
|
+
return JSON.parse(cachedLevels) as PriceLevelsResponse['levels'];
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return {};
|
|
345
376
|
}
|
|
346
377
|
|
|
347
378
|
// Hashflow protocol for native token expects 0x00000... instead of 0xeeeee...
|
|
@@ -816,16 +847,15 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
816
847
|
): Promise<PoolLiquidity[]> {
|
|
817
848
|
const _tokenAddress = tokenAddress.toLowerCase();
|
|
818
849
|
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
const
|
|
822
|
-
const pLevels = await this.api.getPriceLevels(chainId, makers);
|
|
850
|
+
const makers = await this.getMarketMakers();
|
|
851
|
+
const filteredMakers = await this.getFilteredMarketMakers(makers);
|
|
852
|
+
const pLevels = await this.getLevelsWithCache();
|
|
823
853
|
|
|
824
854
|
let baseToken: Token | undefined = undefined;
|
|
825
855
|
// TODO: Improve efficiency of this part. Quite inefficient way to determine
|
|
826
856
|
// Token address and decimals. But since it is not called frequently, not worth
|
|
827
857
|
// optimizing now
|
|
828
|
-
for (const maker of
|
|
858
|
+
for (const maker of filteredMakers) {
|
|
829
859
|
const baseTokenEntry = pLevels[maker]?.find(
|
|
830
860
|
entry => entry.pair.baseToken.toLowerCase() === _tokenAddress,
|
|
831
861
|
);
|
|
@@ -873,4 +903,10 @@ export class Hashflow extends SimpleExchange implements IDex<HashflowData> {
|
|
|
873
903
|
.sort((a, b) => b.liquidityUSD - a.liquidityUSD)
|
|
874
904
|
.slice(0, limit);
|
|
875
905
|
}
|
|
906
|
+
|
|
907
|
+
releaseResources(): void {
|
|
908
|
+
if(this.rateFetcher) {
|
|
909
|
+
this.rateFetcher.stop();
|
|
910
|
+
}
|
|
911
|
+
}
|
|
876
912
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { IDexHelper } from '../../dex-helper';
|
|
2
|
+
import Fetcher from '../../lib/fetcher/fetcher';
|
|
3
|
+
import { validateAndCast } from '../../lib/validators';
|
|
4
|
+
import { Logger } from '../../types';
|
|
5
|
+
import { HashflowRateFetcherConfig, HashflowRatesResponse, HashflowMarketMakersResponse } from './types';
|
|
6
|
+
import { pricesResponseValidator, marketMakersValidator } from './validators';
|
|
7
|
+
|
|
8
|
+
export class RateFetcher {
|
|
9
|
+
private rateFetcher: Fetcher<HashflowRatesResponse>;
|
|
10
|
+
private pricesCacheKey: string;
|
|
11
|
+
private pricesCacheTTL: number;
|
|
12
|
+
private marketMakersCacheKey: string;
|
|
13
|
+
private marketMakersCacheTTL: number;
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
private dexHelper: IDexHelper,
|
|
17
|
+
private dexKey: string,
|
|
18
|
+
private logger: Logger,
|
|
19
|
+
config: HashflowRateFetcherConfig,
|
|
20
|
+
) {
|
|
21
|
+
this.pricesCacheKey = config.rateConfig.pricesCacheKey;
|
|
22
|
+
this.pricesCacheTTL = config.rateConfig.pricesCacheTTLSecs;
|
|
23
|
+
this.marketMakersCacheKey = config.rateConfig.marketMakersCacheKey;
|
|
24
|
+
this.marketMakersCacheTTL = config.rateConfig.marketMakersCacheTTLSecs;
|
|
25
|
+
|
|
26
|
+
this.rateFetcher = new Fetcher<HashflowRatesResponse>(
|
|
27
|
+
dexHelper.httpRequest,
|
|
28
|
+
{
|
|
29
|
+
info: {
|
|
30
|
+
requestOptions: config.rateConfig.pricesReqParams,
|
|
31
|
+
requestFunc: async (options) => {
|
|
32
|
+
const marketMakersResponse = await dexHelper.httpRequest.request({
|
|
33
|
+
...config.rateConfig.marketMakersReqParams,
|
|
34
|
+
});
|
|
35
|
+
const parsedData = validateAndCast<HashflowMarketMakersResponse>(marketMakersResponse.data, marketMakersValidator);
|
|
36
|
+
this.handleMarketMakersResponse(parsedData);
|
|
37
|
+
const { marketMakers } = parsedData;
|
|
38
|
+
const filteredMarketMakers = await config.rateConfig.filterMarketMakers(marketMakers);
|
|
39
|
+
|
|
40
|
+
const prices = await dexHelper.httpRequest.request({
|
|
41
|
+
...options,
|
|
42
|
+
params: { ...options.params, marketMakers: filteredMarketMakers },
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
return prices;
|
|
46
|
+
},
|
|
47
|
+
caster: (data: unknown) => {
|
|
48
|
+
return validateAndCast<HashflowRatesResponse>(data, pricesResponseValidator);
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
handler: this.handleRatesResponse.bind(this),
|
|
52
|
+
},
|
|
53
|
+
config.rateConfig.intervalMs,
|
|
54
|
+
logger,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
start() {
|
|
59
|
+
this.rateFetcher.startPolling();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
stop() {
|
|
63
|
+
this.rateFetcher.stopPolling();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private handleMarketMakersResponse(resp: HashflowMarketMakersResponse): void {
|
|
67
|
+
const { marketMakers } = resp;
|
|
68
|
+
this.dexHelper.cache.rawset(this.marketMakersCacheKey, JSON.stringify(marketMakers), this.marketMakersCacheTTL);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private handleRatesResponse(resp: HashflowRatesResponse): void {
|
|
72
|
+
const { levels } = resp;
|
|
73
|
+
this.dexHelper.cache.rawset(this.pricesCacheKey, JSON.stringify(levels), this.pricesCacheTTL)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
checkHealth(): boolean {
|
|
77
|
+
return this.rateFetcher.lastFetchSucceeded;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { QuoteData } from '@hashflow/taker-js/dist/types/common';
|
|
2
|
+
import { RequestHeaders } from '../../dex-helper';
|
|
2
3
|
|
|
3
4
|
export type HashflowData = {
|
|
4
5
|
mm: string;
|
|
@@ -24,3 +25,40 @@ export enum RFQType {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export class SlippageCheckError extends Error {}
|
|
28
|
+
|
|
29
|
+
export type HashflowRatesLevel = {
|
|
30
|
+
pair: Record<string, string>;
|
|
31
|
+
levels: Array<Record<string, string>>;
|
|
32
|
+
includesFees: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type HashflowMarketMakersResponse = {
|
|
36
|
+
marketMakers: string[];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type HashflowRatesResponse = {
|
|
40
|
+
status: string;
|
|
41
|
+
networkId: string;
|
|
42
|
+
levels: Record<string, Array<HashflowRatesLevel>>
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type HashflowRateFetcherConfig = {
|
|
46
|
+
rateConfig: {
|
|
47
|
+
marketMakersReqParams: {
|
|
48
|
+
url: string;
|
|
49
|
+
headers?: RequestHeaders;
|
|
50
|
+
params?: any;
|
|
51
|
+
}
|
|
52
|
+
pricesReqParams: {
|
|
53
|
+
url: string;
|
|
54
|
+
headers?: RequestHeaders;
|
|
55
|
+
params?: any;
|
|
56
|
+
},
|
|
57
|
+
intervalMs: number;
|
|
58
|
+
filterMarketMakers: (makers: string[]) => Promise<string[]>;
|
|
59
|
+
pricesCacheKey: string;
|
|
60
|
+
marketMakersCacheKey: string;
|
|
61
|
+
pricesCacheTTLSecs: number;
|
|
62
|
+
marketMakersCacheTTLSecs: number;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
|
|
3
|
+
export const levelValidator = joi.array().items(joi.object({
|
|
4
|
+
pair: joi.object({
|
|
5
|
+
baseTokenName: joi.string().min(1).required(),
|
|
6
|
+
quoteTokenName: joi.string().min(1).required(),
|
|
7
|
+
baseToken: joi.string().min(1).required(),
|
|
8
|
+
quoteToken: joi.string().min(1).required(),
|
|
9
|
+
baseTokenDecimals: joi.number().min(1).required(),
|
|
10
|
+
quoteTokenDecimals: joi.number().min(1).required(),
|
|
11
|
+
}),
|
|
12
|
+
levels: joi.array().items(joi.object({
|
|
13
|
+
level: joi.string().min(1).required(),
|
|
14
|
+
price: joi.string().min(1).required(),
|
|
15
|
+
})),
|
|
16
|
+
includesFees: joi.boolean().required(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
export const pricesResponseValidator = joi.object({
|
|
20
|
+
status: joi.string().required(),
|
|
21
|
+
networkId: joi.number().required(),
|
|
22
|
+
levels: joi.object().pattern(joi.string().min(1), levelValidator),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const marketMakersValidator = joi.object({
|
|
26
|
+
marketMakers: joi.array().items(joi.string().min(1).required()),
|
|
27
|
+
});
|
|
@@ -7,6 +7,7 @@ const FETCH_FAIL_MAX_ATTEMPT = 5;
|
|
|
7
7
|
const FETCH_FAIL_RETRY_TIMEOUT_MS = 60 * 1000;
|
|
8
8
|
|
|
9
9
|
export type RequestInfo<T> = {
|
|
10
|
+
requestFunc?: (options: RequestConfig) => Promise<Response<T>>;
|
|
10
11
|
requestOptions: RequestConfig;
|
|
11
12
|
caster: (data: unknown) => T;
|
|
12
13
|
authenticate?: (options: RequestConfig) => RequestConfig;
|
|
@@ -56,15 +57,25 @@ export default class Fetcher<T> {
|
|
|
56
57
|
async (reqInfo: RequestInfoWithHandler<T>) => {
|
|
57
58
|
const info = reqInfo.info;
|
|
58
59
|
let options = info.requestOptions;
|
|
60
|
+
|
|
59
61
|
if (info.authenticate) {
|
|
60
62
|
info.authenticate(options);
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
let result;
|
|
67
|
+
if(info.requestFunc) {
|
|
68
|
+
result = await info.requestFunc({
|
|
69
|
+
timeout: FETCH_TIMEOUT_MS,
|
|
70
|
+
...options,
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
result = await this.requestWrapper.request({
|
|
74
|
+
timeout: FETCH_TIMEOUT_MS,
|
|
75
|
+
...options,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
68
79
|
return result;
|
|
69
80
|
} catch (e) {
|
|
70
81
|
return e as Error;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import joi from 'joi';
|
|
2
|
+
|
|
3
|
+
export class ValidationError extends Error {
|
|
4
|
+
readonly rawMessage: string;
|
|
5
|
+
|
|
6
|
+
readonly key?: string;
|
|
7
|
+
|
|
8
|
+
constructor(message: string, key?: string) {
|
|
9
|
+
super(key !== undefined ? `'${key}': ${message}` : message);
|
|
10
|
+
this.rawMessage = message;
|
|
11
|
+
this.key = key;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const validateAndCast = <T>(
|
|
16
|
+
value: unknown,
|
|
17
|
+
schema: joi.Schema,
|
|
18
|
+
name?: string,
|
|
19
|
+
): T => {
|
|
20
|
+
const { error, value: parsed } = schema.validate(value);
|
|
21
|
+
|
|
22
|
+
if (error !== undefined) {
|
|
23
|
+
let message;
|
|
24
|
+
if (name) {
|
|
25
|
+
message = `"${name}" ${error.message.slice(
|
|
26
|
+
error.message.indexOf('must'),
|
|
27
|
+
)}`;
|
|
28
|
+
} else {
|
|
29
|
+
message = error.message;
|
|
30
|
+
}
|
|
31
|
+
throw new ValidationError(message);
|
|
32
|
+
}
|
|
33
|
+
return parsed as T;
|
|
34
|
+
};
|