@instadapp/interop-x 0.0.0-dev.ee3d74b → 0.0.0-dev.ef7acff

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. package/dist/package.json +3 -1
  2. package/dist/src/abi/index.js +2 -0
  3. package/dist/src/abi/instList.json +232 -0
  4. package/dist/src/api/index.js +7 -0
  5. package/dist/src/constants/addresses.js +4 -2
  6. package/dist/src/db/models/transaction.js +15 -7
  7. package/dist/src/errors/index.js +17 -0
  8. package/dist/src/gnosis/actions/aaveV2/source.js +15 -4
  9. package/dist/src/gnosis/actions/aaveV2/target.js +78 -0
  10. package/dist/src/index.js +1 -1
  11. package/dist/src/tasks/InteropX/{ProcessSubmitSubmitEvents.js → ProcessSubmitEvents.js} +29 -5
  12. package/dist/src/tasks/InteropX/ProcessValidateEvents.js +184 -0
  13. package/dist/src/tasks/InteropX/SyncLogExecuteEvents.js +112 -0
  14. package/dist/src/tasks/InteropX/SyncLogSubmitEvents.js +1 -0
  15. package/dist/src/tasks/InteropX/SyncLogValidateEvents.js +105 -0
  16. package/dist/src/tasks/index.js +13 -5
  17. package/dist/src/typechain/InstList.js +2 -0
  18. package/dist/src/typechain/factories/InstList__factory.js +249 -0
  19. package/dist/src/typechain/factories/index.js +3 -1
  20. package/dist/src/typechain/index.js +3 -1
  21. package/dist/src/utils/async.js +18 -0
  22. package/dist/src/utils/dsa.js +24 -0
  23. package/dist/src/utils/formatting.js +17 -0
  24. package/dist/src/utils/gnosis.js +62 -0
  25. package/dist/src/utils/http.js +10 -0
  26. package/dist/src/utils/index.js +21 -219
  27. package/dist/src/utils/interop.js +16 -0
  28. package/dist/src/utils/validate.js +23 -0
  29. package/dist/src/utils/web3.js +92 -0
  30. package/package.json +3 -1
  31. package/src/abi/index.ts +2 -0
  32. package/src/abi/instList.json +232 -0
  33. package/src/api/index.ts +8 -0
  34. package/src/constants/addresses.ts +5 -3
  35. package/src/db/models/transaction.ts +134 -80
  36. package/src/errors/index.ts +13 -0
  37. package/src/gnosis/actions/aaveV2/source.ts +19 -5
  38. package/src/gnosis/actions/aaveV2/target.ts +130 -2
  39. package/src/tasks/InteropX/{ProcessSubmitSubmitEvents.ts → ProcessSubmitEvents.ts} +35 -7
  40. package/src/tasks/InteropX/ProcessValidateEvents.ts +272 -0
  41. package/src/tasks/InteropX/SyncLogExecuteEvents.ts +160 -0
  42. package/src/tasks/InteropX/SyncLogSubmitEvents.ts +3 -4
  43. package/src/tasks/InteropX/SyncLogValidateEvents.ts +150 -0
  44. package/src/tasks/index.ts +16 -5
  45. package/src/typechain/InstList.ts +402 -0
  46. package/src/typechain/factories/InstList__factory.ts +253 -0
  47. package/src/typechain/factories/index.ts +1 -0
  48. package/src/typechain/index.ts +2 -0
  49. package/src/utils/async.ts +22 -0
  50. package/src/utils/dsa.ts +30 -0
  51. package/src/utils/formatting.ts +15 -0
  52. package/src/utils/gnosis.ts +123 -0
  53. package/src/utils/http.ts +6 -0
  54. package/src/utils/index.ts +8 -365
  55. package/src/utils/interop.ts +28 -0
  56. package/src/utils/validate.ts +24 -0
  57. package/src/utils/web3.ts +131 -0
