@instadapp/interop-x 0.0.0-dev.dc4f10a → 0.0.0-dev.e69b5e8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. package/dist/package.json +5 -5
  2. package/dist/src/api/index.js +3 -3
  3. package/dist/src/config/index.js +1 -0
  4. package/dist/src/index.js +44 -5
  5. package/dist/src/net/peer/index.js +2 -1
  6. package/dist/src/net/pool/index.js +18 -2
  7. package/dist/src/net/protocol/dial/SignatureDialProtocol.1.js +28 -0
  8. package/dist/src/net/protocol/index.js +41 -1
  9. package/dist/src/tasks/AutoUpdateTask.js +67 -0
  10. package/dist/src/tasks/BaseTask.js +7 -3
  11. package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +2 -3
  12. package/dist/src/tasks/InteropBridge/SyncWithdrawEvents.js +0 -1
  13. package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +3 -1
  14. package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +0 -1
  15. package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +53 -0
  16. package/dist/src/tasks/index.js +4 -0
  17. package/dist/src/utils/index.js +21 -6
  18. package/package.json +5 -5
  19. package/src/api/index.ts +2 -2
  20. package/src/config/index.ts +2 -0
  21. package/src/index.ts +56 -7
  22. package/src/net/peer/index.ts +2 -1
  23. package/src/net/pool/index.ts +25 -5
  24. package/src/net/protocol/dial/SignatureDialProtocol.1.ts +31 -0
  25. package/src/net/protocol/index.ts +57 -1
  26. package/src/tasks/AutoUpdateTask.ts +81 -0
  27. package/src/tasks/BaseTask.ts +8 -3
  28. package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +2 -12
  29. package/src/tasks/InteropBridge/SyncWithdrawEvents.ts +0 -2
  30. package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +4 -2
  31. package/src/tasks/InteropXGateway/SyncDepositEvents.ts +0 -2
  32. package/src/tasks/Transactions/SyncTransactionStatusTask.ts +65 -0
  33. package/src/tasks/index.ts +5 -0
  34. package/src/utils/index.ts +23 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instadapp/interop-x",
3
- "version": "0.0.0-dev.dc4f10a",
3
+ "version": "0.0.0-dev.e69b5e8",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -24,9 +24,10 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@achingbrain/libp2p-gossipsub": "^0.12.2",
27
+ "@fastify/cors": "^7.0.0",
28
+ "await-spawn": "^4.0.2",
27
29
  "axios": "^0.27.1",
28
30
  "axios-retry": "^3.2.4",
29
- "bignumber.js": "^9.0.2",
30
31
  "chalk": "4.1.2",
31
32
  "dotenv": "^16.0.0",
32
33
  "ethereumjs-util": "^7.1.4",
@@ -34,7 +35,6 @@
34
35
  "ethers-multisend": "^2.1.1",
35
36
  "expand-home-dir": "^0.0.3",
36
37
  "fastify": "^3.28.0",
37
- "fastify-cors": "^6.0.3",
38
38
  "libp2p": "^0.36.2",
39
39
  "libp2p-bootstrap": "^0.14.0",
40
40
  "libp2p-kad-dht": "^0.28.6",
@@ -46,6 +46,8 @@
46
46
  "libp2p-websockets": "^0.16.2",
47
47
  "luxon": "^2.3.2",
48
48
  "module-alias": "^2.2.2",
49
+ "patch-package": "^6.4.7",
50
+ "postinstall-postinstall": "^2.1.0",
49
51
  "sequelize": "6.18.0",
50
52
  "sqlite3": "^5.0.5",
51
53
  "waait": "^1.0.5"
@@ -60,8 +62,6 @@
60
62
  "@types/fs-extra": "^9.0.13",
61
63
  "@types/node": "^17.0.17",
62
64
  "nodemon": "^2.0.15",
63
- "patch-package": "^6.4.7",
64
- "postinstall-postinstall": "^2.1.0",
65
65
  "replace-in-file": "^6.3.2",
