@instadapp/interop-x 0.0.0-dev.e916c22 → 0.0.0-dev.ea4acf6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. package/dist/package.json +9 -2
  2. package/dist/src/abi/aaveV2Resolver.json +832 -0
  3. package/dist/src/abi/aaveV3Resolver.json +628 -0
  4. package/dist/src/abi/balanceResolver.json +211 -0
  5. package/dist/src/abi/index.js +6 -0
  6. package/dist/src/api/index.js +7 -0
  7. package/dist/src/constants/addresses.js +6 -0
  8. package/dist/src/constants/capPerChain.js +8 -0
  9. package/dist/src/constants/index.js +2 -0
  10. package/dist/src/constants/tokens.js +44 -44
  11. package/dist/src/constants/wrappedNativeToken.js +8 -0
  12. package/dist/src/crons/index.js +3 -0
  13. package/dist/src/crons/prices.js +16 -0
  14. package/dist/src/db/models/transaction.js +1 -1
  15. package/dist/src/errors/index.js +30 -0
  16. package/dist/src/gnosis/actions/aaveV2/source.js +26 -1
  17. package/dist/src/gnosis/actions/aaveV2/target.js +18 -4
  18. package/dist/src/gnosis/actions/aaveV3/index.js +11 -0
  19. package/dist/src/gnosis/actions/aaveV3/source.js +74 -0
  20. package/dist/src/gnosis/actions/aaveV3/target.js +87 -0
  21. package/dist/src/gnosis/actions/index.js +2 -0
  22. package/dist/src/index.js +2 -1
  23. package/dist/src/providers/index.js +17 -0
  24. package/dist/src/providers/retry-provider.js +45 -0
  25. package/dist/src/services/Prices.js +74 -0
  26. package/dist/src/services/index.js +8 -0
  27. package/dist/src/tasks/InteropX/{ProcessSubmitSubmitEvents.js → ProcessSubmitEvents.js} +108 -14
  28. package/dist/src/tasks/InteropX/ProcessValidateEvents.js +30 -10
  29. package/dist/src/tasks/InteropX/SyncLogExecuteEvents.js +3 -2
  30. package/dist/src/tasks/InteropX/SyncLogSubmitEvents.js +3 -2
  31. package/dist/src/tasks/InteropX/SyncLogValidateEvents.js +3 -2
  32. package/dist/src/tasks/index.js +3 -4
  33. package/dist/src/typechain/AaveV2Resolver.js +2 -0
  34. package/dist/src/typechain/AaveV3Resolver.js +2 -0
  35. package/dist/src/typechain/BalanceResolver.js +2 -0
  36. package/dist/src/typechain/factories/AaveV2Resolver__factory.js +1191 -0
  37. package/dist/src/typechain/factories/AaveV3Resolver__factory.js +887 -0
  38. package/dist/src/typechain/factories/BalanceResolver__factory.js +228 -0
  39. package/dist/src/typechain/factories/index.js +7 -1
  40. package/dist/src/typechain/index.js +7 -1
  41. package/dist/src/utils/async.js +18 -0
  42. package/dist/src/utils/dsa.js +36 -0
  43. package/dist/src/utils/formatting.js +67 -0
  44. package/dist/src/utils/gnosis.js +87 -0
  45. package/dist/src/utils/http.js +10 -0
  46. package/dist/src/utils/index.js +22 -220
  47. package/dist/src/utils/interop.js +16 -0
  48. package/dist/src/utils/tokens.js +22 -0
  49. package/dist/src/utils/validate.js +111 -0
  50. package/dist/src/utils/web3.js +93 -0
  51. package/package.json +9 -2
  52. package/src/abi/aaveV2Resolver.json +832 -0
  53. package/src/abi/aaveV3Resolver.json +628 -0
  54. package/src/abi/balanceResolver.json +211 -0
  55. package/src/abi/index.ts +6 -0
  56. package/src/api/index.ts +8 -0
  57. package/src/constants/addresses.ts +18 -1
  58. package/src/constants/capPerChain.ts +5 -0
  59. package/src/constants/index.ts +2 -0
  60. package/src/constants/tokens.ts +44 -44
  61. package/src/constants/wrappedNativeToken.ts +5 -0
  62. package/src/crons/index.ts +1 -0
  63. package/src/crons/prices.ts +12 -0
  64. package/src/db/models/transaction.ts +1 -1
  65. package/src/errors/index.ts +26 -0
  66. package/src/gnosis/actions/aaveV2/source.ts +56 -3
  67. package/src/gnosis/actions/aaveV2/target.ts +30 -11
  68. package/src/gnosis/actions/aaveV3/index.ts +9 -0
  69. package/src/gnosis/actions/aaveV3/source.ts +119 -0
  70. package/src/gnosis/actions/aaveV3/target.ts +142 -0
  71. package/src/gnosis/actions/index.ts +2 -0
  72. package/src/index.ts +1 -0
  73. package/src/providers/index.ts +1 -0
  74. package/src/providers/retry-provider.ts +51 -0
  75. package/src/services/Prices.ts +89 -0
  76. package/src/services/index.ts +1 -0
  77. package/src/tasks/InteropX/{ProcessSubmitSubmitEvents.ts → ProcessSubmitEvents.ts} +135 -20
  78. package/src/tasks/InteropX/ProcessValidateEvents.ts +42 -19
  79. package/src/tasks/InteropX/SyncLogExecuteEvents.ts +5 -6
  80. package/src/tasks/InteropX/SyncLogSubmitEvents.ts +6 -7
  81. package/src/tasks/InteropX/SyncLogValidateEvents.ts +6 -7
  82. package/src/tasks/index.ts +3 -4
  83. package/src/typechain/AaveV2Resolver.ts +1017 -0
  84. package/src/typechain/AaveV3Resolver.ts +935 -0
  85. package/src/typechain/BalanceResolver.ts +266 -0
  86. package/src/typechain/factories/AaveV2Resolver__factory.ts +1198 -0
  87. package/src/typechain/factories/AaveV3Resolver__factory.ts +894 -0
  88. package/src/typechain/factories/BalanceResolver__factory.ts +235 -0
  89. package/src/typechain/factories/index.ts +3 -0
  90. package/src/typechain/index.ts +6 -0
  91. package/src/utils/async.ts +22 -0
  92. package/src/utils/dsa.ts +56 -0
  93. package/src/utils/formatting.ts +68 -0
  94. package/src/utils/gnosis.ts +166 -0
  95. package/src/utils/http.ts +6 -0
  96. package/src/utils/index.ts +9 -365
  97. package/src/utils/interop.ts +28 -0
  98. package/src/utils/tokens.ts +21 -0
  99. package/src/utils/validate.ts +179 -0
  100. package/src/utils/web3.ts +132 -0
