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

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 (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
  }),