66
66
  "rimraf": "^3.0.2",
67
67
  "ts-node": "^10.5.0",
package/src/api/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import fastify from "fastify"
2
- import cors from 'fastify-cors'
2
+ import cors from '@fastify/cors'
3
3
  import Logger from "@/logger"
4
4
  import { Transaction } from "@/db";
5
5
 
@@ -27,7 +27,7 @@ export const startApiServer = async () => {
27
27
 
28
28
  logger.log(`RPC Server listening at http://${HOST}:${PORT}`)
29
29
  } catch (err) {
30
- logger.error(err)
30
+ logger.error(err.message)
31
31
  process.exit(1)
32
32
  }
33
33
  }
@@ -8,12 +8,14 @@ class Config {
8
8
  public readonly privateKey: string
9
9
  public readonly wallet: Wallet
10
10
  public readonly staging: boolean
11
+ public readonly autoUpdate: boolean
11
12
 
12
13
  constructor() {
13
14
  this.events = new EventBus() as EventBusType
14
15
  this.maxPeers = 10
15
16
  this.privateKey = process.env.PRIVATE_KEY as string;
16
17
  this.staging = !! process.env.STAGING && process.env.STAGING === 'true';
18
+ this.autoUpdate = !! process.env.AUTO_UPDATE && process.env.AUTO_UPDATE === 'true';
17
19
  this.wallet = new Wallet(this.privateKey);
18
20
  this.leadNodeAddress = '0x910E413DBF3F6276Fe8213fF656726bDc142E08E'
19
21
  }
package/src/index.ts CHANGED
@@ -16,8 +16,8 @@ moduleAlias.addAliases({
16
16
  })
17
17
 
18
18
  moduleAlias();
19
- import assert from "assert";
20
19
  import dotenv from "dotenv";
20
+ import chalk from 'chalk';
21
21
  import { ethers } from "ethers";
22
22
  import packageJson from '../package.json'
23
23
  dotenv.config();
@@ -25,28 +25,46 @@ dotenv.config();
25
25
  import Logger from "@/logger";
26
26
  const logger = new Logger('Process')
27
27
 
28
-
29
- if (process.argv.at(-1) === 'help') {
28
+ const printUsage = () => {
30
29
  console.log('Usage:')
31
30
  console.log(' PRIVATE_KEY=abcd1234 interop-x')
32
31
  console.log(' PRIVATE_KEY=abcd1234 STAGING=true interop-x')
32
+ console.log(' PRIVATE_KEY=abcd1234 AUTO_UPDATE=true interop-x')
33
+ console.log(' PRIVATE_KEY=abcd1234 API_HOST=0.0.0.0 API_PORT=8080 interop-x')
34
+ }
35
+
36
+ if (process.argv.at(-1) === 'help') {
37
+ printUsage()
33
38
  process.exit(0)
34
39
  }
35
40
 
36
- assert(process.env.PRIVATE_KEY, "PRIVATE_KEY is not defined");
41
+ const GIT_SHORT_HASH = '@GIT_SHORT_HASH@';
37
42
 
43
+ if (process.argv.at(-1) === 'version') {
44
+ console.log(`Interop X Node (v${packageJson.version} - rev.${GIT_SHORT_HASH})`)
45
+ process.exit(0)
46
+ }
47
+
48
+ if(! process.env.PRIVATE_KEY) {
49
+ console.error(chalk.bgRed.white.bold('Please provide a private key\n'))
50
+ printUsage()
51
+ process.exit(1)
52
+ }
38
53
  try {
39
54
  new ethers.Wallet(process.env.PRIVATE_KEY!)
40
55
  } catch (e) {
41
- logger.error('Invalid private key')
56
+ console.error(chalk.bgRed.white('Invalid private key\n'))
57
+ printUsage()
42
58
  process.exit(1)
43
59
  }
44
60
 
45
- logger.debug(`Starting Interop X Node (v${packageJson.version} - rev.@GIT_SHORT_HASH@)`)
61
+ logger.debug(`Starting Interop X Node (v${packageJson.version} - rev.${GIT_SHORT_HASH})`)
46
62
 
47
63
  import { Tasks } from "@/tasks";
48
- import { startPeer } from "@/net";
64
+ import { startPeer, protocol, peerPool } from "@/net";
49
65
  import { startApiServer } from '@/api';
66
+ import { Transaction } from './db';
67
+ import { shortenHash } from './utils';
50
68
 
51
69
  async function main() {
52
70
 
@@ -57,6 +75,37 @@ async function main() {
57
75
  tasks.start();
58
76
 
59
77
  startApiServer()
78
+
79
+ protocol.on('TransactionStatus', async (payload) => {
80
+ if (!peerPool.isLeadNode(payload.peerId)) {
81
+ const peer = peerPool.getPeer(payload.peerId)
82
+
83
+ if(! peer) {
84
+ return;
85
+ }
86
+
87
+ logger.info(`ignored transaction status from ${payload.peerId} ${shortenHash(peer.publicAddress)} `)
88
+ return;
89
+ }
90
+
91
+ const transaction = await Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } })
92
+
93
+ if (!transaction) {
94
+ return;
95
+ }
96
+
97
+ transaction.sourceStatus = payload.data.sourceStatus
98
+ transaction.sourceTransactionHash = payload.data.sourceTransactionHash
99
+ transaction.sourceErrors = payload.data.sourceErrors
100
+
101
+ transaction.targetStatus = payload.data.targetStatus
102
+ transaction.targetTransactionHash = payload.data.targetTransactionHash
103
+ transaction.targetErrors = payload.data.targetErrors
104
+
105
+ transaction.status = payload.data.status
106
+
107
+ await transaction.save()
108
+ })
60
109
  }