@@ -1,365 +1,9 @@
1
- /**
2
- * @module util
3
- */
4
- import axios from "axios";
5
- import axiosRetry from "axios-retry";
6
- import { addresses } from "@/constants";
7
- import { ChainId } from "@/types";
8
- import { ethers } from "ethers";
9
- import { GnosisSafe } from "@/typechain";
10
- import retry from "async-retry";
11
- import { connectors } from "@/abi/connectors";
12
- import Web3EthAbi from "web3-eth-abi";
13
-
14
- export const http = axios.create();
15
-
16
- axiosRetry(http, { retries: 3, retryDelay: axiosRetry.exponentialDelay });
17
-
18
- export function shortenHash(hash: string, length: number = 4) {
19
- if (!hash) return;
20
-
21
- if (hash.length < 12) return hash;
22
-
23
- const beginningChars = hash.startsWith("0x") ? length + 2 : length;
24
-
25
- const shortened = hash.substr(0, beginningChars) + "…" + hash.substr(-length);
26
-
27
- return shortened;
28
- }
29
-
30
- export function short(buffer: Buffer): string {
31
- return buffer.toString("hex").slice(0, 8) + "...";
32
- }
33
-
34
- export const signGnosisSafeTx = async (
35
- {
36
- to,
37
- data = null as any,
38
- value = "0",
39
- operation = "1",
40
- baseGas = "0",
41
- gasPrice = "0",
42
- gasToken = "0x0000000000000000000000000000000000000000",
43
- refundReceiver = "0x0000000000000000000000000000000000000000",
44
- safeTxGas = "79668" as string | number,
45
- nonce = "0",
46
- chainId = 137 as ChainId,
47
- },
48
- { signer }
49
- ) => {
50
- const gnosisSafe = addresses[chainId].gnosisSafe;
51
-
52
- const domain = {
53
- verifyingContract: gnosisSafe,
54
- chainId,
55
- };
56
-
57
- const types = {
58
- SafeTx: [
59
- { type: "address", name: "to" },
60
- { type: "uint256", name: "value" },
61
- { type: "bytes", name: "data" },
62
- { type: "uint8", name: "operation" },
63
- { type: "uint256", name: "safeTxGas" },
64
- { type: "uint256", name: "baseGas" },
65
- { type: "uint256", name: "gasPrice" },
66
- { type: "address", name: "gasToken" },
67
- { type: "address", name: "refundReceiver" },
68
- { type: "uint256", name: "nonce" },
69
- ],
70
- };
71
-
72
- const message = {
73
- baseGas,
74
- data,
75
- gasPrice,
76
- gasToken,
77
- nonce: Number(nonce),
78
- operation,
79
- refundReceiver,
80
- safeAddress: gnosisSafe,
81
- safeTxGas: String(safeTxGas),
82
- to,
83
- value,
84
- };
85
-
86
- return await signer._signTypedData(domain, types, message);
87
- };
88
-
89
- export const getRpcProviderUrl = (chainId: ChainId) => {
90
- switch (chainId) {
91
- case 1:
92
- return "https://rpc.ankr.com/eth";
93
- case 137:
94
- return "https://rpc.ankr.com/polygon";
95
- case 43114:
96
- return "https://rpc.ankr.com/avalanche";
97
- default:
98
- throw new Error(`Unknown chainId: ${chainId}`);
99
- }
100
- };
101
-
102
- export interface Signature {
103
- signer: string;
104
- hash?: string;
105
- data: string;
106
- }
107
-
108
- export const buildSignatureBytes = (signatures: Signature[]): string => {
109
- signatures.sort((left, right) =>
110
- left.signer.toLowerCase().localeCompare(right.signer.toLowerCase())
111
- );
112
- let signatureBytes = "0x";
113
- for (const sig of signatures) {
114
- signatureBytes += sig.data.slice(2);
115
- }
116
- return signatureBytes;
117
- };
118
-
119
- /**
120
- * Call an async function with a maximum time limit (in milliseconds) for the timeout
121
- * Resolved promise for async function call, or an error if time limit reached
122
- */
123
- export const asyncCallWithTimeout = async <T>(
124
- asyncPromise: Promise<T>,
125
- timeout: number
126
- ) => {
127
- let timeoutHandle;
128
-
129
- const timeoutPromise = new Promise((_resolve, reject) => {
130
- timeoutHandle = setTimeout(
131
- () => reject(new Error("Async call timeout limit reached")),
132
- timeout
133
- );
134
- });
135
-
136
- return Promise.race([asyncPromise, timeoutPromise]).then((result) => {
137
- clearTimeout(timeoutHandle);
138
- return result;
139
- }) as Promise<T>;
140
- };
141
-
142
- type GenerateInteropTransactionHashParam = {
143
- actionId: string;
144
- vnonce: string;
145
- sourceSender: string;
146
- sourceChainId: string | number;
147
- sourceDsaId: string;
148
- targetChainId: string | number;
149
- targetDsaId: string;
150
- };
151
-
152
- export const generateInteropTransactionHash = (
153
- data: GenerateInteropTransactionHashParam
154
- ) => {
155
- return ethers.utils.solidityKeccak256(
156
- Array.from({ length: 7 }, () => "string"),
157
- [
158
- String(data.actionId),
159
- String(data.vnonce),
160
- String(data.sourceSender),
161
- String(data.sourceChainId),
162
- String(data.sourceDsaId),
163
- String(data.targetChainId),
164
- String(data.targetDsaId),
165
- ]
166
- );
167
- };
168
-
169
- export class ContractError extends Error {
170
- method: string;
171
- address: string;
172
- args: any[];
173
- }
174
-
175
- export function getContract<TContract extends ethers.Contract>(
176
- address: string,
177
- contractInterface: ethers.ContractInterface | any,
178
- signerOrProvider?: ethers.Signer | ethers.providers.Provider
179
- ) {
180
- if (
181
- !ethers.utils.getAddress(address) ||
182
- address === ethers.constants.AddressZero
183
- ) {
184
- throw Error(`Invalid 'address' parameter '${address}'.`);
185
- }
186
-
187
- const contract = new ethers.Contract(
188
- address,
189
- contractInterface,
190
- signerOrProvider
191
- ) as TContract;
192
-
193
- // Make sure the contract properties is writable
194
- const desc = Object.getOwnPropertyDescriptor(contract, "functions");
195
-
196
- if (!desc || desc.writable !== true) {
197
- return contract;
198
- }
199
-
200
- return new Proxy(contract, {
201
- get(target, prop, receiver) {
202
- const value = Reflect.get(target, prop, receiver);
203
-
204
- if (
205
- typeof value === "function" &&
206
- (contract.functions.hasOwnProperty(prop) ||
207
- ["queryFilter"].includes(String(prop)))
208
- ) {
209
- let isConstant = false;
210
-
211
- try {
212
- isConstant = contract.interface.getFunction(String(prop)).constant;
213
- } catch (error) {}
214
-
215
- return async (...args: any[]) => {
216
- try {
217
- return await retry(
218
- async () => await value.bind(contract)(...args),
219
- { retries: isConstant ? 1 : 3 }
220
- );
221
- } catch (error) {
222
- const err = new ContractError(
223
- `Error calling "${String(prop)}" on "${address}": ${
224
- error.reason || error.message
225
- }`
226
- );
227
-
228
- err.method = String(prop);
229
- err.address = address;
230
- err.args = [...args];
231
-
232
- throw err;
233
- }
234
- };
235
- }
236
-
237
- if (
238
- typeof value === "object" &&
239
- [
240
- "populateTransaction",
241
- "estimateGas",
242
- "functions",
243
- "callStatic",
244
- ].includes(String(prop))
245
- ) {
246
- const parentProp = String(prop);
247
-
248
- return new Proxy(value, {
249
- get(target, prop, receiver) {
250
- const value = Reflect.get(target, prop, receiver);
251
-
252
- if (typeof value === "function") {
253
- return async (...args: any[]) => {
254
- try {
255
- return await retry(
256
- async () => await value.bind(contract)(...args),
257
- { retries: parentProp === "callStatic" ? 3 : 1 }
258
- );
259
- } catch (error) {
260
- const err = new ContractError(
261
- `Error calling "${String(
262
- prop
263
- )}" using "${parentProp}" on "${address}": ${
264
- error.reason || error.message
265
- }`
266
- );
267
-
268
- err.method = String(prop);
269
- err.address = address;
270
- err.args = [...args];
271
-
272
- throw err;
273
- }
274
- };
275
- }
276
- },
277
- });
278
- }
279
-
280
- return value;
281
- },
282
- });
283
- }
284
-
285
- export const generateGnosisTransaction = async (
286
- transactionData: any,
287
- safeContract: GnosisSafe
288
- ) => {
289
- console.log(transactionData);
290
-
291
- let isExecuted = await safeContract.dataHashes(
292
- await safeContract.getTransactionHash(
293
- transactionData.to,
294
- transactionData.value,
295
- transactionData.data,
296
- transactionData.operation,
297
- transactionData.safeTxGas,
298
- transactionData.baseGas,
299
- transactionData.gasPrice,
300
- transactionData.gasToken,
301
- transactionData.refundReceiver,
302
- transactionData.nonce
303
- )
304
- );
305
-
306
- while (isExecuted == 1) {
307
- transactionData.safeTxGas = ethers.BigNumber.from(
308
- String(transactionData.safeTxGas)
309
- )
310
- .add(1)
311
- .toString();
312
-
313
- isExecuted = await safeContract.dataHashes(
314
- await safeContract.getTransactionHash(
315
- transactionData.to,
316
- transactionData.value,
317
- transactionData.data,
318
- transactionData.operation,
319
- transactionData.safeTxGas,
320
- transactionData.baseGas,
321
- transactionData.gasPrice,
322
- transactionData.gasToken,
323
- transactionData.refundReceiver,
324
- transactionData.nonce
325
- )
326
- );
327
- }
328
-
329
- return transactionData;
330
- };
331
-
332
- export class LiquidityError extends Error {
333
- constructor(message?: string) {
334
- super(message || "Not enough liquidity");
335
- Object.setPrototypeOf(this, new.target.prototype);
336
- }
337
- }
338
-
339
- export const encodeConnectorMethod = (params: {
340
- connector: string;
341
- method: string;
342
- args: string[];
343
- }) => {
344
- const connectorInterface = getInterface(
345
- connectors.versions[2][params.connector],
346
- params.method
347
- );
348
-
349
- if (!connectorInterface)
350
- throw new Error(`ConnectorInterface '${params.method}' not found`);
351
-
352
- //@ts-ignore
353
- return Web3EthAbi.encodeFunctionCall(connectorInterface, params.args);
354
- };
355
-
356
- const getInterface = (abiItems: any[], method: string) => {
357
- const abiItem = abiItems.find((abiItem) => abiItem.name === method);
358
-
359
- if (!abiItem) {
360
- console.error(`${method} is an invalid method.`);
361
- return;
362
- }
363
-
364
- return abiItem;
365
- };
1
+ export * from './async';
2
+ export * from './dsa';
3
+ export * from './formatting';
4
+ export * from './gnosis';
5
+ export * from './http';
6
+ export * from './interop';
7
+ export * from './web3';
8
+ export * from './validate';
9
+ export * from './tokens';
@@ -0,0 +1,28 @@
1
+ import { ethers } from "ethers";
2
+
3
+ type GenerateInteropTransactionHashParam = {
4
+ actionId: string;
5
+ vnonce: string;
6
+ sourceSender: string;
7
+ sourceChainId: string | number;
8
+ sourceDsaId: string;
9
+ targetChainId: string | number;
10
+ targetDsaId: string;
11
+ };
12
+
13
+ export const generateInteropTransactionHash = (
14
+ data: GenerateInteropTransactionHashParam
15
+ ) => {
16
+ return ethers.utils.solidityKeccak256(
17
+ Array.from({ length: 7 }, () => "string"),
18
+ [
19
+ String(data.actionId),
20
+ String(data.vnonce),
21
+ String(data.sourceSender),
22
+ String(data.sourceChainId),
23
+ String(data.sourceDsaId),
24
+ String(data.targetChainId),
25
+ String(data.targetDsaId),
26
+ ]
27
+ );
28
+ };
@@ -0,0 +1,21 @@
1
+ import { wrappedNativeToken } from "@/constants"
2
+
3
+ export const isNativeToken = (tokenAddress: string) => {
4
+ return tokenAddress.toLowerCase() === "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE".toLowerCase()
5
+ }
6
+
7
+ export const isNativeWrappedToken = (tokenAddress: string, chainId: number | string) => {
8
+ return wrappedNativeToken[chainId].toLowerCase() == tokenAddress.toLowerCase()
9
+ }
10
+
11
+ export const isNativeOrWrappedToken = (tokenAddress: string, chainId: number | string) => {
12
+ if (isNativeToken(tokenAddress)) {
13
+ return true
14
+ }
15
+
16
+ if (isNativeWrappedToken(tokenAddress, chainId)) {
17
+ return true
18
+ }
19
+
20
+ return false
21
+ }
@@ -0,0 +1,179 @@
1
+ import abi from "@/abi";
2
+ import { addresses, capPerChain, tokens } from "@/constants";
3
+ import { InvalidChaindIdError, LowLiquidityError } from "@/errors";
4
+ import { ethers } from "ethers";
5
+ import { getContract, getRpcProviderUrl } from "./web3";
6
+ import BigNumber from "bignumber.js";
7
+ import { chainIdToName, formatUsd } from "./formatting";
8
+ import { isNativeWrappedToken } from "./tokens";
9
+ import { Prices } from "@/services";
10
+ import { JsonRpcRetryProvider } from "@/providers";
11
+ import { IPosition } from "@/db";
12
+ import { BalanceResolver } from "@/typechain";
13
+ import { getDsaAccountAddress } from "./dsa";
14
+
15
+ export const validateChains = ({ sourceChainId, targetChainId }) => {
16
+ if (!sourceChainId) {
17
+ throw new InvalidChaindIdError("Source chain id is required");
18
+ }
19
+
20
+ if (!targetChainId) {
21
+ throw new InvalidChaindIdError("Target chain id is required");
22
+ }
23
+
24
+ if (sourceChainId == targetChainId) {
25
+ throw new InvalidChaindIdError("Source and target chain cannot be the same");
26
+ }
27
+
28
+ if (!addresses[sourceChainId]) {
29
+ throw new InvalidChaindIdError("Invalid source chain id");
30
+ }
31
+
32
+ if (!addresses[targetChainId]) {
33
+ throw new InvalidChaindIdError("Invalid target chain id");
34
+ }
35
+ };
36
+
37
+
38
+ export const validateSourceLiquidity = async ({
39
+ position = null as unknown as IPosition,
40
+ sourceChainId,
41
+ sourceDsaId,
42
+ isSupply = false,
43
+ sourceProvider = null as unknown as JsonRpcRetryProvider,
44
+ }) => {
45
+ sourceProvider = sourceProvider || new JsonRpcRetryProvider(getRpcProviderUrl(sourceChainId));
46
+
47
+
48
+ const sourceBalanceResolverContract = getContract<BalanceResolver>(
49
+ addresses[sourceChainId].balanceResolver,
50
+ abi.balanceResolver,
51
+ sourceProvider,
52
+ )
53
+
54
+ const srcDsaAddress = await getDsaAccountAddress({ dsaId: sourceDsaId, chainId: sourceChainId , provider: sourceProvider });
55
+ const srcBalance = await sourceBalanceResolverContract.checkLiquidity(position, srcDsaAddress, isSupply, false)
56
+
57
+ if (!srcBalance.isOk) {
58
+
59
+ let liquidityRequired = ""
60
+
61
+ srcBalance.withdraw.forEach(a => {
62
+ const token = tokens[sourceChainId].find(t => t.address.toLowerCase() === a.token.toLowerCase());
63
+
64
+ if (token && (new BigNumber(a.liquidityShort.toString()).isZero()) == false) {
65
+ liquidityRequired += `- Need ${new BigNumber(a.liquidityShort.toString()).dividedBy(10 ** token.decimals).toFormat()} ${token.symbol}\n`
66
+ }
67
+ })
68
+
69
+ throw new LowLiquidityError(`Liquidity low on ${chainIdToName(sourceChainId)}: \n` + liquidityRequired);
70
+ }
71
+ };
72
+
73
+ export const validateTargetLiquidity = async ({
74
+ position = null as unknown as IPosition,
75
+ targetChainId,
76
+ targetDsaId,
77
+ targetProvider = null as unknown as JsonRpcRetryProvider,
78
+ }) => {
79
+ targetProvider = targetProvider || new JsonRpcRetryProvider(getRpcProviderUrl(targetChainId));
80
+
81
+
82
+ const sourceBalanceResolverContract = getContract<BalanceResolver>(
83
+ addresses[targetChainId].balanceResolver,
84
+ abi.balanceResolver,
85
+ targetProvider,
86
+ )
87
+ // TODO:
88
+
89
+ const targetDsaAddress = await getDsaAccountAddress({ dsaId: targetDsaId, chainId: targetChainId, provider: targetProvider });
90
+
91
+ const targetBalance = await sourceBalanceResolverContract.checkLiquidity(position, targetDsaAddress, true, true)
92
+
93
+ if (!targetBalance.isOk) {
94
+
95
+ let liquidityRequired = ""
96
+
97
+ targetBalance.supply.forEach(a => {
98
+ const token = tokens[targetChainId].find(t => t.address.toLowerCase() === a.token.toLowerCase());
99
+
100
+
101
+ if (token) {
102
+ liquidityRequired += `- Need ${new BigNumber(a.liquidityShort.toString()).dividedBy(10 ** token.decimals).toFormat()} ${token.symbol}\n`
103
+ }
104
+ })
105
+
106
+ throw new LowLiquidityError(`Liquidity low on ${chainIdToName(targetChainId)}: \n` + liquidityRequired);
107
+ }
108
+ };
109
+
110
+ const mapTokenAddressToMainnetToken = (
111
+ address: string,
112
+ targetChainId: number | string
113
+ ) => {
114
+ targetChainId = String(targetChainId);
115
+ const token = tokens[targetChainId].find(
116
+ (t) => t.address.toLowerCase() === address.toLowerCase()
117
+ );
118
+
119
+ if (targetChainId === "1") {
120
+ return token;
121
+ }
122
+
123
+ if (!token) {
124
+ return null;
125
+ }
126
+
127
+ return tokens["1"].find((t) => t.symbol === token.symbol);
128
+ };
129
+
130
+ export const validateLiquidityCap = async (
131
+ position: IPosition,
132
+ sourceChainId: number | string,
133
+ targetChainId: number | string
134
+ ) => {
135
+ const cap = capPerChain[targetChainId] || 1_000_000;
136
+ const mainnetPrices = Prices.getMainnetPrices();
137
+ const nativeTokenPrice = Prices.getNetworkTokenPrices()[targetChainId];
138
+
139
+ let total = new BigNumber(0);
140
+
141
+ const supplyPosition = position.supply;
142
+
143
+ for (const { sourceToken: srcTokenAddress, targetToken: tokenAddress, amount } of supplyPosition) {
144
+ let tokenPrice;
145
+ let token;
146
+
147
+ if (isNativeWrappedToken(srcTokenAddress, sourceChainId)) {
148
+ tokenPrice = nativeTokenPrice;
149
+ token = tokens[targetChainId].find(t => t.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE');
150
+ } else {
151
+ const mainnetToken = mapTokenAddressToMainnetToken(
152
+ tokenAddress,
153
+ targetChainId
154
+ );
155
+ if (!mainnetToken) {
156
+ throw new Error(`Token ${tokenAddress} is not valid.`);
157
+ }
158
+
159
+ tokenPrice = mainnetPrices[mainnetToken.address];
160
+
161
+ if (!tokenPrice) {
162
+ throw new Error(`Token ${tokenAddress} is not valid!`);
163
+ }
164
+
165
+ token = mainnetToken;
166
+ }
167
+
168
+
169
+ total = total.plus((tokenPrice * Number(amount)) / 10 ** token.decimals);
170
+ }
171
+
172
+ if (total.isGreaterThan(cap)) {
173
+ throw new Error(
174
+ `Total amount of tokens in the transaction is greater than the maximum limit of estimated ${formatUsd(
175
+ cap
176
+ )}`
177
+ );
178
+ }
179
+ };