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

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.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
+ }