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

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.
package/dist/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.eb2b141",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -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/dist/src/index.js CHANGED
@@ -19,36 +19,65 @@ 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 API_HOST=0.0.0.0 API_PORT=8080 interop-x');
34
+ };
35
+ if (process.argv.at(-1) === 'help') {
36
+ printUsage();
33
37
  process.exit(0);
34
38
  }
35
- (0, assert_1.default)(process.env.PRIVATE_KEY, "PRIVATE_KEY is not defined");
39
+ if (!process.env.PRIVATE_KEY) {
40
+ console.error(chalk_1.default.bgRed.white('Please provide a private key\n'));
41
+ printUsage();
42
+ process.exit(1);
43
+ }
36
44
  try {
37
45
  new ethers_1.ethers.Wallet(process.env.PRIVATE_KEY);
38
46
  }
39
47
  catch (e) {
40
- logger.error('Invalid private key');
48
+ console.error(chalk_1.default.bgRed.white('Invalid private key\n'));
49
+ printUsage();
41
50
  process.exit(1);
42
51
  }
43
- logger.debug(`Starting Interop X Node (v${package_json_1.default.version} - rev.dc4f10a)`);
52
+ logger.debug(`Starting Interop X Node (v${package_json_1.default.version} - rev.eb2b141)`);
44
53
  const tasks_1 = require("@/tasks");
45
54
  const net_1 = require("@/net");
46
55
  const api_1 = require("@/api");
56
+ const db_1 = require("./db");
47
57
  async function main() {
48
58
  (0, net_1.startPeer)({});
49
59
  const tasks = new tasks_1.Tasks();
50
60
  tasks.start();
51
61
  (0, api_1.startApiServer)();
62
+ net_1.protocol.on('TransactionStatus', async (payload) => {
63
+ if (!net_1.peerPool.isLeadNode(payload.peerId)) {
64
+ const peer = net_1.peerPool.getPeer(payload.peerId);
65
+ logger.info(`ignored transaction status from ${payload.peerId} ${peer === null || peer === void 0 ? void 0 : peer.publicAddress} `);
66
+ return;
67
+ }
68
+ const transaction = await db_1.Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } });
69
+ if (!transaction) {
70
+ return;
71
+ }
72
+ transaction.sourceStatus = payload.data.sourceStatus;
73
+ transaction.sourceTransactionHash = payload.data.sourceTransactionHash;
74
+ transaction.sourceErrors = payload.data.sourceErrors;
75
+ transaction.targetStatus = payload.data.targetStatus;
76
+ transaction.targetTransactionHash = payload.data.targetTransactionHash;
77
+ transaction.targetErrors = payload.data.targetErrors;
78
+ transaction.status = payload.data.status;
79
+ await transaction.save();
80
+ });
52
81
  }
53
82
  main()
54
83
  .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;
@@ -126,21 +126,21 @@ 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
  }
138
140
  }
139
141
  async start() {
140
142
  this.logger.info(`Starting execution watcher on interop chain`);
141
- this.contractAddress = constants_1.addresses[this.chainId].interopXGateway;
142
143
  this.provider = new ethers_1.ethers.providers.JsonRpcProvider((0, utils_1.getRpcProviderUrl)(this.chainId));
143
- this.contract = (0, utils_1.getContract)(this.contractAddress, abi_1.default.interopXGateway, new ethers_1.ethers.Wallet(config_1.default.privateKey, this.provider));
144
144
  await super.start();
145
145
  }
146
146
  }
