@instadapp/interop-x 0.0.0-dev.ef7acff → 0.0.0-dev.f45bd03
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +8 -2
- package/dist/src/abi/aaveV2Resolver.json +832 -0
- package/dist/src/abi/aaveV3Resolver.json +628 -0
- package/dist/src/abi/balanceResolver.json +211 -0
- package/dist/src/abi/index.js +6 -0
- package/dist/src/constants/addresses.js +6 -0
- package/dist/src/constants/capPerChain.js +8 -0
- package/dist/src/constants/index.js +2 -0
- package/dist/src/constants/tokens.js +44 -44
- package/dist/src/constants/wrappedNativeToken.js +8 -0
- package/dist/src/crons/index.js +3 -0
- package/dist/src/crons/prices.js +16 -0
- package/dist/src/db/models/transaction.js +1 -1
- package/dist/src/errors/index.js +14 -1
- package/dist/src/gnosis/actions/aaveV2/source.js +26 -1
- package/dist/src/gnosis/actions/aaveV2/target.js +16 -1
- package/dist/src/gnosis/actions/aaveV3/index.js +11 -0
- package/dist/src/gnosis/actions/aaveV3/source.js +74 -0
- package/dist/src/gnosis/actions/aaveV3/target.js +87 -0
- package/dist/src/gnosis/actions/index.js +2 -0
- package/dist/src/index.js +2 -1
- package/dist/src/providers/index.js +17 -0
- package/dist/src/providers/retry-provider.js +45 -0
- package/dist/src/services/Prices.js +74 -0
- package/dist/src/services/index.js +8 -0
- package/dist/src/tasks/InteropX/ProcessSubmitEvents.js +92 -12
- package/dist/src/tasks/InteropX/ProcessValidateEvents.js +28 -9
- package/dist/src/tasks/InteropX/SyncLogExecuteEvents.js +2 -1
- package/dist/src/tasks/InteropX/SyncLogSubmitEvents.js +2 -1
- package/dist/src/tasks/InteropX/SyncLogValidateEvents.js +2 -1
- package/dist/src/typechain/AaveV2Resolver.js +2 -0
- package/dist/src/typechain/AaveV3Resolver.js +2 -0
- package/dist/src/typechain/BalanceResolver.js +2 -0
- package/dist/src/typechain/factories/AaveV2Resolver__factory.js +1191 -0
- package/dist/src/typechain/factories/AaveV3Resolver__factory.js +887 -0
- package/dist/src/typechain/factories/BalanceResolver__factory.js +228 -0
- package/dist/src/typechain/factories/index.js +7 -1
- package/dist/src/typechain/index.js +7 -1
- package/dist/src/utils/formatting.js +51 -1
- package/dist/src/utils/gnosis.js +42 -17
- package/dist/src/utils/index.js +1 -0
- package/dist/src/utils/tokens.js +22 -0
- package/dist/src/utils/validate.js +85 -1
- package/dist/src/utils/web3.js +2 -1
- package/package.json +8 -2
- package/src/abi/aaveV2Resolver.json +832 -0
- package/src/abi/aaveV3Resolver.json +628 -0
- package/src/abi/balanceResolver.json +211 -0
- package/src/abi/index.ts +6 -0
- package/src/constants/addresses.ts +18 -1
- package/src/constants/capPerChain.ts +5 -0
- package/src/constants/index.ts +2 -0
- package/src/constants/tokens.ts +44 -44
- package/src/constants/wrappedNativeToken.ts +5 -0
- package/src/crons/index.ts +1 -0
- package/src/crons/prices.ts +12 -0
- package/src/db/models/transaction.ts +1 -1
- package/src/errors/index.ts +13 -0
- package/src/gnosis/actions/aaveV2/source.ts +58 -2
- package/src/gnosis/actions/aaveV2/target.ts +29 -2
- package/src/gnosis/actions/aaveV3/index.ts +9 -0
- package/src/gnosis/actions/aaveV3/source.ts +119 -0
- package/src/gnosis/actions/aaveV3/target.ts +142 -0
- package/src/gnosis/actions/index.ts +2 -0
- package/src/index.ts +1 -0
- package/src/providers/index.ts +1 -0
- package/src/providers/retry-provider.ts +51 -0
- package/src/services/Prices.ts +89 -0
- package/src/services/index.ts +1 -0
- package/src/tasks/InteropX/ProcessSubmitEvents.ts +120 -17
- package/src/tasks/InteropX/ProcessValidateEvents.ts +39 -14
- package/src/tasks/InteropX/SyncLogExecuteEvents.ts +3 -2
- package/src/tasks/InteropX/SyncLogSubmitEvents.ts +3 -2
- package/src/tasks/InteropX/SyncLogValidateEvents.ts +3 -2
- package/src/typechain/AaveV2Resolver.ts +1017 -0
- package/src/typechain/AaveV3Resolver.ts +935 -0
- package/src/typechain/BalanceResolver.ts +266 -0
- package/src/typechain/factories/AaveV2Resolver__factory.ts +1198 -0
- package/src/typechain/factories/AaveV3Resolver__factory.ts +894 -0
- package/src/typechain/factories/BalanceResolver__factory.ts +235 -0
- package/src/typechain/factories/index.ts +3 -0
- package/src/typechain/index.ts +6 -0
- package/src/utils/formatting.ts +53 -0
- package/src/utils/gnosis.ts +75 -32
- package/src/utils/index.ts +1 -0
- package/src/utils/tokens.ts +21 -0
- package/src/utils/validate.ts +149 -2
- package/src/utils/web3.ts +3 -2
@@ -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: spellData.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
|
+
}
|
package/src/index.ts
CHANGED
@@ -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
|
-
|
11
|
+
getChainIdNativeSymbol,
|
10
12
|
getContract,
|
13
|
+
getExplorerUrl,
|
11
14
|
getRpcProviderUrl,
|
12
15
|
Signature,
|
13
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,10 +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";
|
25
|
-
import { LiquidityError } from "@/errors";
|
31
|
+
import { LiquidityError, UnsupportedChaindIdError } from "@/errors";
|
32
|
+
import { BigNumber } from "bignumber.js";
|
33
|
+
import dedent from "dedent";
|
34
|
+
import { JsonRpcRetryProvider } from "@/providers";
|
26
35
|
|
27
36
|
export default class ProcessSubmitEvents extends BaseTask {
|
28
|
-
sourceProvider:
|
37
|
+
sourceProvider: JsonRpcRetryProvider;
|
29
38
|
sourceGnosisContract: GnosisSafe;
|
30
39
|
sourceWallet: Wallet;
|
31
40
|
chainId: ChainId;
|
@@ -34,7 +43,7 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
34
43
|
|
35
44
|
constructor({ chainId }: { chainId: ChainId }) {
|
36
45
|
super({
|
37
|
-
logger: new Logger("InteropX::
|
46
|
+
logger: new Logger("InteropX::ProcessSubmitEvents"),
|
38
47
|
});
|
39
48
|
this.chainId = chainId;
|
40
49
|
}
|
@@ -74,7 +83,7 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
74
83
|
transaction.sourceStatus = "proccessing";
|
75
84
|
await transaction.save();
|
76
85
|
|
77
|
-
const { sourceChainId, targetChainId } = transaction;
|
86
|
+
const { submitEvent: { position, sourceChainId, targetChainId } } = transaction;
|
78
87
|
try {
|
79
88
|
validateChains({ sourceChainId, targetChainId });
|
80
89
|
} catch (error) {
|
@@ -86,6 +95,65 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
86
95
|
return;
|
87
96
|
}
|
88
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
|
+
sourceProvider: this.sourceProvider,
|
136
|
+
});
|
137
|
+
} catch (error) {
|
138
|
+
if (error instanceof UnsupportedChaindIdError) {
|
139
|
+
console.log(`Dropping transaction ${transaction.transactionHash}`);
|
140
|
+
|
141
|
+
transaction.sourceErrors = [error.message];
|
142
|
+
transaction.sourceStatus = "failed";
|
143
|
+
transaction.targetStatus = "failed";
|
144
|
+
transaction.status = "failed";
|
145
|
+
await transaction.save();
|
146
|
+
} else {
|
147
|
+
transaction.sourceStatus = "pending";
|
148
|
+
transaction.sourceErrors = [error.message];
|
149
|
+
transaction.sourceDelayUntil = moment().add({ minutes: 5 }).toDate();
|
150
|
+
await transaction.save();
|
151
|
+
|
152
|
+
console.log("[validateSourceLiquidity][Warning]", error.message);
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
89
157
|
const ownersThreshold = await this.sourceGnosisContract.getThreshold();
|
90
158
|
await wait(10000);
|
91
159
|
|
@@ -139,19 +207,36 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
139
207
|
this.sourceGnosisContract
|
140
208
|
);
|
141
209
|
|
142
|
-
const owners = await this.sourceGnosisContract
|
143
|
-
.getOwners()
|
144
|
-
.then((owners) => owners.map((owner) => owner.toLowerCase()));
|
145
210
|
|
146
|
-
|
147
|
-
|
148
|
-
|
211
|
+
async function getGnosisOwnerPeerIds({
|
212
|
+
gnosisContract
|
213
|
+
}) {
|
214
|
+
const owners = await gnosisContract
|
215
|
+
.getOwners()
|
216
|
+
.then((owners) => owners.map((owner) => owner.toLowerCase()));
|
217
|
+
|
218
|
+
return peerPool.activePeers
|
219
|
+
.filter((peer) => owners.includes(peer.publicAddress.toLowerCase()))
|
220
|
+
.map((peer) => peer.id);
|
221
|
+
}
|
222
|
+
|
223
|
+
const ownerPeerIds = await getGnosisOwnerPeerIds({
|
224
|
+
gnosisContract: this.sourceGnosisContract,
|
225
|
+
});
|
149
226
|
|
150
227
|
console.log(
|
151
|
-
`Collecting signatures for execution ${transaction.transactionHash}`
|
228
|
+
`Collecting signatures for execution ${transaction.transactionHash} `
|
152
229
|
);
|
153
230
|
|
154
231
|
console.log(ownerPeerIds);
|
232
|
+
|
233
|
+
const message = generateGnosisSignatureMessage({
|
234
|
+
to: addresses[data.chainId].multisend,
|
235
|
+
data,
|
236
|
+
chainId: this.chainId,
|
237
|
+
safeTxGas: gnosisTx.safeTxGas,
|
238
|
+
nonce: gnosisTx.safeNonce,
|
239
|
+
});
|
155
240
|
|
156
241
|
const signatures = await protocol.requestSignatures(
|
157
242
|
{
|
@@ -164,9 +249,27 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
164
249
|
ownerPeerIds
|
165
250
|
);
|
166
251
|
|
167
|
-
const validSignatures = signatures
|
168
|
-
(
|
169
|
-
|
252
|
+
const validSignatures = signatures
|
253
|
+
.filter(
|
254
|
+
(s) => !!s.data && s.data !== "0x"
|
255
|
+
)
|
256
|
+
.filter((s) => {
|
257
|
+
|
258
|
+
try {
|
259
|
+
|
260
|
+
const address = getGnosisSignatureAddress({
|
261
|
+
message,
|
262
|
+
signature: s.data!,
|
263
|
+
chainId: this.chainId,
|
264
|
+
})
|
265
|
+
|
266
|
+
return address?.toLowerCase() === s.signer.toLowerCase();
|
267
|
+
|
268
|
+
} catch (error) {
|
269
|
+
return false
|
270
|
+
}
|
271
|
+
|
272
|
+
}) as Signature[];
|
170
273
|
|
171
274
|
console.log({
|
172
275
|
signatures,
|
@@ -185,7 +288,7 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
185
288
|
await transaction.save();
|
186
289
|
const errorMessage = signatures.find((s) => !!s.error)?.error;
|
187
290
|
throw new Error(
|
188
|
-
`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : "")
|
291
|
+
`Not enough signatures` + (errorMessage ? `: ${errorMessage} ` : "")
|
189
292
|
);
|
190
293
|
}
|
191
294
|
|
@@ -260,7 +363,7 @@ export default class ProcessSubmitEvents extends BaseTask {
|
|
260
363
|
async start(): Promise<void> {
|
261
364
|
this.blockConfirmationsCount = blockConfirmations[this.chainId] + 1;
|
262
365
|
|
263
|
-
this.sourceProvider = new
|
366
|
+
this.sourceProvider = new JsonRpcRetryProvider(
|
264
367
|
getRpcProviderUrl(this.chainId)
|
265
368
|
);
|
266
369
|
|