@instadapp/interop-x 0.0.0-dev.9387bd9 → 0.0.0-dev.a168c79

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. package/.env.example +2 -1
  2. package/dist/package.json +69 -0
  3. package/dist/src/abi/erc20.json +350 -0
  4. package/dist/src/abi/gnosisSafe.json +747 -0
  5. package/dist/src/abi/index.js +15 -0
  6. package/dist/src/abi/interopBridgeToken.json +286 -0
  7. package/dist/src/abi/interopXGateway.json +184 -0
  8. package/dist/src/api/index.js +33 -0
  9. package/dist/{config → src/config}/index.js +5 -1
  10. package/dist/src/constants/addresses.js +20 -0
  11. package/dist/{constants → src/constants}/index.js +2 -0
  12. package/dist/src/constants/itokens.js +13 -0
  13. package/dist/src/constants/tokens.js +107 -0
  14. package/dist/{db → src/db}/index.js +0 -0
  15. package/dist/{db → src/db}/models/index.js +1 -1
  16. package/dist/src/db/models/transaction.js +54 -0
  17. package/dist/{db → src/db}/sequelize.js +2 -1
  18. package/dist/{index.js → src/index.js} +29 -3
  19. package/dist/{logger → src/logger}/index.js +0 -0
  20. package/dist/{net → src/net}/index.js +0 -0
  21. package/dist/{net → src/net}/peer/index.js +5 -5
  22. package/dist/{net → src/net}/pool/index.js +2 -2
  23. package/dist/{net → src/net}/protocol/dial/BaseDialProtocol.js +1 -1
  24. package/dist/{net → src/net}/protocol/dial/SignatureDialProtocol.js +15 -14
  25. package/dist/{net → src/net}/protocol/index.js +3 -3
  26. package/dist/{tasks → src/tasks}/BaseTask.js +2 -2
  27. package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +140 -0
  28. package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +75 -0
  29. package/dist/{tasks → src/tasks}/index.js +9 -1
  30. package/dist/src/typechain/Erc20.js +2 -0
  31. package/dist/src/typechain/GnosisSafe.js +2 -0
  32. package/dist/src/typechain/InteropBridgeToken.js +2 -0
  33. package/dist/src/typechain/InteropXGateway.js +2 -0
  34. package/dist/src/typechain/common.js +2 -0
  35. package/dist/src/typechain/factories/Erc20__factory.js +367 -0
  36. package/dist/src/typechain/factories/GnosisSafe__factory.js +1174 -0
  37. package/dist/src/typechain/factories/InteropBridgeToken__factory.js +459 -0
  38. package/dist/src/typechain/factories/InteropXGateway__factory.js +265 -0
  39. package/dist/src/typechain/factories/index.js +14 -0
  40. package/dist/src/typechain/index.js +35 -0
  41. package/dist/{types.js → src/types.js} +0 -0
  42. package/dist/{utils → src/utils}/index.js +50 -2
  43. package/package.json +14 -4
  44. package/src/abi/erc20.json +350 -0
  45. package/src/abi/gnosisSafe.json +747 -0
  46. package/src/abi/index.ts +11 -0
  47. package/src/abi/interopBridgeToken.json +286 -0
  48. package/src/abi/interopXGateway.json +184 -0
  49. package/src/api/index.ts +33 -0
  50. package/src/config/index.ts +7 -1
  51. package/src/constants/addresses.ts +9 -2
  52. package/src/constants/index.ts +2 -0
  53. package/src/constants/itokens.ts +10 -0
  54. package/src/constants/tokens.ts +104 -0
  55. package/src/db/index.ts +1 -1
  56. package/src/db/models/index.ts +1 -1
  57. package/src/db/models/transaction.ts +96 -0
  58. package/src/db/sequelize.ts +2 -1
  59. package/src/index.ts +35 -3
  60. package/src/net/peer/index.ts +3 -3
  61. package/src/net/pool/index.ts +2 -2
  62. package/src/net/protocol/dial/BaseDialProtocol.ts +1 -1
  63. package/src/net/protocol/dial/SignatureDialProtocol.ts +18 -17
  64. package/src/net/protocol/index.ts +3 -3
  65. package/src/tasks/BaseTask.ts +2 -3
  66. package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +232 -0
  67. package/src/tasks/InteropXGateway/SyncDepositEvents.ts +126 -0
  68. package/src/tasks/index.ts +4 -1
  69. package/src/typechain/Erc20.ts +491 -0
  70. package/src/typechain/GnosisSafe.ts +1728 -0
  71. package/src/typechain/InteropBridgeToken.ts +686 -0
  72. package/src/typechain/InteropXGateway.ts +407 -0
  73. package/src/typechain/common.ts +44 -0
  74. package/src/typechain/factories/Erc20__factory.ts +368 -0
  75. package/src/typechain/factories/GnosisSafe__factory.ts +1178 -0
  76. package/src/typechain/factories/InteropBridgeToken__factory.ts +466 -0
  77. package/src/typechain/factories/InteropXGateway__factory.ts +272 -0
  78. package/src/typechain/factories/index.ts +7 -0
  79. package/src/typechain/index.ts +12 -0
  80. package/src/types.ts +2 -2
  81. package/src/utils/index.ts +72 -3
  82. package/tsconfig.json +3 -0
  83. package/dist/constants/addresses.js +0 -13
  84. package/dist/db/models/execution.js +0 -38
  85. package/src/db/models/execution.ts +0 -57
