@instadapp/interop-x 0.0.0-dev.9b1fcb8 → 0.0.0-dev.9e91661

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/package.json +6 -5
  2. package/dist/src/abi/interopBridgeToken.json +21 -9
  3. package/dist/src/abi/interopXGateway.json +11 -11
  4. package/dist/src/api/index.js +6 -3
  5. package/dist/src/config/index.js +11 -1
  6. package/dist/src/constants/addresses.js +1 -1
  7. package/dist/src/constants/itokens.js +1 -1
  8. package/dist/src/gnosis/actions/deposit.js +40 -0
  9. package/dist/src/gnosis/actions/index.js +11 -0
  10. package/dist/src/gnosis/actions/withdraw.js +45 -0
  11. package/dist/src/gnosis/index.js +16 -0
  12. package/dist/src/index.js +69 -7
  13. package/dist/src/net/peer/index.js +2 -1
  14. package/dist/src/net/pool/index.js +18 -2
  15. package/dist/src/net/protocol/dial/SignatureDialProtocol.js +2 -8
  16. package/dist/src/net/protocol/dial/TransactionStatusDialProtocol.js +28 -0
  17. package/dist/src/net/protocol/index.js +41 -1
  18. package/dist/src/tasks/AutoUpdateTask.js +70 -0
  19. package/dist/src/tasks/BaseTask.js +11 -3
  20. package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +147 -0
  21. package/dist/src/tasks/InteropBridge/{SyncWithdrawEvents.js → SyncBurnEvents.js} +12 -9
  22. package/dist/src/tasks/InteropBridge/SyncMintEvents.js +67 -0
  23. package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +18 -2
  24. package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +2 -3
  25. package/dist/src/tasks/InteropXGateway/SyncWithdrawtEvents.js +72 -0
  26. package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +53 -0
  27. package/dist/src/tasks/index.js +22 -3
  28. package/dist/src/typechain/factories/InteropBridgeToken__factory.js +23 -11
  29. package/dist/src/typechain/factories/InteropXGateway__factory.js +14 -14
  30. package/dist/src/utils/index.js +19 -40
  31. package/package.json +6 -5
  32. package/src/abi/interopBridgeToken.json +21 -9
  33. package/src/abi/interopXGateway.json +11 -11
  34. package/src/api/index.ts +5 -2
  35. package/src/config/index.ts +11 -1
  36. package/src/constants/addresses.ts +1 -1
  37. package/src/constants/itokens.ts +1 -1
  38. package/src/gnosis/actions/deposit.ts +54 -0
  39. package/src/gnosis/actions/index.ts +7 -0
  40. package/src/gnosis/actions/withdraw.ts +61 -0
  41. package/src/gnosis/index.ts +13 -0
  42. package/src/index.ts +90 -9
  43. package/src/net/peer/index.ts +2 -1
  44. package/src/net/pool/index.ts +25 -5
  45. package/src/net/protocol/dial/SignatureDialProtocol.ts +3 -10
  46. package/src/net/protocol/dial/TransactionStatusDialProtocol.ts +31 -0
  47. package/src/net/protocol/index.ts +57 -1
  48. package/src/tasks/AutoUpdateTask.ts +82 -0
  49. package/src/tasks/BaseTask.ts +13 -3
  50. package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +232 -0
  51. package/src/tasks/InteropBridge/{SyncWithdrawEvents.ts → SyncBurnEvents.ts} +13 -11
  52. package/src/tasks/InteropBridge/SyncMintEvents.ts +99 -0
  53. package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +24 -7
  54. package/src/tasks/InteropXGateway/SyncDepositEvents.ts +2 -4
  55. package/src/tasks/InteropXGateway/SyncWithdrawtEvents.ts +105 -0
  56. package/src/tasks/Transactions/SyncTransactionStatusTask.ts +65 -0
  57. package/src/tasks/index.ts +33 -3
  58. package/src/typechain/InteropBridgeToken.ts +23 -17
  59. package/src/typechain/InteropXGateway.ts +13 -13
  60. package/src/typechain/factories/InteropBridgeToken__factory.ts +23 -11
  61. package/src/typechain/factories/InteropXGateway__factory.ts +14 -14
  62. package/src/utils/index.ts +22 -62