@@ -0,0 +1,13 @@
1
+ export class LiquidityError extends Error {
2
+ constructor(message?: string) {
3
+ super(message || "Not enough liquidity");
4
+ Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ }
7
+
8
+ export class InvalidChaindIdError extends Error {
9
+ constructor(message?: string) {
10
+ super(message || "Invalid chain id");
11
+ Object.setPrototypeOf(this, new.target.prototype);
12
+ }
13
+ }
@@ -32,6 +32,9 @@ export default async function (transaction: Transaction) {
32
32
  config.privateKey,
33
33
  sourceChainProvider
34
34
  );
35
+ const dsaAddress = addresses[sourceChainId].dsaAddress;
36
+ const sourceUserAddress =
37
+ Number(sourceDsaId) == 0 ? sourceSender : dsaAddress;
35
38
  const interopAddress = addresses[sourceChainId].interopX;
36
39
  const contract = getContract<InteropX>(
37
40
  interopAddress,
@@ -40,7 +43,7 @@ export default async function (transaction: Transaction) {
40
43
  );
41
44
 
42
45
  const sourceSpells: any[] = [];
43
- const commonSpells = [];
46
+ const commonSpells: any[] = [];
44
47
 
45
48
  for (const withdraw of position.withdraw) {
46
49
  let spellData = {
@@ -50,9 +53,20 @@ export default async function (transaction: Transaction) {
50
53
  };
51
54
 
52
55
  sourceSpells.push({
53
- connector: spellData.method,
56
+ connector: spellData.connector,
54
57
  data: encodeConnectorMethod(spellData),
55
58
  });
59
+
60
+ let spellDataBasicWithdraw = {
61
+ connector: "BASIC-A",
62
+ method: "withdraw",
63
+ args: [withdraw.sourceToken, withdraw.amount, sourceUserAddress, "0", "0"],
64
+ };
65
+
66
+ commonSpells.push({
67
+ connector: spellDataBasicWithdraw.connector,
68
+ data: encodeConnectorMethod(spellDataBasicWithdraw),
69
+ });
56
70
  }
57
71
 
58
72
  for (const supply of position.supply) {
@@ -63,18 +77,18 @@ export default async function (transaction: Transaction) {
63
77
  };
64
78
 
65
79
  sourceSpells.push({
66
- connector: spellDataWithdraw.method,
80
+ connector: spellDataWithdraw.connector,
67
81
  data: encodeConnectorMethod(spellDataWithdraw),
68
82
  });
69
83
 
70
84
  let spellDataBasicWithdraw = {
71
85
  connector: "BASIC-A",
72
86
  method: "withdraw",
73
- args: [supply.sourceToken, supply.amount, interopAddress, "0", "0"],
87
+ args: [supply.sourceToken, supply.amount, dsaAddress, "0", "0"],
74
88
  };
75
89
 
76
90
  sourceSpells.push({
77
- connector: spellDataBasicWithdraw.method,
91
+ connector: spellDataBasicWithdraw.connector,
78
92
  data: encodeConnectorMethod(spellDataBasicWithdraw),
79
93
  });
80
94
  }
@@ -1,6 +1,12 @@
1
-
2
-
1
+ import abi from "@/abi";
2
+ import config from "@/config";
3
+ import { addresses } from "@/constants";
3
4
  import { Transaction } from "@/db";
5
+ import { InteropX } from "@/typechain";
6
+ import { InstList } from "@/typechain/InstList";
7
+ import { ChainId } from "@/types";
8
+ import { encodeConnectorMethod, getContract, getRpcProviderUrl } from "@/utils";
9
+ import { ethers } from "ethers";
4
10
  import { MetaTransaction, OperationType } from "ethers-multisend";
5
11
 
6
12
 
@@ -8,6 +14,128 @@ export default async function (transaction: Transaction) {
8
14
  const transactions: MetaTransaction[] = [];
9
15
  const logs: any[] = [];
10
16
 
17
+ const {
18
+ sourceSpells,
19
+ position,
20
+ actionId,
21
+ sourceSender,
22
+ sourceDsaId,
23
+ targetDsaId,
24
+ sourceChainId,
25
+ targetChainId,
26
+ vnonce,
27
+ metadata,
28
+ } = transaction.validateEvent;
29
+
30
+ const targetChainProvider = new ethers.providers.JsonRpcProvider(
31
+ getRpcProviderUrl(targetChainId as ChainId)
32
+ );
33
+ const targetWallet = new ethers.Wallet(
34
+ config.privateKey,
35
+ targetChainProvider
36
+ );
37
+
38
+
39
+ const targetInstListContract = getContract<InstList>(
40
+ addresses[targetChainId].instList,
41
+ abi.instList,
42
+ targetChainProvider,
43
+ );
44
+
45
+ const targetDsaAddress = await targetInstListContract.accountAddr(targetDsaId)
46
+ const dsaAddress = addresses[targetChainId].dsaAddress;
47
+ const interopAddress = addresses[targetChainId].interopX;
48
+ const contract = getContract<InteropX>(
49
+ interopAddress,
50
+ abi.interopX,
51
+ targetWallet
52
+ );
53
+
54
+ const targetSpells: any[] = [];
55
+ const commonSpells: any[] = [];
56
+
57
+ for (const supplyToken of position.supply) {
58
+ let spellData = {
59
+ connector: "AAVE-V2-A",
60
+ method: "deposit",
61
+ args: [supplyToken.targetToken, supplyToken.amount, "0", "0"],
62
+ };
63
+
64
+ targetSpells.push({
65
+ connector: spellData.connector,
66
+ data: encodeConnectorMethod(spellData),
67
+ });
68
+
69
+ let spellDataBasicWithdraw = {
70
+ connector: "BASIC-A",
71
+ method: "withdraw",
72
+ args: [supplyToken.targetToken, supplyToken.amount, targetDsaAddress, "0", "0"],
73
+ };
74
+
75
+ commonSpells.push({
76
+ connector: spellDataBasicWithdraw.connector,
77
+ data: encodeConnectorMethod(spellDataBasicWithdraw),
78
+ });
79
+ }
80
+
81
+ for (const withdrawToken of position.withdraw) {
82
+
83
+ let spellData = {
84
+ connector: "AAVE-V2-A",
85
+ method: "borrow",
86
+ args: [
87
+ withdrawToken.targetToken,
88
+ withdrawToken.amount,
89
+ "2",
90
+ "0",
91
+ "0",
92
+ ],
93
+ };
94
+
95
+ targetSpells.push({
96
+ connector: spellData.connector,
97
+ data: encodeConnectorMethod(spellData),
98
+ });
99
+
100
+ let spellData2 = {
101
+ connector: "BASIC-A",
102
+ method: "withdraw",
103
+ args: [
104
+ withdrawToken.targetToken,
105
+ withdrawToken.amount,
106
+ dsaAddress,
107
+ "0",
108
+ "0",
109
+ ],
110
+ };
111
+
112
+ targetSpells.push({
113
+ connector: spellData.connector,
114
+ data: encodeConnectorMethod(spellData2),
115
+ });
116
+ }
117
+
118
+ const { data } = await contract.populateTransaction.targetAction(
119
+ sourceSpells,
120
+ targetSpells,
121
+ commonSpells,
122
+ position,
123
+ actionId,
124
+ sourceSender,
125
+ sourceDsaId,
126
+ targetDsaId,
127
+ sourceChainId,
128
+ targetChainId,
129
+ vnonce,
130
+ metadata
131
+ );
132
+
133
+ transactions.push({
134
+ to: interopAddress,
135
+ data: data!,
136
+ value: "0",
137
+ operation: OperationType.Call,
138
+ });
11
139
 
12
140
  return { transactions, logs }
13
141
  }
@@ -9,8 +9,8 @@ import {
9
9
  generateInteropTransactionHash,
10
10
  getContract,
11
11
  getRpcProviderUrl,
12
- LiquidityError,
13
12
  Signature,
13
+ validateChains,
14
14
  } from "@/utils";
15
15
  import { addresses, blockConfirmations } from "@/constants";
16
16
  import { ChainId } from "@/types";
@@ -22,8 +22,9 @@ import { buildGnosisAction } from "@/gnosis";
22
22
  import { peerPool, protocol } from "@/net";
23
23
  import { LogDescription } from "ethers/lib/utils";
24
24
  import wait from "waait";
25
+ import { LiquidityError } from "@/errors";
25
26
 
26
- class ProcessSubmitSubmitEvents extends BaseTask {
27
+ export default class ProcessSubmitEvents extends BaseTask {
27
28
  sourceProvider: ethers.providers.JsonRpcProvider;
28
29
  sourceGnosisContract: GnosisSafe;
29
30
  sourceWallet: Wallet;
@@ -68,12 +69,28 @@ class ProcessSubmitSubmitEvents extends BaseTask {
68
69
  return;
69
70
  }
70
71
 
72
+ this.logger.debug(`Processing transaction ${transaction.transactionHash}`);
73
+
71
74
  transaction.sourceStatus = "proccessing";
72
75
  await transaction.save();
73
76
 
77
+ const { sourceChainId, targetChainId } = transaction;
78
+ try {
79
+ validateChains({ sourceChainId, targetChainId });
80
+ } catch (error) {
81
+ transaction.sourceErrors = [error.message];
82
+ transaction.sourceStatus = "failed";
83
+ transaction.targetStatus = "failed";
84
+ transaction.status = "failed";
85
+ await transaction.save();
86
+ return;
87
+ }
88
+
74
89
  const ownersThreshold = await this.sourceGnosisContract.getThreshold();
75
90
  await wait(10000);
76
91
 
92
+ this.logger.debug(`Build gnosis action for ${transaction.transactionHash}`);
93
+
77
94
  let data,
78
95
  logs = [];
79
96
 
@@ -101,6 +118,10 @@ class ProcessSubmitSubmitEvents extends BaseTask {
101
118
  return;
102
119
  }
103
120
 
121
+ this.logger.debug(
122
+ `Generating gnosis tx for ${transaction.transactionHash}`
123
+ );
124
+
104
125
  let gnosisTx = await generateGnosisTransaction(
105
126
  {
106
127
  baseGas: "0",
@@ -186,10 +207,20 @@ class ProcessSubmitSubmitEvents extends BaseTask {
186
207
  buildSignatureBytes(validSignatures)
187
208
  );
188
209
 
210
+ const [gasPrice, gasLimit] = await Promise.all([
211
+ this.sourceProvider.getGasPrice(),
212
+ this.sourceProvider.estimateGas({
213
+ from: this.sourceWallet.address,
214
+ to: this.sourceGnosisContract.address,
215
+ data: txData,
216
+ }),
217
+ ]);
218
+
189
219
  const txSent = await this.sourceWallet.sendTransaction({
190
220
  from: this.sourceWallet.address,
191
- gasPrice: ethers.BigNumber.from(120 * 10 ** 9),
192
221
  to: this.sourceGnosisContract.address,
222
+ gasPrice: gasPrice.mul(120).div(100),
223
+ gasLimit: 5_000_000,//gasLimit.mul(120).div(100),
193
224
  data: txData,
194
225
  });
195
226
 
@@ -202,7 +233,7 @@ class ProcessSubmitSubmitEvents extends BaseTask {
202
233
  receipt.logs.forEach((log) => {
203
234
  try {
204
235
  parsedLogs.push(this.sourceGnosisContract.interface.parseLog(log));
205
- } catch (e) {}
236
+ } catch (e) { }
206
237
  });
207
238
 
208
239
  if (parsedLogs.find((e) => e.name === "ExecutionSuccess")) {
@@ -219,7 +250,6 @@ class ProcessSubmitSubmitEvents extends BaseTask {
219
250
  if (txSent.blockNumber)
220
251
  transaction.sourceBlockNumber = txSent.blockNumber;
221
252
  transaction.sourceTransactionHash = txSent.hash;
222
- transaction.sourceTransactionHash = txSent.hash;
223
253
  transaction.status = "failed";
224
254
  await transaction.save();
225
255
  }
@@ -248,5 +278,3 @@ class ProcessSubmitSubmitEvents extends BaseTask {
248
278
  await super.start();
249
279
  }
250
280
  }
251
-
252
- export default ProcessSubmitSubmitEvents;
@@ -0,0 +1,272 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from "@/logger";
3
+ import { ethers, Wallet } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import {
7
+ buildSignatureBytes,
8
+ generateGnosisTransaction,
9
+ generateInteropTransactionHash,
10
+ getContract,
11
+ getRpcProviderUrl,
12
+ Signature,
13
+ } from "@/utils";
14
+ import { addresses, blockConfirmations } from "@/constants";
15
+ import { ChainId } from "@/types";
16
+ import config from "@/config";
17
+ import { GnosisSafe, InteropX } from "@/typechain";
18
+ import moment from "moment";
19
+ import { Op } from "sequelize";
20
+ import { buildGnosisAction } from "@/gnosis";
21
+ import { peerPool, protocol } from "@/net";
22
+ import { LogDescription } from "ethers/lib/utils";
23
+ import wait from "waait";
24
+ import { LiquidityError } from "@/errors";
25
+
26
+ export default class ProcessValidateEvents extends BaseTask {
27
+ sourceProvider: ethers.providers.JsonRpcProvider;
28
+ chainId: ChainId;
29
+ leadNodeOnly: boolean = true;
30
+ blockConfirmationsCount: number = 12;
31
+
32
+ constructor({ chainId }: { chainId: ChainId }) {
33
+ super({
34
+ logger: new Logger("InteropX::ProcessValidateEvents"),
35
+ });
36
+ this.chainId = chainId;
37
+ }
38
+
39
+ async pollHandler() {
40
+ const currentBlockNumber = await this.sourceProvider.getBlockNumber();
41
+
42
+ const transaction = await Transaction.findOne({
43
+ where: {
44
+ status: "pending",
45
+ sourceStatus: "success",
46
+ targetStatus: "pending",
47
+ sourceChainId: this.chainId,
48
+ sourceBlockNumber: {
49
+ [Op.lt]: currentBlockNumber - this.blockConfirmationsCount,
50
+ },
51
+ targetDelayUntil: {
52
+ [Op.or]: {
53
+ [Op.is]: null,
54
+ [Op.lt]: new Date(),
55
+ },
56
+ },
57
+
58
+ submitEvent: { $ne: null },
59
+ validateEvent: { $ne: null },
60
+
61
+ createdAt: {
62
+ [Op.gt]: moment().subtract({ hours: 12 }).toDate(),
63
+ },
64
+ },
65
+ });
66
+
67
+ if (!transaction) {
68
+ return;
69
+ }
70
+
71
+ this.logger.debug(`Processing transaction ${transaction.transactionHash}`);
72
+
73
+ transaction.targetStatus = "proccessing";
74
+ await transaction.save();
75
+
76
+ const { sourceChainId, targetChainId } = transaction.validateEvent
77
+
78
+ const targetProvider = new ethers.providers.JsonRpcProvider(
79
+ getRpcProviderUrl(targetChainId as ChainId)
80
+ );
81
+
82
+ const targetWallet = new ethers.Wallet(
83
+ config.privateKey!,
84
+ targetProvider
85
+ );
86
+
87
+ const targetGnosisContract = getContract<GnosisSafe>(
88
+ addresses[targetChainId].gnosisSafe,
89
+ abi.gnosisSafe,
90
+ targetWallet
91
+ );
92
+
93
+ const ownersThreshold = await targetGnosisContract.getThreshold();
94
+ await wait(10000);
95
+
96
+ this.logger.debug(`Build gnosis action for ${transaction.transactionHash}`);
97
+
98
+ let data,
99
+ logs = [];
100
+
101
+ try {
102
+ ({ data, logs } = await buildGnosisAction(transaction, "target"));
103
+ } catch (error) {
104
+ if (error instanceof LiquidityError) {
105
+ await transaction.save();
106
+ transaction.targetDelayUntil = new Date(Date.now() + 60 * 5 * 1000);
107
+ transaction.targetStatus = "pending";
108
+
109
+ await transaction.save();
110
+
111
+ throw error;
112
+ return;
113
+ }
114
+
115
+ transaction.targetStatus = "failed";
116
+ transaction.targetErrors = [error.message];
117
+ transaction.status = "failed";
118
+ await transaction.save();
119
+ protocol.sendTransaction(transaction);
120
+ return;
121
+ }
122
+
123
+ this.logger.debug(
124
+ `Generating gnosis tx for ${transaction.transactionHash}`
125
+ );
126
+
127
+ let gnosisTx = await generateGnosisTransaction(
128
+ {
129
+ baseGas: "0",
130
+ data,
131
+ gasPrice: "0",
132
+ gasToken: "0x0000000000000000000000000000000000000000",
133
+ nonce: "0",
134
+ operation: "1",
135
+ refundReceiver: "0x0000000000000000000000000000000000000000",
136
+ safeAddress: targetGnosisContract.address,
137
+ safeTxGas: "79668",
138
+ to: addresses[transaction.targetChainId].multisend,
139
+ value: "0",
140
+ },
141
+ targetGnosisContract
142
+ );
143
+
144
+ const owners = await targetGnosisContract
145
+ .getOwners()
146
+ .then((owners) => owners.map((owner) => owner.toLowerCase()));
147
+
148
+ const ownerPeerIds = peerPool.activePeers
149
+ .filter((peer) => owners.includes(peer.publicAddress.toLowerCase()))
150
+ .map((peer) => peer.id);
151
+
152
+ console.log(
153
+ `Collecting signatures for execution ${transaction.transactionHash}`
154
+ );
155
+
156
+ console.log(ownerPeerIds);
157
+
158
+ const signatures = await protocol.requestSignatures(
159
+ {
160
+ type: "target",
161
+ transactionHash: transaction.transactionHash,
162
+ safeTxGas: gnosisTx.safeTxGas,
163
+ safeNonce: gnosisTx.nonce,
164
+ chainId: targetChainId,
165
+ },
166
+ ownerPeerIds
167
+ );
168
+
169
+ const validSignatures = signatures.filter(
170
+ (s) => !!s.data && s.data !== "0x"
171
+ ) as Signature[];
172
+
173
+ console.log({
174
+ signatures,
175
+ validSignatures,
176
+ ownersThreshold: ownersThreshold.toString(),
177
+ });
178
+
179
+ if (
180
+ validSignatures.length === 0 ||
181
+ ownersThreshold.gt(validSignatures.length)
182
+ ) {
183
+ await transaction.save();
184
+ transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
185
+ transaction.targetStatus = "pending";
186
+
187
+ await transaction.save();
188
+ const errorMessage = signatures.find((s) => !!s.error)?.error;
189
+ throw new Error(
190
+ `Not enough signatures` + (errorMessage ? `: ${errorMessage}` : "")
191
+ );
192
+ }
193
+
194
+ console.log(
195
+ `Executing transaction for execution ${transaction.transactionHash}`
196
+ );
197
+
198
+ const { data: txData } =
199
+ await targetGnosisContract.populateTransaction.execTransaction(
200
+ gnosisTx.to,
201
+ gnosisTx.value,
202
+ gnosisTx.data,
203
+ gnosisTx.operation,
204
+ gnosisTx.safeTxGas,
205
+ gnosisTx.baseGas,
206
+ gnosisTx.gasPrice,
207
+ gnosisTx.gasToken,
208
+ gnosisTx.refundReceiver,
209
+ buildSignatureBytes(validSignatures)
210
+ );
211
+
212
+ const [gasPrice, gasLimit] = await Promise.all([
213
+ targetProvider.getGasPrice(),
214
+ targetProvider.estimateGas({
215
+ from: targetWallet.address,
216
+ to: targetGnosisContract.address,
217
+ data: txData,
218
+ }),
219
+ ]);
220
+
221
+ const txSent = await targetWallet.sendTransaction({
222
+ from: targetWallet.address,
223
+ to: targetGnosisContract.address,
224
+ gasPrice: gasPrice.mul(120).div(100),
225
+ gasLimit: 5_000_000,//gasLimit.mul(120).div(100),
226
+ data: txData,
227
+ });
228
+
229
+ console.log(txSent);
230
+
231
+ const receipt = await txSent.wait();
232
+
233
+ const parsedLogs: LogDescription[] = [];
234
+
235
+ receipt.logs.forEach((log) => {
236
+ try {
237
+ parsedLogs.push(targetGnosisContract.interface.parseLog(log));
238
+ } catch (e) { }
239
+ });
240
+
241
+ if (parsedLogs.find((e) => e.name === "ExecutionSuccess")) {
242
+ console.log("ExecutionSuccess");
243
+ transaction.targetStatus = "success";
244
+ transaction.status = "success";
245
+ if (txSent.blockNumber)
246
+ transaction.targetBlockNumber = txSent.blockNumber;
247
+ transaction.targetTransactionHash = txSent.hash;
248
+ transaction.targetLogs = logs;
249
+ await transaction.save();
250
+ } else {
251
+ console.log("ExecutionFailure");
252
+ transaction.targetStatus = "failed";
253
+ if (txSent.blockNumber)
254
+ transaction.targetBlockNumber = txSent.blockNumber;
255
+ transaction.targetTransactionHash = txSent.hash;
256
+ transaction.status = "failed";
257
+ await transaction.save();
258
+ }
259
+
260
+ protocol.sendTransaction(transaction);
261
+ }
262
+
263
+ async start(): Promise<void> {
264
+ this.blockConfirmationsCount = blockConfirmations[this.chainId] + 1;
265
+
266
+ this.sourceProvider = new ethers.providers.JsonRpcProvider(
267
+ getRpcProviderUrl(this.chainId)
268
+ );
269
+
270
+ await super.start();
271
+ }
272
+ }