@@ -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`);
@@ -157,7 +157,7 @@ const buildWithdrawDataForTransaction = async (transaction, type) => {
157
157
  if (!transaction.submitEvent) {
158
158
  throw Error('Cannot build data for transaction without submitEvent');
159
159
  }
160
- const { to, amount, chainId, itokenAddress } = transaction.submitEvent;
160
+ const { to, amount, chainId, itoken: itokenAddress } = transaction.submitEvent;
161
161
  const itoken = constants_1.itokens[transaction.sourceChainId].find(token => token.address.toLowerCase() === itokenAddress.toLowerCase());
162
162
  if (!itoken) {
163
163
  throw Error('Cannot build data for transaction without itoken');
@@ -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.dc4f10a",
3
+ "version": "0.0.0-dev.eb2b141",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -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/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,38 @@ 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 API_HOST=0.0.0.0 API_PORT=8080 interop-x')
33
+ }
34
+
35
+ if (process.argv.at(-1) === 'help') {
36
+ printUsage()
33
37
  process.exit(0)
34
38
  }
35
39
 
36
- assert(process.env.PRIVATE_KEY, "PRIVATE_KEY is not defined");
37
40
 
41
+ if(! process.env.PRIVATE_KEY) {
42
+ console.error(chalk.bgRed.white('Please provide a private key\n'))
43
+ printUsage()
44
+ process.exit(1)
45
+ }
38
46
  try {
39
47
  new ethers.Wallet(process.env.PRIVATE_KEY!)
40
48
  } catch (e) {
41
- logger.error('Invalid private key')
49
+ console.error(chalk.bgRed.white('Invalid private key\n'))
50
+ printUsage()
42
51
  process.exit(1)
43
52
  }
44
53
 
45
54
  logger.debug(`Starting Interop X Node (v${packageJson.version} - rev.@GIT_SHORT_HASH@)`)
46
55
 
47
56
  import { Tasks } from "@/tasks";
48
- import { startPeer } from "@/net";
57
+ import { startPeer, protocol, peerPool } from "@/net";
49
58
  import { startApiServer } from '@/api';
59
+ import { Transaction } from './db';
50
60
 
51
61
  async function main() {
52
62
 
@@ -57,6 +67,32 @@ async function main() {
57
67
  tasks.start();
58
68
 
59
69
  startApiServer()
70
+
71
+ protocol.on('TransactionStatus', async (payload) => {
72
+ if (!peerPool.isLeadNode(payload.peerId)) {
73
+ const peer = peerPool.getPeer(payload.peerId)
74
+ logger.info(`ignored transaction status from ${payload.peerId} ${peer?.publicAddress} `)
75
+ return;
76
+ }
77
+
78
+ const transaction = await Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } })
79
+
80
+ if (!transaction) {
81
+ return;
82
+ }
83
+
84
+ transaction.sourceStatus = payload.data.sourceStatus
85
+ transaction.sourceTransactionHash = payload.data.sourceTransactionHash
86
+ transaction.sourceErrors = payload.data.sourceErrors
87
+
88
+ transaction.targetStatus = payload.data.targetStatus
89
+ transaction.targetTransactionHash = payload.data.targetTransactionHash
90
+ transaction.targetErrors = payload.data.targetErrors
91
+
92
+ transaction.status = payload.data.status
93
+
94
+ await transaction.save()
95
+ })
60
96
  }
61
97
 
62
98
  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;
@@ -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,11 +207,13 @@ 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
  }
@@ -222,18 +222,10 @@ class ProcessWithdrawEvents extends BaseTask {
222
222
  async start(): Promise<void> {
223
223
  this.logger.info(`Starting execution watcher on interop chain`);
224
224
 
225
- this.contractAddress = addresses[this.chainId].interopXGateway;
226
-
227
225
  this.provider = new ethers.providers.JsonRpcProvider(
228
226
  getRpcProviderUrl(this.chainId)
229
227
  );
230
228
 
231
- this.contract = getContract<InteropXGateway>(
232
- this.contractAddress,
233
- abi.interopXGateway,
234
- new ethers.Wallet(config.privateKey!, this.provider)
235
- );
236
-
237
229
  await super.start()
238
230
  }
239
231
  }
@@ -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> {
@@ -210,7 +210,7 @@ export const buildWithdrawDataForTransaction = async (transaction: Transaction,
210
210
  throw Error('Cannot build data for transaction without submitEvent');
211
211
  }
212
212
 
213
- const { to, amount, chainId, itokenAddress } = transaction.submitEvent;
213
+ const { to, amount, chainId, itoken: itokenAddress } = transaction.submitEvent;
214
214
 
215
215
  const itoken = itokens[transaction.sourceChainId].find(token => token.address.toLowerCase() === itokenAddress.toLowerCase());
216
216
 
@@ -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) {