@instadapp/interop-x 0.0.0-dev.ef78459 → 0.0.0-dev.f0a6281

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. package/.env.example +2 -1
  2. package/bin/interop-x +1 -1
  3. package/dist/package.json +73 -0
  4. package/dist/src/abi/erc20.json +350 -0
  5. package/dist/src/abi/gnosisSafe.json +747 -0
  6. package/dist/src/abi/index.js +15 -0
  7. package/dist/src/abi/interopBridgeToken.json +298 -0
  8. package/dist/src/abi/interopXGateway.json +184 -0
  9. package/dist/src/api/index.js +33 -0
  10. package/dist/src/config/index.js +31 -0
  11. package/dist/src/constants/addresses.js +20 -0
  12. package/dist/{constants → src/constants}/index.js +2 -0
  13. package/dist/src/constants/itokens.js +13 -0
  14. package/dist/src/constants/tokens.js +107 -0
  15. package/dist/{db → src/db}/index.js +0 -0
  16. package/dist/{db → src/db}/models/index.js +1 -1
  17. package/dist/src/db/models/transaction.js +54 -0
  18. package/dist/{db → src/db}/sequelize.js +2 -1
  19. package/dist/src/index.js +130 -0
  20. package/dist/{logger → src/logger}/index.js +0 -0
  21. package/dist/{net → src/net}/index.js +0 -0
  22. package/dist/{net → src/net}/peer/index.js +8 -3
  23. package/dist/{net → src/net}/pool/index.js +32 -9
  24. package/dist/{net → src/net}/protocol/dial/BaseDialProtocol.js +0 -0
  25. package/dist/{net → src/net}/protocol/dial/SignatureDialProtocol.js +20 -12
  26. package/dist/src/net/protocol/dial/TransactionStatusDialProtocol.js +28 -0
  27. package/dist/{net → src/net}/protocol/index.js +44 -4
  28. package/dist/src/tasks/AutoUpdateTask.js +70 -0
  29. package/dist/{tasks → src/tasks}/BaseTask.js +13 -5
  30. package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +146 -0
  31. package/dist/src/tasks/InteropBridge/SyncWithdrawEvents.js +71 -0
  32. package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +161 -0
  33. package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +74 -0
  34. package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +53 -0
  35. package/dist/src/tasks/index.js +44 -0
  36. package/dist/src/typechain/Erc20.js +2 -0
  37. package/dist/src/typechain/GnosisSafe.js +2 -0
  38. package/dist/src/typechain/InteropBridgeToken.js +2 -0
  39. package/dist/src/typechain/InteropXGateway.js +2 -0
  40. package/dist/src/typechain/common.js +2 -0
  41. package/dist/src/typechain/factories/Erc20__factory.js +367 -0
  42. package/dist/src/typechain/factories/GnosisSafe__factory.js +1174 -0
  43. package/dist/src/typechain/factories/InteropBridgeToken__factory.js +471 -0
  44. package/dist/src/typechain/factories/InteropXGateway__factory.js +265 -0
  45. package/dist/src/typechain/factories/index.js +14 -0
  46. package/dist/src/typechain/index.js +35 -0
  47. package/dist/{types.js → src/types.js} +0 -0
  48. package/dist/src/utils/index.js +238 -0
  49. package/package.json +18 -10
  50. package/patches/@ethersproject+properties+5.6.0.patch +13 -0
  51. package/src/abi/erc20.json +350 -0
  52. package/src/abi/gnosisSafe.json +747 -0
  53. package/src/abi/index.ts +11 -0
  54. package/src/abi/interopBridgeToken.json +298 -0
  55. package/src/abi/interopXGateway.json +184 -0
  56. package/src/api/index.ts +33 -0
  57. package/src/config/index.ts +17 -1
  58. package/src/constants/addresses.ts +9 -2
  59. package/src/constants/index.ts +2 -0
  60. package/src/constants/itokens.ts +10 -0
  61. package/src/constants/tokens.ts +104 -0
  62. package/src/db/models/index.ts +1 -1
  63. package/src/db/models/transaction.ts +96 -0
  64. package/src/db/sequelize.ts +2 -1
  65. package/src/index.ts +119 -7
  66. package/src/net/peer/index.ts +9 -7
  67. package/src/net/pool/index.ts +41 -11
  68. package/src/net/protocol/dial/SignatureDialProtocol.ts +24 -15
  69. package/src/net/protocol/dial/TransactionStatusDialProtocol.ts +31 -0
  70. package/src/net/protocol/index.ts +60 -4
  71. package/src/tasks/AutoUpdateTask.ts +82 -0
  72. package/src/tasks/BaseTask.ts +15 -6
  73. package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +231 -0
  74. package/src/tasks/InteropBridge/SyncWithdrawEvents.ts +121 -0
  75. package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +256 -0
  76. package/src/tasks/InteropXGateway/SyncDepositEvents.ts +124 -0
  77. package/src/tasks/Transactions/SyncTransactionStatusTask.ts +65 -0
  78. package/src/tasks/index.ts +26 -1
  79. package/src/typechain/Erc20.ts +491 -0
  80. package/src/typechain/GnosisSafe.ts +1728 -0
  81. package/src/typechain/InteropBridgeToken.ts +692 -0
  82. package/src/typechain/InteropXGateway.ts +407 -0
  83. package/src/typechain/common.ts +44 -0
  84. package/src/typechain/factories/Erc20__factory.ts +368 -0
  85. package/src/typechain/factories/GnosisSafe__factory.ts +1178 -0
  86. package/src/typechain/factories/InteropBridgeToken__factory.ts +478 -0
  87. package/src/typechain/factories/InteropXGateway__factory.ts +272 -0
  88. package/src/typechain/factories/index.ts +7 -0
  89. package/src/typechain/index.ts +12 -0
  90. package/src/types.ts +1 -1
  91. package/src/utils/index.ts +206 -3
  92. package/dist/config/index.js +0 -17
  93. package/dist/constants/addresses.js +0 -13
  94. package/dist/db/models/execution.js +0 -38
  95. package/dist/index.js +0 -43
  96. package/dist/tasks/index.js +0 -19
  97. package/dist/utils/index.js +0 -89
  98. package/src/db/models/execution.ts +0 -57
