@instadapp/interop-x 0.0.0-dev.a168c79 → 0.0.0-dev.a775e30
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/bin/interop-x +1 -1
- package/dist/package.json +9 -5
- package/dist/src/api/index.js +3 -3
- package/dist/src/config/index.js +11 -1
- package/dist/src/constants/itokens.js +1 -1
- package/dist/src/index.js +69 -7
- package/dist/src/net/peer/index.js +8 -3
- package/dist/src/net/pool/index.js +32 -9
- package/dist/src/net/protocol/dial/SignatureDialProtocol.1.js +28 -0
- package/dist/src/net/protocol/dial/SignatureDialProtocol.js +11 -4
- package/dist/src/net/protocol/index.js +41 -1
- package/dist/src/tasks/AutoUpdateTask.js +70 -0
- package/dist/src/tasks/BaseTask.js +12 -4
- package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +146 -0
- package/dist/src/tasks/InteropBridge/SyncWithdrawEvents.js +69 -0
- package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +32 -23
- package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +4 -5
- package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +53 -0
- package/dist/src/tasks/index.js +17 -0
- package/dist/src/utils/index.js +110 -9
- package/package.json +9 -5
- package/patches/@ethersproject+properties+5.6.0.patch +13 -0
- package/src/api/index.ts +2 -2
- package/src/config/index.ts +11 -1
- package/src/constants/itokens.ts +1 -1
- package/src/index.ts +90 -9
- package/src/net/peer/index.ts +9 -7
- package/src/net/pool/index.ts +41 -11
- package/src/net/protocol/dial/SignatureDialProtocol.1.ts +31 -0
- package/src/net/protocol/dial/SignatureDialProtocol.ts +12 -4
- package/src/net/protocol/index.ts +57 -1
- package/src/tasks/AutoUpdateTask.ts +82 -0
- package/src/tasks/BaseTask.ts +14 -4
- package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +231 -0
- package/src/tasks/InteropBridge/SyncWithdrawEvents.ts +119 -0
- package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +44 -33
- package/src/tasks/InteropXGateway/SyncDepositEvents.ts +6 -8
- package/src/tasks/Transactions/SyncTransactionStatusTask.ts +65 -0
- package/src/tasks/index.ts +24 -2
- package/src/utils/index.ts +145 -11
@@ -0,0 +1,231 @@
|
|
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 ProcessWithdrawEvents extends BaseTask {
|
57
|
+
provider: ethers.providers.JsonRpcProvider;
|
58
|
+
chainId: ChainId;
|
59
|
+
leadNodeOnly = true
|
60
|
+
|
61
|
+
constructor({ chainId }: { chainId: ChainId }) {
|
62
|
+
super({
|
63
|
+
logger: new Logger("InteropXGateway::ProcessWithdrawEvents"),
|
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
|
+
targetStatus: 'uninitialised',
|
76
|
+
action: 'withdraw',
|
77
|
+
sourceCreatedAt: {
|
78
|
+
[Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
|
79
|
+
},
|
80
|
+
targetDelayUntil: {
|
81
|
+
[Op.or]: {
|
82
|
+
[Op.is]: null,
|
83
|
+
[Op.lt]: new Date(),
|
84
|
+
}
|
85
|
+
},
|
86
|
+
sourceBlockNumber: {
|
87
|
+
[Op.lt]: blockNumber - 12,
|
88
|
+
},
|
89
|
+
sourceChainId: this.chainId,
|
90
|
+
}
|
91
|
+
})
|
92
|
+
|
93
|
+
if (!transaction) {
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
|
97
|
+
console.log(`Processing transaction ${transaction.transactionHash}`);
|
98
|
+
|
99
|
+
transaction.targetStatus = 'pending';
|
100
|
+
await transaction.save();
|
101
|
+
|
102
|
+
// refresh event data?
|
103
|
+
|
104
|
+
const targetChainProvider = new ethers.providers.JsonRpcProvider(
|
105
|
+
getRpcProviderUrl(transaction.targetChainId as ChainId)
|
106
|
+
);
|
107
|
+
|
108
|
+
const targetWallet = new ethers.Wallet(config.privateKey!, targetChainProvider);
|
109
|
+
|
110
|
+
const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
|
111
|
+
|
112
|
+
|
113
|
+
const safeContract = getContract<GnosisSafe>(
|
114
|
+
safeAddress,
|
115
|
+
abi.gnosisSafe,
|
116
|
+
targetWallet
|
117
|
+
)
|
118
|
+
|
119
|
+
const ownersThreshold = await safeContract.getThreshold();
|
120
|
+
await wait(10000);
|
121
|
+
|
122
|
+
let gnosisTx = await generateGnosisTransaction({
|
123
|
+
baseGas: "0",
|
124
|
+
data: await buildDataForTransaction(transaction),
|
125
|
+
gasPrice: "0",
|
126
|
+
gasToken: "0x0000000000000000000000000000000000000000",
|
127
|
+
nonce: '0',
|
128
|
+
operation: "1",
|
129
|
+
refundReceiver: "0x0000000000000000000000000000000000000000",
|
130
|
+
safeAddress: safeAddress,
|
131
|
+
safeTxGas: "79668",
|
132
|
+
to: addresses[transaction.targetChainId].multisend,
|
133
|
+
value: "0",
|
134
|
+
}, safeContract);
|
135
|
+
|
136
|
+
const owners = await safeContract.getOwners().then(owners => owners.map(owner => owner.toLowerCase()));
|
137
|
+
|
138
|
+
const ownerPeerIds = peerPool.activePeers.filter(peer => owners.includes(peer.publicAddress.toLowerCase())).map(peer => peer.id)
|
139
|
+
|
140
|
+
console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
|
141
|
+
|
142
|
+
console.log(ownerPeerIds);
|
143
|
+
|
144
|
+
const signatures = await protocol.requestSignatures({
|
145
|
+
type: 'source',
|
146
|
+
transactionHash: transaction.transactionHash,
|
147
|
+
safeTxGas: gnosisTx.safeTxGas,
|
148
|
+
safeNonce: gnosisTx.nonce
|
149
|
+
}, ownerPeerIds)
|
150
|
+
|
151
|
+
|
152
|
+
const validSignatures = signatures.filter(s => !!s.data && s.data !== '0x') as Signature[];
|
153
|
+
|
154
|
+
console.log({ signatures, validSignatures, ownersThreshold: ownersThreshold.toString() });
|
155
|
+
|
156
|
+
if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
|
157
|
+
await transaction.save();
|
158
|
+
transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
|
159
|
+
transaction.targetStatus = 'uninitialised'
|
160
|
+
|
161
|
+
await transaction.save();
|
162
|
+
const errorMessage = signatures.find(s => !!s.error)?.error;
|
163
|
+
throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
console.log(`Executing transaction for execution ${transaction.transactionHash}`)
|
168
|
+
|
169
|
+
const { data: txData } = await safeContract.populateTransaction.execTransaction(
|
170
|
+
gnosisTx.to,
|
171
|
+
gnosisTx.value,
|
172
|
+
gnosisTx.data,
|
173
|
+
gnosisTx.operation,
|
174
|
+
gnosisTx.safeTxGas,
|
175
|
+
gnosisTx.baseGas,
|
176
|
+
gnosisTx.gasPrice,
|
177
|
+
gnosisTx.gasToken,
|
178
|
+
gnosisTx.refundReceiver,
|
179
|
+
buildSignatureBytes(validSignatures)
|
180
|
+
);
|
181
|
+
|
182
|
+
console.log({
|
183
|
+
from: targetWallet.address,
|
184
|
+
gasPrice: BigNumber.from(120 * 10 ** 9).toString(),
|
185
|
+
to: safeAddress,
|
186
|
+
data: txData,
|
187
|
+
})
|
188
|
+
|
189
|
+
|
190
|
+
const txSent = await targetWallet.sendTransaction({
|
191
|
+
from: targetWallet.address,
|
192
|
+
gasPrice: BigNumber.from(120 * 10 ** 9),
|
193
|
+
to: safeAddress,
|
194
|
+
data: txData,
|
195
|
+
})
|
196
|
+
|
197
|
+
const receipt = await txSent.wait();
|
198
|
+
|
199
|
+
const parsedLogs: LogDescription[] = [];
|
200
|
+
|
201
|
+
receipt.logs.forEach((log) => {
|
202
|
+
try {
|
203
|
+
parsedLogs.push(safeContract.interface.parseLog(log));
|
204
|
+
} catch (e) { }
|
205
|
+
});
|
206
|
+
|
207
|
+
if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
|
208
|
+
console.log('ExecutionSuccess')
|
209
|
+
transaction.targetStatus = 'success'
|
210
|
+
transaction.targetTransactionHash = txSent.hash
|
211
|
+
transaction.status = 'success'
|
212
|
+
await transaction.save();
|
213
|
+
} else {
|
214
|
+
console.log('ExecutionFailure')
|
215
|
+
transaction.targetStatus = 'failed'
|
216
|
+
transaction.targetTransactionHash = txSent.hash
|
217
|
+
transaction.status = 'failed'
|
218
|
+
await transaction.save();
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
async start(): Promise<void> {
|
223
|
+
this.provider = new ethers.providers.JsonRpcProvider(
|
224
|
+
getRpcProviderUrl(this.chainId)
|
225
|
+
);
|
226
|
+
|
227
|
+
await super.start()
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
export default ProcessWithdrawEvents;
|
@@ -0,0 +1,119 @@
|
|
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 { ChainId } from "@/types";
|
8
|
+
import config from "@/config";
|
9
|
+
import { InteropBridgeToken } from "@/typechain";
|
10
|
+
|
11
|
+
class SyncWithdrawEvents extends BaseTask {
|
12
|
+
contractAddress: string;
|
13
|
+
provider: ethers.providers.JsonRpcProvider;
|
14
|
+
contract: InteropBridgeToken;
|
15
|
+
chainId: ChainId;
|
16
|
+
itokenAddress: string;
|
17
|
+
|
18
|
+
constructor({ chainId, itokenAddress }: { chainId: ChainId, itokenAddress: string }) {
|
19
|
+
super({
|
20
|
+
logger: new Logger("InteropBridgeToken::SyncWithdrawEvents"),
|
21
|
+
})
|
22
|
+
this.chainId = chainId;
|
23
|
+
this.itokenAddress = itokenAddress;
|
24
|
+
}
|
25
|
+
|
26
|
+
async pollHandler() {
|
27
|
+
const currentBlock = await this.provider.getBlockNumber();
|
28
|
+
|
29
|
+
const events = await this.contract.queryFilter(
|
30
|
+
this.contract.filters.Burn(),
|
31
|
+
currentBlock - 2000,
|
32
|
+
currentBlock,
|
33
|
+
);
|
34
|
+
|
35
|
+
let processedEvents = 0;
|
36
|
+
|
37
|
+
for (const event of events) {
|
38
|
+
|
39
|
+
try {
|
40
|
+
if (!event.args) {
|
41
|
+
continue;
|
42
|
+
}
|
43
|
+
|
44
|
+
const { to, amount, chainId } = event.args;
|
45
|
+
|
46
|
+
const uniqueIdentifier = {
|
47
|
+
action: 'withdraw',
|
48
|
+
submitTransactionHash: event.transactionHash,
|
49
|
+
sourceChainId:this.chainId,
|
50
|
+
targetChainId: chainId.toNumber(),
|
51
|
+
}
|
52
|
+
|
53
|
+
if (await Transaction.findOne({ where: uniqueIdentifier })) {
|
54
|
+
continue;
|
55
|
+
}
|
56
|
+
|
57
|
+
const tx = await event.getTransaction()
|
58
|
+
|
59
|
+
await Transaction.create({
|
60
|
+
...uniqueIdentifier,
|
61
|
+
transactionHash: generateInteropTransactionHash(uniqueIdentifier),
|
62
|
+
from: tx.from,
|
63
|
+
to,
|
64
|
+
|
65
|
+
|
66
|
+
submitTransactionHash: event.transactionHash,
|
67
|
+
submitBlockNumber: event.blockNumber,
|
68
|
+
|
69
|
+
// submit & source are the same
|
70
|
+
sourceTransactionHash: event.transactionHash,
|
71
|
+
sourceBlockNumber: event.blockNumber,
|
72
|
+
sourceStatus: "success",
|
73
|
+
|
74
|
+
targetStatus: "uninitialised",
|
75
|
+
|
76
|
+
submitEvent: {
|
77
|
+
to,
|
78
|
+
amount: amount.toString(),
|
79
|
+
itoken: this.itokenAddress,
|
80
|
+
chainId: chainId.toString()
|
81
|
+
},
|
82
|
+
|
83
|
+
sourceEvent: {
|
84
|
+
to,
|
85
|
+
amount: amount.toString(),
|
86
|
+
itoken: this.itokenAddress,
|
87
|
+
chainId: chainId.toString(),
|
88
|
+
},
|
89
|
+
status: "pending",
|
90
|
+
})
|
91
|
+
|
92
|
+
this.logger.info(
|
93
|
+
`Withdraw queued: ${event.transactionHash} ${event.blockNumber}`
|
94
|
+
);
|
95
|
+
} catch (error) {
|
96
|
+
this.logger.error(error);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
if (processedEvents > 0)
|
101
|
+
this.logger.info(`${processedEvents} events processed`);
|
102
|
+
}
|
103
|
+
|
104
|
+
async start(): Promise<void> {
|
105
|
+
this.provider = new ethers.providers.JsonRpcProvider(
|
106
|
+
getRpcProviderUrl(this.chainId)
|
107
|
+
);
|
108
|
+
|
109
|
+
this.contract = getContract<InteropBridgeToken>(
|
110
|
+
this.itokenAddress,
|
111
|
+
abi.interopBridgeToken,
|
112
|
+
new ethers.Wallet(config.privateKey!, this.provider)
|
113
|
+
);
|
114
|
+
|
115
|
+
await super.start()
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
export default SyncWithdrawEvents;
|
@@ -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:
|
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
|
|
@@ -86,11 +96,11 @@ class ProcessDepositEvents extends BaseTask {
|
|
86
96
|
return;
|
87
97
|
}
|
88
98
|
|
89
|
-
|
90
|
-
|
99
|
+
console.log(`Processing transaction ${transaction.transactionHash}`);
|
100
|
+
|
101
|
+
transaction.targetStatus = 'pending';
|
91
102
|
await transaction.save();
|
92
103
|
|
93
|
-
|
94
104
|
// refresh event data?
|
95
105
|
|
96
106
|
const targetChainProvider = new ethers.providers.JsonRpcProvider(
|
@@ -101,19 +111,19 @@ class ProcessDepositEvents extends BaseTask {
|
|
101
111
|
|
102
112
|
const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
|
103
113
|
|
104
|
-
|
114
|
+
|
115
|
+
const safeContract = getContract<GnosisSafe>(
|
105
116
|
safeAddress,
|
106
117
|
abi.gnosisSafe,
|
107
118
|
targetWallet
|
108
|
-
)
|
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,33 +157,17 @@ class ProcessDepositEvents extends BaseTask {
|
|
145
157
|
|
146
158
|
if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
|
147
159
|
await transaction.save();
|
148
|
-
transaction.
|
149
|
-
transaction.
|
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;
|
153
165
|
throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
|
154
166
|
}
|
155
167
|
|
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
168
|
|
169
169
|
console.log(`Executing transaction for execution ${transaction.transactionHash}`)
|
170
170
|
|
171
|
-
console.log({
|
172
|
-
execTransactionParams
|
173
|
-
})
|
174
|
-
|
175
171
|
const { data: txData } = await safeContract.populateTransaction.execTransaction(
|
176
172
|
gnosisTx.to,
|
177
173
|
gnosisTx.value,
|
@@ -185,10 +181,17 @@ class ProcessDepositEvents extends BaseTask {
|
|
185
181
|
buildSignatureBytes(validSignatures)
|
186
182
|
);
|
187
183
|
|
184
|
+
console.log({
|
185
|
+
from: targetWallet.address,
|
186
|
+
gasPrice: BigNumber.from(120 * 10 ** 9).toString(),
|
187
|
+
to: safeAddress,
|
188
|
+
data: txData,
|
189
|
+
})
|
190
|
+
|
191
|
+
|
188
192
|
const txSent = await targetWallet.sendTransaction({
|
189
193
|
from: targetWallet.address,
|
190
194
|
gasPrice: BigNumber.from(120 * 10 ** 9),
|
191
|
-
gasLimit: BigNumber.from(6_000_000),
|
192
195
|
to: safeAddress,
|
193
196
|
data: txData,
|
194
197
|
})
|
@@ -205,25 +208,33 @@ class ProcessDepositEvents extends BaseTask {
|
|
205
208
|
|
206
209
|
if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
|
207
210
|
console.log('ExecutionSuccess')
|
211
|
+
transaction.targetStatus = 'success'
|
212
|
+
transaction.targetTransactionHash = txSent.hash
|
213
|
+
transaction.status = 'success'
|
214
|
+
await transaction.save();
|
208
215
|
} else {
|
209
216
|
console.log('ExecutionFailure')
|
217
|
+
transaction.targetStatus = 'failed'
|
218
|
+
transaction.targetTransactionHash = txSent.hash
|
219
|
+
transaction.status = 'failed'
|
220
|
+
await transaction.save();
|
210
221
|
}
|
222
|
+
|
223
|
+
protocol.sendTransaction(transaction)
|
211
224
|
}
|
212
225
|
|
213
226
|
async start(): Promise<void> {
|
214
|
-
this.logger.info(`Starting execution watcher on interop chain`);
|
215
|
-
|
216
227
|
this.contractAddress = addresses[this.chainId].interopXGateway;
|
217
228
|
|
218
229
|
this.provider = new ethers.providers.JsonRpcProvider(
|
219
230
|
getRpcProviderUrl(this.chainId)
|
220
231
|
);
|
221
232
|
|
222
|
-
this.contract =
|
233
|
+
this.contract = getContract<InteropXGateway>(
|
223
234
|
this.contractAddress,
|
224
235
|
abi.interopXGateway,
|
225
236
|
new ethers.Wallet(config.privateKey!, this.provider)
|
226
|
-
)
|
237
|
+
);
|
227
238
|
|
228
239
|
await super.start()
|
229
240
|
}
|
@@ -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
|
-
|
80
|
+
amount: amount.toString(),
|
81
81
|
vnonce: vnonce.toString(),
|
82
82
|
},
|
83
83
|
|
@@ -86,14 +86,14 @@ class SyncDepositEvents extends BaseTask {
|
|
86
86
|
sourceChainId: sourceChainId.toString(),
|
87
87
|
targetChainId: targetChainId.toString(),
|
88
88
|
token: token,
|
89
|
-
|
89
|
+
amount: amount.toString(),
|
90
90
|
vnonce: vnonce.toString(),
|
91
91
|
},
|
92
92
|
status: "pending",
|
93
93
|
})
|
94
94
|
|
95
95
|
this.logger.info(
|
96
|
-
`
|
96
|
+
`Deposit queued: ${event.transactionHash} ${event.blockNumber}`
|
97
97
|
);
|
98
98
|
} catch (error) {
|
99
99
|
this.logger.error(error);
|
@@ -105,19 +105,17 @@ class SyncDepositEvents extends BaseTask {
|
|
105
105
|
}
|
106
106
|
|
107
107
|
async start(): Promise<void> {
|
108
|
-
this.logger.info(`Starting execution watcher on interop chain`);
|
109
|
-
|
110
108
|
this.contractAddress = addresses[this.chainId].interopXGateway;
|
111
109
|
|
112
110
|
this.provider = new ethers.providers.JsonRpcProvider(
|
113
111
|
getRpcProviderUrl(this.chainId)
|
114
112
|
);
|
115
113
|
|
116
|
-
this.contract =
|
114
|
+
this.contract = getContract<InteropXGateway>(
|
117
115
|
this.contractAddress,
|
118
116
|
abi.interopXGateway,
|
119
117
|
new ethers.Wallet(config.privateKey!, this.provider)
|
120
|
-
)
|
118
|
+
);
|
121
119
|
|
122
120
|
await super.start()
|
123
121
|
}
|
@@ -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;
|
package/src/tasks/index.ts
CHANGED
@@ -1,11 +1,33 @@
|
|
1
1
|
import { BaseTask } from "./BaseTask";
|
2
|
-
import
|
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";
|
3
9
|
|
4
10
|
export class Tasks {
|
5
11
|
|
6
12
|
tasks: BaseTask[] = [
|
7
|
-
new
|
13
|
+
new SyncTransactionStatusTask(),
|
14
|
+
new AutoUpdateTask(),
|
15
|
+
|
16
|
+
new InteropXGatewaySyncDepositEvents({
|
17
|
+
chainId: 43114
|
18
|
+
}),
|
19
|
+
|
20
|
+
new InteropXGatewayProcessDepositEvents({
|
8
21
|
chainId: 43114
|
22
|
+
}),
|
23
|
+
|
24
|
+
new InteropBridgeSyncWithdrawEvents({
|
25
|
+
chainId: 137,
|
26
|
+
itokenAddress: '0xEab02fe1F016eE3e4106c1C6aad35FeEe657268E',
|
27
|
+
}),
|
28
|
+
|
29
|
+
new InteropBridgeProcessWithdrawEvents({
|
30
|
+
chainId: 137,
|
9
31
|
})
|
10
32
|
];
|
11
33
|
|