@instadapp/interop-x 0.0.0-dev.b8c571d → 0.0.0-dev.c109c51

Sign up to get free protection for your applications and to get access to all the features.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instadapp/interop-x",
3
- "version": "0.0.0-dev.b8c571d",
3
+ "version": "0.0.0-dev.c109c51",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@achingbrain/libp2p-gossipsub": "^0.12.2",
27
+ "await-spawn": "^4.0.2",
27
28
  "axios": "^0.27.1",
28
29
  "axios-retry": "^3.2.4",
29
30
  "bignumber.js": "^9.0.2",
@@ -46,6 +47,8 @@
46
47
  "libp2p-websockets": "^0.16.2",
47
48
  "luxon": "^2.3.2",
48
49
  "module-alias": "^2.2.2",
50
+ "patch-package": "^6.4.7",
51
+ "postinstall-postinstall": "^2.1.0",
49
52
  "sequelize": "6.18.0",
50
53
  "sqlite3": "^5.0.5",
51
54
  "waait": "^1.0.5"
@@ -60,8 +63,6 @@
60
63
  "@types/fs-extra": "^9.0.13",
61
64
  "@types/node": "^17.0.17",
62
65
  "nodemon": "^2.0.15",
63
- "patch-package": "^6.4.7",
64
- "postinstall-postinstall": "^2.1.0",
65
66
  "replace-in-file": "^6.3.2",
66
67
  "rimraf": "^3.0.2",
67
68
  "ts-node": "^10.5.0",
@@ -8,6 +8,7 @@ class Config {
8
8
  this.maxPeers = 10;
9
9
  this.privateKey = process.env.PRIVATE_KEY;
10
10
  this.staging = !!process.env.STAGING && process.env.STAGING === 'true';
11
+ this.autoUpdate = !!process.env.AUTO_UPDATE && process.env.AUTO_UPDATE === 'true';
11
12
  this.wallet = new ethers_1.Wallet(this.privateKey);
12
13
  this.leadNodeAddress = '0x910E413DBF3F6276Fe8213fF656726bDc142E08E';
13
14
  }
package/dist/src/index.js CHANGED
@@ -19,36 +19,71 @@ module_alias_1.default.addAliases({
19
19
  "@/typechain": __dirname + "/typechain"
20
20
  });
21
21
  (0, module_alias_1.default)();
22
- const assert_1 = __importDefault(require("assert"));
23
22
  const dotenv_1 = __importDefault(require("dotenv"));
23
+ const chalk_1 = __importDefault(require("chalk"));
24
24
  const ethers_1 = require("ethers");
25
25
  const package_json_1 = __importDefault(require("../package.json"));
26
26
  dotenv_1.default.config();
27
27
  const logger_1 = __importDefault(require("@/logger"));
28
28
  const logger = new logger_1.default('Process');
