@instadapp/interop-x 0.0.0-dev.7a02577 → 0.0.0-dev.7c2b0e5

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.7a02577",
3
+ "version": "0.0.0-dev.7c2b0e5",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -12,7 +12,8 @@
12
12
  "build": "yarn generate-abi-types && export GIT_REF=$(git rev-parse --short HEAD) && rimraf ./dist && tsc -p tsconfig.json && replace-in-file '@GIT_SHORT_HASH@' $GIT_REF ./dist/**/*.js",
13
13
  "dev": "yarn generate-abi-types && NODE_ENV=development nodemon",
14
14
  "generate-abi-types": "typechain --target=ethers-v5 'src/abi/*.json' --out-dir 'src/typechain'",
15
- "prepublishOnly": "yarn build"
15
+ "prepublishOnly": "yarn build",
16
+ "postinstall": "patch-package"
16
17
  },
17
18
  "nodemonConfig": {
18
19
  "watch": [
@@ -45,7 +46,7 @@
45
46
  "libp2p-websockets": "^0.16.2",
46
47
  "luxon": "^2.3.2",
47
48
  "module-alias": "^2.2.2",
48
- "sequelize": "^6.19.0",
49
+ "sequelize": "6.18.0",
49
50
  "sqlite3": "^5.0.5",
50
51
  "waait": "^1.0.5"
51
52
  },
@@ -59,6 +60,8 @@
59
60
  "@types/fs-extra": "^9.0.13",
60
61
  "@types/node": "^17.0.17",
61
62
  "nodemon": "^2.0.15",
63
+ "patch-package": "^6.4.7",
64
+ "postinstall-postinstall": "^2.1.0",
62
65
  "replace-in-file": "^6.3.2",
63
66
  "rimraf": "^3.0.2",
64
67
  "ts-node": "^10.5.0",
package/dist/src/index.js CHANGED
@@ -40,7 +40,7 @@ catch (e) {
40
40
  logger.error('Invalid private key');
41
41
  process.exit(1);
42
42
  }
43
- logger.debug(`Starting Interop X Node (v${package_json_1.default.version} - rev.7a02577)`);
43
+ logger.debug(`Starting Interop X Node (v${package_json_1.default.version} - rev.7c2b0e5)`);
44
44
  const tasks_1 = require("@/tasks");
45
45
  const net_1 = require("@/net");
46
46
  const api_1 = require("@/api");
@@ -82,8 +82,12 @@ const startPeer = async ({}) => {
82
82
  net_1.protocol.start({
83
83
  libp2p: node
84
84
  });
85
- node.on("peer:discovery", (peer) => logger.log(`Discovered peer ${peer}`)); // peer disc.
86
- node.connectionManager.on("peer:connect", (connection) => logger.log(`Connected to ${connection.remotePeer.toB58String()}`));
85
+ node.on("peer:discovery", (peer) => {
86
+ // logger.log(`Discovered peer ${peer}`)
87
+ }); // peer disc.
88
+ node.connectionManager.on("peer:connect", (connection) => {
89
+ // logger.log(`Connected to ${connection.remotePeer.toB58String()}`)
90
+ });
87
91
  logger.log("Peer discovery started");
88
92
  await (0, waait_1.default)(1000);
89
93
  setInterval(() => net_1.protocol.sendPeerInfo({
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.peerPool = exports.PeerPool = void 0;
7
7
  const types_1 = require("@/types");
8
8
  const config_1 = __importDefault(require("@/config"));
9
+ const logger_1 = __importDefault(require("@/logger"));
10
+ const logger = new logger_1.default('PeerPool');
9
11
  class PeerPool {
10
12
  constructor() {
11
13
  this.PEERS_CLEANUP_TIME_LIMIT = 1;
@@ -62,10 +64,14 @@ class PeerPool {
62
64
  * @emits {@link Event.POOL_PEER_ADDED}
63
65
  */
64
66
  add(peer) {
65
- if (peer && peer.id && !this.pool.get(peer.id)) {
67
+ if (peer && peer.id) {
68
+ const newPeer = !this.pool.get(peer.id);
66
69
  this.pool.set(peer.id, peer);
67
70
  peer.pooled = true;
68
- config_1.default.events.emit(types_1.Event.POOL_PEER_ADDED, peer);
71
+ if (newPeer) {
72
+ config_1.default.events.emit(types_1.Event.POOL_PEER_ADDED, peer);
73
+ logger.info(`Peer ${peer.id} with address ${peer.publicAddress} added to pool`);
74
+ }
69
75
  }
70
76
  }
71
77
  /**
@@ -78,6 +84,7 @@ class PeerPool {
78
84
  if (this.pool.delete(peer.id)) {
79
85
  peer.pooled = false;
80
86
  config_1.default.events.emit(types_1.Event.POOL_PEER_REMOVED, peer);
87
+ logger.info(`Peer ${peer.id} with address ${peer.publicAddress} removed from pool`);
81
88
  }
82
89
  }
83
90
  }
@@ -94,13 +101,13 @@ class PeerPool {
94
101
  return this.activePeers.map((p) => p.id);
95
102
  }
96
103
  cleanup() {
97
- let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60;
98
- this.peers.forEach((peerInfo) => {
99
- if (peerInfo.updated.getTime() < compDate) {
100
- console.log(`Peer ${peerInfo.id} idle for ${this.PEERS_CLEANUP_TIME_LIMIT} minutes`);
101
- this.remove(peerInfo);
102
- }
103
- });
104
+ // let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
105
+ // this.peers.forEach((peerInfo) => {
106
+ // if (peerInfo.updated.getTime() < compDate) {
107
+ // console.log(`Peer ${peerInfo.id} idle for ${this.PEERS_CLEANUP_TIME_LIMIT} minutes`)
108
+ // this.remove(peerInfo)
109
+ // }
110
+ // })
104
111
  }
105
112
  }
106
113
  exports.PeerPool = PeerPool;
@@ -33,12 +33,19 @@ class SignatureDialProtocol extends BaseDialProtocol_1.BaseDialProtocol {
33
33
  error: 'Event not found'
34
34
  };
35
35
  }
36
+ console.log("signing:", {
37
+ to: constants_1.addresses[transaction.targetChainId].multisend,
38
+ data: await (0, utils_1.buildDataForTransaction)(transaction, data.type),
39
+ chainId: transaction.targetChainId,
40
+ safeTxGas: data.safeTxGas,
41
+ nonce: data.safeNonce,
42
+ });
36
43
  const signedData = await (0, utils_1.signGnosisSafeTx)({
37
- //TODO: chain id depends on event type
38
- to: constants_1.addresses[transaction.sourceChainId].multisend,
39
- data: (0, utils_1.buildDataForTransaction)(transaction, data.type),
40
- chainId: transaction.sourceChainId,
44
+ to: constants_1.addresses[transaction.targetChainId].multisend,
45
+ data: await (0, utils_1.buildDataForTransaction)(transaction, data.type),
46
+ chainId: transaction.targetChainId,
41
47
  safeTxGas: data.safeTxGas,
48
+ nonce: data.safeNonce,
42
49
  }, { signer });
43
50
  return {
44
51
  signer: signer.address,
@@ -28,7 +28,7 @@ class BaseTask extends events_1.default {
28
28
  }
29
29
  }
30
30
  catch (err) {
31
- this.logger.error(`poll check error: ${err.message}\ntrace: ${err.stack}`);
31
+ this.logger.error(`poll check error:\n${err.message}\ntrace: ${err.stack}`);
32
32
  }
33
33
  await this.postPollHandler();
34
34
  }
@@ -15,6 +15,7 @@ const sequelize_1 = require("sequelize");
15
15
  const waait_1 = __importDefault(require("waait"));
16
16
  const net_1 = require("@/net");
17
17
  const generateGnosisTransaction = async (transactionData, safeContract) => {
18
+ console.log(transactionData);
18
19
  let isExecuted = await safeContract.dataHashes(await safeContract.getTransactionHash(transactionData.to, transactionData.value, transactionData.data, transactionData.operation, transactionData.safeTxGas, transactionData.baseGas, transactionData.gasPrice, transactionData.gasToken, transactionData.refundReceiver, transactionData.nonce));
19
20
  while (isExecuted == 1) {
20
21
  transactionData.safeTxGas = ethers_1.BigNumber.from(String(transactionData.safeTxGas)).add(1).toString();
@@ -37,30 +38,38 @@ class ProcessDepositEvents extends BaseTask_1.BaseTask {
37
38
  where: {
38
39
  status: 'pending',
39
40
  sourceStatus: 'success',
41
+ targetStatus: 'uninitialised',
40
42
  action: 'deposit',
41
43
  sourceCreatedAt: {
42
44
  [sequelize_1.Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
43
45
  },
46
+ targetDelayUntil: {
47
+ [sequelize_1.Op.or]: {
48
+ [sequelize_1.Op.is]: null,
49
+ [sequelize_1.Op.lt]: new Date(),
50
+ }
51
+ },
44
52
  sourceBlockNumber: {
45
53
  [sequelize_1.Op.lt]: blockNumber - 12,
46
- }
54
+ },
55
+ sourceChainId: this.chainId,
47
56
  }
48
57
  });
49
58
  if (!transaction) {
50
59
  return;
51
60
  }
52
- transaction.sourceStatus = 'pending';
61
+ transaction.targetStatus = 'pending';
53
62
  await transaction.save();
54
63
  // refresh event data?
55
64
  const targetChainProvider = new ethers_1.ethers.providers.JsonRpcProvider((0, utils_1.getRpcProviderUrl)(transaction.targetChainId));
56
65
  const targetWallet = new ethers_1.ethers.Wallet(config_1.default.privateKey, targetChainProvider);
57
66
  const safeAddress = constants_1.addresses[transaction.targetChainId].gnosisSafe;
58
- const safeContract = new ethers_1.ethers.Contract(safeAddress, abi_1.default.gnosisSafe, targetWallet);
67
+ const safeContract = (0, utils_1.getContract)(safeAddress, abi_1.default.gnosisSafe, targetWallet);
59
68
  const ownersThreshold = await safeContract.getThreshold();
60
69
  await (0, waait_1.default)(10000);
61
70
  let gnosisTx = await generateGnosisTransaction({
62
71
  baseGas: "0",
63
- data: (0, utils_1.buildDataForTransaction)(transaction),
72
+ data: await (0, utils_1.buildDataForTransaction)(transaction),
64
73
  gasPrice: "0",
65
74
  gasToken: "0x0000000000000000000000000000000000000000",
66
75
  nonce: '0',
@@ -74,6 +83,7 @@ class ProcessDepositEvents extends BaseTask_1.BaseTask {
74
83
  const owners = await safeContract.getOwners().then(owners => owners.map(owner => owner.toLowerCase()));
75
84
  const ownerPeerIds = net_1.peerPool.activePeers.filter(peer => owners.includes(peer.publicAddress.toLowerCase())).map(peer => peer.id);
76
85
  console.log(`Collecting signatures for execution ${transaction.transactionHash}`);
86
+ console.log(ownerPeerIds);
77
87
  const signatures = await net_1.protocol.requestSignatures({
78
88
  type: 'source',
79
89
  transactionHash: transaction.transactionHash,
@@ -84,8 +94,8 @@ class ProcessDepositEvents extends BaseTask_1.BaseTask {
84
94
  console.log({ signatures, validSignatures, ownersThreshold: ownersThreshold.toString() });
85
95
  if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
86
96
  await transaction.save();
87
- transaction.sourceDelayUntil = new Date(Date.now() + 30 * 1000);
88
- transaction.sourceStatus = 'pending';
97
+ transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
98
+ transaction.targetStatus = 'uninitialised';
89
99
  await transaction.save();
90
100
  const errorMessage = (_a = signatures.find(s => !!s.error)) === null || _a === void 0 ? void 0 : _a.error;
91
101
  throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
@@ -107,6 +117,14 @@ class ProcessDepositEvents extends BaseTask_1.BaseTask {
107
117
  execTransactionParams
108
118
  });
109
119
  const { data: txData } = await safeContract.populateTransaction.execTransaction(gnosisTx.to, gnosisTx.value, gnosisTx.data, gnosisTx.operation, gnosisTx.safeTxGas, gnosisTx.baseGas, gnosisTx.gasPrice, gnosisTx.gasToken, gnosisTx.refundReceiver, (0, utils_1.buildSignatureBytes)(validSignatures));
120
+ console.log({
121
+ from: targetWallet.address,
122
+ gasPrice: ethers_1.BigNumber.from(120 * 10 ** 9).toString(),
123
+ gasLimit: ethers_1.BigNumber.from(6000000).toString(),
124
+ to: safeAddress,
125
+ data: txData,
126
+ });
127
+ return;
110
128
  const txSent = await targetWallet.sendTransaction({
111
129
  from: targetWallet.address,
112
130
  gasPrice: ethers_1.BigNumber.from(120 * 10 ** 9),
@@ -133,7 +151,7 @@ class ProcessDepositEvents extends BaseTask_1.BaseTask {
133
151
  this.logger.info(`Starting execution watcher on interop chain`);
134
152
  this.contractAddress = constants_1.addresses[this.chainId].interopXGateway;
135
153
  this.provider = new ethers_1.ethers.providers.JsonRpcProvider((0, utils_1.getRpcProviderUrl)(this.chainId));
136
- this.contract = new ethers_1.ethers.Contract(this.contractAddress, abi_1.default.interopXGateway, new ethers_1.ethers.Wallet(config_1.default.privateKey, this.provider));
154
+ this.contract = (0, utils_1.getContract)(this.contractAddress, abi_1.default.interopXGateway, new ethers_1.ethers.Wallet(config_1.default.privateKey, this.provider));
137
155
  await super.start();
138
156
  }
139
157
  }
@@ -45,14 +45,14 @@ class SyncDepositEvents extends BaseTask_1.BaseTask {
45
45
  sourceChainId: sourceChainId.toString(),
46
46
  targetChainId: targetChainId.toString(),
47
47
  token: token,
48
- ammout: amount.toString(),
48
+ amount: amount.toString(),
49
49
  vnonce: vnonce.toString(),
50
50
  }, sourceEvent: {
51
51
  user,
52
52
  sourceChainId: sourceChainId.toString(),
53
53
  targetChainId: targetChainId.toString(),
54
54
  token: token,
55
- ammout: amount.toString(),
55
+ amount: amount.toString(),
56
56
  vnonce: vnonce.toString(),
57
57
  }, status: "pending" }));
58
58
  this.logger.info(`Execution queued: ${event.transactionHash} ${event.blockNumber}`);
@@ -68,7 +68,7 @@ class SyncDepositEvents extends BaseTask_1.BaseTask {
68
68
  this.logger.info(`Starting execution watcher on interop chain`);
69
69
  this.contractAddress = constants_1.addresses[this.chainId].interopXGateway;
70
70
  this.provider = new ethers_1.ethers.providers.JsonRpcProvider((0, utils_1.getRpcProviderUrl)(this.chainId));
71
- this.contract = new ethers_1.ethers.Contract(this.contractAddress, abi_1.default.interopXGateway, new ethers_1.ethers.Wallet(config_1.default.privateKey, this.provider));
71
+ this.contract = (0, utils_1.getContract)(this.contractAddress, abi_1.default.interopXGateway, new ethers_1.ethers.Wallet(config_1.default.privateKey, this.provider));
72
72
  await super.start();
73
73
  }
74
74
  }
@@ -4,12 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Tasks = void 0;
7
+ const ProcessDepositEvents_1 = __importDefault(require("./InteropXGateway/ProcessDepositEvents"));
7
8
  const SyncDepositEvents_1 = __importDefault(require("./InteropXGateway/SyncDepositEvents"));
8
9
  class Tasks {
9
10
  constructor() {
10
11
  this.tasks = [
11
12
  new SyncDepositEvents_1.default({
12
13
  chainId: 43114
14
+ }),
15
+ new ProcessDepositEvents_1.default({
16
+ chainId: 43114
13
17
  })
14
18
  ];
15
19
  }
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.buildDataForTransaction = exports.generateInteropTransactionHash = exports.asyncCallWithTimeout = exports.buildSignatureBytes = exports.getRpcProviderUrl = exports.signGnosisSafeTx = exports.short = exports.http = void 0;
6
+ exports.getContract = exports.buildDataForTransaction = exports.generateInteropTransactionHash = exports.asyncCallWithTimeout = exports.buildSignatureBytes = exports.getRpcProviderUrl = exports.signGnosisSafeTx = exports.short = exports.http = void 0;
7
7
  /**
8
8
  * @module util
9
9
  */
@@ -124,8 +124,8 @@ const buildDataForTransaction = async (transaction, type) => {
124
124
  }
125
125
  const targetChainProvider = new ethers_1.ethers.providers.JsonRpcProvider((0, exports.getRpcProviderUrl)(transaction.targetChainId));
126
126
  const targetWallet = new ethers_1.ethers.Wallet(config_1.default.privateKey, targetChainProvider);
127
- const interopBridgeContract = new ethers_1.ethers.Contract(itoken.address, abi_1.default.interopBridgeToken, targetWallet);
128
- const { data } = await interopBridgeContract.populateTransaction.mint(transaction.submitEvent.to, transaction.submitEvent.amount, transaction.sourceChainId, transaction.sourceTransactionHash);
127
+ const interopBridgeContract = getContract(itoken.address, abi_1.default.interopBridgeToken, targetWallet);
128
+ const { data } = await interopBridgeContract.populateTransaction.mint(transaction.submitEvent.user, ethers_1.ethers.BigNumber.from(transaction.submitEvent.amount.toString()), ethers_1.ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()), transaction.sourceTransactionHash);
129
129
  transactions.push({
130
130
  to: itoken.address,
131
131
  data: data,
@@ -135,3 +135,44 @@ const buildDataForTransaction = async (transaction, type) => {
135
135
  return (0, ethers_multisend_1.encodeMulti)(transactions).data;
136
136
  };
137
137
  exports.buildDataForTransaction = buildDataForTransaction;
138
+ function getContract(address, contractInterface, signerOrProvider) {
139
+ if (!ethers_1.ethers.utils.getAddress(address) || address === ethers_1.ethers.constants.AddressZero) {
140
+ throw Error(`Invalid 'address' parameter '${address}'.`);
141
+ }
142
+ const contract = new ethers_1.ethers.Contract(address, contractInterface, signerOrProvider);
143
+ return new Proxy(contract, {
144
+ get(target, prop, receiver) {
145
+ const value = Reflect.get(target, prop, receiver);
146
+ if (typeof value === 'function' && (contract.functions.hasOwnProperty(prop) || ['queryFilter'].includes(String(prop)))) {
147
+ return async (...args) => {
148
+ try {
149
+ return await value.bind(contract)(...args);
150
+ }
151
+ catch (error) {
152
+ throw new Error(`Error calling "${String(prop)}" on "${address}": ${error.reason || error.message}`);
153
+ }
154
+ };
155
+ }
156
+ if (typeof value === 'object' && ['populateTransaction', 'estimateGas', 'functions', 'callStatic'].includes(String(prop))) {
157
+ const parentProp = String(prop);
158
+ return new Proxy(value, {
159
+ get(target, prop, receiver) {
160
+ const value = Reflect.get(target, prop, receiver);
161
+ if (typeof value === 'function') {
162
+ return async (...args) => {
163
+ try {
164
+ return await value.bind(contract)(...args);
165
+ }
166
+ catch (error) {
167
+ throw new Error(`Error calling "${String(prop)}" using "${parentProp}" on "${address}": ${error.reason || error.message}`);
168
+ }
169
+ };
170
+ }
171
+ }
172
+ });
173
+ }
174
+ return value;
175
+ },
176
+ });
177
+ }
178
+ exports.getContract = getContract;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instadapp/interop-x",
3
- "version": "0.0.0-dev.7a02577",
3
+ "version": "0.0.0-dev.7c2b0e5",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -12,7 +12,8 @@
12
12
  "build": "yarn generate-abi-types && export GIT_REF=$(git rev-parse --short HEAD) && rimraf ./dist && tsc -p tsconfig.json && replace-in-file '@GIT_SHORT_HASH@' $GIT_REF ./dist/**/*.js",
13
13
  "dev": "yarn generate-abi-types && NODE_ENV=development nodemon",
14
14
  "generate-abi-types": "typechain --target=ethers-v5 'src/abi/*.json' --out-dir 'src/typechain'",
15
- "prepublishOnly": "yarn build"
15
+ "prepublishOnly": "yarn build",
16
+ "postinstall": "patch-package"
16
17
  },
17
18
  "nodemonConfig": {
18
19
  "watch": [
@@ -45,7 +46,7 @@
45
46
  "libp2p-websockets": "^0.16.2",
46
47
  "luxon": "^2.3.2",
47
48
  "module-alias": "^2.2.2",
48
- "sequelize": "^6.19.0",
49
+ "sequelize": "6.18.0",
49
50
  "sqlite3": "^5.0.5",
50
51
  "waait": "^1.0.5"
51
52
  },
@@ -59,6 +60,8 @@
59
60
  "@types/fs-extra": "^9.0.13",
60
61
  "@types/node": "^17.0.17",
61
62
  "nodemon": "^2.0.15",
63
+ "patch-package": "^6.4.7",
64
+ "postinstall-postinstall": "^2.1.0",
62
65
  "replace-in-file": "^6.3.2",
63
66
  "rimraf": "^3.0.2",
64
67
  "ts-node": "^10.5.0",
@@ -0,0 +1,13 @@
1
+ diff --git a/node_modules/@ethersproject/properties/lib/index.js b/node_modules/@ethersproject/properties/lib/index.js
2
+ index 41e0b52..4c7a9e3 100644
3
+ --- a/node_modules/@ethersproject/properties/lib/index.js
4
+ +++ b/node_modules/@ethersproject/properties/lib/index.js
5
+ @@ -44,7 +44,7 @@ function defineReadOnly(object, name, value) {
6
+ Object.defineProperty(object, name, {
7
+ enumerable: true,
8
+ value: value,
9
+ - writable: false,
10
+ + writable: true,
11
+ });
12
+ }
13
+ exports.defineReadOnly = defineReadOnly;
@@ -88,12 +88,13 @@ export const startPeer = async ({ }: IPeerOptions) => {
88
88
  libp2p: node
89
89
  })
90
90
 
91
- node.on("peer:discovery", (peer) =>
92
- logger.log(`Discovered peer ${peer}`)
93
- ); // peer disc.
94
- node.connectionManager.on("peer:connect", (connection) =>
95
- logger.log(`Connected to ${connection.remotePeer.toB58String()}`)
96
- );
91
+ node.on("peer:discovery", (peer) => {
92
+ // logger.log(`Discovered peer ${peer}`)
93
+ }); // peer disc.
94
+
95
+ node.connectionManager.on("peer:connect", (connection) => {
96
+ // logger.log(`Connected to ${connection.remotePeer.toB58String()}`)
97
+ });
97
98
 
98
99
  logger.log("Peer discovery started");
99
100
 
@@ -1,5 +1,9 @@
1
1
  import { Event } from "@/types";
2
2
  import config from "@/config";
3
+ import Logger from "@/logger";
4
+
5
+
6
+ const logger = new Logger('PeerPool')
3
7
 
4
8
  export interface IPeerInfo {
5
9
  id: string;
@@ -75,10 +79,15 @@ export class PeerPool {
75
79
  * @emits {@link Event.POOL_PEER_ADDED}
76
80
  */
77
81
  add(peer?: IPeerInfo) {
78
- if (peer && peer.id && !this.pool.get(peer.id)) {
82
+ if (peer && peer.id) {
83
+ const newPeer = !this.pool.get(peer.id);
79
84
  this.pool.set(peer.id, peer)
80
85
  peer.pooled = true
81
- config.events.emit(Event.POOL_PEER_ADDED, peer)
86
+
87
+ if(newPeer) {
88
+ config.events.emit(Event.POOL_PEER_ADDED, peer)
89
+ logger.info(`Peer ${peer.id} with address ${peer.publicAddress} added to pool`)
90
+ }
82
91
  }
83
92
  }
84
93
 
@@ -92,6 +101,7 @@ export class PeerPool {
92
101
  if (this.pool.delete(peer.id)) {
93
102
  peer.pooled = false
94
103
  config.events.emit(Event.POOL_PEER_REMOVED, peer)
104
+ logger.info(`Peer ${peer.id} with address ${peer.publicAddress} removed from pool`)
95
105
  }
96
106
  }
97
107
  }
@@ -114,14 +124,14 @@ export class PeerPool {
114
124
 
115
125
 
116
126
  cleanup() {
117
- let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
118
-
119
- this.peers.forEach((peerInfo) => {
120
- if (peerInfo.updated.getTime() < compDate) {
121
- console.log(`Peer ${peerInfo.id} idle for ${this.PEERS_CLEANUP_TIME_LIMIT} minutes`)
122
- this.remove(peerInfo)
123
- }
124
- })
127
+ // let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
128
+
129
+ // this.peers.forEach((peerInfo) => {
130
+ // if (peerInfo.updated.getTime() < compDate) {
131
+ // console.log(`Peer ${peerInfo.id} idle for ${this.PEERS_CLEANUP_TIME_LIMIT} minutes`)
132
+ // this.remove(peerInfo)
133
+ // }
134
+ // })
125
135
  }
126
136
  }
127
137
 
@@ -47,12 +47,20 @@ export class SignatureDialProtocol extends BaseDialProtocol<ISignatureRequest, I
47
47
  };
48
48
  }
49
49
 
50
+ console.log("signing:", {
51
+ to: addresses[transaction.targetChainId].multisend,
52
+ data: await buildDataForTransaction(transaction, data.type),
53
+ chainId: transaction.targetChainId as ChainId,
54
+ safeTxGas: data.safeTxGas,
55
+ nonce: data.safeNonce,
56
+ });
57
+
50
58
  const signedData = await signGnosisSafeTx({
51
- //TODO: chain id depends on event type
52
- to: addresses[transaction.sourceChainId].multisend,
53
- data: buildDataForTransaction(transaction, data.type),
54
- chainId: transaction.sourceChainId as ChainId,
59
+ to: addresses[transaction.targetChainId].multisend,
60
+ data: await buildDataForTransaction(transaction, data.type),
61
+ chainId: transaction.targetChainId as ChainId,
55
62
  safeTxGas: data.safeTxGas,
63
+ nonce: data.safeNonce,
56
64
  }, { signer });
57
65
 
58
66
  return {
@@ -37,7 +37,7 @@ export class BaseTask extends EventEmitter implements IBaseTask {
37
37
  await this.pollHandler()
38
38
  }
39
39
  } catch (err) {
40
- this.logger.error(`poll check error: ${err.message}\ntrace: ${err.stack}`)
40
+ this.logger.error(`poll check error:\n${err.message}\ntrace: ${err.stack}`)
41
41
  }
42
42
 
43
43
  await this.postPollHandler()
@@ -3,7 +3,7 @@ import Logger from '@/logger';
3
3
  import { BigNumber, ethers } from "ethers";
4
4
  import abi from "@/abi";
5
5
  import { Transaction } from "@/db";
6
- import { buildDataForTransaction, buildSignatureBytes, getRpcProviderUrl, Signature } from "@/utils";
6
+ import { buildDataForTransaction, buildSignatureBytes, getContract, getRpcProviderUrl, Signature } from "@/utils";
7
7
  import { addresses } from "@/constants";
8
8
  import { ChainId } from "@/types";
9
9
  import config from "@/config";
@@ -13,7 +13,9 @@ import wait from "waait";
13
13
  import { peerPool, protocol } from "@/net";
14
14
  import { LogDescription } from "ethers/lib/utils";
15
15
 
16
- const generateGnosisTransaction = async (transactionData: any, safeContract: any) => {
16
+ const generateGnosisTransaction = async (transactionData: any, safeContract: GnosisSafe) => {
17
+ console.log(transactionData);
18
+
17
19
  let isExecuted = await safeContract.dataHashes(
18
20
  await safeContract.getTransactionHash(
19
21
  transactionData.to,
@@ -72,13 +74,21 @@ class ProcessDepositEvents extends BaseTask {
72
74
  where: {
73
75
  status: 'pending',
74
76
  sourceStatus: 'success',
77
+ targetStatus: 'uninitialised',
75
78
  action: 'deposit',
76
79
  sourceCreatedAt: {
77
80
  [Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
78
81
  },
82
+ targetDelayUntil: {
83
+ [Op.or]: {
84
+ [Op.is]: null,
85
+ [Op.lt]: new Date(),
86
+ }
87
+ },
79
88
  sourceBlockNumber: {
80
89
  [Op.lt]: blockNumber - 12,
81
- }
90
+ },
91
+ sourceChainId: this.chainId,
82
92
  }
83
93
  })
84
94
 
@@ -87,7 +97,7 @@ class ProcessDepositEvents extends BaseTask {
87
97
  }
88
98
 
89
99
 
90
- transaction.sourceStatus = 'pending';
100
+ transaction.targetStatus = 'pending';
91
101
  await transaction.save();
92
102
 
93
103
 
@@ -101,19 +111,19 @@ class ProcessDepositEvents extends BaseTask {
101
111
 
102
112
  const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
103
113
 
104
- const safeContract = new ethers.Contract(
114
+
115
+ const safeContract = getContract<GnosisSafe>(
105
116
  safeAddress,
106
117
  abi.gnosisSafe,
107
118
  targetWallet
108
- ) as GnosisSafe;
119
+ )
109
120
 
110
121
  const ownersThreshold = await safeContract.getThreshold();
111
-
112
122
  await wait(10000);
113
123
 
114
124
  let gnosisTx = await generateGnosisTransaction({
115
125
  baseGas: "0",
116
- data: buildDataForTransaction(transaction),
126
+ data: await buildDataForTransaction(transaction),
117
127
  gasPrice: "0",
118
128
  gasToken: "0x0000000000000000000000000000000000000000",
119
129
  nonce: '0',
@@ -131,6 +141,8 @@ class ProcessDepositEvents extends BaseTask {
131
141
 
132
142
  console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
133
143
 
144
+ console.log(ownerPeerIds);
145
+
134
146
  const signatures = await protocol.requestSignatures({
135
147
  type: 'source',
136
148
  transactionHash: transaction.transactionHash,
@@ -145,8 +157,8 @@ class ProcessDepositEvents extends BaseTask {
145
157
 
146
158
  if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
147
159
  await transaction.save();
148
- transaction.sourceDelayUntil = new Date(Date.now() + 30 * 1000);
149
- transaction.sourceStatus = 'pending'
160
+ transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
161
+ transaction.targetStatus = 'uninitialised'
150
162
 
151
163
  await transaction.save();
152
164
  const errorMessage = signatures.find(s => !!s.error)?.error;
@@ -185,6 +197,15 @@ class ProcessDepositEvents extends BaseTask {
185
197
  buildSignatureBytes(validSignatures)
186
198
  );
187
199
 
200
+ console.log({
201
+ from: targetWallet.address,
202
+ gasPrice: BigNumber.from(120 * 10 ** 9).toString(),
203
+ gasLimit: BigNumber.from(6_000_000).toString(),
204
+ to: safeAddress,
205
+ data: txData,
206
+ })
207
+ return;
208
+
188
209
  const txSent = await targetWallet.sendTransaction({
189
210
  from: targetWallet.address,
190
211
  gasPrice: BigNumber.from(120 * 10 ** 9),
@@ -219,11 +240,11 @@ class ProcessDepositEvents extends BaseTask {
219
240
  getRpcProviderUrl(this.chainId)
220
241
  );
221
242
 
222
- this.contract = new ethers.Contract(
243
+ this.contract = getContract<InteropXGateway>(
223
244
  this.contractAddress,
224
245
  abi.interopXGateway,
225
246
  new ethers.Wallet(config.privateKey!, this.provider)
226
- ) as InteropXGateway;
247
+ );
227
248
 
228
249
  await super.start()
229
250
  }
@@ -3,7 +3,7 @@ import Logger from '@/logger';
3
3
  import { ethers } from "ethers";
4
4
  import abi from "@/abi";
5
5
  import { Transaction } from "@/db";
6
- import { generateInteropTransactionHash, getRpcProviderUrl } from "@/utils";
6
+ import { generateInteropTransactionHash, getContract, getRpcProviderUrl } from "@/utils";
7
7
  import { addresses } from "@/constants";
8
8
  import { ChainId } from "@/types";
9
9
  import config from "@/config";
@@ -77,7 +77,7 @@ class SyncDepositEvents extends BaseTask {
77
77
  sourceChainId: sourceChainId.toString(),
78
78
  targetChainId: targetChainId.toString(),
79
79
  token: token,
80
- ammout: amount.toString(),
80
+ amount: amount.toString(),
81
81
  vnonce: vnonce.toString(),
82
82
  },
83
83
 
@@ -86,7 +86,7 @@ class SyncDepositEvents extends BaseTask {
86
86
  sourceChainId: sourceChainId.toString(),
87
87
  targetChainId: targetChainId.toString(),
88
88
  token: token,
89
- ammout: amount.toString(),
89
+ amount: amount.toString(),
90
90
  vnonce: vnonce.toString(),
91
91
  },
92
92
  status: "pending",
@@ -113,11 +113,11 @@ class SyncDepositEvents extends BaseTask {
113
113
  getRpcProviderUrl(this.chainId)
114
114
  );
115
115
 
116
- this.contract = new ethers.Contract(
116
+ this.contract = getContract<InteropXGateway>(
117
117
  this.contractAddress,
118
118
  abi.interopXGateway,
119
119
  new ethers.Wallet(config.privateKey!, this.provider)
120
- ) as InteropXGateway;
120
+ );
121
121
 
122
122
  await super.start()
123
123
  }
@@ -1,10 +1,15 @@
1
1
  import { BaseTask } from "./BaseTask";
2
- import SyncInteropXGatewayDepositEvents from "./InteropXGateway/SyncDepositEvents";
2
+ import InteropXGatewayProcessDepositEvents from "./InteropXGateway/ProcessDepositEvents";
3
+ import InteropXGatewaySyncDepositEvents from "./InteropXGateway/SyncDepositEvents";
3
4
 
4
5
  export class Tasks {
5
6
 
6
7
  tasks: BaseTask[] = [
7
- new SyncInteropXGatewayDepositEvents({
8
+ new InteropXGatewaySyncDepositEvents({
9
+ chainId: 43114
10
+ }),
11
+
12
+ new InteropXGatewayProcessDepositEvents({
8
13
  chainId: 43114
9
14
  })
10
15
  ];
@@ -138,7 +138,7 @@ export const buildDataForTransaction = async (transaction: Transaction, type?: '
138
138
 
139
139
  const transactions: MetaTransaction[] = [];
140
140
 
141
- if(transaction.action != 'deposit') {
141
+ if (transaction.action != 'deposit') {
142
142
  throw new Error('Invalid action');
143
143
  }
144
144
 
@@ -165,12 +165,12 @@ export const buildDataForTransaction = async (transaction: Transaction, type?: '
165
165
 
166
166
  const targetChainProvider = new ethers.providers.JsonRpcProvider(getRpcProviderUrl(transaction.targetChainId as ChainId));
167
167
  const targetWallet = new ethers.Wallet(config.privateKey, targetChainProvider);
168
- const interopBridgeContract = new ethers.Contract(itoken.address, abi.interopBridgeToken, targetWallet) as InteropBridgeToken;
168
+ const interopBridgeContract = getContract<InteropBridgeToken>(itoken.address, abi.interopBridgeToken, targetWallet);
169
169
 
170
170
  const { data } = await interopBridgeContract.populateTransaction.mint(
171
- transaction.submitEvent.to,
172
- transaction.submitEvent.amount,
173
- transaction.sourceChainId,
171
+ transaction.submitEvent.user,
172
+ ethers.BigNumber.from(transaction.submitEvent.amount.toString()),
173
+ ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()),
174
174
  transaction.sourceTransactionHash,
175
175
  );
176
176
 
@@ -183,3 +183,56 @@ export const buildDataForTransaction = async (transaction: Transaction, type?: '
183
183
 
184
184
  return encodeMulti(transactions).data
185
185
  }
186
+
187
+
188
+ export function getContract<TContract extends ethers.Contract>(address: string, contractInterface: ethers.ContractInterface | any, signerOrProvider?: ethers.Signer | ethers.providers.Provider) {
189
+ if (!ethers.utils.getAddress(address) || address === ethers.constants.AddressZero) {
190
+ throw Error(`Invalid 'address' parameter '${address}'.`)
191
+ }
192
+
193
+ const contract = new ethers.Contract(
194
+ address,
195
+ contractInterface,
196
+ signerOrProvider
197
+ ) as TContract
198
+
199
+
200
+ return new Proxy(contract, {
201
+ get(target, prop, receiver) {
202
+ const value = Reflect.get(target, prop, receiver);
203
+
204
+ if (typeof value === 'function' && (contract.functions.hasOwnProperty(prop) || ['queryFilter'].includes(String(prop)))) {
205
+ return async (...args: any[]) => {
206
+ try {
207
+ return await value.bind(contract)(...args);
208
+ } catch (error) {
209
+ throw new Error(`Error calling "${String(prop)}" on "${address}": ${error.reason || error.message}`)
210
+ }
211
+ }
212
+ }
213
+
214
+
215
+ if (typeof value === 'object' && ['populateTransaction', 'estimateGas', 'functions', 'callStatic'].includes(String(prop))) {
216
+ const parentProp = String(prop);
217
+
218
+ return new Proxy(value, {
219
+ get(target, prop, receiver) {
220
+ const value = Reflect.get(target, prop, receiver);
221
+
222
+ if (typeof value === 'function') {
223
+ return async (...args: any[]) => {
224
+ try {
225
+ return await value.bind(contract)(...args);
226
+ } catch (error) {
227
+ throw new Error(`Error calling "${String(prop)}" using "${parentProp}" on "${address}": ${error.reason || error.message}`)
228
+ }
229
+ }
230
+ }
231
+ }
232
+ })
233
+ }
234
+
235
+ return value;
236
+ },
237
+ });
238
+ }