@@ -0,0 +1,96 @@
1
+ import { sequelize } from '@/db/sequelize'
2
+ import { CreationOptional, InferAttributes, InferCreationAttributes, Model, DataTypes } from 'sequelize';
3
+
4
+ export class Transaction extends Model<InferAttributes<Transaction>, InferCreationAttributes<Transaction>> {
5
+ declare id: CreationOptional<number>;
6
+
7
+ declare transactionHash: string;
8
+ declare action: string;
9
+ declare from: string;
10
+ declare to: string;
11
+
12
+ declare submitTransactionHash: string;
13
+ declare submitBlockNumber: number;
14
+
15
+ declare sourceChainId: number;
16
+ declare sourceTransactionHash: CreationOptional<string>;
17
+ declare sourceBlockNumber: CreationOptional<number>;
18
+ declare sourceStatus: string;
19
+ declare sourceErrors: CreationOptional<string[]>;
20
+ declare sourceCreatedAt: CreationOptional<Date>;
21
+ declare sourceDelayUntil: CreationOptional<Date>;
22
+
23
+ declare targetChainId: number;
24
+ declare targetTransactionHash: CreationOptional<string>;
25
+ declare targetBlockNumber: CreationOptional<number>;
26
+ declare targetStatus: string;
27
+ declare targetErrors: CreationOptional<string[]>;
28
+ declare targetCreatedAt: CreationOptional<Date>;
29
+ declare targetDelayUntil: CreationOptional<Date>;
30
+
31
+ declare submitEvent: any;
32
+ declare sourceEvent: CreationOptional<any>;
33
+ declare targetEvent: CreationOptional<any>;
34
+
35
+ declare metadata: CreationOptional<any>;
36
+
37
+ declare status: string;
38
+
39
+ declare createdAt: CreationOptional<Date>;
40
+ declare updatedAt: CreationOptional<Date>;
41
+ }
42
+
43
+ Transaction.init({
44
+ id: {
45
+ type: DataTypes.INTEGER,
46
+ autoIncrement: true,
47
+ primaryKey: true
48
+ },
49
+
50
+ submitTransactionHash: DataTypes.NUMBER,
51
+ submitBlockNumber: DataTypes.NUMBER,
52
+
53
+ transactionHash: DataTypes.STRING,
54
+ action: DataTypes.STRING,
55
+
56
+ from: DataTypes.STRING,
57
+ to: DataTypes.STRING,
58
+
59
+ sourceChainId: DataTypes.NUMBER,
60
+ sourceTransactionHash: DataTypes.STRING,
61
+ sourceBlockNumber: DataTypes.NUMBER,
62
+ sourceStatus: DataTypes.STRING,
63
+ sourceErrors: {
64
+ type: DataTypes.JSON,
65
+ // defaultValue: [],
66
+ },
67
+ sourceCreatedAt: {
68
+ type: DataTypes.DATE,
69
+ defaultValue: Date.now()
70
+ },
71
+ sourceDelayUntil: DataTypes.STRING,
72
+
73
+ targetChainId: DataTypes.NUMBER,
74
+ targetTransactionHash: DataTypes.STRING,
75
+ targetBlockNumber: DataTypes.NUMBER,
76
+ targetStatus: DataTypes.STRING,
77
+ targetErrors: {
78
+ type: DataTypes.JSON,
79
+ // defaultValue: [],
80
+ },
81
+ targetCreatedAt: DataTypes.DATE,
82
+ targetDelayUntil: DataTypes.DATE,
83
+
84
+ submitEvent: DataTypes.JSON,
85
+ sourceEvent: DataTypes.JSON,
86
+ targetEvent: DataTypes.JSON,
87
+
88
+ metadata: DataTypes.JSON,
89
+
90
+ status: {
91
+ type: DataTypes.STRING,
92
+ defaultValue: 'pending'
93
+ },
94
+ createdAt: DataTypes.DATE,
95
+ updatedAt: DataTypes.DATE,
96
+ }, { sequelize, tableName: 'transactions' });
@@ -1,9 +1,10 @@
1
1
  //@ts-ignore