29
- if (process.argv.at(-1) === 'help') {
29
+ const printUsage = () => {
30
30
  console.log('Usage:');
31
31
  console.log(' PRIVATE_KEY=abcd1234 interop-x');
32
32
  console.log(' PRIVATE_KEY=abcd1234 STAGING=true interop-x');
33
+ console.log(' PRIVATE_KEY=abcd1234 AUTO_UPDATE=true interop-x');
34
+ console.log(' PRIVATE_KEY=abcd1234 API_HOST=0.0.0.0 API_PORT=8080 interop-x');
35
+ };
36
+ if (process.argv.at(-1) === 'help') {
37
+ printUsage();
33
38
  process.exit(0);
34
39
  }
35
- (0, assert_1.default)(process.env.PRIVATE_KEY, "PRIVATE_KEY is not defined");
40
+ const GIT_SHORT_HASH = 'c109c51';
41
+ if (process.argv.at(-1) === 'version') {
42
+ console.log(`Interop X Node (v${package_json_1.default.version} - rev.${GIT_SHORT_HASH})`);
43
+ process.exit(0);
44
+ }
45
+ if (!process.env.PRIVATE_KEY) {
46
+ console.error(chalk_1.default.bgRed.white.bold('Please provide a private key\n'));
47
+ printUsage();
48
+ process.exit(1);
49
+ }
36
50
  try {
37
51
  new ethers_1.ethers.Wallet(process.env.PRIVATE_KEY);
38
52
  }
39
53
  catch (e) {
40
- logger.error('Invalid private key');
54
+ console.error(chalk_1.default.bgRed.white('Invalid private key\n'));
55
+ printUsage();
41
56
  process.exit(1);
42
57
  }
43
- logger.debug(`Starting Interop X Node (v${package_json_1.default.version} - rev.b8c571d)`);
58
+ logger.debug(`Starting Interop X Node (v${package_json_1.default.version} - rev.${GIT_SHORT_HASH})`);
44
59
  const tasks_1 = require("@/tasks");
45
60
  const net_1 = require("@/net");
46
61
  const api_1 = require("@/api");
62
+ const db_1 = require("./db");
47
63
  async function main() {
48
64
  (0, net_1.startPeer)({});
49
65
  const tasks = new tasks_1.Tasks();
50
66
  tasks.start();
51
67
  (0, api_1.startApiServer)();
68
+ net_1.protocol.on('TransactionStatus', async (payload) => {
69
+ if (!net_1.peerPool.isLeadNode(payload.peerId)) {
70
+ const peer = net_1.peerPool.getPeer(payload.peerId);
71
+ logger.info(`ignored transaction status from ${payload.peerId} ${peer === null || peer === void 0 ? void 0 : peer.publicAddress} `);
72
+ return;
73
+ }
74
+ const transaction = await db_1.Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } });
75
+ if (!transaction) {
76
+ return;
77
+ }
78
+ transaction.sourceStatus = payload.data.sourceStatus;
79
+ transaction.sourceTransactionHash = payload.data.sourceTransactionHash;
80
+ transaction.sourceErrors = payload.data.sourceErrors;
81
+ transaction.targetStatus = payload.data.targetStatus;
82
+ transaction.targetTransactionHash = payload.data.targetTransactionHash;
83
+ transaction.targetErrors = payload.data.targetErrors;
84
+ transaction.status = payload.data.status;
85
+ await transaction.save();
86
+ });
52
87
  }
53
88
  main()
