@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.
Files changed (76) hide show
  1. package/.idea/aws.xml +17 -0
  2. package/.idea/codeStyles/Project.xml +19 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  5. package/.idea/misc.xml +6 -0
  6. package/.idea/modules.xml +8 -0
  7. package/.idea/paraswap-dex-lib.iml +9 -0
  8. package/.idea/runConfigurations.xml +10 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/build/dex/aave-v3/tokens/arbitrum.json +50 -0
  11. package/build/dex/aave-v3/tokens/avalanche.json +74 -0
  12. package/build/dex/aave-v3/tokens/fantom.json +62 -0
  13. package/build/dex/aave-v3/tokens/optimism.json +50 -0
  14. package/build/dex/aave-v3/tokens/polygon.json +116 -0
  15. package/build/dex/generic-rfq/fetch-mm-api.js +6 -5
  16. package/build/dex/generic-rfq/fetch-mm-api.js.map +1 -1
  17. package/build/dex/generic-rfq/rate-fetcher.js +7 -6
  18. package/build/dex/generic-rfq/rate-fetcher.js.map +1 -1
  19. package/build/dex/generic-rfq/validators.d.ts +0 -6
  20. package/build/dex/generic-rfq/validators.js +1 -24
  21. package/build/dex/generic-rfq/validators.js.map +1 -1
  22. package/build/dex/hashflow/constants.d.ts +5 -0
  23. package/build/dex/hashflow/constants.js +6 -1
  24. package/build/dex/hashflow/constants.js.map +1 -1
  25. package/build/dex/hashflow/hashflow.d.ts +8 -1
  26. package/build/dex/hashflow/hashflow.js +51 -15
  27. package/build/dex/hashflow/hashflow.js.map +1 -1
  28. package/build/dex/hashflow/rate-fetcher.d.ts +19 -0
  29. package/build/dex/hashflow/rate-fetcher.js +62 -0
  30. package/build/dex/hashflow/rate-fetcher.js.map +1 -0
  31. package/build/dex/hashflow/types.d.ts +34 -0
  32. package/build/dex/hashflow/types.js.map +1 -1
  33. package/build/dex/hashflow/validators.d.ts +4 -0
  34. package/build/dex/hashflow/validators.js +31 -0
  35. package/build/dex/hashflow/validators.js.map +1 -0
  36. package/build/lib/fetcher/fetcher.d.ts +2 -1
  37. package/build/lib/fetcher/fetcher.js +13 -4
  38. package/build/lib/fetcher/fetcher.js.map +1 -1
  39. package/build/lib/validators.d.ts +7 -0
  40. package/build/lib/validators.js +27 -0
  41. package/build/lib/validators.js.map +1 -0
  42. package/package.json +1 -1
  43. package/src/dex/generic-rfq/fetch-mm-api.ts +1 -1
  44. package/src/dex/generic-rfq/rate-fetcher.ts +3 -4
  45. package/src/dex/generic-rfq/validators.test.ts +1 -1
  46. package/src/dex/generic-rfq/validators.ts +0 -33
  47. package/src/dex/hashflow/constants.ts +10 -0
  48. package/src/dex/hashflow/hashflow.ts +76 -40
  49. package/src/dex/hashflow/rate-fetcher.ts +79 -0
  50. package/src/dex/hashflow/types.ts +38 -0
  51. package/src/dex/hashflow/validators.ts +27 -0
  52. package/src/lib/fetcher/fetcher.ts +15 -4
  53. package/src/lib/validators.ts +34 -0
  54. package/build/abi/maverick/pool.json +0 -913
  55. package/build/abi/maverick/router.json +0 -703
  56. package/build/dex/maverick/config.d.ts +0 -4
  57. package/build/dex/maverick/config.js +0 -20
  58. package/build/dex/maverick/config.js.map +0 -1
  59. package/build/dex/maverick/maverick-math/maverick-pool-math.d.ts +0 -67
  60. package/build/dex/maverick/maverick-math/maverick-pool-math.js +0 -406
  61. package/build/dex/maverick/maverick-math/maverick-pool-math.js.map +0 -1
  62. package/build/dex/maverick/maverick-math/maverick-sol-math.d.ts +0 -17
  63. package/build/dex/maverick/maverick-math/maverick-sol-math.js +0 -139
  64. package/build/dex/maverick/maverick-math/maverick-sol-math.js.map +0 -1
  65. package/build/dex/maverick/maverick-pool.d.ts +0 -41
  66. package/build/dex/maverick/maverick-pool.js +0 -130
  67. package/build/dex/maverick/maverick-pool.js.map +0 -1
  68. package/build/dex/maverick/maverick.d.ts +0 -42
  69. package/build/dex/maverick/maverick.js +0 -174
  70. package/build/dex/maverick/maverick.js.map +0 -1
  71. package/build/dex/maverick/subgraph-queries.d.ts +0 -4
  72. package/build/dex/maverick/subgraph-queries.js +0 -114
  73. package/build/dex/maverick/subgraph-queries.js.map +0 -1
  74. package/build/dex/maverick/types.d.ts +0 -46
  75. package/build/dex/maverick/types.js +0 -3
  76. 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;AAc9C,MAAqB,OAAO;IAM1B,YACU,cAA+B,EACvC,YAAqE,EAC7D,cAAsB,EACtB,MAAc;QAHd,mBAAc,GAAd,cAAc,CAAiB;QAE/B,mBAAc,GAAd,cAAc,CAAQ;QACtB,WAAM,GAAN,MAAM,CAAQ;QARjB,uBAAkB,GAAY,KAAK,CAAC;QACnC,gBAAW,GAAG,CAAC,CAAC;QAChB,SAAI,GAAY,IAAI,CAAC;QAQ3B,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;YAC/B,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC;SAC9B;aAAM;YACL,IAAI,CAAC,QAAQ,GAAG,CAAC,YAAY,CAAC,CAAC;SAChC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAiB,KAAK;QAChC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE;YAChC,OAAO;SACR;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,sBAAsB,EAAE;YAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;YAEnB,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;YACvB,CAAC,EAAE,2BAA2B,CAAC,CAAC;YAChC,OAAO;SACR;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAChC,KAAK,EAAE,OAAkC,EAAE,EAAE;YAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,IAAI,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC;YAClC,IAAI,IAAI,CAAC,YAAY,EAAE;gBACrB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;aAC5B;YAED,IAAI;gBACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;oBAC/C,OAAO,EAAE,gBAAgB;oBACzB,GAAG,OAAO;iBACX,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC;aACf;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,CAAU,CAAC;aACnB;QACH,CAAC,CACF,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,OAAO;aACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;aAChB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC;QAE5C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,eAAe,EACf,IAAI,CAAC,SAAS,CAAE,MAAc,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAChE,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,kBAAkB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAC3E,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE;YACtC,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;YAChC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;SACvB;aAAM;YACL,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;SAChC;QAED,OAAO;aACJ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;aAChB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC;aAC3C,OAAO,CAAC,CAAC,CAAC,EAAE;YACX,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAgB,CAAC;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,qBAAqB,CAAC,CAAC;YAExD,IAAI;gBACF,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC9C,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;aAC7B;YAAC,OAAO,CAAC,EAAE;gBACV,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,IAAI,OAAO,CAAC,GAAG,6BAA6B,IAAI,CAAC,SAAS,CACxD,QAAQ,CAAC,IAAI,CACd,EAAE,EACH,CAAC,CACF,CAAC;gBACF,OAAO;aACR;QACH,CAAC,CAAC,CAAC;QACL,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAEvD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,OAAO;QACb,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAI,CAAC,CAAC;IAC9D,CAAC;IAED,YAAY;QACV,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,WAAW;QACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,SAAS;QACP,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;IACpB,CAAC;CACF;AA3HD,0BA2HC"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paraswap/dex-lib",
