@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
@@ -0,0 +1,119 @@
1
+ import abi from "@/abi";
2
+ import config from "@/config";
3
+ import { addresses } from "@/constants";
4
+ import { Transaction } from "@/db";
5
+ import { JsonRpcRetryProvider } from "@/providers";
6
+ import { InteropX } from "@/typechain";
7
+ import { ChainId } from "@/types";
8
+ import { encodeConnectorMethod, getContract, getRpcProviderUrl } from "@/utils";
9
+ import { ethers } from "ethers";
10
+ import { MetaTransaction, OperationType } from "ethers-multisend";
11
+
12
+ export default async function (transaction: Transaction) {
13
+ const transactions: MetaTransaction[] = [];
14
+ const logs: any[] = [];
15
+
16
+ const {
17
+ position,
18
+ actionId,
19
+ actionIdHashHash,
20
+ sourceSender,
21
+ sourceDsaId,
22
+ targetDsaId,
23
+ sourceChainId,
24
+ targetChainId,
25
+ vnonce,
26
+ metadata,
27
+ } = transaction.submitEvent;
28
+
29
+ const sourceChainProvider = new JsonRpcRetryProvider(
30
+ getRpcProviderUrl(sourceChainId as ChainId)
31
+ );
32
+ const sourceWallet = new ethers.Wallet(
33
+ config.privateKey,
34
+ sourceChainProvider
35
+ );
36
+ const dsaAddress = addresses[sourceChainId].dsaAddress;
37
+ const sourceUserAddress =
38
+ Number(sourceDsaId) == 0 ? sourceSender : dsaAddress;
39
+ const interopAddress = addresses[sourceChainId].interopX;
40
+ const contract = getContract<InteropX>(
41
+ interopAddress,
42
+ abi.interopX,
43
+ sourceWallet
44
+ );
45
+
46
+ const sourceSpells: any[] = [];
47
+ const commonSpells: any[] = [];
48
+
49
+ for (const withdraw of position.withdraw) {
50
+ let spellData = {
51
+ connector: "AAVE-V3-A",
52
+ method: "payback",
53
+ args: [withdraw.sourceToken, withdraw.amount, "2", "0", "0"],
54
+ };
55
+
56
+ sourceSpells.push({
57
+ connector: spellData.connector,
58
+ data: encodeConnectorMethod(spellData),
59
+ });
60
+
61
+ let spellDataBasicWithdraw = {
62
+ connector: "BASIC-A",
63
+ method: "withdraw",
64
+ args: [withdraw.sourceToken, withdraw.amount, sourceUserAddress, "0", "0"],
65
+ };
66
+
67
+ commonSpells.push({
68
+ connector: spellDataBasicWithdraw.connector,
69
+ data: encodeConnectorMethod(spellDataBasicWithdraw),
70
+ });
71
+ }
72
+
73
+ for (const supply of position.supply) {
74
+ let spellDataWithdraw = {
75
+ connector: "AAVE-V3-A",
76
+ method: "withdraw",
77
+ args: [supply.sourceToken, supply.amount, "0", "0"],
78
+ };
79
+
80
+ sourceSpells.push({
81
+ connector: spellDataWithdraw.connector,
82
+ data: encodeConnectorMethod(spellDataWithdraw),
83
+ });
84
+
85
+ let spellDataBasicWithdraw = {
86
+ connector: "BASIC-A",
87
+ method: "withdraw",
88
+ args: [supply.sourceToken, supply.amount, dsaAddress, "0", "0"],
89
+ };
90
+
91
+ sourceSpells.push({
92
+ connector: spellDataBasicWithdraw.connector,
93
+ data: encodeConnectorMethod(spellDataBasicWithdraw),
94
+ });
95
+ }
96
+
97
+ const { data } = await contract.populateTransaction.sourceAction(
98
+ sourceSpells,
99
+ commonSpells,
100
+ position,
101
+ actionId,
102
+ sourceSender,
103
+ sourceDsaId,
104
+ targetDsaId,
105
+ sourceChainId,
106
+ targetChainId,
107
+ vnonce,
108
+ metadata
109
+ );
110
+
111
+ transactions.push({
112
+ to: interopAddress,
113
+ data: data!,
114
+ value: "0",
115
+ operation: OperationType.Call,
116
+ });
117
+
118
+ return { transactions, logs };
119
+ }
@@ -0,0 +1,142 @@
1
+ import abi from "@/abi";
2
+ import config from "@/config";
3
+ import { addresses } from "@/constants";
4
+ import { Transaction } from "@/db";
5
+ import { JsonRpcRetryProvider } from "@/providers";
6
+ import { InteropX } from "@/typechain";
7
+ import { InstList } from "@/typechain/InstList";
8
+ import { ChainId } from "@/types";
9
+ import { encodeConnectorMethod, getContract, getRpcProviderUrl } from "@/utils";
10
+ import { ethers } from "ethers";
11
+ import { MetaTransaction, OperationType } from "ethers-multisend";
12
+
13
+
14
+ export default async function (transaction: Transaction) {
15
+ const transactions: MetaTransaction[] = [];
16
+ const logs: any[] = [];
17
+
18
+ const {
19
+ sourceSpells,
20
+ position,
21
+ actionId,
22
+ sourceSender,
23
+ sourceDsaId,
24
+ targetDsaId,
25
+ sourceChainId,
26
+ targetChainId,
27
+ vnonce,
28
+ metadata,
29
+ } = transaction.validateEvent;
30
+
31
+ const targetChainProvider = new JsonRpcRetryProvider(
32
+ getRpcProviderUrl(targetChainId as ChainId)
33
+ );
34
+ const targetWallet = new ethers.Wallet(
35
+ config.privateKey,
36
+ targetChainProvider
37
+ );
38
+
39
+
40
+ const targetInstListContract = getContract<InstList>(
41
+ addresses[targetChainId].instList,
42
+ abi.instList,
43
+ targetChainProvider,
44
+ );
45
+
46
+ const targetDsaAddress = await targetInstListContract.accountAddr(targetDsaId)
47
+ const dsaAddress = addresses[targetChainId].dsaAddress;
48
+ const interopAddress = addresses[targetChainId].interopX;
49
+ const contract = getContract<InteropX>(
50
+ interopAddress,
51
+ abi.interopX,
52
+ targetWallet
53
+ );
54
+
55
+ const targetSpells: any[] = [];
56
+ const commonSpells: any[] = [];
57
+
58
+ for (const supplyToken of position.supply) {
59
+ let spellData = {
60
+ connector: "AAVE-V3-A",
61
+ method: "deposit",
62
+ args: [supplyToken.targetToken, supplyToken.amount, "0", "0"],
63
+ };
64
+
65
+ targetSpells.push({
66
+ connector: spellData.connector,
67
+ data: encodeConnectorMethod(spellData),
68
+ });
69
+
70
+ let spellDataBasicWithdraw = {
71
+ connector: "BASIC-A",
72
+ method: "withdraw",
73
+ args: [supplyToken.targetToken, supplyToken.amount, targetDsaAddress, "0", "0"],
74
+ };
75
+
76
+ commonSpells.push({
77
+ connector: spellDataBasicWithdraw.connector,
78
+ data: encodeConnectorMethod(spellDataBasicWithdraw),
79
+ });
80
+ }
81
+
82
+ for (const withdrawToken of position.withdraw) {
83
+
84
+ let spellData = {
85
+ connector: "AAVE-V3-A",
86
+ method: "borrow",
87
+ args: [
88
+ withdrawToken.targetToken,
89
+ withdrawToken.amount,
90
+ "2",
91
+ "0",
92
+ "0",
93
+ ],
94
+ };
95
+
96
+ targetSpells.push({
97
+ connector: spellData.connector,
98
+ data: encodeConnectorMethod(spellData),
99
+ });
100
+
101
+ let spellData2 = {
102
+ connector: "BASIC-A",
103
+ method: "withdraw",
104
+ args: [
105
+ withdrawToken.targetToken,
106
+ withdrawToken.amount,
107
+ dsaAddress,
108
+ "0",
109
+ "0",
110
+ ],
111
+ };
112
+
113
+ targetSpells.push({
114
+ connector: spellData2.connector,
115
+ data: encodeConnectorMethod(spellData2),
116
+ });
117
+ }
118
+
119
+ const { data } = await contract.populateTransaction.targetAction(
120
+ sourceSpells,
121
+ targetSpells,
122
+ commonSpells,
123
+ position,
124
+ actionId,
125
+ sourceSender,
126
+ sourceDsaId,
127
+ targetDsaId,
128
+ sourceChainId,
129
+ targetChainId,
130
+ vnonce,
131
+ metadata
132
+ );
133
+
134
+ transactions.push({
135
+ to: interopAddress,
136
+ data: data!,
137
+ value: "0",
138
+ operation: OperationType.Call,
139
+ });
140
+
141
+ return { transactions, logs }
142
+ }
@@ -1,5 +1,7 @@
1
1
  import aaveV2 from "./aaveV2"
