@paraswap/dex-lib 4.0.2 → 4.0.3-Cables.0

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 (207) 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/misc.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/paraswap-dex-lib.iml +9 -0
  7. package/.idea/prettier.xml +7 -0
  8. package/.idea/vcs.xml +6 -0
  9. package/build/abi/integral/factory.json +333 -0
  10. package/build/abi/integral/oracle.json +501 -0
  11. package/build/abi/{inception/inception-ineth-pool.json → integral/pool.json} +522 -543
  12. package/build/abi/{wombat/pool.json → integral/relayer.json} +720 -473
  13. package/build/dex/aave-v1/aave-v1.d.ts +1 -2
  14. package/build/dex/aave-v1/aave-v1.js +0 -23
  15. package/build/dex/aave-v1/aave-v1.js.map +1 -1
  16. package/build/dex/bebop/bebop.js +1 -1
  17. package/build/dex/bebop/bebop.js.map +1 -1
  18. package/build/dex/cables/cables.d.ts +1 -0
  19. package/build/dex/cables/cables.js +145 -88
  20. package/build/dex/cables/cables.js.map +1 -1
  21. package/build/dex/cables/constants.js +1 -1
  22. package/build/dex/cables/constants.js.map +1 -1
  23. package/build/dex/cables/rate-fetcher.d.ts +1 -0
  24. package/build/dex/cables/rate-fetcher.js +30 -10
  25. package/build/dex/cables/rate-fetcher.js.map +1 -1
  26. package/build/dex/cables/types.d.ts +16 -15
  27. package/build/dex/cables/types.js +2 -5
  28. package/build/dex/cables/types.js.map +1 -1
  29. package/build/dex/dexalot/dexalot.js.map +1 -1
  30. package/build/dex/fluid-dex/fluid-dex-generate-pool.d.ts +49 -0
  31. package/build/dex/fluid-dex/fluid-dex-generate-pool.js +104 -0
  32. package/build/dex/fluid-dex/fluid-dex-generate-pool.js.map +1 -0
  33. package/build/dex/index.js +2 -0
  34. package/build/dex/index.js.map +1 -1
  35. package/build/dex/integral/config.d.ts +4 -0
  36. package/build/dex/integral/config.js +20 -0
  37. package/build/dex/integral/config.js.map +1 -0
  38. package/build/dex/integral/context.d.ts +40 -0
  39. package/build/dex/integral/context.js +158 -0
  40. package/build/dex/integral/context.js.map +1 -0
  41. package/build/dex/integral/integral-factory.d.ts +24 -0
  42. package/build/dex/integral/integral-factory.js +95 -0
  43. package/build/dex/integral/integral-factory.js.map +1 -0
  44. package/build/dex/integral/integral-pool.d.ts +50 -0
  45. package/build/dex/integral/integral-pool.js +149 -0
  46. package/build/dex/integral/integral-pool.js.map +1 -0
  47. package/build/dex/integral/integral-pricing.d.ts +18 -0
  48. package/build/dex/integral/integral-pricing.js +114 -0
  49. package/build/dex/integral/integral-pricing.js.map +1 -0
  50. package/build/dex/integral/integral-relayer.d.ts +42 -0
  51. package/build/dex/integral/integral-relayer.js +192 -0
  52. package/build/dex/integral/integral-relayer.js.map +1 -0
  53. package/build/dex/integral/integral-token.d.ts +27 -0
  54. package/build/dex/integral/integral-token.js +59 -0
  55. package/build/dex/integral/integral-token.js.map +1 -0
  56. package/build/dex/integral/integral.d.ts +41 -0
  57. package/build/dex/integral/integral.js +376 -0
  58. package/build/dex/integral/integral.js.map +1 -0
  59. package/build/dex/integral/types.d.ts +85 -0
  60. package/build/dex/integral/types.js +9 -0
  61. package/build/dex/integral/types.js.map +1 -0
  62. package/build/dex/integral/utils-e2e.d.ts +9 -0
  63. package/build/dex/integral/utils-e2e.js +131 -0
  64. package/build/dex/integral/utils-e2e.js.map +1 -0
  65. package/build/dex/integral/utils.d.ts +17 -0
  66. package/build/dex/integral/utils.js +94 -0
  67. package/build/dex/integral/utils.js.map +1 -0
  68. package/build/dex/jarvis.d.ts +1 -2
  69. package/build/dex/jarvis.js +0 -58
  70. package/build/dex/jarvis.js.map +1 -1
  71. package/build/dex/platypus/platypus.d.ts +1 -2
  72. package/build/dex/platypus/platypus.js +0 -45
  73. package/build/dex/platypus/platypus.js.map +1 -1
  74. package/build/dex/stable-pool.js +8 -1
  75. package/build/dex/stable-pool.js.map +1 -1
  76. package/build/dex/swaap-v1/swaap-v1.d.ts +1 -2
  77. package/build/dex/swaap-v1/swaap-v1.js +0 -14
  78. package/build/dex/swaap-v1/swaap-v1.js.map +1 -1
  79. package/build/dex/trader-joe-v2.1/optimizer.d.ts +2 -0
  80. package/build/dex/trader-joe-v2.1/optimizer.js +47 -0
  81. package/build/dex/trader-joe-v2.1/optimizer.js.map +1 -0
  82. package/build/dex/zerox/index.d.ts +26 -4
  83. package/build/dex/zerox/index.js +42 -50
  84. package/build/dex/zerox/index.js.map +1 -1
  85. package/build/dex/zerox/types.d.ts +0 -29
  86. package/build/dex/zerox/types.js +1 -8
  87. package/build/dex/zerox/types.js.map +1 -1
  88. package/build/executor/Executor01BytecodeBuilder.js +11 -6
  89. package/build/executor/Executor01BytecodeBuilder.js.map +1 -1
  90. package/build/executor/Executor02BytecodeBuilder.js +11 -6
  91. package/build/executor/Executor02BytecodeBuilder.js.map +1 -1
  92. package/build/executor/Executor03BytecodeBuilder.js +11 -6
  93. package/build/executor/Executor03BytecodeBuilder.js.map +1 -1
  94. package/build/types.d.ts +1 -0
  95. package/package.json +1 -1
  96. package/src/abi/cables/CablesMainnetRFQ.json +1083 -0
  97. package/src/dex/bebop/bebop.ts +1 -1
  98. package/src/dex/cables/cables-e2e.test.ts +207 -0
  99. package/src/dex/cables/cables-integration.test.ts +391 -0
  100. package/src/dex/cables/cables.ts +1006 -0
  101. package/src/dex/cables/config.ts +13 -0
  102. package/src/dex/cables/constants.ts +35 -0
  103. package/src/dex/cables/rate-fetcher.ts +219 -0
  104. package/src/dex/cables/types.ts +130 -0
  105. package/src/dex/cables/validators.test.ts +151 -0
  106. package/src/dex/cables/validators.ts +61 -0
  107. package/src/dex/dexalot/dexalot.ts +1 -0
  108. package/src/dex/index.ts +2 -0
  109. package/src/executor/Executor01BytecodeBuilder.ts +15 -11
  110. package/src/executor/Executor02BytecodeBuilder.ts +13 -9
  111. package/src/executor/Executor03BytecodeBuilder.ts +16 -9
  112. package/src/types.ts +1 -0
  113. package/tests/constants-e2e.ts +2 -2
  114. package/.vscode/launch.json +0 -53
  115. package/.vscode/settings.json +0 -2
  116. package/.vscode/tasks.json +0 -15
  117. package/build/abi/inception/inception-ratio-feed.json +0 -329
  118. package/build/abi/inception/inception-vault.json +0 -991
  119. package/build/abi/uniswap-v3/AlienBaseV3Router.abi.json +0 -52
  120. package/build/abi/usual-m-smart-m/usualM.abi.json +0 -483
  121. package/build/abi/usual-m-usd0/usualCollateralDao.abi.json +0 -681
  122. package/build/dex/aave-v2/tokens-avalanche.json +0 -44
  123. package/build/dex/aave-v2/tokens-mainnet.json +0 -188
  124. package/build/dex/aave-v2/tokens-polygon.json +0 -44
  125. package/build/dex/balancer-v3/abi/balancerBatchRouter.d.ts +0 -729
  126. package/build/dex/balancer-v3/abi/balancerBatchRouter.js +0 -732
  127. package/build/dex/balancer-v3/abi/balancerBatchRouter.js.map +0 -1
  128. package/build/dex/balancer-v3/abi/balancerRouter.d.ts +0 -1406
  129. package/build/dex/balancer-v3/abi/balancerRouter.js +0 -1175
  130. package/build/dex/balancer-v3/abi/balancerRouter.js.map +0 -1
  131. package/build/dex/balancer-v3/abi/vaultExtension.V3.d.ts +0 -2081
  132. package/build/dex/balancer-v3/abi/vaultExtension.V3.js +0 -1851
  133. package/build/dex/balancer-v3/abi/vaultExtension.V3.js.map +0 -1
  134. package/build/dex/balancer-v3/balancer-v3-sepolia-pools.d.ts +0 -34
  135. package/build/dex/balancer-v3/balancer-v3-sepolia-pools.js +0 -406
  136. package/build/dex/balancer-v3/balancer-v3-sepolia-pools.js.map +0 -1
  137. package/build/dex/inception/config.d.ts +0 -4
  138. package/build/dex/inception/config.js +0 -109
  139. package/build/dex/inception/config.js.map +0 -1
  140. package/build/dex/inception/inception-event-pool.d.ts +0 -16
  141. package/build/dex/inception/inception-event-pool.js +0 -49
  142. package/build/dex/inception/inception-event-pool.js.map +0 -1
  143. package/build/dex/inception/inception.d.ts +0 -43
  144. package/build/dex/inception/inception.js +0 -180
  145. package/build/dex/inception/inception.js.map +0 -1
  146. package/build/dex/inception/tokens.d.ts +0 -9
  147. package/build/dex/inception/tokens.js +0 -28
  148. package/build/dex/inception/tokens.js.map +0 -1
  149. package/build/dex/inception/types.d.ts +0 -22
  150. package/build/dex/inception/types.js +0 -3
  151. package/build/dex/inception/types.js.map +0 -1
  152. package/build/dex/inception/utils.d.ts +0 -7
  153. package/build/dex/inception/utils.js +0 -58
  154. package/build/dex/inception/utils.js.map +0 -1
  155. package/build/dex/maker-psm/scripts/gem.abi.json +0 -136
  156. package/build/dex/maker-psm/scripts/validate-state.d.ts +0 -0
  157. package/build/dex/maker-psm/scripts/validate-state.js +0 -185
  158. package/build/dex/maker-psm/scripts/validate-state.js.map +0 -1
  159. package/build/dex/maker-psm/scripts/vat.abi.json +0 -243
  160. package/build/dex/solidly-v3/scripts/check-event-pool-event.d.ts +0 -1
  161. package/build/dex/solidly-v3/scripts/check-event-pool-event.js +0 -53
  162. package/build/dex/solidly-v3/scripts/check-event-pool-event.js.map +0 -1
  163. package/build/dex/uniswap-v3/forks/alien-base-v3/alien-base-v3.d.ts +0 -17
  164. package/build/dex/uniswap-v3/forks/alien-base-v3/alien-base-v3.js +0 -64
  165. package/build/dex/uniswap-v3/forks/alien-base-v3/alien-base-v3.js.map +0 -1
  166. package/build/dex/uniswap-v3/forks/alien-v3/alien-v3.d.ts +0 -17
  167. package/build/dex/uniswap-v3/forks/alien-v3/alien-v3.js +0 -79
  168. package/build/dex/uniswap-v3/forks/alien-v3/alien-v3.js.map +0 -1
  169. package/build/dex/uniswap-v3/uniswap-v3-pricing.d.ts +0 -4
  170. package/build/dex/uniswap-v3/uniswap-v3-pricing.js +0 -43
  171. package/build/dex/uniswap-v3/uniswap-v3-pricing.js.map +0 -1
  172. package/build/dex/uniswap-v3/uniswap-v3-worker.d.ts +0 -1
  173. package/build/dex/uniswap-v3/uniswap-v3-worker.js +0 -10
  174. package/build/dex/uniswap-v3/uniswap-v3-worker.js.map +0 -1
  175. package/build/dex/usual/types.d.ts +0 -13
  176. package/build/dex/usual/types.js +0 -3
  177. package/build/dex/usual/types.js.map +0 -1
  178. package/build/dex/usual/usual-bond.d.ts +0 -18
  179. package/build/dex/usual/usual-bond.js +0 -52
  180. package/build/dex/usual/usual-bond.js.map +0 -1
  181. package/build/dex/usual/usual-m-smart-m.d.ts +0 -17
  182. package/build/dex/usual/usual-m-smart-m.js +0 -50
  183. package/build/dex/usual/usual-m-smart-m.js.map +0 -1
  184. package/build/dex/usual/usual-m-usd0.d.ts +0 -17
  185. package/build/dex/usual/usual-m-usd0.js +0 -51
  186. package/build/dex/usual/usual-m-usd0.js.map +0 -1
  187. package/build/dex/usual/usual.d.ts +0 -27
  188. package/build/dex/usual/usual.js +0 -125
  189. package/build/dex/usual/usual.js.map +0 -1
  190. package/build/dex/usual-m-smart-m/config.d.ts +0 -3
  191. package/build/dex/usual-m-smart-m/config.js +0 -13
  192. package/build/dex/usual-m-smart-m/config.js.map +0 -1
  193. package/build/dex/usual-m-smart-m/types.d.ts +0 -7
  194. package/build/dex/usual-m-smart-m/types.js +0 -3
  195. package/build/dex/usual-m-smart-m/types.js.map +0 -1
  196. package/build/dex/usual-m-smart-m/usual-m-smart-m.d.ts +0 -35
  197. package/build/dex/usual-m-smart-m/usual-m-smart-m.js +0 -161
  198. package/build/dex/usual-m-smart-m/usual-m-smart-m.js.map +0 -1
  199. package/build/dex/usual-m-usd0/config.d.ts +0 -3
  200. package/build/dex/usual-m-usd0/config.js +0 -14
  201. package/build/dex/usual-m-usd0/config.js.map +0 -1
  202. package/build/dex/usual-m-usd0/types.d.ts +0 -8
  203. package/build/dex/usual-m-usd0/types.js +0 -3
  204. package/build/dex/usual-m-usd0/types.js.map +0 -1
  205. package/build/dex/usual-m-usd0/usual-m-usd0.d.ts +0 -35
  206. package/build/dex/usual-m-usd0/usual-m-usd0.js +0 -159
  207. package/build/dex/usual-m-usd0/usual-m-usd0.js.map +0 -1
