@instadapp/interop-x 0.0.0-dev.a168c79 → 0.0.0-dev.adea608
Sign up to get free protection for your applications and to get access to all the features.
- package/bin/interop-x +1 -1
- package/dist/package.json +6 -3
- package/dist/src/constants/itokens.js +1 -1
- package/dist/src/index.js +19 -1
- package/dist/src/net/peer/index.js +6 -2
- package/dist/src/net/pool/index.js +24 -9
- package/dist/src/net/protocol/dial/SignatureDialProtocol.js +11 -4
- package/dist/src/net/protocol/index.js +30 -1
- package/dist/src/tasks/BaseTask.js +1 -1
- package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +147 -0
- package/dist/src/tasks/InteropBridge/SyncWithdrawEvents.js +70 -0
- package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +32 -22
- package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +4 -4
- package/dist/src/tasks/index.js +13 -0
- package/dist/src/utils/index.js +92 -6
- package/package.json +6 -3
- package/patches/@ethersproject+properties+5.6.0.patch +13 -0
- package/src/constants/itokens.ts +1 -1
- package/src/index.ts +26 -1
- package/src/net/peer/index.ts +7 -6
- package/src/net/pool/index.ts +33 -11
- package/src/net/protocol/dial/SignatureDialProtocol.ts +12 -4
- package/src/net/protocol/index.ts +45 -1
- package/src/tasks/BaseTask.ts +1 -1
- package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +233 -0
- package/src/tasks/InteropBridge/SyncWithdrawEvents.ts +121 -0
- package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +44 -31
- package/src/tasks/InteropXGateway/SyncDepositEvents.ts +6 -6
- package/src/tasks/index.ts +19 -2
- package/src/utils/index.ts +124 -8
@@ -0,0 +1,121 @@
|
|
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.logger.info(`Starting execution watcher on interop chain`);
|
106
|
+
|
107
|
+
this.provider = new ethers.providers.JsonRpcProvider(
|
108
|
+
getRpcProviderUrl(this.chainId)
|
109
|
+
);
|
110
|
+
|
111
|
+
this.contract = getContract<InteropBridgeToken>(
|
112
|
+
this.itokenAddress,
|
113
|
+
abi.interopBridgeToken,
|
114
|
+
new ethers.Wallet(config.privateKey!, this.provider)
|
115
|
+
);
|
116
|
+
|
117
|
+
await super.start()
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
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,9 +208,19 @@ 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> {
|
@@ -219,11 +232,11 @@ class ProcessDepositEvents extends BaseTask {
|
|
219
232
|
getRpcProviderUrl(this.chainId)
|
220
233
|
);
|
221
234
|
|
222
|
-
this.contract =
|
235
|
+
this.contract = getContract<InteropXGateway>(
|
223
236
|
this.contractAddress,
|
224
237
|
abi.interopXGateway,
|
225
238
|
new ethers.Wallet(config.privateKey!, this.provider)
|
226
|
-
)
|
239
|
+
);
|
227
240
|
|
228
241
|
await super.start()
|
229
242
|
}
|
@@ -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);
|
@@ -113,11 +113,11 @@ class SyncDepositEvents extends BaseTask {
|
|
113
113
|
getRpcProviderUrl(this.chainId)
|
114
114
|
);
|
115
115
|
|
116
|
-
this.contract =
|
116
|
+
this.contract = getContract<InteropXGateway>(
|
117
117
|
this.contractAddress,
|
118
118
|
abi.interopXGateway,
|
119
119
|
new ethers.Wallet(config.privateKey!, this.provider)
|
120
|
-
)
|
120
|
+
);
|
121
121
|
|
122
122
|
await super.start()
|
123
123
|
}
|
package/src/tasks/index.ts
CHANGED
@@ -1,11 +1,28 @@
|
|
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";
|
3
7
|
|
4
8
|
export class Tasks {
|
5
9
|
|
6
10
|
tasks: BaseTask[] = [
|
7
|
-
new
|
11
|
+
new InteropXGatewaySyncDepositEvents({
|
12
|
+
chainId: 43114
|
13
|
+
}),
|
14
|
+
|
15
|
+
new InteropXGatewayProcessDepositEvents({
|
8
16
|
chainId: 43114
|
17
|
+
}),
|
18
|
+
|
19
|
+
new InteropBridgeSyncWithdrawEvents({
|
20
|
+
chainId: 137,
|
21
|
+
itokenAddress: '0xEab02fe1F016eE3e4106c1C6aad35FeEe657268E',
|
22
|
+
}),
|
23
|
+
|
24
|
+
new InteropBridgeProcessWithdrawEvents({
|
25
|
+
chainId: 137,
|
9
26
|
})
|
10
27
|
];
|
11
28
|
|
package/src/utils/index.ts
CHANGED
@@ -10,7 +10,7 @@ import { encodeMulti, MetaTransaction, OperationType } from 'ethers-multisend';
|
|
10
10
|
import { Transaction } from '@/db';
|
11
11
|
import config from '@/config';
|
12
12
|
import abi from '@/abi';
|
13
|
-
import { InteropBridgeToken } from '@/typechain';
|
13
|
+
import { InteropBridgeToken, InteropXGateway } from '@/typechain';
|
14
14
|
|
15
15
|
export const http = axios.create();
|
16
16
|
|
@@ -136,10 +136,21 @@ export const generateInteropTransactionHash = (data: { action: string, submitTra
|
|
136
136
|
export const buildDataForTransaction = async (transaction: Transaction, type?: 'source' | 'target') => {
|
137
137
|
type = type || transaction.sourceStatus === 'pending' ? 'source' : 'target';
|
138
138
|
|
139
|
+
switch (transaction.action) {
|
140
|
+
case "deposit":
|
141
|
+
return await buildDepositDataForTransaction(transaction, type);
|
142
|
+
case "withdraw":
|
143
|
+
return await buildWithdrawDataForTransaction(transaction, type);
|
144
|
+
default:
|
145
|
+
throw new Error(`Unknown action: ${transaction.action}`);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
export const buildDepositDataForTransaction = async (transaction: Transaction, type: 'source' | 'target') => {
|
139
150
|
const transactions: MetaTransaction[] = [];
|
140
151
|
|
141
|
-
if(transaction.action
|
142
|
-
throw new Error(
|
152
|
+
if (transaction.action !== 'deposit') {
|
153
|
+
throw new Error(`Invalid action: ${transaction.action}`)
|
143
154
|
}
|
144
155
|
|
145
156
|
if (transaction.action === 'deposit' && transaction.sourceStatus === 'pending') {
|
@@ -165,13 +176,13 @@ export const buildDataForTransaction = async (transaction: Transaction, type?: '
|
|
165
176
|
|
166
177
|
const targetChainProvider = new ethers.providers.JsonRpcProvider(getRpcProviderUrl(transaction.targetChainId as ChainId));
|
167
178
|
const targetWallet = new ethers.Wallet(config.privateKey, targetChainProvider);
|
168
|
-
const interopBridgeContract =
|
179
|
+
const interopBridgeContract = getContract<InteropBridgeToken>(itoken.address, abi.interopBridgeToken, targetWallet);
|
169
180
|
|
170
181
|
const { data } = await interopBridgeContract.populateTransaction.mint(
|
171
|
-
transaction.submitEvent.
|
172
|
-
transaction.submitEvent.amount,
|
173
|
-
transaction.sourceChainId,
|
174
|
-
transaction.
|
182
|
+
transaction.submitEvent.user,
|
183
|
+
ethers.BigNumber.from(transaction.submitEvent.amount.toString()),
|
184
|
+
ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()),
|
185
|
+
transaction.submitTransactionHash,
|
175
186
|
);
|
176
187
|
|
177
188
|
transactions.push({
|
@@ -183,3 +194,108 @@ export const buildDataForTransaction = async (transaction: Transaction, type?: '
|
|
183
194
|
|
184
195
|
return encodeMulti(transactions).data
|
185
196
|
}
|
197
|
+
|
198
|
+
export const buildWithdrawDataForTransaction = async (transaction: Transaction, type: 'source' | 'target') => {
|
199
|
+
const transactions: MetaTransaction[] = [];
|
200
|
+
|
201
|
+
if (transaction.action !== 'withdraw') {
|
202
|
+
throw new Error(`Invalid action: ${transaction.action}`)
|
203
|
+
}
|
204
|
+
|
205
|
+
if (transaction.action === 'withdraw' && transaction.sourceStatus === 'pending') {
|
206
|
+
throw Error('Cannot build data for pending withdraw transaction');
|
207
|
+
}
|
208
|
+
|
209
|
+
if (!transaction.submitEvent) {
|
210
|
+
throw Error('Cannot build data for transaction without submitEvent');
|
211
|
+
}
|
212
|
+
|
213
|
+
const { to, amount, chainId, itoken: itokenAddress } = transaction.submitEvent;
|
214
|
+
|
215
|
+
const itoken = itokens[transaction.sourceChainId].find(token => token.address.toLowerCase() === itokenAddress.toLowerCase());
|
216
|
+
|
217
|
+
if (!itoken) {
|
218
|
+
throw Error('Cannot build data for transaction without itoken');
|
219
|
+
}
|
220
|
+
|
221
|
+
const token = tokens[chainId].find(t => t.symbol.toLowerCase() === itoken.symbol.toLowerCase());
|
222
|
+
|
223
|
+
if (!token) {
|
224
|
+
throw Error('Cannot build data for transaction without token');
|
225
|
+
}
|
226
|
+
|
227
|
+
const targetChainProvider = new ethers.providers.JsonRpcProvider(getRpcProviderUrl(transaction.targetChainId as ChainId));
|
228
|
+
const targetWallet = new ethers.Wallet(config.privateKey, targetChainProvider);
|
229
|
+
const gatewayAddress = addresses[chainId].interopXGateway;
|
230
|
+
const interopBridgeContract = getContract<InteropXGateway>(gatewayAddress, abi.interopXGateway, targetWallet);
|
231
|
+
|
232
|
+
const { data } = await interopBridgeContract.populateTransaction.systemWithdraw(
|
233
|
+
ethers.BigNumber.from(amount.toString()),
|
234
|
+
to,
|
235
|
+
token.address,
|
236
|
+
ethers.BigNumber.from(transaction.sourceChainId.toString()),
|
237
|
+
transaction.submitTransactionHash,
|
238
|
+
);
|
239
|
+
|
240
|
+
transactions.push({
|
241
|
+
to: gatewayAddress,
|
242
|
+
data: data!,
|
243
|
+
value: '0',
|
244
|
+
operation: OperationType.Call,
|
245
|
+
});
|
246
|
+
|
247
|
+
return encodeMulti(transactions).data
|
248
|
+
}
|
249
|
+
|
250
|
+
|
251
|
+
export function getContract<TContract extends ethers.Contract>(address: string, contractInterface: ethers.ContractInterface | any, signerOrProvider?: ethers.Signer | ethers.providers.Provider) {
|
252
|
+
if (!ethers.utils.getAddress(address) || address === ethers.constants.AddressZero) {
|
253
|
+
throw Error(`Invalid 'address' parameter '${address}'.`)
|
254
|
+
}
|
255
|
+
|
256
|
+
const contract = new ethers.Contract(
|
257
|
+
address,
|
258
|
+
contractInterface,
|
259
|
+
signerOrProvider
|
260
|
+
) as TContract
|
261
|
+
|
262
|
+
|
263
|
+
return new Proxy(contract, {
|
264
|
+
get(target, prop, receiver) {
|
265
|
+
const value = Reflect.get(target, prop, receiver);
|
266
|
+
|
267
|
+
if (typeof value === 'function' && (contract.functions.hasOwnProperty(prop) || ['queryFilter'].includes(String(prop)))) {
|
268
|
+
return async (...args: any[]) => {
|
269
|
+
try {
|
270
|
+
return await value.bind(contract)(...args);
|
271
|
+
} catch (error) {
|
272
|
+
throw new Error(`Error calling "${String(prop)}" on "${address}": ${error.reason || error.message}`)
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
|
278
|
+
if (typeof value === 'object' && ['populateTransaction', 'estimateGas', 'functions', 'callStatic'].includes(String(prop))) {
|
279
|
+
const parentProp = String(prop);
|
280
|
+
|
281
|
+
return new Proxy(value, {
|
282
|
+
get(target, prop, receiver) {
|
283
|
+
const value = Reflect.get(target, prop, receiver);
|
284
|
+
|
285
|
+
if (typeof value === 'function') {
|
286
|
+
return async (...args: any[]) => {
|
287
|
+
try {
|
288
|
+
return await value.bind(contract)(...args);
|
289
|
+
} catch (error) {
|
290
|
+
throw new Error(`Error calling "${String(prop)}" using "${parentProp}" on "${address}": ${error.reason || error.message}`)
|
291
|
+
}
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
})
|
296
|
+
}
|
297
|
+
|
298
|
+
return value;
|
299
|
+
},
|
300
|
+
});
|
301
|
+
}
|