2
+ import aaveV3 from "./aaveV3"
2
3
 
3
4
  export default {
4
5
  'A:AAVE-V2:AAVE-V2': aaveV2,
6
+ 'A:AAVE-V3:AAVE-V3': aaveV3,
5
7
  }
package/src/index.ts CHANGED
@@ -82,6 +82,7 @@ import { startPeer, protocol, peerPool } from "@/net";
82
82
  import { startApiServer } from '@/api';
83
83
  import { Transaction } from './db';
84
84
  import { shortenHash } from './utils';
85
+ import './crons';
85
86
 
86
87
  async function main() {
87
88
 
@@ -0,0 +1 @@
1
+ export * from './retry-provider';
@@ -0,0 +1,51 @@
1
+ import { ethers } from "ethers";
2
+ import wait from "waait";
3
+ import Bluebird from "bluebird";
4
+
5
+ export interface RetryOptions {
6
+ delay?: number;
7
+ timeouts: number[];
8
+ }
9
+
10
+ export function promiseTimeout<T>(ms: number, promise: Promise<T>): Promise<T> {
11
+ return Bluebird.resolve(promise).timeout(ms);
12
+ }
13
+
14
+ export function retryOperation(
15
+ retriesLeft: number,
16
+ operation: () => Promise<any>,
17
+ options: RetryOptions
18
+ ) {
19
+ return new Promise((resolve, reject) => {
20
+ const { timeouts } = options;
21
+ // Find the timeout for this specific iteration
22
+ const timeout = timeouts[timeouts.length - retriesLeft];
23
+
24
+ // Wrap the original operation in a timeout
25
+ const execution = promiseTimeout(timeout, operation());
26
+
27
+ // If the promise is successful, resolve it and bubble the result up
28
+ return execution.then(resolve).catch((reason: any) => {
29
+ // If there are any retries left, we call the same retryOperation function again,
30
+ // but decrementing the number of retries left by 1
31
+ if (retriesLeft - 1 > 0) {
32
+ // Delay the new attempt slightly
33
+ return wait(options.delay || 50)
34
+ .then(retryOperation.bind(null, retriesLeft - 1, operation, options))
35
+ .then(resolve)
36
+ .catch(reject);
37
+ }
38
+ // Reject (and bubble the result up) if there are no more retries
39
+ return reject(reason);
40
+ });
41
+ });
42
+ }
43
+
44
+ export class JsonRpcRetryProvider extends ethers.providers.JsonRpcProvider {
45
+ public perform(method: string, params: any): Promise<any> {
46
+ const timeouts = [5_000, 10_000];
47
+ const operation = () => super.perform(method, params);
48
+
49
+ return retryOperation(2, operation, { timeouts, delay: 50 });
50
+ }
51
+ }
@@ -0,0 +1,89 @@
1
+ import Web3Utils from "web3-utils";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import { tokens } from "@/constants";
5
+ import expandHomeDir from "expand-home-dir";
6
+ import config from "@/config";
7
+ import { http } from "@/utils";
8
+
9
+ const basePath = expandHomeDir(`~/.interop-x/data/${config.publicAddress}/${config.staging ? 'staging' : ''}`);
10
+ const mainnetPricesFilePath = path.resolve(basePath, "./mainnetPrices.json");
11
+ const networkTokenPricesFilePath = path.resolve(basePath, "./networkTokenPrices.json");
12
+
13
+ class Prices {
14
+ private static mainnetPrices = {};
15
+
16
+ private static networkTokenPrices = {};
17
+
18
+ static async fetch() {
19
+
20
+ if (!fs.existsSync(mainnetPricesFilePath)) {
21
+ fs.writeFileSync(mainnetPricesFilePath, JSON.stringify({}));
22
+ }
23
+
24
+ if (!fs.existsSync(networkTokenPricesFilePath)) {
25
+ fs.writeFileSync(networkTokenPricesFilePath, JSON.stringify({}));
26
+ }
27
+
28
+ this.mainnetPrices = JSON.parse(fs.readFileSync(mainnetPricesFilePath, "utf8"));
29
+ this.networkTokenPrices = JSON.parse(fs.readFileSync(networkTokenPricesFilePath, "utf8"));
30
+
31
+ try {
32
+ const path = tokens["1"]
33
+ .filter((a) => a.symbol !== "ETH")
34
+ .map((token) => token.address)
35
+ .join(",");
36
+
37
+ const [response, ethResponse, avaxResponse, polygonResponse] =
38
+ await Promise.all([
39
+ http.get(
40
+ "https://api.coingecko.com/api/v3/simple/token_price/ethereum",
41
+ {
42
+ params: { contract_addresses: path, vs_currencies: "usd" },
43
+ }
44
+ ),
45
+ http.get("https://api.coingecko.com/api/v3/simple/price", {
46
+ params: { ids: "ethereum", vs_currencies: "usd" },
47
+ }),
48
+ http.get("https://api.coingecko.com/api/v3/simple/price", {
49
+ params: { ids: "avalanche-2", vs_currencies: "usd" },
50
+ }),
51
+ http.get("https://api.coingecko.com/api/v3/simple/price", {
52
+ params: { ids: "matic-network", vs_currencies: "usd" },
53
+ }),
54
+ ]);
55
+
56
+ this.networkTokenPrices = {
57
+ "1": ethResponse.data.ethereum.usd.toString(),
58
+ "137": polygonResponse.data["matic-network"].usd.toString(),
59
+ "43114": avaxResponse.data["avalanche-2"].usd.toString(),
60
+ };
61
+
62
+ const data = response.data;
63
+
64
+ for (const key in data) {
65
+ const _key = Web3Utils.toChecksumAddress(key);
66
+ if (!data[key].usd) continue;
67
+ this.mainnetPrices[_key] = data[key].usd.toString();
68
+ }
69
+
70
+ this.mainnetPrices["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"] =
71
+ ethResponse.data.ethereum.usd.toString();
72
+ } catch (error) { }
73
+
74
+ fs.writeFileSync(mainnetPricesFilePath, JSON.stringify(this.mainnetPrices));
75
+ fs.writeFileSync(networkTokenPricesFilePath, JSON.stringify(this.networkTokenPrices));
76
+
77
+ return this.mainnetPrices;
78
+ }
79
+
80
+ static getMainnetPrices() {
81
+ return this.mainnetPrices;
82
+ }
83
+
84
+ static getNetworkTokenPrices() {
85
+ return this.networkTokenPrices;
86
+ }
87
+ }
88
+
89
+ export default Prices;
@@ -0,0 +1 @@
1
+ export { default as Prices } from './Prices';
@@ -5,12 +5,18 @@ import abi from "@/abi";
5
5
  import { Transaction } from "@/db";
6
6
  import {
7
7
  buildSignatureBytes,
8
+ chainIdToName,
9
+ generateGnosisSignatureMessage,
8
10
  generateGnosisTransaction,
9
- generateInteropTransactionHash,
11
+ getChainIdNativeSymbol,
10
12
  getContract,
13
+ getExplorerUrl,
11
14
  getRpcProviderUrl,
12
- LiquidityError,
13
15
  Signature,
16
+ validateChains,
17
+ validateLiquidityCap,
18
+ validateSourceLiquidity,
19
+ getGnosisSignatureAddress,
14
20
  } from "@/utils";
15
21
  import { addresses, blockConfirmations } from "@/constants";
16
22
  import { ChainId } from "@/types";
@@ -22,9 +28,13 @@ import { buildGnosisAction } from "@/gnosis";
22
28
  import { peerPool, protocol } from "@/net";
23
29
  import { LogDescription } from "ethers/lib/utils";
24
30
  import wait from "waait";
31
+ import { LiquidityError, UnsupportedChaindIdError } from "@/errors";
32
+ import { BigNumber } from "bignumber.js";
33
+ import dedent from "dedent";
34
+ import { JsonRpcRetryProvider } from "@/providers";
25
35
 
26
- class ProcessSubmitSubmitEvents extends BaseTask {
27
- sourceProvider: ethers.providers.JsonRpcProvider;
36
+ export default class ProcessSubmitEvents extends BaseTask {
37
+ sourceProvider: JsonRpcRetryProvider;
28
38
  sourceGnosisContract: GnosisSafe;
29
39
  sourceWallet: Wallet;
30
40
  chainId: ChainId;
@@ -33,7 +43,7 @@ class ProcessSubmitSubmitEvents extends BaseTask {
33
43
 
34
44
  constructor({ chainId }: { chainId: ChainId }) {
35
45
  super({
36
- logger: new Logger("InteropX::ProcessSubmitSubmitEvents"),
46
+ logger: new Logger("InteropX::ProcessSubmitEvents"),
37
47
  });
38
48
  this.chainId = chainId;
39
49
  }
@@ -73,6 +83,78 @@ class ProcessSubmitSubmitEvents extends BaseTask {
73
83
  transaction.sourceStatus = "proccessing";
74
84
  await transaction.save();
75
85
 
86
+ const { submitEvent: { position, sourceChainId, targetChainId, sourceDsaId } } = transaction;
87
+ try {
88
+ validateChains({ sourceChainId, targetChainId });
89
+ } catch (error) {
90
+ transaction.sourceErrors = [error.message];
91
+ transaction.sourceStatus = "failed";
92
+ transaction.targetStatus = "failed";
93
+ transaction.status = "failed";
94
+ await transaction.save();
95
+ return;
96
+ }
97
+
98
+ const walletBalance = (await this.sourceWallet.getBalance()).toString();
99
+ const currentGasPrice = (await this.sourceWallet.getGasPrice()).toString()
100
+
101
+ const minBalanceRequired = new BigNumber(currentGasPrice)
102
+ .multipliedBy(4_000_000)
103
+ .multipliedBy(2) // 2x balance
104
+
105
+ if (
106
+ new BigNumber(walletBalance).isLessThan(minBalanceRequired)
107
+ ) {
108
+ console.log(
109
+ dedent`Not enough balance in wallet ${getExplorerUrl(sourceChainId, '/address/' + this.sourceWallet.address)} on ${chainIdToName(sourceChainId)}
110
+ Balance: ${ethers.utils.parseEther(walletBalance)} ${getChainIdNativeSymbol(sourceChainId)}
111
+ Required Balance: ${ethers.utils.parseEther(minBalanceRequired.toString())}
112
+ Require more: ${ethers.utils.parseEther(minBalanceRequired.minus(walletBalance).toString())}`
113
+ );
114
+ transaction.sourceDelayUntil = moment().add({ minutes: 5 }).toDate();
115
+ transaction.sourceStatus = "pending";
116
+ await transaction.save();
117
+ return;
118
+ }
119
+
120
+ try {
121
+ await validateLiquidityCap(position, sourceChainId, targetChainId);
122
+ } catch (error) {
123
+ transaction.sourceErrors = [error.message];
124
+ transaction.sourceStatus = "failed";
125
+ transaction.targetStatus = "failed";
126
+ transaction.status = "failed";
127
+ await transaction.save();
128
+ return;
129
+ }
130
+
131
+ try {
132
+ await validateSourceLiquidity({
133
+ position,
134
+ sourceChainId,
135
+ sourceDsaId,
136
+ sourceProvider: this.sourceProvider,
137
+ });
138
+ } catch (error) {
139
+ if (error instanceof UnsupportedChaindIdError) {
140
+ console.log(`Dropping transaction ${transaction.transactionHash}`);
141
+
142
+ transaction.sourceErrors = [error.message];
143
+ transaction.sourceStatus = "failed";
144
+ transaction.targetStatus = "failed";
145
+ transaction.status = "failed";
146
+ await transaction.save();
147
+ } else {
148
+ transaction.sourceStatus = "pending";
149
+ transaction.sourceErrors = [error.message];
150
+ transaction.sourceDelayUntil = moment().add({ minutes: 5 }).toDate();
151
+ await transaction.save();
152
+
153
+ console.log("[validateSourceLiquidity][Warning]", error.message);
154
+ return;
155
+ }
156
+ }
157
+
76
158
  const ownersThreshold = await this.sourceGnosisContract.getThreshold();
77
159
  await wait(10000);
78
160
 
@@ -126,20 +208,37 @@ class ProcessSubmitSubmitEvents extends BaseTask {
126
208
  this.sourceGnosisContract
127
209
  );
128
210
 
129
- const owners = await this.sourceGnosisContract
130
- .getOwners()
131
- .then((owners) => owners.map((owner) => owner.toLowerCase()));
132
211
 
133
- const ownerPeerIds = peerPool.activePeers
134
- .filter((peer) => owners.includes(peer.publicAddress.toLowerCase()))
135
- .map((peer) => peer.id);
212
+ async function getGnosisOwnerPeerIds({
213
+ gnosisContract
214
+ }) {
215
+ const owners = await gnosisContract
216
+ .getOwners()
217
+ .then((owners) => owners.map((owner) => owner.toLowerCase()));
218
+
219
+ return peerPool.activePeers
220
+ .filter((peer) => owners.includes(peer.publicAddress.toLowerCase()))
221
+ .map((peer) => peer.id);
222
+ }
223
+
224
+ const ownerPeerIds = await getGnosisOwnerPeerIds({
225
+ gnosisContract: this.sourceGnosisContract,
226
+ });
136
227
 
137
228
  console.log(
138
- `Collecting signatures for execution ${transaction.transactionHash}`
229
+ `Collecting signatures for execution ${transaction.transactionHash} `
139
230
  );
140
231
 
141
232
  console.log(ownerPeerIds);
142
233
 
234
+ const message = generateGnosisSignatureMessage({
235
+ to: addresses[this.chainId].multisend,
236
+ data,
237
+ chainId: this.chainId,
238
+ safeTxGas: gnosisTx.safeTxGas,
239
+ nonce: gnosisTx.safeNonce,
240
+ });
241
+
143
242
  const signatures = await protocol.requestSignatures(
144
243
  {
145
244
  type: "source",
@@ -151,9 +250,27 @@ class ProcessSubmitSubmitEvents extends BaseTask {
151
250
  ownerPeerIds
152
251
  );
153
252
 
154
- const validSignatures = signatures.filter(
155
- (s) => !!s.data && s.data !== "0x"
156
- ) as Signature[];
253
+ const validSignatures = signatures
254
+ .filter(
255
+ (s) => !!s.data && s.data !== "0x"
256
+ )
257
+ .filter((s) => {
258
+
259
+ try {
260
+
261
+ const address = getGnosisSignatureAddress({
262
+ message,
263
+ signature: s.data!,
264
+ chainId: this.chainId,
265
+ })
266
+
267
+ return address?.toLowerCase() === s.signer.toLowerCase();
268
+
269
+ } catch (error) {
270
+ return false
271
+ }
272
+
273
+ }) as Signature[];
157
274
 
158
275
  console.log({
159
276
  signatures,
@@ -172,7 +289,7 @@ class ProcessSubmitSubmitEvents extends BaseTask {
172
289
  await transaction.save();
173
290
  const errorMessage = signatures.find((s) => !!s.error)?.error;
174
291
  throw new Error(
175
- `Not enough signatures` + (errorMessage ? `: ${errorMessage}` : "")
292
+ `Not enough signatures` + (errorMessage ? `: ${errorMessage} ` : "")
176
293
  );
177
294
  }
178
295
 
@@ -220,7 +337,7 @@ class ProcessSubmitSubmitEvents extends BaseTask {
220
337
  receipt.logs.forEach((log) => {
221
338
  try {
222
339
  parsedLogs.push(this.sourceGnosisContract.interface.parseLog(log));
223
- } catch (e) {}
340
+ } catch (e) { }
224
341
  });
225
342
 
226
343
  if (parsedLogs.find((e) => e.name === "ExecutionSuccess")) {
@@ -247,7 +364,7 @@ class ProcessSubmitSubmitEvents extends BaseTask {
247
364
  async start(): Promise<void> {
248
365
  this.blockConfirmationsCount = blockConfirmations[this.chainId] + 1;
249
366
 
250
- this.sourceProvider = new ethers.providers.JsonRpcProvider(
367
+ this.sourceProvider = new JsonRpcRetryProvider(
251
368
  getRpcProviderUrl(this.chainId)
252
369
  );
253
370
 
@@ -265,5 +382,3 @@ class ProcessSubmitSubmitEvents extends BaseTask {
265
382
  await super.start();
266
383
  }
267
384
  }
268
-
269
- export default ProcessSubmitSubmitEvents;