@@ -0,0 +1,256 @@
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, getContract, 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: GnosisSafe) => {
17
+ console.log(transactionData);
18
+
19
+ let isExecuted = await safeContract.dataHashes(
20
+ await safeContract.getTransactionHash(
21
+ transactionData.to,
22
+ transactionData.value,
23
+ transactionData.data,
24
+ transactionData.operation,
25
+ transactionData.safeTxGas,
26
+ transactionData.baseGas,
27
+ transactionData.gasPrice,
28
+ transactionData.gasToken,
29
+ transactionData.refundReceiver,
30
+ transactionData.nonce
31
+ )
32
+ )
33
+
34
+ while (isExecuted == 1) {
35
+ transactionData.safeTxGas = BigNumber.from(String(transactionData.safeTxGas)).add(1).toString()
36
+
37
+ isExecuted = await safeContract.dataHashes(
38
+ await safeContract.getTransactionHash(
39
+ transactionData.to,
40
+ transactionData.value,
41
+ transactionData.data,
42
+ transactionData.operation,
43
+ transactionData.safeTxGas,
44
+ transactionData.baseGas,
45
+ transactionData.gasPrice,
46
+ transactionData.gasToken,
47
+ transactionData.refundReceiver,
48
+ transactionData.nonce
49
+ )
50
+ )
51
+ }
52
+
53
+ return transactionData
54
+ }
55
+
56
+ class ProcessDepositEvents extends BaseTask {
57
+ contractAddress: string;
58
+ provider: ethers.providers.JsonRpcProvider;
59
+ contract: InteropXGateway;
60
+ chainId: ChainId;
61
+ leadNodeOnly = true
62
+
63
+ constructor({ chainId }: { chainId: ChainId }) {
64
+ super({
65
+ logger: new Logger("InteropXGateway::ProcessDepositEvents"),
66
+ })
67
+ this.chainId = chainId;
68
+ }
69
+
70
+ async pollHandler() {
71
+ const blockNumber = await this.provider.getBlockNumber()
72
+
73
+ const transaction = await Transaction.findOne({
74
+ where: {
75
+ status: 'pending',
76
+ sourceStatus: 'success',
77
+ targetStatus: 'uninitialised',
78
+ action: 'deposit',
79
+ sourceCreatedAt: {
80
+ [Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
81
+ },
82
+ targetDelayUntil: {
83
+ [Op.or]: {
84
+ [Op.is]: null,
85
+ [Op.lt]: new Date(),
86
+ }
87
+ },
88
+ sourceBlockNumber: {
89
+ [Op.lt]: blockNumber - 12,
90
+ },
91
+ sourceChainId: this.chainId,
92
+ }
93
+ })
94
+
95
+ if (!transaction) {
96
+ return;
97
+ }
98
+
99
+ console.log(`Processing transaction ${transaction.transactionHash}`);
100
+
101
+ transaction.targetStatus = 'pending';
102
+ await transaction.save();
103
+
104
+ // refresh event data?
105
+
106
+ const targetChainProvider = new ethers.providers.JsonRpcProvider(
107
+ getRpcProviderUrl(transaction.targetChainId as ChainId)
108
+ );
109
+
110
+ const targetWallet = new ethers.Wallet(config.privateKey!, targetChainProvider);
111
+
112
+ const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
113
+
114
+
115
+ const safeContract = getContract<GnosisSafe>(
116
+ safeAddress,
117
+ abi.gnosisSafe,
118
+ targetWallet
119
+ )
120
+
121
+ const ownersThreshold = await safeContract.getThreshold();
122
+ await wait(10000);
123
+
124
+ let data;
125
+
126
+ try {
127
+ data = await buildDataForTransaction(transaction);
128
+ } catch (error) {
129
+ console.log(error);
130
+ transaction.targetStatus = 'failed';
131
+ transaction.targetErrors = [error.message];
132
+ await transaction.save();
133
+ protocol.sendTransaction(transaction)
134
+ return;
135
+ }
136
+
137
+ let gnosisTx = await generateGnosisTransaction({
138
+ baseGas: "0",
139
+ data,
140
+ gasPrice: "0",
141
+ gasToken: "0x0000000000000000000000000000000000000000",
142
+ nonce: '0',
143
+ operation: "1",
144
+ refundReceiver: "0x0000000000000000000000000000000000000000",
145
+ safeAddress: safeAddress,
146
+ safeTxGas: "79668",
147
+ to: addresses[transaction.targetChainId].multisend,
148
+ value: "0",
149
+ }, safeContract);
150
+
151
+ const owners = await safeContract.getOwners().then(owners => owners.map(owner => owner.toLowerCase()));
152
+
153
+ const ownerPeerIds = peerPool.activePeers.filter(peer => owners.includes(peer.publicAddress.toLowerCase())).map(peer => peer.id)
154
+
155
+ console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
156
+
157
+ console.log(ownerPeerIds);
158
+
159
+ const signatures = await protocol.requestSignatures({
160
+ type: 'source',
161
+ transactionHash: transaction.transactionHash,
162
+ safeTxGas: gnosisTx.safeTxGas,
163
+ safeNonce: gnosisTx.nonce
164
+ }, ownerPeerIds)
165
+
166
+
167
+ const validSignatures = signatures.filter(s => !!s.data && s.data !== '0x') as Signature[];
168
+
169
+ console.log({ signatures, validSignatures, ownersThreshold: ownersThreshold.toString() });
170
+
171
+ if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
172
+ await transaction.save();
173
+ transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
174
+ transaction.targetStatus = 'uninitialised'
175
+
176
+ await transaction.save();
177
+ const errorMessage = signatures.find(s => !!s.error)?.error;
178
+ throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
179
+ }
180
+
181
+
182
+ console.log(`Executing transaction for execution ${transaction.transactionHash}`)
183
+
184
+ const { data: txData } = await safeContract.populateTransaction.execTransaction(
185
+ gnosisTx.to,
186
+ gnosisTx.value,
187
+ gnosisTx.data,
188
+ gnosisTx.operation,
189
+ gnosisTx.safeTxGas,
190
+ gnosisTx.baseGas,
191
+ gnosisTx.gasPrice,
192
+ gnosisTx.gasToken,
193
+ gnosisTx.refundReceiver,
194
+ buildSignatureBytes(validSignatures)
195
+ );
196
+
197
+ console.log({
198
+ from: targetWallet.address,
199
+ gasPrice: BigNumber.from(120 * 10 ** 9).toString(),
200
+ to: safeAddress,
201
+ data: txData,
202
+ })
203
+
204
+
205
+ const txSent = await targetWallet.sendTransaction({
206
+ from: targetWallet.address,
207
+ gasPrice: BigNumber.from(120 * 10 ** 9),
208
+ to: safeAddress,
209
+ data: txData,
210
+ })
211
+
212
+ const receipt = await txSent.wait();
213
+
214
+ const parsedLogs: LogDescription[] = [];
215
+
216
+ receipt.logs.forEach((log) => {
217
+ try {
218
+ parsedLogs.push(safeContract.interface.parseLog(log));
219
+ } catch (e) { }
220
+ });
221
+
222
+ if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
223
+ console.log('ExecutionSuccess')
224
+ transaction.targetStatus = 'success'
225
+ transaction.targetTransactionHash = txSent.hash
226
+ transaction.status = 'success'
227
+ await transaction.save();
228
+ } else {
229
+ console.log('ExecutionFailure')
230
+ transaction.targetStatus = 'failed'
231
+ transaction.targetTransactionHash = txSent.hash
232
+ transaction.status = 'failed'
233
+ await transaction.save();
234
+ }
235
+
236
+ protocol.sendTransaction(transaction)
237
+ }
238
+
239
+ async start(): Promise<void> {
240
+ this.contractAddress = addresses[this.chainId].interopXGateway;
241
+
242
+ this.provider = new ethers.providers.JsonRpcProvider(
243
+ getRpcProviderUrl(this.chainId)
244
+ );
245
+
246
+ this.contract = getContract<InteropXGateway>(
247
+ this.contractAddress,
248
+ abi.interopXGateway,
249
+ new ethers.Wallet(config.privateKey!, this.provider)
250
+ );
251
+
252
+ await super.start()
253
+ }
254
+ }
255
+
256
+ export default ProcessDepositEvents;
@@ -0,0 +1,124 @@
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, getContract, 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,
49
+ targetChainId: targetChainId,
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
+ amount: amount.toString(),
81
+ vnonce: vnonce.toString(),
82
+ },
83
+
84
+ sourceEvent: {
85
+ user,
86
+ sourceChainId: sourceChainId.toString(),
87
+ targetChainId: targetChainId.toString(),
88
+ token: token,
89
+ amount: amount.toString(),
90
+ vnonce: vnonce.toString(),
91
+ },
92
+ status: "pending",
93
+ })
94
+
95
+ this.logger.info(
96
+ `Deposit 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.contractAddress = addresses[this.chainId].interopXGateway;
109
+
110
+ this.provider = new ethers.providers.JsonRpcProvider(
111
+ getRpcProviderUrl(this.chainId)
112
+ );
113
+
114
+ this.contract = getContract<InteropXGateway>(
115
+ this.contractAddress,
116
+ abi.interopXGateway,
117
+ new ethers.Wallet(config.privateKey!, this.provider)
118
+ );
119
+
120
+ await super.start()
121
+ }
122
+ }
123
+
124
+ export default SyncDepositEvents;
@@ -0,0 +1,65 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import config from "@/config";
4
+ import { peerPool, protocol } from "@/net";
5
+ import { Transaction } from "@/db";
6
+ import { Op } from "sequelize";
7
+
8
+ class SyncTransactionStatusTask extends BaseTask {
9
+ pollIntervalMs: number = 60 * 1000
10
+ exceptLeadNode: boolean = true;
11
+
12
+ constructor() {
13
+ super({
14
+ logger: new Logger("SyncTransactionStatusTask"),
15
+ })
16
+ }
17
+
18
+ async pollHandler() {
19
+ // if transaction is pending for more than 1 hour, check lead node for status
20
+ const leadNode = peerPool.getLeadPeer();
21
+
22
+ if (!leadNode) {
23
+ return;
24
+ }
25
+
26
+ const transaction = await Transaction.findOne({
27
+ where: {
28
+ status: 'pending',
29
+ sourceCreatedAt: {
30
+ [Op.gte]: new Date(Date.now() - 60 * 60 * 1000),
31
+ },
32
+ }
33
+ })
34
+
35
+ if (!transaction) {
36
+ return;
37
+ }
38
+
39
+ this.logger.info(`Requesting transaction status for ${transaction.transactionHash}`)
40
+
41
+ const transactionStatus = await protocol.requestTransactionStatus(transaction.transactionHash, leadNode.id);
42
+
43
+ if (!transactionStatus) {
44
+ return;
45
+ }
46
+
47
+ this.logger.info(`Received transaction status for ${transaction.transactionHash}`)
48
+
49
+ transaction.sourceStatus = transactionStatus.sourceStatus
50
+ transaction.sourceTransactionHash = transactionStatus.sourceTransactionHash
51
+ transaction.sourceErrors = transactionStatus.sourceErrors
52
+
53
+ transaction.targetStatus = transactionStatus.targetStatus
54
+ transaction.targetTransactionHash = transactionStatus.targetTransactionHash
55
+ transaction.targetErrors = transactionStatus.targetErrors
56
+
57
+ transaction.status = transactionStatus.status
58
+
59
+ await transaction.save()
60
+
61
+ this.logger.info(`Updated transaction status for ${transaction.transactionHash}`)
62
+ }
63
+ }
64
+
65
+ export default SyncTransactionStatusTask;
@@ -1,9 +1,34 @@
1
1
  import { BaseTask } from "./BaseTask";
2
+ import InteropXGatewayProcessDepositEvents from "./InteropXGateway/ProcessDepositEvents";
3
+ import InteropXGatewaySyncDepositEvents from "./InteropXGateway/SyncDepositEvents";
4
+
5
+ import InteropBridgeSyncWithdrawEvents from "./InteropBridge/SyncWithdrawEvents";
6
+ import InteropBridgeProcessWithdrawEvents from "./InteropBridge/ProcessWithdrawEvents";
7
+ import AutoUpdateTask from "./AutoUpdateTask";
8
+ import SyncTransactionStatusTask from "./Transactions/SyncTransactionStatusTask";
2
9
 
3
10
  export class Tasks {
4
11
 
5
12
  tasks: BaseTask[] = [
6
-
13
+ new SyncTransactionStatusTask(),
14
+ new AutoUpdateTask(),
15
+
16
+ new InteropXGatewaySyncDepositEvents({
17
+ chainId: 43114
18
+ }),
19
+
20
+ new InteropXGatewayProcessDepositEvents({
21
+ chainId: 43114
22
+ }),
23
+
24
+ new InteropBridgeSyncWithdrawEvents({
25
+ chainId: 137,
26
+ itokenAddress: '0xEab02fe1F016eE3e4106c1C6aad35FeEe657268E',
27
+ }),
28
+
29
+ new InteropBridgeProcessWithdrawEvents({
30
+ chainId: 137,
31
+ })
7
32
  ];
8
33
 
9
34
  async start() {