@@ -0,0 +1,232 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import { BigNumber, ethers } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import { buildSignatureBytes, getContract, getRpcProviderUrl, Signature } from "@/utils";
7
+ import { addresses } from "@/constants";
8
+ import { ChainId } from "@/types";
9
+ import config from "@/config";
10
+ import { GnosisSafe } from "@/typechain";
11
+ import { Op } from "sequelize";
12
+ import wait from "waait";
13
+ import { peerPool, protocol } from "@/net";
14
+ import { LogDescription } from "ethers/lib/utils";
15
+ import { buildGnosisData } from "@/gnosis";
16
+
17
+ const generateGnosisTransaction = async (transactionData: any, safeContract: GnosisSafe) => {
18
+ console.log(transactionData);
19
+
20
+ let isExecuted = await safeContract.dataHashes(
21
+ await safeContract.getTransactionHash(
22
+ transactionData.to,
23
+ transactionData.value,
24
+ transactionData.data,
25
+ transactionData.operation,
26
+ transactionData.safeTxGas,
27
+ transactionData.baseGas,
28
+ transactionData.gasPrice,
29
+ transactionData.gasToken,
30
+ transactionData.refundReceiver,
31
+ transactionData.nonce
32
+ )
33
+ )
34
+
35
+ while (isExecuted == 1) {
36
+ transactionData.safeTxGas = BigNumber.from(String(transactionData.safeTxGas)).add(1).toString()
37
+
38
+ isExecuted = await safeContract.dataHashes(
39
+ await safeContract.getTransactionHash(
40
+ transactionData.to,
41
+ transactionData.value,
42
+ transactionData.data,
43
+ transactionData.operation,
44
+ transactionData.safeTxGas,
45
+ transactionData.baseGas,
46
+ transactionData.gasPrice,
47
+ transactionData.gasToken,
48
+ transactionData.refundReceiver,
49
+ transactionData.nonce
50
+ )
51
+ )
52
+ }
53
+
54
+ return transactionData
55
+ }
56
+
57
+ class ProcessWithdrawEvents extends BaseTask {
58
+ provider: ethers.providers.JsonRpcProvider;
59
+ chainId: ChainId;
60
+ leadNodeOnly = true
61
+
62
+ constructor({ chainId }: { chainId: ChainId }) {
63
+ super({
64
+ logger: new Logger("InteropXGateway::ProcessWithdrawEvents"),
65
+ })
66
+ this.chainId = chainId;
67
+ }
68
+
69
+ async pollHandler() {
70
+ const blockNumber = await this.provider.getBlockNumber()
71
+
72
+ const transaction = await Transaction.findOne({
73
+ where: {
74
+ status: 'pending',
75
+ sourceStatus: 'success',
76
+ targetStatus: 'uninitialised',
77
+ action: 'withdraw',
78
+ sourceCreatedAt: {
79
+ [Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
80
+ },
81
+ targetDelayUntil: {
82
+ [Op.or]: {
83
+ [Op.is]: null,
84
+ [Op.lt]: new Date(),
85
+ }
86
+ },
87
+ sourceBlockNumber: {
88
+ [Op.lt]: blockNumber - 12,
89
+ },
90
+ sourceChainId: this.chainId,
91
+ }
92
+ })
93
+
94
+ if (!transaction) {
95
+ return;
96
+ }
97
+
98
+ console.log(`Processing transaction ${transaction.transactionHash}`);
99
+
100
+ transaction.targetStatus = 'pending';
101
+ await transaction.save();
102
+
103
+ // refresh event data?
104
+
105
+ const targetChainProvider = new ethers.providers.JsonRpcProvider(
106
+ getRpcProviderUrl(transaction.targetChainId as ChainId)
107
+ );
108
+
109
+ const targetWallet = new ethers.Wallet(config.privateKey!, targetChainProvider);
110
+
111
+ const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
112
+
113
+
114
+ const safeContract = getContract<GnosisSafe>(
115
+ safeAddress,
116
+ abi.gnosisSafe,
117
+ targetWallet
118
+ )
119
+
120
+ const ownersThreshold = await safeContract.getThreshold();
121
+ await wait(10000);
122
+
123
+ let gnosisTx = await generateGnosisTransaction({
124
+ baseGas: "0",
125
+ data: await buildGnosisData(transaction),
126
+ gasPrice: "0",
127
+ gasToken: "0x0000000000000000000000000000000000000000",
128
+ nonce: '0',
129
+ operation: "1",
130
+ refundReceiver: "0x0000000000000000000000000000000000000000",
131
+ safeAddress: safeAddress,
132
+ safeTxGas: "79668",
133
+ to: addresses[transaction.targetChainId].multisend,
134
+ value: "0",
135
+ }, safeContract);
136
+
137
+ const owners = await safeContract.getOwners().then(owners => owners.map(owner => owner.toLowerCase()));
138
+
139
+ const ownerPeerIds = peerPool.activePeers.filter(peer => owners.includes(peer.publicAddress.toLowerCase())).map(peer => peer.id)
140
+
141
+ console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
142
+
143
+ console.log(ownerPeerIds);
144
+
145
+ const signatures = await protocol.requestSignatures({
146
+ type: 'source',
147
+ transactionHash: transaction.transactionHash,
148
+ safeTxGas: gnosisTx.safeTxGas,
149
+ safeNonce: gnosisTx.nonce
150
+ }, ownerPeerIds)
151
+
152
+
153
+ const validSignatures = signatures.filter(s => !!s.data && s.data !== '0x') as Signature[];
154
+
155
+ console.log({ signatures, validSignatures, ownersThreshold: ownersThreshold.toString() });
156
+
157
+ if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
158
+ await transaction.save();
159
+ transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
160
+ transaction.targetStatus = 'uninitialised'
161
+
162
+ await transaction.save();
163
+ const errorMessage = signatures.find(s => !!s.error)?.error;
164
+ throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
165
+ }
166
+
167
+
168
+ console.log(`Executing transaction for execution ${transaction.transactionHash}`)
169
+
170
+ const { data: txData } = await safeContract.populateTransaction.execTransaction(
171
+ gnosisTx.to,
172
+ gnosisTx.value,
173
+ gnosisTx.data,
174
+ gnosisTx.operation,
175
+ gnosisTx.safeTxGas,
176
+ gnosisTx.baseGas,
177
+ gnosisTx.gasPrice,
178
+ gnosisTx.gasToken,
179
+ gnosisTx.refundReceiver,
180
+ buildSignatureBytes(validSignatures)
181
+ );
182
+
183
+ console.log({
184
+ from: targetWallet.address,
185
+ gasPrice: BigNumber.from(120 * 10 ** 9).toString(),
186
+ to: safeAddress,
187
+ data: txData,
188
+ })
189
+
190
+
191
+ const txSent = await targetWallet.sendTransaction({
192
+ from: targetWallet.address,
193
+ gasPrice: BigNumber.from(120 * 10 ** 9),
194
+ to: safeAddress,
195
+ data: txData,
196
+ })
197
+
198
+ const receipt = await txSent.wait();
199
+
200
+ const parsedLogs: LogDescription[] = [];
201
+
202
+ receipt.logs.forEach((log) => {
203
+ try {
204
+ parsedLogs.push(safeContract.interface.parseLog(log));
205
+ } catch (e) { }
206
+ });
207
+
208
+ if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
209
+ console.log('ExecutionSuccess')
210
+ transaction.targetStatus = 'success'
211
+ transaction.targetTransactionHash = txSent.hash
212
+ transaction.status = 'success'
213
+ await transaction.save();
214
+ } else {
215
+ console.log('ExecutionFailure')
216
+ transaction.targetStatus = 'failed'
217
+ transaction.targetTransactionHash = txSent.hash
218
+ transaction.status = 'failed'
219
+ await transaction.save();
220
+ }
221
+ }
222
+
223
+ async start(): Promise<void> {
224
+ this.provider = new ethers.providers.JsonRpcProvider(
225
+ getRpcProviderUrl(this.chainId)
226
+ );
227
+
228
+ await super.start()
229
+ }
230
+ }
231
+
232
+ export default ProcessWithdrawEvents;
@@ -8,7 +8,7 @@ import { ChainId } from "@/types";
8
8
  import config from "@/config";