3
- "version": "2.14.6",
3
+ "version": "2.14.7-hashflow-state-polling-dex",
4
4
  "main": "build/index.js",
5
5
  "types": "build/index.d.ts",
6
6
  "repository": "https://github.com/paraswap/paraswap-dex-lib",
@@ -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
- secet: RFQSecret,
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 { Adapters, HashflowConfig } from './config';
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
- PRICE_LEVELS_TTL_SECONDS,
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', 'paraswap', this.hashFlowAuthToken);
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(chainId: ChainId): Promise<string[]> {
148
- const [makers, cachedRestrictionUnparsed] = await Promise.all([
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 getLevelsWithCache(): Promise<PriceLevelsResponse['levels']> {
316
- const cachedLevels = await this.dexHelper.cache.get(
317
- this.dexKey,
318
- this.network as ChainId,
319
- `levels`,
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
- const makers = await Utils.timeoutPromise(
326
- this.getFilteredMarketMakers(this.network as ChainId),
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
- await this.dexHelper.cache.setex(
337
- this.dexKey,
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
- return levels;
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 chainId = this.network as ChainId;
820
-
821
- const makers = await this.getFilteredMarketMakers(chainId);
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 makers) {
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
- const result = await this.requestWrapper.request({
65
- timeout: FETCH_TIMEOUT_MS,
66
- ...options,
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
+ };