61
110
 
62
111
  main()
@@ -17,6 +17,7 @@ import KadDHT from "libp2p-kad-dht";
17
17
  import PubsubPeerDiscovery from "libp2p-pubsub-peer-discovery";
18
18
  import { protocol } from "@/net";
19
19
  import config from "@/config";
20
+ import chalk from "chalk";
20
21
 
21
22
  const logger = new Logger("Peer");
22
23
 
@@ -80,7 +81,7 @@ export const startPeer = async ({ }: IPeerOptions) => {
80
81
  },
81
82
  });
82
83
 
83
- logger.info("Peer ID:", node.peerId.toB58String());
84
+ logger.info("Peer ID:", chalk.bold(node.peerId.toB58String()));
84
85
 
85
86
  await node.start();
86
87
 
@@ -1,6 +1,9 @@
1
1
  import { Event } from "@/types";
2
2
  import config from "@/config";
3
3
  import Logger from "@/logger";
4
+ import { getAddress } from "ethers/lib/utils";
5
+ import { shortenHash } from "@/utils";
6
+ import chalk from "chalk";
4
7
 
5
8
 
6
9
  const logger = new Logger('PeerPool')
@@ -83,10 +86,10 @@ export class PeerPool {
83
86
  const newPeer = !this.pool.get(peer.id);
84
87
  this.pool.set(peer.id, peer)
85
88
  peer.pooled = true
86
-
87
- if(newPeer) {
89
+
90
+ if (newPeer) {
88
91
  config.events.emit(Event.POOL_PEER_ADDED, peer)
89
- logger.info(`Peer ${peer.id} with address ${peer.publicAddress} added to pool`)
92
+ logger.info(`Peer ${chalk.bold(shortenHash(peer.id, 16))} with address ${chalk.bold(shortenHash(peer.publicAddress))} added to pool`)
90
93
  }
91
94
  }
92
95
  }