54
89
  .then(() => {
@@ -7,6 +7,7 @@ exports.peerPool = exports.PeerPool = void 0;
7
7
  const types_1 = require("@/types");
8
8
  const config_1 = __importDefault(require("@/config"));
9
9
  const logger_1 = __importDefault(require("@/logger"));
10
+ const utils_1 = require("ethers/lib/utils");
10
11
  const logger = new logger_1.default('PeerPool');
11
12
  class PeerPool {
12
13
  constructor() {
@@ -100,6 +101,16 @@ class PeerPool {
100
101
  get activePeerIds() {
101
102
  return this.activePeers.map((p) => p.id);
102
103
  }
104
+ getPeer(id) {
105
+ return this.pool.get(id);
106
+ }
107
+ isLeadNode(id) {
108
+ const peer = this.pool.get(id);
109
+ if (!peer) {
110
+ return false;
111
+ }
112
+ return (0, utils_1.getAddress)(peer.publicAddress) === (0, utils_1.getAddress)(config_1.default.leadNodeAddress);
113
+ }
103
114
  cleanup() {
104
115
  // let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
105
116
  // this.peers.forEach((peerInfo) => {
@@ -16,7 +16,7 @@ class Protocol extends stream_1.EventEmitter {
16
16
  this.protocolMessages = [
17
17
  {
18
18
  name: 'PeerInfo',
19
- code: 0x09,
19
+ code: 0x01,
20
20
  encode: (info) => [
21
21
  Buffer.from(info.publicAddress),
22
22
  ],
@@ -24,6 +24,30 @@ class Protocol extends stream_1.EventEmitter {
24
24
  publicAddress: publicAddress.toString(),
25
25
  }),
26
26
  },
27
+ {
28
+ name: 'TransactionStatus',
29
+ code: 0x02,
30
+ encode: (transaction) => [
31
+ Buffer.from(transaction.transactionHash),
32
+ Buffer.from(transaction.sourceStatus),
33
+ Buffer.from(transaction.sourceTransactionHash),
34
+ transaction.sourceErrors ? transaction.sourceErrors.map((e) => Buffer.from(e)) : [],
35
+ Buffer.from(transaction.targetStatus),
36
+ Buffer.from(transaction.targetTransactionHash),
37
+ transaction.targetErrors ? transaction.targetErrors.map((e) => Buffer.from(e)) : [],
38
+ Buffer.from(transaction.status),
39
+ ],
40
+ decode: ([transactionHash, sourceStatus, sourceTransactionHash, sourceErrors, targetStatus, targetTransactionHash, targetErrors, status]) => ({
41
+ transactionHash: transactionHash.toString(),
42
+ sourceStatus: sourceStatus.toString(),
43
+ sourceTransactionHash: sourceTransactionHash.toString(),
44
+ sourceErrors: sourceErrors.map((e) => e.toString()),
45
+ targetStatus: targetStatus.toString(),
46
+ targetTransactionHash: targetTransactionHash.toString(),
47
+ targetErrors: targetErrors.map((e) => e.toString()),
48
+ status: status.toString(),
49
+ }),
50
+ },
27
51
  ];
28
52
  }
29
53
  start({ libp2p, topic = null, }) {
@@ -75,6 +99,11 @@ class Protocol extends stream_1.EventEmitter {
75
99
  const encoded = ethereumjs_util_1.rlp.encode([message.code, message.encode(data)]);
76
100
  this.libp2p.pubsub.publish(this.topic, encoded);
77
101
  }
102
+ sendTransaction(transaction) {
103
+ const message = this.protocolMessages.find((m) => m.name === 'TransactionStatus');
104
+ const encoded = ethereumjs_util_1.rlp.encode([message.code, message.encode(transaction)]);
105
+ this.libp2p.pubsub.publish(this.topic, encoded);
106
+ }
78
107
  async requestSignatures(data, peerIds) {
79
108
  try {
80
109
  peerIds = peerIds || __1.peerPool.activePeerIds;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const BaseTask_1 = require("./BaseTask");
7
+ const logger_1 = __importDefault(require("@/logger"));
8
+ const package_json_1 = __importDefault(require("../../package.json"));
9
+ const utils_1 = require("@/utils");
10
+ const await_spawn_1 = __importDefault(require("await-spawn"));
11
+ const config_1 = __importDefault(require("@/config"));
12
+ const currentVersion = package_json_1.default.version;
13
+ class AutoUpdateTask extends BaseTask_1.BaseTask {
14
+ constructor() {
15
+ super({
16
+ logger: new logger_1.default("AutoUpdateTask"),
17
+ });
18
+ this.pollIntervalMs = 60 * 1000;
19
+ }
20
+ prePollHandler() {
21
+ return config_1.default.autoUpdate && !config_1.default.isLeadNode();
22
+ }
23
+ async pollHandler() {
24
+ const { data } = await utils_1.http.get('https://registry.npmjs.org/@instadapp/interop-x');
25
+ const version = data['dist-tags'].latest;
26
+ if (version === currentVersion) {
27
+ return;
28
+ }
29
+ this.logger.warn(`New version ${version} available.`);
30
+ await (0, await_spawn_1.default)('npm', ['-g', 'install', '@instadapp/interop-x']);
31
+ this.logger.warn(`Installed version ${version}`);
32
+ this.logger.warn(`Restarting...`);
33
+ (0, await_spawn_1.default)(process.argv[0], process.argv.slice(1), {
34
+ cwd: process.cwd(),
35
+ detached: true,
36
+ stdio: "inherit"
37
+ });
38
+ process.exit();
39
+ }
40
+ }
41
+ exports.default = AutoUpdateTask;
@@ -126,12 +126,14 @@ class ProcessWithdrawEvents extends BaseTask_1.BaseTask {
126
126
  if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
127
127
  console.log('ExecutionSuccess');
128
128
  transaction.targetStatus = 'success';
129
+ transaction.targetTransactionHash = txSent.hash;
129
130
  transaction.status = 'success';
130
131
  await transaction.save();
131
132
  }
132
133
  else {
133
134
  console.log('ExecutionFailure');
134
135
  transaction.targetStatus = 'failed';
136
+ transaction.targetTransactionHash = txSent.hash;
135
137
  transaction.status = 'failed';
136
138
  await transaction.save();
137
139
  }
@@ -126,15 +126,18 @@ class ProcessDepositEvents extends BaseTask_1.BaseTask {
126
126
  if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
127
127
  console.log('ExecutionSuccess');
128
128
  transaction.targetStatus = 'success';
129
+ transaction.targetTransactionHash = txSent.hash;
129
130
  transaction.status = 'success';
130
131
  await transaction.save();
131
132
  }
132
133
  else {
133
134
  console.log('ExecutionFailure');
134
135
  transaction.targetStatus = 'failed';
136
+ transaction.targetTransactionHash = txSent.hash;
135
137
  transaction.status = 'failed';
136
138
  await transaction.save();
137
139
  }
140
+ net_1.protocol.sendTransaction(transaction);
138
141
  }
139
142
  async start() {
140
143
  this.logger.info(`Starting execution watcher on interop chain`);
@@ -8,9 +8,11 @@ const ProcessDepositEvents_1 = __importDefault(require("./InteropXGateway/Proces
8
8
  const SyncDepositEvents_1 = __importDefault(require("./InteropXGateway/SyncDepositEvents"));
9
9
  const SyncWithdrawEvents_1 = __importDefault(require("./InteropBridge/SyncWithdrawEvents"));
10
10
  const ProcessWithdrawEvents_1 = __importDefault(require("./InteropBridge/ProcessWithdrawEvents"));
11
+ const AutoUpdateTask_1 = __importDefault(require("./AutoUpdateTask"));
11
12
  class Tasks {
12
13
  constructor() {
13
14
  this.tasks = [
15
+ new AutoUpdateTask_1.default(),
14
16
  new SyncDepositEvents_1.default({
15
17
  chainId: 43114
16
18
  }),
@@ -170,7 +170,7 @@ const buildWithdrawDataForTransaction = async (transaction, type) => {
170
170
  const targetWallet = new ethers_1.ethers.Wallet(config_1.default.privateKey, targetChainProvider);
171
171
  const gatewayAddress = constants_1.addresses[chainId].interopXGateway;
172
172
  const interopBridgeContract = getContract(gatewayAddress, abi_1.default.interopXGateway, targetWallet);
173
- const { data } = await interopBridgeContract.populateTransaction.systemWithdraw(ethers_1.ethers.BigNumber.from(amount.toString()), to, token.address, ethers_1.ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()), transaction.submitTransactionHash);
173
+ const { data } = await interopBridgeContract.populateTransaction.systemWithdraw(ethers_1.ethers.BigNumber.from(amount.toString()), to, token.address, ethers_1.ethers.BigNumber.from(transaction.sourceChainId.toString()), transaction.submitTransactionHash);
174
174
  transactions.push({
175
175
  to: gatewayAddress,
176
176
  data: data,
@@ -185,6 +185,11 @@ function getContract(address, contractInterface, signerOrProvider) {
185
185
  throw Error(`Invalid 'address' parameter '${address}'.`);
186
186
  }
187
187
  const contract = new ethers_1.ethers.Contract(address, contractInterface, signerOrProvider);
188
+ // Make sure the contract properties is writable
189
+ const desc = Object.getOwnPropertyDescriptor(contract, 'functions');
190
+ if (!desc || desc.writable !== true) {
191
+ return contract;
192
+ }
188
193
  return new Proxy(contract, {
189
194
  get(target, prop, receiver) {
190
195
  const value = Reflect.get(target, prop, receiver);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instadapp/interop-x",
3
- "version": "0.0.0-dev.b8c571d",
3
+ "version": "0.0.0-dev.c109c51",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@achingbrain/libp2p-gossipsub": "^0.12.2",
27
+ "await-spawn": "^4.0.2",
27
28
  "axios": "^0.27.1",
28
29
  "axios-retry": "^3.2.4",
29
30
  "bignumber.js": "^9.0.2",
@@ -46,6 +47,8 @@
46
47
  "libp2p-websockets": "^0.16.2",
47
48
  "luxon": "^2.3.2",
48
49
  "module-alias": "^2.2.2",
50
+ "patch-package": "^6.4.7",
51
+ "postinstall-postinstall": "^2.1.0",
49
52
  "sequelize": "6.18.0",
50
53
  "sqlite3": "^5.0.5",
51
54
  "waait": "^1.0.5"
@@ -60,8 +63,6 @@
60
63
  "@types/fs-extra": "^9.0.13",
61
64
  "@types/node": "^17.0.17",
62
65
  "nodemon": "^2.0.15",
63
- "patch-package": "^6.4.7",
64
- "postinstall-postinstall": "^2.1.0",
65
66
  "replace-in-file": "^6.3.2",
66
67
  "rimraf": "^3.0.2",
67
68
  "ts-node": "^10.5.0",
@@ -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,45 @@ 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';
50
67
 
51
68
  async function main() {
52
69
 
@@ -57,6 +74,32 @@ async function main() {
57
74
  tasks.start();
58
75
 
59
76
  startApiServer()
77
+
78
+ protocol.on('TransactionStatus', async (payload) => {
79
+ if (!peerPool.isLeadNode(payload.peerId)) {
80
+ const peer = peerPool.getPeer(payload.peerId)
81
+ logger.info(`ignored transaction status from ${payload.peerId} ${peer?.publicAddress} `)
82
+ return;
83
+ }
84
+
85
+ const transaction = await Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } })
86
+
87
+ if (!transaction) {
88
+ return;
89
+ }
90
+
91
+ transaction.sourceStatus = payload.data.sourceStatus
92
+ transaction.sourceTransactionHash = payload.data.sourceTransactionHash
93
+ transaction.sourceErrors = payload.data.sourceErrors
94
+
95
+ transaction.targetStatus = payload.data.targetStatus
96
+ transaction.targetTransactionHash = payload.data.targetTransactionHash
97
+ transaction.targetErrors = payload.data.targetErrors
98
+
99
+ transaction.status = payload.data.status
100
+
101
+ await transaction.save()
102
+ })
60
103
  }
61
104
 
62
105
  main()
@@ -1,6 +1,7 @@
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";
4
5
 
5
6
 
6
7
  const logger = new Logger('PeerPool')
@@ -83,8 +84,8 @@ export class PeerPool {
83
84
  const newPeer = !this.pool.get(peer.id);
84
85
  this.pool.set(peer.id, peer)
85
86
  peer.pooled = true
86
-
87
- if(newPeer) {
87
+
88
+ if (newPeer) {
88
89
  config.events.emit(Event.POOL_PEER_ADDED, peer)
89
90
  logger.info(`Peer ${peer.id} with address ${peer.publicAddress} added to pool`)
90
91
  }
@@ -110,7 +111,7 @@ export class PeerPool {
110
111
  this.cleanup()
111
112
 
112
113
  return this.peers.filter((p) => {
113
- if(!p.pooled) return false;
114
+ if (!p.pooled) return false;
114
115
 
115
116
  const now = new Date()
116
117
 
@@ -123,6 +124,21 @@ export class PeerPool {
123
124
  }
124
125
 
125
126
 
127
+ getPeer(id: string){
128
+ return this.pool.get(id);
129
+ }
130
+
131
+ isLeadNode(id: string) {
132
+ const peer = this.pool.get(id);
133
+
134
+ if (!peer) {
135
+ return false;
136
+ }
137
+
138
+ return getAddress(peer.publicAddress) === getAddress(config.leadNodeAddress)
139
+ }
140
+
141
+
126
142
  cleanup() {
127
143
  // let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
128
144
 
@@ -5,6 +5,7 @@ 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";
8
9
 
9
10
  export interface ProtocolOptions {
10
11
  /* Handshake timeout in ms (default: 8000) */
@@ -33,7 +34,12 @@ interface PeerInfoEvent extends BaseMessageEvent {
33
34
  data: Omit<IPeerInfo, 'id' | 'updated' | 'idle' | 'pooled'>
34
35
  }
35
36
 
37
+ interface TransactionStatusEvent extends BaseMessageEvent {
38
+ data: Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'>
39
+ }
40
+
36
41
  declare interface Protocol {
42
+ on(event: 'TransactionStatus', listener: (payload: TransactionStatusEvent) => void): this;
37
43
  on(event: 'PeerInfo', listener: (payload: PeerInfoEvent) => void): this;
38
44
  on(event: string, listener: (payload: BaseMessageEvent) => void): this;
39
45
  }
@@ -44,7 +50,7 @@ class Protocol extends EventEmitter {
44
50
  private protocolMessages: Message[] = [
45
51
  {
46
52
  name: 'PeerInfo',
47
- code: 0x09,
53
+ code: 0x01,
48
54
  encode: (info: Pick<IPeerInfo, 'publicAddress'>) => [
49
55
  Buffer.from(info.publicAddress),
50
56
  ],
@@ -52,6 +58,36 @@ class Protocol extends EventEmitter {
52
58
  publicAddress: publicAddress.toString(),
53
59
  }),
54
60
  },
61
+ {
62
+ name: 'TransactionStatus',
63
+ code: 0x02,
64
+ encode: (transaction: Transaction) => [
65
+ Buffer.from(transaction.transactionHash),
66
+
67
+ Buffer.from(transaction.sourceStatus),
68
+ Buffer.from(transaction.sourceTransactionHash),
69
+ transaction.sourceErrors ? transaction.sourceErrors.map((e) => Buffer.from(e)) : [],
70
+
71
+ Buffer.from(transaction.targetStatus),
72
+ Buffer.from(transaction.targetTransactionHash),
73
+ transaction.targetErrors ? transaction.targetErrors.map((e) => Buffer.from(e)) : [],
74
+
75
+ Buffer.from(transaction.status),
76
+ ],
77
+ decode: ([transactionHash, sourceStatus, sourceTransactionHash, sourceErrors, targetStatus, targetTransactionHash, targetErrors, status]: [Buffer, Buffer, Buffer, Buffer[], Buffer, Buffer, Buffer[], Buffer]) => ({
78
+ transactionHash: transactionHash.toString(),
79
+
80
+ sourceStatus: sourceStatus.toString(),
81
+ sourceTransactionHash: sourceTransactionHash.toString(),
82
+ sourceErrors: sourceErrors.map((e) => e.toString()),
83
+
84
+ targetStatus: targetStatus.toString(),
85
+ targetTransactionHash: targetTransactionHash.toString(),
86
+ targetErrors: targetErrors.map((e) => e.toString()),
87
+
88
+ status: status.toString(),
89
+ }),
90
+ },
55
91
  ];
56
92
  private signature: SignatureDialProtocol;
57
93
 
@@ -121,6 +157,14 @@ class Protocol extends EventEmitter {
121
157
  this.libp2p.pubsub.publish(this.topic, encoded)
122
158
  }
123
159
 
160
+ public sendTransaction(transaction: Transaction) {
161
+ const message = this.protocolMessages.find((m) => m.name === 'TransactionStatus')!
162
+
163
+ const encoded = rlp.encode([message.code, message.encode(transaction)]);
164
+
165
+ this.libp2p.pubsub.publish(this.topic, encoded)
166
+ }
167
+
124
168
  async requestSignatures(data: ISignatureRequest, peerIds?: string[]) {
125
169
  try {
126
170
  peerIds = peerIds || peerPool.activePeerIds;
@@ -0,0 +1,50 @@
1
+ import { BaseTask } from "./BaseTask";
2
+ import Logger from '@/logger';
3
+ import packageJson from '../../package.json'
4
+ import { http } from "@/utils";
5
+ import spawn from 'await-spawn';
6
+ import config from "@/config";
7
+ const currentVersion = packageJson.version;
8
+
9
+ class AutoUpdateTask extends BaseTask {
10
+ pollIntervalMs: number = 60 * 1000
11
+
12
+ constructor() {
13
+ super({
14
+ logger: new Logger("AutoUpdateTask"),
15
+ })
16
+ }
17
+
18
+ prePollHandler(): boolean {
19
+ return config.autoUpdate && !config.isLeadNode();
20
+ }
21
+
22
+ async pollHandler() {
23
+
24
+ const { data } = await http.get('https://registry.npmjs.org/@instadapp/interop-x')
25
+
26
+ const version = data['dist-tags'].latest
27
+
28
+ if (version === currentVersion) {
29
+ return;
30
+ }
31
+
32
+ this.logger.warn(`New version ${version} available.`)
33
+
34
+
35
+ await spawn('npm', ['-g', 'install', '@instadapp/interop-x']);
36
+
37
+ this.logger.warn(`Installed version ${version}`)
38
+ this.logger.warn(`Restarting...`)
39
+
40
+ spawn(process.argv[0], process.argv.slice(1), {
41
+ cwd: process.cwd(),
42
+ detached: true,
43
+ stdio: "inherit"
44
+ });
45
+
46
+ process.exit()
47
+ }
48
+ }
49
+
50
+ export default AutoUpdateTask;
@@ -207,11 +207,13 @@ class ProcessWithdrawEvents extends BaseTask {
207
207
  if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
208
208
  console.log('ExecutionSuccess')
209
209
  transaction.targetStatus = 'success'
210
+ transaction.targetTransactionHash = txSent.hash
210
211
  transaction.status = 'success'
211
212
  await transaction.save();
212
213
  } else {
213
214
  console.log('ExecutionFailure')
214
215
  transaction.targetStatus = 'failed'
216
+ transaction.targetTransactionHash = txSent.hash
215
217
  transaction.status = 'failed'
216
218
  await transaction.save();
217
219
  }
@@ -209,14 +209,18 @@ 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> {
@@ -4,10 +4,13 @@ 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";
7
8
 
8
9
  export class Tasks {
9
10
 
10
11
  tasks: BaseTask[] = [
12
+ new AutoUpdateTask(),
13
+
11
14
  new InteropXGatewaySyncDepositEvents({
12
15
  chainId: 43114
13
16
  }),
@@ -233,7 +233,7 @@ export const buildWithdrawDataForTransaction = async (transaction: Transaction,
233
233
  ethers.BigNumber.from(amount.toString()),
234
234
  to,
235
235
  token.address,
236
- ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()),
236
+ ethers.BigNumber.from(transaction.sourceChainId.toString()),
237
237
  transaction.submitTransactionHash,
238
238
  );
239
239
 
@@ -259,6 +259,12 @@ export function getContract<TContract extends ethers.Contract>(address: string,
259
259
  signerOrProvider
260
260
  ) as TContract
261
261
 
262
+ // Make sure the contract properties is writable
263
+ const desc = Object.getOwnPropertyDescriptor(contract, 'functions');
264
+
265
+ if (!desc || desc.writable !== true) {
266
+ return contract
267
+ }
262
268
 
263
269
  return new Proxy(contract, {
264
270
  get(target, prop, receiver) {