9
9
  import { InteropBridgeToken } from "@/typechain";
10
10
 
11
- class SyncWithdrawEvents extends BaseTask {
11
+ class SyncBurnEvents extends BaseTask {
12
12
  contractAddress: string;
13
13
  provider: ethers.providers.JsonRpcProvider;
14
14
  contract: InteropBridgeToken;
@@ -17,7 +17,7 @@ class SyncWithdrawEvents extends BaseTask {
17
17
 
18
18
  constructor({ chainId, itokenAddress }: { chainId: ChainId, itokenAddress: string }) {
19
19
  super({
20
- logger: new Logger("InteropBridgeToken::SyncWithdrawEvents"),
20
+ logger: new Logger("InteropBridgeToken::SyncBurnEvents"),
21
21
  })
22
22
  this.chainId = chainId;
23
23
  this.itokenAddress = itokenAddress;
@@ -41,13 +41,13 @@ class SyncWithdrawEvents extends BaseTask {
41
41
  continue;
42
42
  }
43
43
 
44
- const { to, amount, chainId } = event.args;
44
+ const { to, amount, sourceChainId, targetChainId } = event.args;
45
45
 
46
46
  const uniqueIdentifier = {
47
47
  action: 'withdraw',
48
48
  submitTransactionHash: event.transactionHash,
49
- sourceChainId:this.chainId,
50
- targetChainId: chainId.toNumber(),
49
+ sourceChainId: sourceChainId,
50
+ targetChainId: targetChainId,
51
51
  }
52
52
 
53
53
  if (await Transaction.findOne({ where: uniqueIdentifier })) {
@@ -75,14 +75,18 @@ class SyncWithdrawEvents extends BaseTask {
75
75
 
76
76
  submitEvent: {
77
77
  to,
78
- amount: amount.toString(),
79
- chainId: chainId.toString()
78
+ amount: amount.toString(),
79
+ itoken: this.itokenAddress,
80
+ sourceChainId: sourceChainId,
81
+ targetChainId: targetChainId,
80
82
  },
81
83
 
82
84
  sourceEvent: {
83
85
  to,
84
86
  amount: amount.toString(),
85
- chainId: chainId.toString(),
87
+ itoken: this.itokenAddress,
88
+ sourceChainId: sourceChainId,
89
+ targetChainId: targetChainId,
86
90
  },
87
91
  status: "pending",
88
92
  })
@@ -100,8 +104,6 @@ class SyncWithdrawEvents extends BaseTask {
100
104
  }
101
105
 
102
106
  async start(): Promise<void> {
103
- this.logger.info(`Starting execution watcher on interop chain`);
104
-
105
107
  this.provider = new ethers.providers.JsonRpcProvider(
106
108
  getRpcProviderUrl(this.chainId)
107
109
  );
@@ -116,4 +118,4 @@ class SyncWithdrawEvents extends BaseTask {
116
118
  }
117
119
  }
118
120
 
119
- export default SyncWithdrawEvents;
121
+ export default SyncBurnEvents;
@@ -0,0 +1,99 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import { ethers } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import { getContract, getRpcProviderUrl } from "@/utils";
7
+ import { ChainId } from "@/types";
8
+ import config from "@/config";
9
+ import { InteropBridgeToken } from "@/typechain";
10
+
11
+ class SyncMintEvents extends BaseTask {
12
+ contractAddress: string;
13
+ provider: ethers.providers.JsonRpcProvider;
14
+ contract: InteropBridgeToken;
15
+ chainId: ChainId;
16
+ itokenAddress: string;
17
+
18
+ constructor({ chainId, itokenAddress }: { chainId: ChainId, itokenAddress: string }) {
19
+ super({
20
+ logger: new Logger("InteropBridgeToken::SyncMintEvents"),
21
+ })
22
+ this.chainId = chainId;
23
+ this.itokenAddress = itokenAddress;
24
+ }
25
+
26
+ async pollHandler() {
27
+ const currentBlock = await this.provider.getBlockNumber();
28
+
29
+ const events = await this.contract.queryFilter(
30
+ this.contract.filters.Mint(),
31
+ currentBlock - 500,
32
+ currentBlock,
33
+ );
34
+
35
+ for (const event of events) {
36
+
37
+ try {
38
+ if (!event.args) {
39
+ continue;
40
+ }
41
+
42
+ const { sourceChainId, targetChainId, amount, to, submitTransactionHash } = event.args;
43
+
44
+ const uniqueIdentifier = {
45
+ action: 'deposit',
46
+ submitTransactionHash: submitTransactionHash,
47
+ sourceChainId: sourceChainId,
48
+ targetChainId: targetChainId,
49
+
50
+ targetEvent: null
51
+ }
52
+
53
+ const transaction = await Transaction.findOne({ where: uniqueIdentifier });
54
+
55
+ if(! transaction){
56
+ return;
57
+ }
58
+
59
+ const tx = await event.getTransaction()
60
+
61
+ transaction.targetStatus = 'success'
62
+ transaction.targetErrors = []
63
+ transaction.targetTransactionHash = tx.hash
64
+ transaction.targetEvent = {
65
+ sourceChainId,
66
+ targetChainId,
67
+ amount: amount.toString(),
68
+ to,
69
+ submitTransactionHash
70
+ }
71
+ transaction.status = 'success'
72
+
73
+ await transaction.save()
74
+
75
+ this.logger.info(
76
+ `Mint confirmation received: ${transaction.transactionHash} `
77
+ );
78
+ } catch (error) {
79
+ this.logger.error(error);
80
+ }
81
+ }
82
+ }
83
+
84
+ async start(): Promise<void> {
85
+ this.provider = new ethers.providers.JsonRpcProvider(
86
+ getRpcProviderUrl(this.chainId)
87
+ );
88
+
89
+ this.contract = getContract<InteropBridgeToken>(
90
+ this.itokenAddress,
91
+ abi.interopBridgeToken,
92
+ new ethers.Wallet(config.privateKey!, this.provider)
93
+ );
94
+
95
+ await super.start()
96
+ }
97
+ }
98
+
99
+ export default SyncMintEvents;
@@ -3,7 +3,7 @@ import Logger from '@/logger';
3
3
  import { BigNumber, ethers } from "ethers";
4
4
  import abi from "@/abi";
5
5
  import { Transaction } from "@/db";
6
- import { buildDataForTransaction, buildSignatureBytes, getContract, getRpcProviderUrl, Signature } from "@/utils";
6
+ import { buildSignatureBytes, getContract, getRpcProviderUrl, Signature } from "@/utils";
7
7
  import { addresses } from "@/constants";
8
8
  import { ChainId } from "@/types";
9
9
  import config from "@/config";
@@ -12,10 +12,11 @@ import { Op } from "sequelize";
12
12
  import wait from "waait";
13
13
  import { peerPool, protocol } from "@/net";
14
14
  import { LogDescription } from "ethers/lib/utils";
15
+ import { buildGnosisData } from "@/gnosis";
15
16
 
16
17
  const generateGnosisTransaction = async (transactionData: any, safeContract: GnosisSafe) => {
17
18
  console.log(transactionData);
18
-
19
+
19
20
  let isExecuted = await safeContract.dataHashes(
20
21
  await safeContract.getTransactionHash(
21
22
  transactionData.to,
@@ -97,7 +98,7 @@ class ProcessDepositEvents extends BaseTask {
97
98
  }
98
99
 
99
100
  console.log(`Processing transaction ${transaction.transactionHash}`);
100
-
101
+
101
102
  transaction.targetStatus = 'pending';
102
103
  await transaction.save();
103
104
 
@@ -121,9 +122,23 @@ class ProcessDepositEvents extends BaseTask {
121
122
  const ownersThreshold = await safeContract.getThreshold();
122
123
  await wait(10000);
123
124
 
125
+ let data;
126
+
127
+ try {
128
+ data = await buildGnosisData(transaction);
129
+ } catch (error) {
130
+ console.log(error);
131
+ transaction.targetStatus = 'failed';
132
+ transaction.targetErrors = [error.message];
133
+ transaction.status = 'failed'
134
+ await transaction.save();
135
+ protocol.sendTransaction(transaction)
136
+ return;
137
+ }
138
+
124
139
  let gnosisTx = await generateGnosisTransaction({
125
140
  baseGas: "0",
126
- data: await buildDataForTransaction(transaction),
141
+ data,
127
142
  gasPrice: "0",
128
143
  gasToken: "0x0000000000000000000000000000000000000000",
129
144
  nonce: '0',
@@ -142,7 +157,7 @@ class ProcessDepositEvents extends BaseTask {
142
157
  console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
143
158
 
144
159
  console.log(ownerPeerIds);
145
-
160
+
146
161
  const signatures = await protocol.requestSignatures({
147
162
  type: 'source',
148
163
  transactionHash: transaction.transactionHash,
@@ -209,19 +224,21 @@ class ProcessDepositEvents extends BaseTask {
209
224
  if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
210
225
  console.log('ExecutionSuccess')
211
226
  transaction.targetStatus = 'success'
227
+ transaction.targetTransactionHash = txSent.hash
212
228
  transaction.status = 'success'
213
229
  await transaction.save();
214
230
  } else {
215
231
  console.log('ExecutionFailure')
216
232
  transaction.targetStatus = 'failed'
233
+ transaction.targetTransactionHash = txSent.hash
217
234
  transaction.status = 'failed'
218
235
  await transaction.save();
219
236
  }
237
+
238
+ protocol.sendTransaction(transaction)
220
239
  }
221
240
 
222
241
  async start(): Promise<void> {
223
- this.logger.info(`Starting execution watcher on interop chain`);
224
-
225
242
  this.contractAddress = addresses[this.chainId].interopXGateway;
226
243
 
227
244
  this.provider = new ethers.providers.JsonRpcProvider(
@@ -45,8 +45,8 @@ class SyncDepositEvents extends BaseTask {
45
45
  const uniqueIdentifier = {
46
46
  action: 'deposit',
47
47
  submitTransactionHash: event.transactionHash,
48
- sourceChainId: sourceChainId.toNumber(),
49
- targetChainId: targetChainId.toNumber(),
48
+ sourceChainId: sourceChainId,
49
+ targetChainId: targetChainId,
50
50
  }
51
51
 
52
52
  if (await Transaction.findOne({ where: uniqueIdentifier })) {
@@ -105,8 +105,6 @@ class SyncDepositEvents extends BaseTask {
105
105
  }
106
106
 
107
107
  async start(): Promise<void> {
108
- this.logger.info(`Starting execution watcher on interop chain`);
109
-
110
108
  this.contractAddress = addresses[this.chainId].interopXGateway;
111
109
 
112
110
  this.provider = new ethers.providers.JsonRpcProvider(
@@ -0,0 +1,105 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import { ethers } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import { getContract, getRpcProviderUrl } from "@/utils";
7
+ import { addresses } from "@/constants";
8
+ import { ChainId } from "@/types";
9
+ import config from "@/config";
10
+ import { InteropXGateway } from "@/typechain";
11
+
12
+ class SyncWithdrawEvents extends BaseTask {
13
+ contractAddress: string;
14
+ provider: ethers.providers.JsonRpcProvider;
15
+ contract: InteropXGateway;
16
+ chainId: ChainId;
17
+
18
+ constructor({ chainId }: { chainId: ChainId }) {
19
+ super({
20
+ logger: new Logger("InteropXGateway::SyncWithdrawEvents"),
21
+ })
22
+ this.chainId = chainId;
23
+ }
24
+
25
+ async pollHandler() {
26
+ const currentBlock = await this.provider.getBlockNumber();
27
+
28
+ const events = await this.contract.queryFilter(
29
+ this.contract.filters.LogGatewayWithdraw(),
30
+ currentBlock - 500,
31
+ currentBlock,
32
+ );
33
+
34
+ let processedEvents = 0;
35
+
36
+ for (const event of events) {
37
+
38
+ try {
39
+ if (!event.args) {
40
+ continue;
41
+ }
42
+
43
+ const { user, token, amount, sourceChainId, targetChainId, transactionHash } = event.args;
44
+
45
+ const uniqueIdentifier = {
46
+ action: 'withdraw',
47
+ submitTransactionHash: transactionHash,
48
+ sourceChainId: sourceChainId,
49
+ targetChainId: targetChainId,
50
+
51
+ targetEvent: null
52
+ }
53
+ const transaction = await Transaction.findOne({ where: uniqueIdentifier });
54
+
55
+ if (!transaction) {
56
+ return;
57
+ }
58
+
59
+ const tx = await event.getTransaction()
60
+
61
+ transaction.targetStatus = 'success'
62
+ transaction.targetErrors = []
63
+ transaction.targetTransactionHash = tx.hash
64
+ transaction.targetEvent = {
65
+ user,
66
+ token,
67
+ amount: amount.toString(),
68
+ sourceChainId,
69
+ targetChainId,
70
+ transactionHash,
71
+ }
72
+ transaction.status = 'success'
73
+
74
+ await transaction.save()
75
+
76
+ this.logger.info(
77
+ `Witdraw confirmation received: ${transaction.transactionHash} `
78
+ );
79
+ } catch (error) {
80
+ this.logger.error(error);
81
+ }
82
+ }
83
+
84
+ if (processedEvents > 0)
85
+ this.logger.info(`${processedEvents} events processed`);
86
+ }
87
+
88
+ async start(): Promise<void> {
89
+ this.contractAddress = addresses[this.chainId].interopXGateway;
90
+
91
+ this.provider = new ethers.providers.JsonRpcProvider(
92
+ getRpcProviderUrl(this.chainId)
93
+ );
94
+
95
+ this.contract = getContract<InteropXGateway>(
96
+ this.contractAddress,
97
+ abi.interopXGateway,
98
+ new ethers.Wallet(config.privateKey!, this.provider)
99
+ );
100
+
101
+ await super.start()
102
+ }
103
+ }
104
+
105
+ export default SyncWithdrawEvents;
@@ -0,0 +1,65 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import config from "@/config";
4
+ import { peerPool, protocol } from "@/net";
5
+ import { Transaction } from "@/db";
6
+ import { Op } from "sequelize";
7
+
8
+ class SyncTransactionStatusTask extends BaseTask {
9
+ pollIntervalMs: number = 60 * 1000
10
+ exceptLeadNode: boolean = true;
11
+
12
+ constructor() {
13
+ super({
14
+ logger: new Logger("SyncTransactionStatusTask"),
15
+ })
16
+ }
17
+
18
+ async pollHandler() {
19
+ // if transaction is pending for more than 1 hour, check lead node for status
20
+ const leadNode = peerPool.getLeadPeer();
21
+
22
+ if (!leadNode) {
23
+ return;
24
+ }
25
+
26
+ const transaction = await Transaction.findOne({
27
+ where: {
28
+ status: 'pending',
29
+ sourceCreatedAt: {
30
+ [Op.gte]: new Date(Date.now() - 60 * 60 * 1000),
31
+ },
32
+ }
33
+ })
34
+
35
+ if (!transaction) {
36
+ return;
37
+ }
38
+
39
+ this.logger.info(`Requesting transaction status for ${transaction.transactionHash}`)
40
+
41
+ const transactionStatus = await protocol.requestTransactionStatus(transaction.transactionHash, leadNode.id);
42
+
43
+ if (!transactionStatus) {
44
+ return;
45
+ }
46
+
47
+ this.logger.info(`Received transaction status for ${transaction.transactionHash}`)
48
+
49
+ transaction.sourceStatus = transactionStatus.sourceStatus
50
+ transaction.sourceTransactionHash = transactionStatus.sourceTransactionHash
51
+ transaction.sourceErrors = transactionStatus.sourceErrors
52
+
53
+ transaction.targetStatus = transactionStatus.targetStatus
54
+ transaction.targetTransactionHash = transactionStatus.targetTransactionHash
55
+ transaction.targetErrors = transactionStatus.targetErrors
56
+
57
+ transaction.status = transactionStatus.status
58
+
59
+ await transaction.save()
60
+
61
+ this.logger.info(`Updated transaction status for ${transaction.transactionHash}`)
62
+ }
63
+ }
64
+
65
+ export default SyncTransactionStatusTask;