@@ -101,7 +104,7 @@ export class PeerPool {
101
104
  if (this.pool.delete(peer.id)) {
102
105
  peer.pooled = false
103
106
  config.events.emit(Event.POOL_PEER_REMOVED, peer)
104
- logger.info(`Peer ${peer.id} with address ${peer.publicAddress} removed from pool`)
107
+ logger.info(`Peer ${chalk.bold(shortenHash(peer.id, 16))} with address ${chalk.bold(shortenHash(peer.publicAddress))} removed from pool`)
105
108
  }
106
109
  }
107
110
  }
@@ -110,7 +113,7 @@ export class PeerPool {
110
113
  this.cleanup()
111
114
 
112
115
  return this.peers.filter((p) => {
113
- if(!p.pooled) return false;
116
+ if (!p.pooled) return false;
114
117
 
115
118
  const now = new Date()
116
119
 
@@ -122,6 +125,23 @@ export class PeerPool {
122
125
  return this.activePeers.map((p) => p.id)
123
126
  }
124
127
 
128
+ getPeer(id: string){
129
+ return this.pool.get(id);
130
+ }
131
+
132
+ isLeadNode(id: string) {
133
+ const peer = this.pool.get(id);
134
+
135
+ if (!peer) {
136
+ return false;
137
+ }
138
+
139
+ return getAddress(peer.publicAddress) === getAddress(config.leadNodeAddress)
140
+ }
141
+
142
+ getLeadPeer() {
143
+ return this.peers.find((p) => this.isLeadNode(p.id))
144
+ }
125
145
 
126
146
  cleanup() {
127
147
  // let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
@@ -0,0 +1,31 @@
1
+ import { BaseDialProtocol } from "./BaseDialProtocol";
2
+ import { Transaction } from "@/db";
3
+
4
+ export class TransactionStatusDialProtocol extends BaseDialProtocol<string, Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'> | null> {
5
+ protected timeout = 30000;
6
+
7
+ constructor(libp2p) {
8
+ super(libp2p, '/interop-x/transaction-status')
9
+ }
10
+
11
+ async response(transactionHash: string){
12
+ const transaction = await Transaction.findOne({ where: { transactionHash } })
13
+
14
+ if(! transaction){
15
+ return null
16
+ }
17
+ return {
18
+ transactionHash: transaction.transactionHash,
19
+
20
+ sourceStatus: transaction.sourceStatus,
21
+ sourceTransactionHash: transaction.sourceTransactionHash,
22
+ sourceErrors: transaction.sourceErrors,
23
+
24
+ targetStatus: transaction.targetStatus,
25
+ targetTransactionHash: transaction.targetTransactionHash,
26
+ targetErrors: transaction.targetErrors,
27
+
28
+ status: transaction.status,
29
+ }
30
+ }
31
+ }
@@ -5,6 +5,8 @@ import { SignatureDialProtocol, ISignatureRequest, ISignatureResponse } from "./
5
5
  import { IPeerInfo, peerPool } from "..";
6
6
  import config from "@/config";
7
7
  import { Event } from "@/types";
8
+ import { Transaction } from "@/db";
9
+ import { TransactionStatusDialProtocol } from "./dial/SignatureDialProtocol.1";
8
10
 
9
11
  export interface ProtocolOptions {
10
12
  /* Handshake timeout in ms (default: 8000) */
@@ -33,7 +35,12 @@ interface PeerInfoEvent extends BaseMessageEvent {
33
35
  data: Omit<IPeerInfo, 'id' | 'updated' | 'idle' | 'pooled'>
34
36
  }
35
37
 
38
+ interface TransactionStatusEvent extends BaseMessageEvent {
39
+ data: Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'>
40
+ }
41
+
36
42
  declare interface Protocol {
43
+ on(event: 'TransactionStatus', listener: (payload: TransactionStatusEvent) => void): this;
37
44
  on(event: 'PeerInfo', listener: (payload: PeerInfoEvent) => void): this;
38
45
  on(event: string, listener: (payload: BaseMessageEvent) => void): this;
39
46
  }
@@ -44,7 +51,7 @@ class Protocol extends EventEmitter {
44
51
  private protocolMessages: Message[] = [
45
52
  {
46
53
  name: 'PeerInfo',
47
- code: 0x09,
54
+ code: 0x01,
48
55
  encode: (info: Pick<IPeerInfo, 'publicAddress'>) => [
49
56
  Buffer.from(info.publicAddress),
50
57
  ],
@@ -52,8 +59,39 @@ class Protocol extends EventEmitter {
52
59
  publicAddress: publicAddress.toString(),
53
60
  }),
54
61
  },
62
+ {
63
+ name: 'TransactionStatus',
64
+ code: 0x02,
65
+ encode: (transaction: Transaction) => [
66
+ Buffer.from(transaction.transactionHash),
67
+
68
+ Buffer.from(transaction.sourceStatus),
69
+ Buffer.from(transaction.sourceTransactionHash),
70
+ transaction.sourceErrors ? transaction.sourceErrors.map((e) => Buffer.from(e)) : [],
71
+
72
+ Buffer.from(transaction.targetStatus),
73
+ Buffer.from(transaction.targetTransactionHash),
74
+ transaction.targetErrors ? transaction.targetErrors.map((e) => Buffer.from(e)) : [],
75
+
76
+ Buffer.from(transaction.status),
77
+ ],
78
+ decode: ([transactionHash, sourceStatus, sourceTransactionHash, sourceErrors, targetStatus, targetTransactionHash, targetErrors, status]: [Buffer, Buffer, Buffer, Buffer[], Buffer, Buffer, Buffer[], Buffer]) => ({
79
+ transactionHash: transactionHash.toString(),
80
+
81
+ sourceStatus: sourceStatus.toString(),
82
+ sourceTransactionHash: sourceTransactionHash.toString(),
83
+ sourceErrors: sourceErrors.map((e) => e.toString()),
84
+
85
+ targetStatus: targetStatus.toString(),
86
+ targetTransactionHash: targetTransactionHash.toString(),
87
+ targetErrors: targetErrors.map((e) => e.toString()),
88
+
89
+ status: status.toString(),
90
+ }),
91
+ },
55
92
  ];
56
93
  private signature: SignatureDialProtocol;
94
+ private transactionStatus: TransactionStatusDialProtocol;
57
95
 
58
96
 
59
97
  start({ libp2p, topic = null, }) {
@@ -73,6 +111,7 @@ class Protocol extends EventEmitter {
73
111
  })
74
112
 
75
113
  this.signature = new SignatureDialProtocol(this.libp2p);
114
+ this.transactionStatus = new TransactionStatusDialProtocol(this.libp2p);
76
115
  }
77
116
 
78
117
 
@@ -121,6 +160,14 @@ class Protocol extends EventEmitter {
121
160
  this.libp2p.pubsub.publish(this.topic, encoded)
122
161
  }
123
162
 
163
+ public sendTransaction(transaction: Transaction) {
164
+ const message = this.protocolMessages.find((m) => m.name === 'TransactionStatus')!
165
+
166
+ const encoded = rlp.encode([message.code, message.encode(transaction)]);
167
+
168
+ this.libp2p.pubsub.publish(this.topic, encoded)
169
+ }
170
+
124
171
  async requestSignatures(data: ISignatureRequest, peerIds?: string[]) {
125
172
  try {
126
173
  peerIds = peerIds || peerPool.activePeerIds;
@@ -133,6 +180,15 @@ class Protocol extends EventEmitter {
133
180
  return []
134
181
  }
135
182
  }
183
+
184
+ async requestTransactionStatus(transactionHash: string, peerId: string) {
185
+ try {
186
+ return await this.transactionStatus.send(transactionHash, peerId);
187
+ } catch (error) {
188
+ console.log(error);
189
+ return null
190
+ }
191
+ }
136
192
  }
137
193
 
138
194
  export const protocol = new Protocol();
@@ -0,0 +1,81 @@
1
+ import { BaseTask } from "./BaseTask";
2
+ import Logger from '@/logger';
3
+ import { http } from "@/utils";
4
+ import spawn from 'await-spawn';
5
+ import config from "@/config";
6
+ import wait from "waait";
7
+ import packageJson from "../../package.json";
8
+
9
+ const currentVersion = packageJson.version;
10
+
11
+ class AutoUpdateTask extends BaseTask {
12
+ pollIntervalMs: number = 60 * 5 * 1000
13
+
14
+ constructor() {
15
+ super({
16
+ logger: new Logger("AutoUpdateTask"),
17
+ })
18
+ }
19
+
20
+ prePollHandler(): boolean {
21
+ return config.autoUpdate && !config.isLeadNode();
22
+ }
23
+
24
+ async getInstalledVersion() {
25
+ try {
26
+ const stdout = await spawn('npm', ['-g', 'ls', '--depth=0', '--json'])
27
+ return JSON.parse(stdout.toString()).dependencies[packageJson.name].version
28
+ } catch (error) {
29
+ this.logger.error(error)
30
+
31
+ return currentVersion
32
+ }
33
+ }
34
+
35
+ async getLatestVersion() {
36
+ try {
37
+ const stdout = await spawn('npm', ['view', packageJson.name, 'version'])
38
+ return stdout.toString().trim()
39
+ } catch (error) {
40
+ this.logger.error(error)
41
+
42
+ return currentVersion
43
+ }
44
+ }
45
+
46
+ async pollHandler() {
47
+ const version = await this.getLatestVersion()
48
+
49
+ if (version === currentVersion) {
50
+ return;
51
+ }
52
+
53
+ this.logger.warn(`New version ${version} available.`)
54
+
55
+
56
+ this.logger.info('Updating...')
57
+
58
+ const spawner = spawn('npm', ['-g', 'install', '@instadapp/interop-x@latest', '-f']);
59
+ spawner.child.on('data', console.log)
60
+ await spawner
61
+
62
+ await wait(5000)
63
+
64
+ if (version !== await this.getInstalledVersion()) {
65
+ this.logger.warn(`failed to install ${version}, retrying in 5 minutes`)
66
+ return;
67
+ }
68
+
69
+ this.logger.warn(`Installed version ${version}`)
70
+ this.logger.warn(`Restarting...`)
71
+
72
+ spawn(process.argv[0], process.argv.slice(1), {
73
+ cwd: process.cwd(),
74
+ stdio: "inherit"
75
+ });
76
+
77
+ process.exit()
78
+ }
79
+ }
80
+
81
+ export default AutoUpdateTask;
@@ -19,6 +19,7 @@ export class BaseTask extends EventEmitter implements IBaseTask {
19
19
  started: boolean = false
20
20
  pollIntervalMs: number = 10 * 1000
21
21
  leadNodeOnly: boolean = false
22
+ exceptLeadNode: boolean = false
22
23
 
23
24
  public constructor({ logger }: { logger?: Logger }) {
24
25
  super()
@@ -45,11 +46,15 @@ export class BaseTask extends EventEmitter implements IBaseTask {
45
46
  }
46
47
 
47
48
  prePollHandler(): boolean {
48
- if (!this.leadNodeOnly) {
49
- return true
49
+ if (this.exceptLeadNode) {
50
+ return !config.isLeadNode();
50
51
  }
51
52
 
52
- return config.isLeadNode()
53
+ if (this.leadNodeOnly) {
54
+ return config.isLeadNode()
55
+ }
56
+
57
+ return true
53
58
  }
54
59
 
55
60
  async pollHandler() {
@@ -54,9 +54,7 @@ const generateGnosisTransaction = async (transactionData: any, safeContract: Gno
54
54
  }
55
55
 
56
56
  class ProcessWithdrawEvents extends BaseTask {
57
- contractAddress: string;
58
57
  provider: ethers.providers.JsonRpcProvider;
59
- contract: InteropXGateway;
60
58
  chainId: ChainId;
61
59
  leadNodeOnly = true
62
60
 
@@ -209,31 +207,23 @@ class ProcessWithdrawEvents extends BaseTask {
209
207
  if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
210
208
  console.log('ExecutionSuccess')
211
209
  transaction.targetStatus = 'success'
210
+ transaction.targetTransactionHash = txSent.hash
212
211
  transaction.status = 'success'
213
212
  await transaction.save();
214
213
  } else {
215
214
  console.log('ExecutionFailure')
216
215
  transaction.targetStatus = 'failed'
216
+ transaction.targetTransactionHash = txSent.hash
217
217
  transaction.status = 'failed'
218
218
  await transaction.save();
219
219
  }
220
220
  }
221
221
 
222
222
  async start(): Promise<void> {
223
- this.logger.info(`Starting execution watcher on interop chain`);
224
-
225
- this.contractAddress = addresses[this.chainId].interopXGateway;
226
-
227
223
  this.provider = new ethers.providers.JsonRpcProvider(
228
224
  getRpcProviderUrl(this.chainId)
229
225
  );
230
226
 
231
- this.contract = getContract<InteropXGateway>(
232
- this.contractAddress,
233
- abi.interopXGateway,
234
- new ethers.Wallet(config.privateKey!, this.provider)
235
- );
236
-
237
227
  await super.start()
238
228
  }
239
229
  }
@@ -102,8 +102,6 @@ class SyncWithdrawEvents extends BaseTask {
102
102
  }
103
103
 
104
104
  async start(): Promise<void> {
105
- this.logger.info(`Starting execution watcher on interop chain`);
106
-
107
105
  this.provider = new ethers.providers.JsonRpcProvider(
108
106
  getRpcProviderUrl(this.chainId)
109
107
  );
@@ -209,19 +209,21 @@ class ProcessDepositEvents extends BaseTask {
209
209
  if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
210
210
  console.log('ExecutionSuccess')
211
211
  transaction.targetStatus = 'success'
212
+ transaction.targetTransactionHash = txSent.hash
212
213
  transaction.status = 'success'
213
214
  await transaction.save();
214
215
  } else {
215
216
  console.log('ExecutionFailure')
216
217
  transaction.targetStatus = 'failed'
218
+ transaction.targetTransactionHash = txSent.hash
217
219
  transaction.status = 'failed'
218
220
  await transaction.save();
219
221
  }
222
+
223
+ protocol.sendTransaction(transaction)
220
224
  }
221
225
 
222
226
  async start(): Promise<void> {
223
- this.logger.info(`Starting execution watcher on interop chain`);
224
-
225
227
  this.contractAddress = addresses[this.chainId].interopXGateway;
226
228
 
227
229
  this.provider = new ethers.providers.JsonRpcProvider(
@@ -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,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;
@@ -4,10 +4,15 @@ import InteropXGatewaySyncDepositEvents from "./InteropXGateway/SyncDepositEvent
4
4
 
5
5
  import InteropBridgeSyncWithdrawEvents from "./InteropBridge/SyncWithdrawEvents";
6
6
  import InteropBridgeProcessWithdrawEvents from "./InteropBridge/ProcessWithdrawEvents";
7
+ import AutoUpdateTask from "./AutoUpdateTask";
8
+ import SyncTransactionStatusTask from "./Transactions/SyncTransactionStatusTask";
7
9
 
8
10
  export class Tasks {
9
11
 
10
12
  tasks: BaseTask[] = [
13
+ new SyncTransactionStatusTask(),
14
+ new AutoUpdateTask(),
15
+
11
16
  new InteropXGatewaySyncDepositEvents({
12
17
  chainId: 43114
13
18
  }),