2
+ import config from "@/config";
2
3
  import expandHomeDir from "expand-home-dir";
3
4
 
4
5
  import { Sequelize } from 'sequelize';
5
6
 
6
- const basePath = expandHomeDir('~/.interop-x/data');
7
+ const basePath = expandHomeDir(`~/.interop-x/data/${config.publicAddress}/${config.staging ? 'staging' : ''}`);
7
8
 
8
9
  export const sequelize = new Sequelize({
9
10
  dialect: 'sqlite',
package/src/index.ts CHANGED
@@ -1,10 +1,38 @@
1
+ import moduleAlias from 'module-alias';
2
+
3
+ moduleAlias.addAliases({
4
+ "@/": __dirname + "/",
5
+ "@/logger": __dirname + "/logger",
6
+ "@/tasks": __dirname + "/tasks",
7
+ "@/utils": __dirname + "/utils",
8
+ "@/api": __dirname + "/api",
9
+ "@/net": __dirname + "/net",
10
+ "@/db": __dirname + "/db",
11
+ "@/config": __dirname + "/config",
12
+ "@/types": __dirname + "/types",
13
+ "@/abi": __dirname + "/abi",
14
+ "@/constants": __dirname + "/constants",
15
+ "@/typechain": __dirname + "/typechain"
16
+ })
17
+
18
+ moduleAlias();
1
19
  import assert from "assert";
2
20
  import dotenv from "dotenv";
3
- import Logger from "./logger";
4
21
  import { ethers } from "ethers";
22
+ import packageJson from '../package.json'
5
23
  dotenv.config();
24
+
25
+ import Logger from "@/logger";
6
26
  const logger = new Logger('Process')
7
27
 
28
+
29
+ if (process.argv.at(-1) === 'help') {
30
+ console.log('Usage:')
31
+ console.log(' PRIVATE_KEY=abcd1234 interop-x')
32
+ console.log(' PRIVATE_KEY=abcd1234 STAGING=true interop-x')
33
+ process.exit(0)
34
+ }
35
+
8
36
  assert(process.env.PRIVATE_KEY, "PRIVATE_KEY is not defined");
9
37
 
10
38
  try {
@@ -14,9 +42,11 @@ try {
14
42
  process.exit(1)
15
43
  }
16
44
 
17
- import { Tasks } from "./tasks";
18
- import { startPeer } from "./net";
45
+ logger.debug(`Starting Interop X Node (v${packageJson.version} - rev.@GIT_SHORT_HASH@)`)
19
46
 
47
+ import { Tasks } from "@/tasks";
48
+ import { startPeer } from "@/net";
49
+ import { startApiServer } from '@/api';
20
50
 
21
51
  async function main() {
22
52
 
@@ -25,6 +55,8 @@ async function main() {
25
55
  const tasks = new Tasks()
26
56
 
27
57
  tasks.start();
58
+
59
+ startApiServer()
28
60
  }
29
61
 
30
62
  main()
@@ -5,7 +5,7 @@ import WS from "libp2p-websockets";
5
5
  //@ts-ignore
6
6
  import Mplex from "libp2p-mplex";
7
7
  import { NOISE } from "libp2p-noise";
8
- import Logger from "../../logger";
8
+ import Logger from "@/logger";
9
9
  import Bootstrap from "libp2p-bootstrap";
10
10
  import wait from "waait";
11
11
  import Gossipsub from "@achingbrain/libp2p-gossipsub";
@@ -15,8 +15,8 @@ import MulticastDNS from "libp2p-mdns";
15
15
  import KadDHT from "libp2p-kad-dht";
16
16
  //@ts-ignore
17
17
  import PubsubPeerDiscovery from "libp2p-pubsub-peer-discovery";
18
- import { protocol } from "../protocol";
19
- import config from "../../config";
18
+ import { protocol } from "@/net";
19
+ import config from "@/config";
20
20
 
21
21
  const logger = new Logger("Peer");
22
22
 
@@ -1,5 +1,5 @@
1
- import { Event } from "../../types";
2
- import config from "../../config";
1
+ import { Event } from "@/types";
2
+ import config from "@/config";
3
3
 
4
4
  export interface IPeerInfo {
5
5
  id: string;
@@ -1,7 +1,7 @@
1
1
  import pipe from 'it-pipe';
2
2
  import Libp2p from 'libp2p';
3
3
  import PeerId from 'peer-id';
4
- import { asyncCallWithTimeout } from '../../../utils';
4
+ import { asyncCallWithTimeout } from '@/utils';
5
5
  import wait from 'waait';
6
6
 
7
7
  export class BaseDialProtocol<TRequest extends any, TResponse extends any> {
@@ -1,14 +1,14 @@
1
- import { signGnosisSafeTx } from "../../../utils";
2
1
  import { BaseDialProtocol } from "./BaseDialProtocol";
3
2
  import wait from "waait";
4
- import { ChainId } from "../../../types";
5
- import config from "../../../config";
6
- import { addresses } from "../../../constants";
7
- import { Execution } from "db";
3
+ import config from "@/config";
4
+ import { Transaction } from "@/db";
5
+ import { buildDataForTransaction, signGnosisSafeTx } from "@/utils";
6
+ import { addresses } from "@/constants";
7
+ import { ChainId } from "@/types";
8
8
 
9
9
  export interface ISignatureRequest {
10
- type: string,
11
- vnonce: string
10
+ type: 'source' | 'target' ,
11
+ transactionHash: string
12
12
  safeTxGas: string
13
13
  safeNonce: string
14
14
  }
@@ -21,25 +21,25 @@ export class SignatureDialProtocol extends BaseDialProtocol<ISignatureRequest, I
21
21
  protected timeout = 30000;
22
22
 
23
23
  constructor(libp2p) {
24
- super(libp2p, '/signatures')
24
+ super(libp2p, '/interop-x/signatures')
25
25
  }
26
26
 
27
27
  async response(data: ISignatureRequest): Promise<ISignatureResponse> {
28
28
  const signer = config.wallet;
29
29
 
30
- let event: Execution | null;
30
+ let transaction: Transaction | null;
31
31
  let maxTimeout = 20000;
32
32
 
33
33
  do {
34
- event = await Execution.findOne({ where: { vnonce: data.vnonce.toString() } })
34
+ transaction = await Transaction.findOne({ where: { transactionHash: data.transactionHash } })
35
35
 
36
- if (!event) {
36
+ if (!transaction) {
37
37
  await wait(1000);
38
38
  maxTimeout -= 1000;
39
39
  }
40
- } while (!event && maxTimeout > 0)
40
+ } while (!transaction && maxTimeout > 0)
41
41
 
42
- if (!event) {
42
+ if (!transaction) {
43
43
  return {
44
44
  signer: signer.address,
45
45
  data: null,
@@ -48,15 +48,16 @@ export class SignatureDialProtocol extends BaseDialProtocol<ISignatureRequest, I
48
48
  }
49
49
 
50
50
  const signedData = await signGnosisSafeTx({
51
- to: addresses[event.chainId as ChainId].multisend,
52
- data: 'TODO',
53
- chainId: event.chainId as ChainId,
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,
54
55
  safeTxGas: data.safeTxGas,
55
56
  }, { signer });
56
57
 
57
58
  return {
58
59
  signer: signer.address,
59
- data: signedData,
60
+ data: signedData
60
61
  }
61
62
  }
62
63
  }
@@ -3,8 +3,8 @@ import Libp2p from 'libp2p';
3
3
  import { bufferToInt, rlp } from 'ethereumjs-util'
4
4
  import { SignatureDialProtocol, ISignatureRequest, ISignatureResponse } from "./dial/SignatureDialProtocol";
5
5
  import { IPeerInfo, peerPool } from "..";
6
- import config from "config";
7
- import { Event } from "types";
6
+ import config from "@/config";
7
+ import { Event } from "@/types";
8
8
 
9
9
  export interface ProtocolOptions {
10
10
  /* Handshake timeout in ms (default: 8000) */
@@ -58,7 +58,7 @@ class Protocol extends EventEmitter {
58
58
 
59
59
  start({ libp2p, topic = null, }) {
60
60
  this.libp2p = libp2p
61
- this.topic = topic || 'protocol'
61
+ this.topic = topic || 'itnerop-x-protocol'
62
62
 
63
63
  if (this.libp2p.isStarted()) this.init()
64
64
 
@@ -1,8 +1,7 @@
1
- import config from "config";
2
- import { ethers } from "ethers";
1
+ import config from "@/config";
3
2
  import EventEmitter from "events";
4
3
  import wait from "waait";
5
- import Logger from "../logger";
4
+ import Logger from "@/logger";
6
5
 
7
6
  export interface IBaseTask {
8
7
  pollCheck(): Promise<void>
@@ -0,0 +1,232 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import { BigNumber, ethers } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import { buildDataForTransaction, buildSignatureBytes, getRpcProviderUrl, Signature } from "@/utils";
7
+ import { addresses } from "@/constants";
8
+ import { ChainId } from "@/types";
9
+ import config from "@/config";
10
+ import { GnosisSafe, InteropXGateway } from "@/typechain";
11
+ import { Op } from "sequelize";
12
+ import wait from "waait";
13
+ import { peerPool, protocol } from "@/net";
14
+ import { LogDescription } from "ethers/lib/utils";
15
+
16
+ const generateGnosisTransaction = async (transactionData: any, safeContract: any) => {
17
+ let isExecuted = await safeContract.dataHashes(
18
+ await safeContract.getTransactionHash(
19
+ transactionData.to,
20
+ transactionData.value,
21
+ transactionData.data,
22
+ transactionData.operation,
23
+ transactionData.safeTxGas,
24
+ transactionData.baseGas,
25
+ transactionData.gasPrice,
26
+ transactionData.gasToken,
27
+ transactionData.refundReceiver,
28
+ transactionData.nonce
29
+ )
30
+ )
31
+
32
+ while (isExecuted == 1) {
33
+ transactionData.safeTxGas = BigNumber.from(String(transactionData.safeTxGas)).add(1).toString()
34
+
35
+ isExecuted = await safeContract.dataHashes(
36
+ await safeContract.getTransactionHash(
37
+ transactionData.to,
38
+ transactionData.value,
39
+ transactionData.data,
40
+ transactionData.operation,
41
+ transactionData.safeTxGas,
42
+ transactionData.baseGas,
43
+ transactionData.gasPrice,
44
+ transactionData.gasToken,
45
+ transactionData.refundReceiver,
46
+ transactionData.nonce
47
+ )
48
+ )
49
+ }
50
+
51
+ return transactionData
52
+ }
53
+
54
+ class ProcessDepositEvents extends BaseTask {
55
+ contractAddress: string;
56
+ provider: ethers.providers.JsonRpcProvider;
57
+ contract: InteropXGateway;
58
+ chainId: ChainId;
59
+ leadNodeOnly = true
60
+
61
+ constructor({ chainId }: { chainId: ChainId }) {
62
+ super({
63
+ logger: new Logger("InteropXGateway::ProcessDepositEvents"),
64
+ })
65
+ this.chainId = chainId;
66
+ }
67
+
68
+ async pollHandler() {
69
+ const blockNumber = await this.provider.getBlockNumber()
70
+
71
+ const transaction = await Transaction.findOne({
72
+ where: {
73
+ status: 'pending',
74
+ sourceStatus: 'success',
75
+ action: 'deposit',
76
+ sourceCreatedAt: {
77
+ [Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
78
+ },
79
+ sourceBlockNumber: {
80
+ [Op.lt]: blockNumber - 12,
81
+ }
82
+ }
83
+ })
84
+
85
+ if (!transaction) {
86
+ return;
87
+ }
88
+
89
+
90
+ transaction.sourceStatus = 'pending';
91
+ await transaction.save();
92
+
93
+
94
+ // refresh event data?
95
+
96
+ const targetChainProvider = new ethers.providers.JsonRpcProvider(
97
+ getRpcProviderUrl(transaction.targetChainId as ChainId)
98
+ );
99
+
100
+ const targetWallet = new ethers.Wallet(config.privateKey!, targetChainProvider);
101
+
102
+ const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
103
+
104
+ const safeContract = new ethers.Contract(
105
+ safeAddress,
106
+ abi.gnosisSafe,
107
+ targetWallet
108
+ ) as GnosisSafe;
109
+
110
+ const ownersThreshold = await safeContract.getThreshold();
111
+
112
+ await wait(10000);
113
+
114
+ let gnosisTx = await generateGnosisTransaction({
115
+ baseGas: "0",
116
+ data: buildDataForTransaction(transaction),
117
+ gasPrice: "0",
118
+ gasToken: "0x0000000000000000000000000000000000000000",
119
+ nonce: '0',
120
+ operation: "1",
121
+ refundReceiver: "0x0000000000000000000000000000000000000000",
122
+ safeAddress: safeAddress,
123
+ safeTxGas: "79668",
124
+ to: addresses[transaction.targetChainId].multisend,
125
+ value: "0",
126
+ }, safeContract);
127
+
128
+ const owners = await safeContract.getOwners().then(owners => owners.map(owner => owner.toLowerCase()));
129
+
130
+ const ownerPeerIds = peerPool.activePeers.filter(peer => owners.includes(peer.publicAddress.toLowerCase())).map(peer => peer.id)
131
+
132
+ console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
133
+
134
+ const signatures = await protocol.requestSignatures({
135
+ type: 'source',
136
+ transactionHash: transaction.transactionHash,
137
+ safeTxGas: gnosisTx.safeTxGas,
138
+ safeNonce: gnosisTx.nonce
139
+ }, ownerPeerIds)
140
+
141
+
142
+ const validSignatures = signatures.filter(s => !!s.data && s.data !== '0x') as Signature[];
143
+
144
+ console.log({ signatures, validSignatures, ownersThreshold: ownersThreshold.toString() });
145
+
146
+ if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
147
+ await transaction.save();
148
+ transaction.sourceDelayUntil = new Date(Date.now() + 30 * 1000);
149
+ transaction.sourceStatus = 'pending'
150
+
151
+ await transaction.save();
152
+ const errorMessage = signatures.find(s => !!s.error)?.error;
153
+ throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
154
+ }
155
+
156
+ const execTransactionParams = [
157
+ gnosisTx.to,
158
+ gnosisTx.value,
159
+ gnosisTx.data,
160
+ gnosisTx.operation,
161
+ gnosisTx.safeTxGas,
162
+ gnosisTx.baseGas,
163
+ gnosisTx.gasPrice,
164
+ gnosisTx.gasToken,
165
+ gnosisTx.refundReceiver,
166
+ buildSignatureBytes(validSignatures),
167
+ ];
168
+
169
+ console.log(`Executing transaction for execution ${transaction.transactionHash}`)
170
+
171
+ console.log({
172
+ execTransactionParams
173
+ })
174
+
175
+ const { data: txData } = await safeContract.populateTransaction.execTransaction(
176
+ gnosisTx.to,
177
+ gnosisTx.value,
178
+ gnosisTx.data,
179
+ gnosisTx.operation,
180
+ gnosisTx.safeTxGas,
181
+ gnosisTx.baseGas,
182
+ gnosisTx.gasPrice,
183
+ gnosisTx.gasToken,
184
+ gnosisTx.refundReceiver,
185
+ buildSignatureBytes(validSignatures)
186
+ );
187
+
188
+ const txSent = await targetWallet.sendTransaction({
189
+ from: targetWallet.address,
190
+ gasPrice: BigNumber.from(120 * 10 ** 9),
191
+ gasLimit: BigNumber.from(6_000_000),
192
+ to: safeAddress,
193
+ data: txData,
194
+ })
195
+
196
+ const receipt = await txSent.wait();
197
+
198
+ const parsedLogs: LogDescription[] = [];
199
+
200
+ receipt.logs.forEach((log) => {
201
+ try {
202
+ parsedLogs.push(safeContract.interface.parseLog(log));
203
+ } catch (e) { }
204
+ });
205
+
206
+ if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
207
+ console.log('ExecutionSuccess')
208
+ } else {
209
+ console.log('ExecutionFailure')
210
+ }
211
+ }
212
+
213
+ async start(): Promise<void> {
214
+ this.logger.info(`Starting execution watcher on interop chain`);
215
+
216
+ this.contractAddress = addresses[this.chainId].interopXGateway;
217
+
218
+ this.provider = new ethers.providers.JsonRpcProvider(
219
+ getRpcProviderUrl(this.chainId)
220
+ );
221
+
222
+ this.contract = new ethers.Contract(
223
+ this.contractAddress,
224
+ abi.interopXGateway,
225
+ new ethers.Wallet(config.privateKey!, this.provider)
226
+ ) as InteropXGateway;
227
+
228
+ await super.start()
229
+ }
230
+ }
231
+
232
+ export default ProcessDepositEvents;
@@ -0,0 +1,126 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import { ethers } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import { generateInteropTransactionHash, getRpcProviderUrl } from "@/utils";
7
+ import { addresses } from "@/constants";
8
+ import { ChainId } from "@/types";
9
+ import config from "@/config";
10
+ import { InteropXGateway } from "@/typechain";
11
+
12
+ class SyncDepositEvents extends BaseTask {
13
+ contractAddress: string;
14
+ provider: ethers.providers.JsonRpcProvider;
15
+ contract: InteropXGateway;
16
+ chainId: ChainId;
17
+
18
+ constructor({ chainId }: { chainId: ChainId }) {
19
+ super({
20
+ logger: new Logger("InteropXGateway::SyncDepositEvents"),
21
+ })
22
+ this.chainId = chainId;
23
+ }
24
+
25
+ async pollHandler() {
26
+ const currentBlock = await this.provider.getBlockNumber();
27
+
28
+ const events = await this.contract.queryFilter(
29
+ this.contract.filters.LogGatewayDeposit(),
30
+ currentBlock - 2000,
31
+ currentBlock,
32
+ );
33
+
34
+ let processedEvents = 0;
35
+
36
+ for (const event of events) {
37
+
38
+ try {
39
+ if (!event.args) {
40
+ continue;
41
+ }
42
+
43
+ const { sourceChainId, targetChainId, user, vnonce, amount, token } = event.args;
44
+
45
+ const uniqueIdentifier = {
46
+ action: 'deposit',
47
+ submitTransactionHash: event.transactionHash,
48
+ sourceChainId: sourceChainId.toNumber(),
49
+ targetChainId: targetChainId.toNumber(),
50
+ }
51
+
52
+ if (await Transaction.findOne({ where: uniqueIdentifier })) {
53
+ continue;
54
+ }
55
+
56
+ const tx = await event.getTransaction()
57
+
58
+ await Transaction.create({
59
+ ...uniqueIdentifier,
60
+ transactionHash: generateInteropTransactionHash(uniqueIdentifier),
61
+ from: tx.from,
62
+ to: user,
63
+
64
+
65
+ submitTransactionHash: event.transactionHash,
66
+ submitBlockNumber: event.blockNumber,
67
+
68
+ // submit & source are the same
69
+ sourceTransactionHash: event.transactionHash,
70
+ sourceBlockNumber: event.blockNumber,
71
+ sourceStatus: "success",
72
+
73
+ targetStatus: "uninitialised",
74
+
75
+ submitEvent: {
76
+ user,
77
+ sourceChainId: sourceChainId.toString(),
78
+ targetChainId: targetChainId.toString(),
79
+ token: token,
80
+ ammout: amount.toString(),
81
+ vnonce: vnonce.toString(),
82
+ },
83
+
84
+ sourceEvent: {
85
+ user,
86
+ sourceChainId: sourceChainId.toString(),
87
+ targetChainId: targetChainId.toString(),
88
+ token: token,
89
+ ammout: amount.toString(),
90
+ vnonce: vnonce.toString(),
91
+ },
92
+ status: "pending",
93
+ })
94
+
95
+ this.logger.info(
96
+ `Execution queued: ${event.transactionHash} ${event.blockNumber}`
97
+ );
98
+ } catch (error) {
99
+ this.logger.error(error);
100
+ }
101
+ }
102
+
103
+ if (processedEvents > 0)
104
+ this.logger.info(`${processedEvents} events processed`);
105
+ }
106
+
107
+ async start(): Promise<void> {
108
+ this.logger.info(`Starting execution watcher on interop chain`);
109
+
110
+ this.contractAddress = addresses[this.chainId].interopXGateway;
111
+
112
+ this.provider = new ethers.providers.JsonRpcProvider(
113
+ getRpcProviderUrl(this.chainId)
114
+ );
115
+
116
+ this.contract = new ethers.Contract(
117
+ this.contractAddress,
118
+ abi.interopXGateway,
119
+ new ethers.Wallet(config.privateKey!, this.provider)
120
+ ) as InteropXGateway;
121
+
122
+ await super.start()
123
+ }
124
+ }
125
+
126
+ export default SyncDepositEvents;
@@ -1,9 +1,12 @@
1
1
  import { BaseTask } from "./BaseTask";
2
+ import SyncInteropXGatewayDepositEvents from "./InteropXGateway/SyncDepositEvents";
2
3
 
3
4
  export class Tasks {
4
5
 
5
6
  tasks: BaseTask[] = [
6
-
7
+ new SyncInteropXGatewayDepositEvents({
8
+ chainId: 43114
9
+ })
7
10
  ];
8
11
 
9
12
  async start() {