@@ -0,0 +1,1006 @@
1
+ import {
2
+ Address,
3
+ NumberAsString,
4
+ OptimalSwapExchange,
5
+ SwapSide,
6
+ } from '@paraswap/core';
7
+ import { assert, AsyncOrSync } from 'ts-essentials';
8
+ import * as CALLDATA_GAS_COST from '../../calldata-gas-cost';
9
+ import { ETHER_ADDRESS, Network, NULL_ADDRESS } from '../../constants';
10
+ import { IDexHelper } from '../../dex-helper';
11
+ import {
12
+ AdapterExchangeParam,
13
+ DexExchangeParam,
14
+ ExchangePrices,
15
+ ExchangeTxInfo,
16
+ Logger,
17
+ PoolLiquidity,
18
+ PoolPrices,
19
+ PreprocessTransactionOptions,
20
+ Token,
21
+ TransferFeeParams,
22
+ } from '../../types';
23
+ import { getDexKeysWithNetwork, Utils } from '../../utils';
24
+ import { IDex } from '../idex';
25
+ import { SimpleExchange } from '../simple-exchange';
26
+ import { CablesConfig } from './config';
27
+ import {
28
+ CABLES_API_BLACKLIST_POLLING_INTERVAL_MS,
29
+ CABLES_API_PAIRS_POLLING_INTERVAL_MS,
30
+ CABLES_API_PRICES_POLLING_INTERVAL_MS,
31
+ CABLES_API_TOKENS_POLLING_INTERVAL_MS,
32
+ CABLES_API_URL,
33
+ CABLES_BLACKLIST_CACHE_KEY,
34
+ CABLES_BLACKLIST_CACHES_TTL_S,
35
+ CABLES_ERRORS_CACHE_KEY,
36
+ CABLES_FIRM_QUOTE_TIMEOUT_MS,
37
+ CABLES_GAS_COST,
38
+ CABLES_PAIRS_CACHES_TTL_S,
39
+ CABLES_PRICES_CACHES_TTL_S,
40
+ CABLES_RESTRICT_CHECK_INTERVAL_MS,
41
+ CABLES_RESTRICT_COUNT_THRESHOLD,
42
+ CABLES_RESTRICT_TTL_S,
43
+ CABLES_RESTRICTED_CACHE_KEY,
44
+ CABLES_TOKENS_CACHES_TTL_S,
45
+ } from './constants';
46
+ import { CablesRateFetcher } from './rate-fetcher';
47
+ import {
48
+ CablesData,
49
+ CablesRFQResponse,
50
+ RestrictData,
51
+ SlippageError,
52
+ } from './types';
53
+ import mainnetRFQAbi from '../../abi/cables/CablesMainnetRFQ.json';
54
+ import { Interface } from 'ethers/lib/utils';
55
+ import BigNumber from 'bignumber.js';
56
+ import { ethers } from 'ethers';
57
+ import { BI_MAX_UINT256 } from '../../bigint-constants';
58
+ import _ from 'lodash';
59
+
60
+ export class Cables extends SimpleExchange implements IDex<any> {
61
+ public static dexKeysWithNetwork: { key: string; networks: Network[] }[] =
62
+ getDexKeysWithNetwork(CablesConfig);
63
+
64
+ readonly isStatePollingDex = true;
65
+
66
+ private rateFetcher: CablesRateFetcher;
67
+
68
+ logger: Logger;
69
+ private tokensMap: { [address: string]: Token } = {};
70
+
71
+ hasConstantPriceLargeAmounts: boolean = false;
72
+
73
+ constructor(
74
+ readonly network: Network,
75
+ readonly dexKey: string,
76
+ readonly dexHelper: IDexHelper,
77
+ readonly mainnetRFQAddress: string = CablesConfig['Cables'][network]
78
+ .mainnetRFQAddress,
79
+ protected rfqInterface = new Interface(mainnetRFQAbi),
80
+ ) {
81
+ super(dexHelper, dexKey);
82
+ this.logger = dexHelper.getLogger(dexKey);
83
+
84
+ this.rateFetcher = new CablesRateFetcher(
85
+ this.dexHelper,
86
+ this.dexKey,
87
+ this.network,
88
+ this.logger,
89
+ {
90
+ rateConfig: {
91
+ pairsReqParams: {
92
+ url: CABLES_API_URL + '/pairs',
93
+ },
94
+ pricesReqParams: {
95
+ url: CABLES_API_URL + '/prices',
96
+ },
97
+ blacklistReqParams: {
98
+ url: CABLES_API_URL + '/blacklist',
99
+ },
100
+ tokensReqParams: {
101
+ url: CABLES_API_URL + '/tokens',
102
+ },
103
+
104
+ pricesIntervalMs: CABLES_API_PRICES_POLLING_INTERVAL_MS,
105
+ pricesCacheTTLSecs: CABLES_PRICES_CACHES_TTL_S,
106
+ pricesCacheKey: 'prices',
107
+
108
+ pairsIntervalMs: CABLES_API_PAIRS_POLLING_INTERVAL_MS,
109
+ pairsCacheTTLSecs: CABLES_PAIRS_CACHES_TTL_S,
110
+ pairsCacheKey: 'pairs',
111
+
112
+ tokensIntervalMs: CABLES_API_TOKENS_POLLING_INTERVAL_MS,
113
+ tokensCacheTTLSecs: CABLES_TOKENS_CACHES_TTL_S,
114
+ tokensCacheKey: 'tokens',
115
+
116
+ blacklistIntervalMs: CABLES_API_BLACKLIST_POLLING_INTERVAL_MS,
117
+ blacklistCacheTTLSecs: CABLES_BLACKLIST_CACHES_TTL_S,
118
+ blacklistCacheKey: CABLES_BLACKLIST_CACHE_KEY,
119
+
120
+ tokensHandleResponseCallback: async () => {
121
+ await this.setTokensMap();
122
+ },
123
+ },
124
+ },
125
+ );
126
+ }
127
+
128
+ async preProcessTransaction?(
129
+ optimalSwapExchange: OptimalSwapExchange<CablesData>,
130
+ srcToken: Token,
131
+ destToken: Token,
132
+ side: SwapSide,
133
+ options: PreprocessTransactionOptions,
134
+ ): Promise<[OptimalSwapExchange<CablesData>, ExchangeTxInfo]> {
135
+ if (await this.isBlacklisted(options.txOrigin)) {
136
+ this.logger.warn(
137
+ `${this.dexKey}-${this.network}: blacklisted TX Origin address '${options.txOrigin}' trying to build a transaction. Bailing...`,
138
+ );
139
+ throw new Error(
140
+ `${this.dexKey}-${
141
+ this.network
142
+ }: user=${options.txOrigin.toLowerCase()} is blacklisted`,
143
+ );
144
+ }
145
+
146
+ if (BigInt(optimalSwapExchange.srcAmount) === 0n) {
147
+ throw new Error('getFirmRate failed with srcAmount === 0');
148
+ }
149
+
150
+ const normalizedSrcToken = this.normalizeToken(srcToken);
151
+ const normalizedDestToken = this.normalizeToken(destToken);
152
+ const swapIdentifier = `${this.dexKey}_${normalizedSrcToken.address}_${normalizedDestToken.address}_${side}`;
153
+
154
+ try {
155
+ let makerToken = normalizedDestToken;
156
+ let takerToken = normalizedSrcToken;
157
+
158
+ const isSell = side === SwapSide.SELL;
159
+ const isBuy = side === SwapSide.BUY;
160
+
161
+ const rfqParams = {
162
+ makerAsset: ethers.utils.getAddress(makerToken.address),
163
+ takerAsset: ethers.utils.getAddress(takerToken.address),
164
+ ...(isBuy && { makerAmount: optimalSwapExchange.destAmount }),
165
+ ...(isSell && { takerAmount: optimalSwapExchange.srcAmount }),
166
+ userAddress: options.executionContractAddress,
167
+ chainId: String(this.network),
168
+ };
169
+
170
+ const rfq: CablesRFQResponse = await this.dexHelper.httpRequest.post(
171
+ `${CABLES_API_URL}/quote`,
172
+ rfqParams,
173
+ CABLES_FIRM_QUOTE_TIMEOUT_MS,
174
+ );
175
+
176
+ if (!rfq) {
177
+ throw new Error(
178
+ 'Failed to fetch RFQ' +
179
+ swapIdentifier +
180
+ JSON.stringify(rfq + 'params' + rfqParams),
181
+ );
182
+ }
183
+
184
+ const { order } = rfq;
185
+
186
+ assert(
187
+ order.makerAsset.toLowerCase() === makerToken.address,
188
+ `QuoteData makerAsset=${order.makerAsset} is different from Paraswap makerAsset=${makerToken.address}`,
189
+ );
190
+ assert(
191
+ order.takerAsset.toLowerCase() === takerToken.address,
192
+ `QuoteData takerAsset=${order.takerAsset} is different from Paraswap takerAsset=${takerToken.address}`,
193
+ );
194
+ if (isSell) {
195
+ assert(
196
+ order.takerAmount === optimalSwapExchange.srcAmount,
197
+ `QuoteData takerAmount=${order.takerAmount} is different from Paraswap srcAmount=${optimalSwapExchange.srcAmount}`,
198
+ );
199
+ } else {
200
+ assert(
201
+ order.makerAmount === optimalSwapExchange.destAmount,
202
+ `QuoteData makerAmount=${order.makerAmount} is different from Paraswap destAmount=${optimalSwapExchange.destAmount}`,
203
+ );
204
+ }
205
+
206
+ const expiryAsBigInt = BigInt(order.expiry);
207
+ const minDeadline = expiryAsBigInt > 0 ? expiryAsBigInt : BI_MAX_UINT256;
208
+
209
+ if (side === SwapSide.BUY) {
210
+ const requiredAmount = BigInt(optimalSwapExchange.srcAmount);
211
+ const quoteAmount = BigInt(order.takerAmount);
212
+ const requiredAmountWithSlippage = new BigNumber(
213
+ requiredAmount.toString(),
214
+ )
215
+ .multipliedBy(options.slippageFactor)
216
+ .toFixed(0);
217
+ if (quoteAmount > BigInt(requiredAmountWithSlippage)) {
218
+ throw new SlippageError(
219
+ `Slipped, factor: ${quoteAmount.toString()} > ${requiredAmountWithSlippage}`,
220
+ );
221
+ }
222
+ } else {
223
+ const requiredAmount = BigInt(optimalSwapExchange.destAmount);
224
+ const quoteAmount = BigInt(order.makerAmount);
225
+ const requiredAmountWithSlippage = new BigNumber(
226
+ requiredAmount.toString(),
227
+ )
228
+ .multipliedBy(options.slippageFactor)
229
+ .toFixed(0);
230
+ if (quoteAmount < BigInt(requiredAmountWithSlippage)) {
231
+ throw new SlippageError(
232
+ `Slipped, factor: ${
233
+ options.slippageFactor
234
+ } ${quoteAmount.toString()} < ${requiredAmountWithSlippage}`,
235
+ );
236
+ }
237
+ }
238
+
239
+ return [
240
+ {
241
+ ...optimalSwapExchange,
242
+ data: {
243
+ quoteData: order,
244
+ },
245
+ },
246
+ { deadline: minDeadline },
247
+ ];
248
+ } catch (e: any) {
249
+ const message = `${this.dexKey}-${this.network}: ${e}`;
250
+ this.logger.error(message);
251
+ if (!e?.isSlippageError) {
252
+ this.restrict();
253
+ }
254
+ throw new Error(message);
255
+ }
256
+ }
257
+
258
+ getDexParam(
259
+ srcToken: Address,
260
+ destToken: Address,
261
+ srcAmount: NumberAsString,
262
+ destAmount: NumberAsString,
263
+ recipient: Address,
264
+ data: CablesData,
265
+ side: SwapSide,
266
+ ): DexExchangeParam {
267
+ const { quoteData } = data;
268
+
269
+ assert(
270
+ quoteData !== undefined,
271
+ `${this.dexKey}-${this.network}: quoteData undefined`,
272
+ );
273
+
274
+ const swapFunction = 'partialSwap';
275
+ const swapFunctionParams = [
276
+ [
277
+ quoteData.nonceAndMeta,
278
+ quoteData.expiry,
279
+ quoteData.makerAsset,
280
+ quoteData.takerAsset,
281
+ quoteData.maker,
282
+ quoteData.taker,
283
+ quoteData.makerAmount,
284
+ quoteData.takerAmount,
285
+ ],
286
+ quoteData.signature,
287
+ // might be overwritten on Executors
288
+ quoteData.takerAmount,
289
+ ];
290
+
291
+ const exchangeData = this.rfqInterface.encodeFunctionData(
292
+ swapFunction,
293
+ swapFunctionParams,
294
+ );
295
+
296
+ const fromAmount = ethers.utils.defaultAbiCoder.encode(
297
+ ['uint256'],
298
+ [quoteData.takerAmount],
299
+ );
300
+
301
+ const filledAmountIndex = exchangeData
302
+ .replace('0x', '')
303
+ .lastIndexOf(fromAmount.replace('0x', ''));
304
+
305
+ const filledAmountPos =
306
+ (filledAmountIndex !== -1 ? filledAmountIndex : exchangeData.length) / 2;
307
+
308
+ return {
309
+ exchangeData,
310
+ needWrapNative: this.needWrapNative,
311
+ dexFuncHasRecipient: false,
312
+ targetExchange: this.mainnetRFQAddress,
313
+ returnAmountPos: undefined,
314
+ insertFromAmountPos: filledAmountPos,
315
+ };
316
+ }
317
+
318
+ getAdapterParam(
319
+ srcToken: string,
320
+ destToken: string,
321
+ srcAmount: string,
322
+ destAmount: string,
323
+ data: CablesData,
324
+ side: SwapSide,
325
+ ): AdapterExchangeParam {
326
+ const { quoteData } = data;
327
+
328
+ assert(
329
+ quoteData !== undefined,
330
+ `${this.dexKey}-${this.network}: quoteData undefined`,
331
+ );
332
+
333
+ const params = [
334
+ {
335
+ nonceAndMeta: quoteData.nonceAndMeta,
336
+ expiry: quoteData.expiry,
337
+ makerAsset: quoteData.makerAsset,
338
+ takerAsset: quoteData.takerAsset,
339
+ maker: quoteData.maker,
340
+ taker: quoteData.taker,
341
+ makerAmount: quoteData.makerAmount,
342
+ takerAmount: quoteData.takerAmount,
343
+ },
344
+ quoteData.signature,
345
+ ];
346
+
347
+ const payload = this.abiCoder.encodeParameter(
348
+ {
349
+ ParentStruct: {
350
+ order: {
351
+ nonceAndMeta: 'uint256',
352
+ expiry: 'uint128',
353
+ makerAsset: 'address',
354
+ takerAsset: 'address',
355
+ maker: 'address',
356
+ taker: 'address',
357
+ makerAmount: 'uint256',
358
+ takerAmount: 'uint256',
359
+ },
360
+ signature: 'bytes',
361
+ },
362
+ },
363
+ {
364
+ order: params[0],
365
+ signature: params[1],
366
+ },
367
+ );
368
+
369
+ return {
370
+ targetExchange: this.mainnetRFQAddress,
371
+ payload,
372
+ networkFee: '0',
373
+ };
374
+ }
375
+
376
+ normalizeToken(token: Token): Token {
377
+ return {
378
+ ...token,
379
+ address: this.normalizeTokenAddress(token.address),
380
+ };
381
+ }
382
+
383
+ normalizeTokenAddress(address: Address): Address {
384
+ return address.toLowerCase();
385
+ }
386
+
387
+ getTokenFromAddress(address: Address): Token {
388
+ return this.tokensMap[this.normalizeAddress(address)];
389
+ }
390
+
391
+ getPoolIdentifier(srcAddress: Address, destAddress: Address, mm?: string) {
392
+ return `${this.dexKey}_${srcAddress}_${destAddress}`.toLowerCase();
393
+ return `${this.dexKey}_${srcAddress}_${destAddress}_${mm}`.toLowerCase();
394
+ }
395
+
396
+ async getPoolIdentifiers(
397
+ srcToken: Token,
398
+ destToken: Token,
399
+ side: SwapSide,
400
+ blockNumber: number,
401
+ ): Promise<string[]> {
402
+ await this.setTokensMap();
403
+
404
+ if (!srcToken || !destToken) {
405
+ return [];
406
+ }
407
+
408
+ if (srcToken.address.toLowerCase() === destToken.address.toLowerCase()) {
409
+ return [];
410
+ }
411
+
412
+ const pairData = await this.getPairData(srcToken, destToken);
413
+
414
+ if (!pairData) {
415
+ return [];
416
+ }
417
+
418
+ const tokensAddr = (await this.getCachedTokensAddr()) || {};
419
+
420
+ return [
421
+ this.getPoolIdentifier(
422
+ tokensAddr[pairData.base.toLowerCase()],
423
+ tokensAddr[pairData.quote.toLowerCase()],
424
+ ),
425
+ ];
426
+ }
427
+
428
+ calculateOrderPrice(
429
+ amounts: bigint[],
430
+ orderbook: string[][],
431
+ baseToken: Token,
432
+ quoteToken: Token,
433
+ isInputQuote: boolean,
434
+ ) {
435
+ let result = [];
436
+
437
+ for (let i = 0; i < amounts.length; i++) {
438
+ let amt = amounts[i];
439
+ if (amt === 0n) {
440
+ result.push(amt);
441
+ continue;
442
+ }
443
+
444
+ let decimals = baseToken.decimals;
445
+ let out_decimals = quoteToken.decimals;
446
+
447
+ let price = this.calculatePriceSwap(
448
+ orderbook,
449
+ Number(amt) / 10 ** decimals,
450
+ isInputQuote,
451
+ );
452
+ result.push(BigInt(Math.round(price * 10 ** out_decimals)));
453
+ }
454
+ return result;
455
+ }
456
+
457
+ calculatePriceSwap(
458
+ prices: string[][],
459
+ requiredQty: number,
460
+ qtyMode: Boolean,
461
+ ) {
462
+ let sumBaseQty = 0;
463
+ let sumQuoteQty = 0;
464
+ const selectedRows: string[][] = [];
465
+
466
+ const isBase = qtyMode;
467
+ const isQuote = !qtyMode;
468
+
469
+ for (const [price, volume] of prices) {
470
+ if (isBase) {
471
+ if (sumBaseQty >= requiredQty) {
472
+ break;
473
+ }
474
+ }
475
+
476
+ if (isQuote) {
477
+ if (sumQuoteQty >= requiredQty) {
478
+ break;
479
+ }
480
+ }
481
+
482
+ let currentBaseQty = Number(volume);
483
+ let currentQuoteQty = Number(volume) * Number(price);
484
+
485
+ const overQty = isBase
486
+ ? currentBaseQty + sumBaseQty > requiredQty
487
+ : currentQuoteQty + sumQuoteQty > requiredQty;
488
+
489
+ if (overQty) {
490
+ if (isBase) {
491
+ currentBaseQty = requiredQty - sumBaseQty;
492
+ currentQuoteQty = currentBaseQty * Number(price);
493
+ }
494
+
495
+ if (isQuote) {
496
+ currentQuoteQty = requiredQty - sumQuoteQty;
497
+ currentBaseQty =
498
+ currentQuoteQty *
499
+ new BigNumber(1).dividedBy(new BigNumber(price)).toNumber();
500
+ }
501
+ }
502
+
503
+ sumBaseQty += currentBaseQty;
504
+ sumQuoteQty += currentQuoteQty;
505
+ selectedRows.push([price, currentBaseQty.toString()]);
506
+ }
507
+
508
+ const vSumBase = selectedRows.reduce((sum: number, [price, volume]) => {
509
+ return sum + Number(price) * Number(volume);
510
+ }, 0);
511
+
512
+ const price = new BigNumber(vSumBase)
513
+ .dividedBy(new BigNumber(sumBaseQty))
514
+ .toNumber();
515
+
516
+ if (isBase) {
517
+ return requiredQty / price;
518
+ } else {
519
+ return requiredQty * price;
520
+ }
521
+ }
522
+
523
+ async getPricesVolume(
524
+ srcToken: Token,
525
+ destToken: Token,
526
+ amounts: bigint[],
527
+ side: SwapSide,
528
+ blockNumber: number,
529
+ limitPools?: string[],
530
+ transferFees?: TransferFeeParams,
531
+ isFirstSwap?: boolean,
532
+ ): Promise<ExchangePrices<CablesData> | null> {
533
+ const isRestricted = await this.isRestricted();
534
+ if (isRestricted) {
535
+ return null;
536
+ }
537
+
538
+ await this.setTokensMap();
539
+
540
+ try {
541
+ const normalizedSrcToken = this.normalizeToken(srcToken);
542
+ const normalizedDestToken = this.normalizeToken(destToken);
543
+ // If: same token, return null
544
+ if (
545
+ normalizedSrcToken.address.toLowerCase() ===
546
+ normalizedDestToken.address.toLowerCase()
547
+ ) {
548
+ return null;
549
+ }
550
+
551
+ for (const symbol of Object.keys(this.tokensMap)) {
552
+ const normalizedTokenAddress =
553
+ this.tokensMap[symbol].address.toLowerCase();
554
+
555
+ if (normalizedSrcToken.address === normalizedTokenAddress) {
556
+ normalizedSrcToken.symbol = this.tokensMap[symbol].symbol;
557
+ }
558
+ if (normalizedDestToken.address === normalizedTokenAddress) {
559
+ normalizedDestToken.symbol = this.tokensMap[symbol].symbol;
560
+ }
561
+ }
562
+
563
+ // ---------- Pools ----------
564
+ let pools = await this.getPoolIdentifiers(
565
+ srcToken,
566
+ destToken,
567
+ side,
568
+ blockNumber,
569
+ );
570
+ if (pools.length === 0) return null;
571
+
572
+ // ---------- Prices ----------
573
+ const priceMap = await this.getCachedPrices();
574
+
575
+ if (!priceMap) return null;
576
+
577
+ let isInputQuote = false;
578
+ let pairKey = `${normalizedSrcToken.symbol}/${normalizedDestToken.symbol}`;
579
+ const pairsKeys = Object.keys(priceMap);
580
+
581
+ if (!pairsKeys.includes(pairKey)) {
582
+ // Revert
583
+ isInputQuote = true;
584
+ pairKey = `${normalizedDestToken.symbol}/${normalizedSrcToken.symbol}`;
585
+ if (!pairsKeys.includes(pairKey)) {
586
+ return null;
587
+ }
588
+ }
589
+
590
+ /**
591
+ * Orderbook
592
+ */
593
+ const priceData = priceMap[pairKey];
594
+
595
+ let orderbook: any[] = [];
596
+ if (side === SwapSide.BUY) {
597
+ orderbook = priceData.asks;
598
+ } else {
599
+ orderbook = priceData.bids;
600
+ }
601
+ if (orderbook?.length === 0) {
602
+ throw new Error(`Empty orderbook for ${pairKey}`);
603
+ }
604
+
605
+ const prices = this.calculateOrderPrice(
606
+ amounts,
607
+ orderbook,
608
+ side === SwapSide.SELL ? srcToken : destToken,
609
+ side === SwapSide.SELL ? destToken : srcToken,
610
+ side === SwapSide.SELL ? isInputQuote : !isInputQuote,
611
+ );
612
+
613
+ const result = [
614
+ {
615
+ prices: prices,
616
+ unit: BigInt(normalizedDestToken.decimals),
617
+ exchange: this.dexKey,
618
+ gasCost: CABLES_GAS_COST,
619
+ poolAddresses: [this.mainnetRFQAddress],
620
+ data: {},
621
+ },
622
+ ];
623
+
624
+ return result;
625
+ } catch (e: unknown) {
626
+ this.logger.error(
627
+ `Error in getPricesVolume`,
628
+ {
629
+ srcToken: srcToken.address || srcToken.symbol,
630
+ destToken: destToken.address || destToken.symbol,
631
+ side,
632
+ },
633
+ e,
634
+ );
635
+ return null;
636
+ }
637
+ }
638
+
639
+ getCalldataGasCost(poolPrices: PoolPrices<CablesData>): number | number[] {
640
+ return (
641
+ CALLDATA_GAS_COST.DEX_OVERHEAD +
642
+ // addresses: makerAsset, takerAsset, maker, taker
643
+ CALLDATA_GAS_COST.ADDRESS * 4 +
644
+ // uint256: expiry
645
+ CALLDATA_GAS_COST.wordNonZeroBytes(16) +
646
+ // uint256: nonceAndMeta, makerAmount, takerAmount
647
+ CALLDATA_GAS_COST.AMOUNT * 3 +
648
+ // bytes: _signature (65 bytes)
649
+ CALLDATA_GAS_COST.FULL_WORD * 2 +
650
+ CALLDATA_GAS_COST.OFFSET_SMALL
651
+ );
652
+ }
653
+
654
+ async initializePricing(blockNumber: number): Promise<void> {
655
+ if (!this.dexHelper.config.isSlave) {
656
+ this.rateFetcher.start();
657
+ }
658
+ return;
659
+ }
660
+
661
+ getAdapters(side: SwapSide): { name: string; index: number }[] | null {
662
+ return null;
663
+ }
664
+
665
+ releaseResources?(): AsyncOrSync<void> {
666
+ if (this.rateFetcher) {
667
+ this.rateFetcher.stop();
668
+ }
669
+ }
670
+
671
+ normalizeAddress(address: string): string {
672
+ return address.toLowerCase() === ETHER_ADDRESS
673
+ ? NULL_ADDRESS
674
+ : address.toLowerCase();
675
+ }
676
+
677
+ async setTokensMap() {
678
+ const tokens = await this.getCachedTokens();
679
+
680
+ if (tokens) {
681
+ this.tokensMap = Object.keys(tokens).reduce((acc, key) => {
682
+ //@ts-ignore
683
+ acc[tokens[key].address.toLowerCase()] = tokens[key];
684
+ return acc;
685
+ }, {});
686
+ }
687
+ }
688
+
689
+ async getTopPoolsForToken(
690
+ tokenAddress: Address,
691
+ limit: number,
692
+ ): Promise<PoolLiquidity[]> {
693
+ const isETH = tokenAddress.toLowerCase() === ETHER_ADDRESS;
694
+ const denormalizedTokenAddress = isETH ? NULL_ADDRESS : tokenAddress;
695
+
696
+ const tokens = (await this.getCachedTokens()) as { [key: string]: Token };
697
+ const token = Object.values(tokens).find(
698
+ token =>
699
+ token.address.toLowerCase() === denormalizedTokenAddress.toLowerCase(),
700
+ );
701
+
702
+ if (!token) {
703
+ return [];
704
+ }
705
+
706
+ const pairs = (await this.getCachedPairs()) as {
707
+ [key: string]: { base: string; quote: string };
708
+ };
709
+
710
+ const connectorTokens = Object.keys(pairs)
711
+ .filter(pairKey => {
712
+ const { base, quote } = pairs[pairKey];
713
+
714
+ if (
715
+ base.toLowerCase() === token.symbol?.toLowerCase() ||
716
+ quote.toLowerCase() === token.symbol?.toLowerCase()
717
+ ) {
718
+ return true;
719
+ }
720
+
721
+ return false;
722
+ })
723
+ .map(pairKey => {
724
+ const { base, quote } = pairs[pairKey];
725
+
726
+ if (base.toLowerCase() === token.symbol?.toLowerCase()) {
727
+ return tokens[quote];
728
+ }
729
+
730
+ if (quote.toLowerCase() === token.symbol?.toLowerCase()) {
731
+ return tokens[base];
732
+ }
733
+ });
734
+
735
+ if (connectorTokens.length === 0) {
736
+ return [];
737
+ }
738
+
739
+ connectorTokens.push(token);
740
+
741
+ const tokensBalanceMultiCall = connectorTokens.map(token => {
742
+ let erc20BalanceCalldata;
743
+ if (token?.address.toLowerCase() === NULL_ADDRESS) {
744
+ erc20BalanceCalldata = this.dexHelper.multiContract.methods
745
+ .getEthBalance(this.mainnetRFQAddress)
746
+ .encodeABI();
747
+ } else {
748
+ erc20BalanceCalldata = this.erc20Interface.encodeFunctionData(
749
+ 'balanceOf',
750
+ [this.mainnetRFQAddress],
751
+ );
752
+ }
753
+
754
+ return {
755
+ target:
756
+ token?.address.toLowerCase() === NULL_ADDRESS
757
+ ? this.dexHelper.config.data.multicallV2Address.toLowerCase()
758
+ : token?.address,
759
+ callData: erc20BalanceCalldata,
760
+ };
761
+ });
762
+
763
+ const res = (
764
+ await this.dexHelper.multiContract.methods
765
+ .aggregate(tokensBalanceMultiCall)
766
+ .call()
767
+ ).returnData;
768
+
769
+ const balances = res.map((item: any) => {
770
+ if (item === '0x') {
771
+ return 0n;
772
+ }
773
+ return BigInt(item.toString());
774
+ });
775
+
776
+ const connectorsPricesUSD = await Promise.all(
777
+ connectorTokens.map(async (token, index) =>
778
+ this.dexHelper.getTokenUSDPrice(token!, balances[index]),
779
+ ),
780
+ );
781
+
782
+ const extendedConnectors = connectorTokens.map((token, index) => ({
783
+ ...token,
784
+ usdPrice: connectorsPricesUSD[index],
785
+ }));
786
+
787
+ const tokenUSDPrice = _.last(extendedConnectors)!.usdPrice;
788
+ extendedConnectors.pop(); // to remove token which was added before
789
+
790
+ const connectors = extendedConnectors.map(connector => {
791
+ return {
792
+ exchange: this.dexKey,
793
+ address: this.mainnetRFQAddress,
794
+ connectorTokens: [
795
+ {
796
+ address:
797
+ connector.address === NULL_ADDRESS
798
+ ? ETHER_ADDRESS
799
+ : connector!.address,
800
+ decimals: connector!.decimals,
801
+ },
802
+ ],
803
+ liquidityUSD: Number(connector!.usdPrice) + Number(tokenUSDPrice),
804
+ };
805
+ });
806
+
807
+ return _.slice(
808
+ _.sortBy(connectors as PoolLiquidity[], [pool => -1 * pool.liquidityUSD]),
809
+ 0,
810
+ limit,
811
+ );
812
+ }
813
+
814
+ /**
815
+ * CACHED UTILS
816
+ */
817
+ async getCachedTokens(): Promise<any> {
818
+ const cachedTokens = await this.dexHelper.cache.get(
819
+ this.dexKey,
820
+ this.network,
821
+ this.rateFetcher.tokensCacheKey,
822
+ );
823
+
824
+ return cachedTokens ? JSON.parse(cachedTokens) : {};
825
+ }
826
+
827
+ async getCachedPairs(): Promise<any> {
828
+ const cachedPairs = await this.dexHelper.cache.get(
829
+ this.dexKey,
830
+ this.network,
831
+ this.rateFetcher.pairsCacheKey,
832
+ );
833
+
834
+ return cachedPairs ? JSON.parse(cachedPairs) : {};
835
+ }
836
+
837
+ async getCachedPrices(): Promise<any> {
838
+ const cachedPrices = await this.dexHelper.cache.get(
839
+ this.dexKey,
840
+ this.network,
841
+ this.rateFetcher.pricesCacheKey,
842
+ );
843
+
844
+ return cachedPrices ? JSON.parse(cachedPrices) : {};
845
+ }
846
+
847
+ async getCachedTokensAddr(): Promise<any> {
848
+ const tokens = await this.getCachedTokens();
849
+ const tokensAddr: Record<string, Address> = {};
850
+ for (const key of Object.keys(tokens)) {
851
+ tokensAddr[tokens[key].symbol.toLowerCase()] = tokens[key].address;
852
+ }
853
+ return tokensAddr;
854
+ }
855
+
856
+ getPairString(baseToken: Token, quoteToken: Token): string {
857
+ return `${baseToken.symbol}/${quoteToken.symbol}`.toLowerCase();
858
+ }
859
+
860
+ // Function to find a key by address
861
+ private findKeyByAddress = (
862
+ jsonData: Record<string, { address: string }>,
863
+ targetAddress: string,
864
+ ): string | undefined => {
865
+ const entries = Object.entries(jsonData);
866
+ const foundEntry = entries.find(
867
+ ([_, value]) =>
868
+ value.address.toLowerCase() === targetAddress.toLowerCase(),
869
+ );
870
+ return foundEntry ? foundEntry[0] : undefined;
871
+ };
872
+
873
+ async getPairData(srcToken: Token, destToken: Token): Promise<any> {
874
+ const normalizedSrcToken = this.normalizeToken(srcToken);
875
+ const normalizedDestToken = this.normalizeToken(destToken);
876
+
877
+ if (normalizedSrcToken.address === normalizedDestToken.address) {
878
+ return null;
879
+ }
880
+
881
+ const cachedTokens = await this.getCachedTokens();
882
+
883
+ normalizedSrcToken.symbol = this.findKeyByAddress(
884
+ cachedTokens,
885
+ normalizedSrcToken.address,
886
+ );
887
+ normalizedDestToken.symbol = this.findKeyByAddress(
888
+ cachedTokens,
889
+ normalizedDestToken.address,
890
+ );
891
+
892
+ const cachedPairs = await this.getCachedPairs();
893
+
894
+ const potentialPairs = [
895
+ {
896
+ base: normalizedSrcToken.symbol,
897
+ quote: normalizedDestToken.symbol,
898
+ identifier: this.getPairString(normalizedSrcToken, normalizedDestToken),
899
+ isSrcBase: true,
900
+ },
901
+ {
902
+ base: normalizedDestToken.symbol,
903
+ quote: normalizedSrcToken.symbol,
904
+ identifier: this.getPairString(normalizedDestToken, normalizedSrcToken),
905
+ isSrcBase: false,
906
+ },
907
+ ];
908
+
909
+ for (const pair of potentialPairs) {
910
+ if (pair.identifier in cachedPairs) {
911
+ const pairData = cachedPairs[pair.identifier];
912
+ pairData.isSrcBase = pair.isSrcBase;
913
+ return pairData;
914
+ }
915
+ }
916
+ return null;
917
+ }
918
+
919
+ async isBlacklisted(txOrigin: Address): Promise<boolean> {
920
+ const cachedBlacklist = await this.dexHelper.cache.get(
921
+ this.dexKey,
922
+ this.network,
923
+ CABLES_BLACKLIST_CACHE_KEY,
924
+ );
925
+
926
+ if (cachedBlacklist) {
927
+ const blacklist = JSON.parse(cachedBlacklist) as string[];
928
+ return blacklist.includes(txOrigin.toLowerCase());
929
+ }
930
+
931
+ return false;
932
+ }
933
+
934
+ async isRestricted(): Promise<boolean> {
935
+ const result = await this.dexHelper.cache.get(
936
+ this.dexKey,
937
+ this.network,
938
+ CABLES_RESTRICTED_CACHE_KEY,
939
+ );
940
+
941
+ return result === 'true';
942
+ }
943
+
944
+ async restrict() {
945
+ const errorsDataRaw = await this.dexHelper.cache.get(
946
+ this.dexKey,
947
+ this.network,
948
+ CABLES_ERRORS_CACHE_KEY,
949
+ );
950
+
951
+ const errorsData: RestrictData = Utils.Parse(errorsDataRaw);
952
+ const ERRORS_TTL_S = Math.floor(CABLES_RESTRICT_CHECK_INTERVAL_MS / 1000);
953
+
954
+ if (
955
+ !errorsData ||
956
+ errorsData?.addedDatetimeMs + CABLES_RESTRICT_CHECK_INTERVAL_MS <
957
+ Date.now()
958
+ ) {
959
+ this.logger.warn(
960
+ `${this.dexKey}-${this.network}: First encounter of error OR error ocurred outside of threshold, setting up counter`,
961
+ );
962
+ const data: RestrictData = {
963
+ count: 1,
964
+ addedDatetimeMs: Date.now(),
965
+ };
966
+ await this.dexHelper.cache.setex(
967
+ this.dexKey,
968
+ this.network,
969
+ CABLES_ERRORS_CACHE_KEY,
970
+ ERRORS_TTL_S,
971
+ Utils.Serialize(data),
972
+ );
973
+ return;
974
+ } else {
975
+ if (errorsData.count + 1 >= CABLES_RESTRICT_COUNT_THRESHOLD) {
976
+ this.logger.warn(
977
+ `${this.dexKey}-${this.network}: Restricting due to error count=${
978
+ errorsData.count + 1
979
+ } within ${CABLES_RESTRICT_CHECK_INTERVAL_MS / 1000 / 60} minutes`,
980
+ );
981
+ await this.dexHelper.cache.setex(
982
+ this.dexKey,
983
+ this.network,
984
+ CABLES_RESTRICTED_CACHE_KEY,
985
+ CABLES_RESTRICT_TTL_S,
986
+ 'true',
987
+ );
988
+ } else {
989
+ this.logger.warn(
990
+ `${this.dexKey}-${this.network}: Error count increased`,
991
+ );
992
+ const data: RestrictData = {
993
+ count: errorsData.count + 1,
994
+ addedDatetimeMs: errorsData.addedDatetimeMs,
995
+ };
996
+ await this.dexHelper.cache.setex(
997
+ this.dexKey,
998
+ this.network,
999
+ CABLES_RESTRICTED_CACHE_KEY,
1000
+ ERRORS_TTL_S,
1001
+ Utils.Serialize(data),
1002
+ );
1003
+ }
1004
+ }
1005
+ }
1006
+ }