@zircuit/ovault-evm 0.0.1
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/README.md +141 -0
- package/dist/addresses.d.ts +41 -0
- package/dist/addresses.d.ts.map +1 -0
- package/dist/addresses.js +48 -0
- package/dist/contracts/EIP2612.d.ts +14 -0
- package/dist/contracts/EIP2612.d.ts.map +1 -0
- package/dist/contracts/EIP2612.js +38 -0
- package/dist/contracts/ERC20.d.ts +169 -0
- package/dist/contracts/ERC20.d.ts.map +1 -0
- package/dist/contracts/ERC20.js +222 -0
- package/dist/contracts/ERC4626.d.ts +2020 -0
- package/dist/contracts/ERC4626.d.ts.map +1 -0
- package/dist/contracts/ERC4626.js +2638 -0
- package/dist/contracts/OFT.d.ts +1736 -0
- package/dist/contracts/OFT.d.ts.map +1 -0
- package/dist/contracts/OFT.js +2251 -0
- package/dist/contracts/OVaultComposer.d.ts +94 -0
- package/dist/contracts/OVaultComposer.d.ts.map +1 -0
- package/dist/contracts/OVaultComposer.js +1629 -0
- package/dist/contracts/OVaultComposerSync.d.ts +528 -0
- package/dist/contracts/OVaultComposerSync.d.ts.map +1 -0
- package/dist/contracts/OVaultComposerSync.js +682 -0
- package/dist/contracts/OVaultComposerSyncNative.d.ts +560 -0
- package/dist/contracts/OVaultComposerSyncNative.d.ts.map +1 -0
- package/dist/contracts/OVaultComposerSyncNative.js +723 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/oVaultSync/index.d.ts +3 -0
- package/dist/oVaultSync/index.d.ts.map +1 -0
- package/dist/oVaultSync/index.js +2 -0
- package/dist/oVaultSync/tracking.d.ts +46 -0
- package/dist/oVaultSync/tracking.d.ts.map +1 -0
- package/dist/oVaultSync/tracking.js +458 -0
- package/dist/oVaultSync/transfer.d.ts +116 -0
- package/dist/oVaultSync/transfer.d.ts.map +1 -0
- package/dist/oVaultSync/transfer.js +515 -0
- package/dist/types.d.ts +202 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/package.json +51 -0
- package/src/addresses.ts +100 -0
- package/src/contracts/EIP2612.ts +38 -0
- package/src/contracts/ERC20.ts +222 -0
- package/src/contracts/ERC4626.ts +2638 -0
- package/src/contracts/OFT.ts +2251 -0
- package/src/contracts/OVaultComposer.ts +1629 -0
- package/src/contracts/OVaultComposerSync.ts +682 -0
- package/src/index.ts +3 -0
- package/src/oVaultSync/index.ts +2 -0
- package/src/oVaultSync/tracking.ts +614 -0
- package/src/oVaultSync/transfer.ts +742 -0
- package/src/types.ts +260 -0
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Chain,
|
|
3
|
+
createPublicClient,
|
|
4
|
+
decodeEventLog,
|
|
5
|
+
http,
|
|
6
|
+
PublicClient,
|
|
7
|
+
type Abi,
|
|
8
|
+
} from "viem";
|
|
9
|
+
import {
|
|
10
|
+
OVaultFailureReason,
|
|
11
|
+
OVaultTransactionStep,
|
|
12
|
+
OVaultMessageWithTxHash,
|
|
13
|
+
OVaultWithdrawalInfo,
|
|
14
|
+
} from "../types";
|
|
15
|
+
import { V2 as scanClient, V2Types } from "@layerzerolabs/scan-client-v2";
|
|
16
|
+
import { OVaultComposerSyncAbi } from "../contracts/OVaultComposerSync";
|
|
17
|
+
import { OVaultComposerAbi } from "../contracts/OVaultComposer";
|
|
18
|
+
|
|
19
|
+
interface TrackingChainConfigs {
|
|
20
|
+
sourceChain: Chain;
|
|
21
|
+
hubChain: Chain;
|
|
22
|
+
dstChain: Chain;
|
|
23
|
+
rpcUrls?: {
|
|
24
|
+
sourceChain?: string;
|
|
25
|
+
hubChain?: string;
|
|
26
|
+
dstChain?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function getTxStatus(txHash: `0x${string}`, client: PublicClient) {
|
|
31
|
+
const receipt = await client.getTransactionReceipt({ hash: txHash });
|
|
32
|
+
if (receipt.status === "reverted") {
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
error: OVaultFailureReason.UNKNOWN,
|
|
36
|
+
};
|
|
37
|
+
} else if (receipt.status === "success") {
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function isRefunded(txHash: `0x${string}`, client: PublicClient) {
|
|
49
|
+
const receipt = await client.waitForTransactionReceipt({
|
|
50
|
+
hash: txHash,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (receipt.status !== "success") {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const log of receipt.logs) {
|
|
58
|
+
try {
|
|
59
|
+
const values = decodeEventLog({
|
|
60
|
+
abi: OVaultComposerSyncAbi,
|
|
61
|
+
data: log.data as `0x${string}`,
|
|
62
|
+
topics: log.topics,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (values.eventName === "Refunded") {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// Ignore errors in decoding logs, they might not be OFT events
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Helper function to find the withdrawal index by looking at WithdrawalProcessed events
|
|
77
|
+
const findWithdrawalIndexInReceipt = async (
|
|
78
|
+
message: V2Types.ScanAPIMessage | OVaultMessageWithTxHash | undefined,
|
|
79
|
+
withdrawalInfo: OVaultWithdrawalInfo,
|
|
80
|
+
client: PublicClient,
|
|
81
|
+
): Promise<number | null> => {
|
|
82
|
+
try {
|
|
83
|
+
// Get the transaction hash from the source
|
|
84
|
+
const txHash = message?.source?.tx?.txHash;
|
|
85
|
+
if (!txHash) {
|
|
86
|
+
console.warn("No txHash found in message");
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get the transaction receipt
|
|
91
|
+
const receipt = await client.getTransactionReceipt({ hash: txHash });
|
|
92
|
+
|
|
93
|
+
if (!receipt || receipt.logs.length === 0) {
|
|
94
|
+
console.warn("No receipt or logs found for transaction", txHash);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const withdrawalProcessedEvents: Array<{
|
|
99
|
+
index: bigint;
|
|
100
|
+
initiator: `0x${string}`;
|
|
101
|
+
timestamp: bigint;
|
|
102
|
+
}> = [];
|
|
103
|
+
|
|
104
|
+
for (const log of receipt.logs) {
|
|
105
|
+
try {
|
|
106
|
+
const decoded = decodeEventLog({
|
|
107
|
+
abi: OVaultComposerAbi as Abi,
|
|
108
|
+
data: log.data as `0x${string}`,
|
|
109
|
+
topics: log.topics,
|
|
110
|
+
eventName: "WithdrawalProcessed",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const args = decoded.args as unknown as {
|
|
114
|
+
index: bigint;
|
|
115
|
+
initiator: `0x${string}`;
|
|
116
|
+
timestamp: bigint;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
withdrawalProcessedEvents.push({
|
|
120
|
+
index: args.index,
|
|
121
|
+
initiator: args.initiator,
|
|
122
|
+
timestamp: args.timestamp,
|
|
123
|
+
});
|
|
124
|
+
} catch {
|
|
125
|
+
// Ignore, event is not WithdrawalProcessed
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const matchIndex = withdrawalProcessedEvents.findIndex((event) => {
|
|
130
|
+
const indexMatch =
|
|
131
|
+
event.index?.toString() === withdrawalInfo.index?.toString();
|
|
132
|
+
const initiatorMatch =
|
|
133
|
+
event.initiator?.toLowerCase() ===
|
|
134
|
+
withdrawalInfo.initiator?.toLowerCase();
|
|
135
|
+
|
|
136
|
+
if (indexMatch && initiatorMatch) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return false;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
if (matchIndex < 0) {
|
|
144
|
+
console.warn("Could not find matching withdrawal in events", {
|
|
145
|
+
searchingForIndex: withdrawalInfo.index,
|
|
146
|
+
searchingForInitiator: withdrawalInfo.initiator,
|
|
147
|
+
foundInEvents: withdrawalProcessedEvents.map((e) => ({
|
|
148
|
+
index: e.index.toString(),
|
|
149
|
+
initiator: e.initiator,
|
|
150
|
+
timestamp: e.timestamp.toString(),
|
|
151
|
+
})),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return matchIndex >= 0 ? matchIndex : null;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error("Error finding withdrawal in receipt:", error);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
async function getLzTxStatus(txHash: `0x${string}`) {
|
|
163
|
+
try {
|
|
164
|
+
const messages = await scanClient.getMessagesBySrcTxHash(txHash);
|
|
165
|
+
if (!Array.isArray(messages)) {
|
|
166
|
+
console.error("Invalid response from LayerZero scan API", {
|
|
167
|
+
txHash,
|
|
168
|
+
messages,
|
|
169
|
+
});
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
return messages;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error("Error fetching LayerZero messages", {
|
|
175
|
+
txHash,
|
|
176
|
+
error: error instanceof Error ? error.message : error,
|
|
177
|
+
});
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function trackBBB(
|
|
183
|
+
txHash: `0x${string}`,
|
|
184
|
+
viemConfigs: TrackingChainConfigs,
|
|
185
|
+
) {
|
|
186
|
+
const { sourceChain } = viemConfigs;
|
|
187
|
+
|
|
188
|
+
const sourceClient = createPublicClient({
|
|
189
|
+
chain: sourceChain,
|
|
190
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
194
|
+
|
|
195
|
+
// In a BBB transaction, the source chain transaction is the only transaction.
|
|
196
|
+
// If the source chain transaction fails, the transaction is refunded.
|
|
197
|
+
return {
|
|
198
|
+
step: sourceTx.success
|
|
199
|
+
? OVaultTransactionStep.COMPLETED
|
|
200
|
+
: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
201
|
+
refunded: sourceTx.error ? true : undefined,
|
|
202
|
+
failureReason: sourceTx.error,
|
|
203
|
+
destinationTxHash: sourceTx.success ? txHash : undefined,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function trackABB(
|
|
208
|
+
txHash: `0x${string}`,
|
|
209
|
+
viemConfigs: TrackingChainConfigs,
|
|
210
|
+
withdrawalInfo?: OVaultWithdrawalInfo,
|
|
211
|
+
) {
|
|
212
|
+
const { sourceChain, hubChain } = viemConfigs;
|
|
213
|
+
|
|
214
|
+
const sourceClient = createPublicClient({
|
|
215
|
+
chain: sourceChain,
|
|
216
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const hubClient = createPublicClient({
|
|
220
|
+
chain: hubChain,
|
|
221
|
+
transport: http(viemConfigs.rpcUrls?.hubChain),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
225
|
+
|
|
226
|
+
if (sourceTx.error) {
|
|
227
|
+
return {
|
|
228
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
229
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
230
|
+
};
|
|
231
|
+
} else if (!sourceTx.success) {
|
|
232
|
+
// Transaction is still in progress
|
|
233
|
+
return {
|
|
234
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Source Tx is successful, now we need to track the hub chain transaction.
|
|
239
|
+
const sourceToHubMessages = await getLzTxStatus(txHash);
|
|
240
|
+
|
|
241
|
+
if (sourceToHubMessages.length === 0) {
|
|
242
|
+
return {
|
|
243
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let sourceToHubMessage: V2Types.ScanAPIMessage = sourceToHubMessages[0];
|
|
248
|
+
|
|
249
|
+
// For withdrawals, find which message index corresponds to this specific withdrawal
|
|
250
|
+
if (withdrawalInfo) {
|
|
251
|
+
const msgIndex = await findWithdrawalIndexInReceipt(
|
|
252
|
+
sourceToHubMessage,
|
|
253
|
+
withdrawalInfo,
|
|
254
|
+
sourceClient,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (msgIndex === null) {
|
|
258
|
+
console.warn(
|
|
259
|
+
"Could not find withdrawal in receipt events",
|
|
260
|
+
withdrawalInfo,
|
|
261
|
+
);
|
|
262
|
+
return {
|
|
263
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
sourceToHubMessage = sourceToHubMessages[msgIndex];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
sourceToHubMessage.status.name === "INFLIGHT" ||
|
|
272
|
+
sourceToHubMessage.status.name === "CONFIRMING"
|
|
273
|
+
) {
|
|
274
|
+
// Transaction is still in progress
|
|
275
|
+
return {
|
|
276
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (sourceToHubMessage.status.name !== "DELIVERED") {
|
|
281
|
+
return {
|
|
282
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
283
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Track hub chain transaction
|
|
288
|
+
const executorDst = sourceToHubMessage.destination as V2Types.ExecutorTx;
|
|
289
|
+
const composeTxHash = executorDst?.lzCompose?.txs?.[0]
|
|
290
|
+
?.txHash as `0x${string}`;
|
|
291
|
+
const failedCompose = executorDst?.lzCompose?.failedTx?.[0]
|
|
292
|
+
?.txHash as `0x${string}`;
|
|
293
|
+
if (failedCompose) {
|
|
294
|
+
return {
|
|
295
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
296
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
297
|
+
refunded: false,
|
|
298
|
+
hubTxHash: failedCompose,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (!composeTxHash) {
|
|
302
|
+
// Waiting for the compose tx to be created
|
|
303
|
+
return {
|
|
304
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
const hubTx = await getTxStatus(composeTxHash, hubClient);
|
|
308
|
+
|
|
309
|
+
const refunded = await isRefunded(composeTxHash, hubClient);
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
step: hubTx.success
|
|
313
|
+
? OVaultTransactionStep.COMPLETED
|
|
314
|
+
: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
315
|
+
refunded: hubTx.error || refunded ? true : undefined,
|
|
316
|
+
failureReason:
|
|
317
|
+
hubTx.error || (refunded ? OVaultFailureReason.UNKNOWN : undefined),
|
|
318
|
+
destinationTxHash: hubTx.success ? composeTxHash : undefined,
|
|
319
|
+
hubTxHash: composeTxHash,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async function trackBBA(
|
|
324
|
+
txHash: `0x${string}`,
|
|
325
|
+
viemConfigs: TrackingChainConfigs,
|
|
326
|
+
withdrawalInfo?: OVaultWithdrawalInfo,
|
|
327
|
+
) {
|
|
328
|
+
const { sourceChain, dstChain } = viemConfigs;
|
|
329
|
+
|
|
330
|
+
const sourceClient = createPublicClient({
|
|
331
|
+
chain: sourceChain,
|
|
332
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const dstClient = createPublicClient({
|
|
336
|
+
chain: dstChain,
|
|
337
|
+
transport: http(viemConfigs.rpcUrls?.dstChain),
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
341
|
+
|
|
342
|
+
if (sourceTx.error) {
|
|
343
|
+
return {
|
|
344
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
345
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
346
|
+
};
|
|
347
|
+
} else if (!sourceTx.success) {
|
|
348
|
+
// Transaction is still in progress
|
|
349
|
+
return {
|
|
350
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const hubToDstMessages = await getLzTxStatus(txHash);
|
|
355
|
+
|
|
356
|
+
if (hubToDstMessages.length === 0) {
|
|
357
|
+
return {
|
|
358
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
let hubToDstMessage: V2Types.ScanAPIMessage = hubToDstMessages[0];
|
|
363
|
+
|
|
364
|
+
// For withdrawals, find which message index corresponds to this specific withdrawal
|
|
365
|
+
if (withdrawalInfo) {
|
|
366
|
+
const msgIndex = await findWithdrawalIndexInReceipt(
|
|
367
|
+
hubToDstMessage,
|
|
368
|
+
withdrawalInfo,
|
|
369
|
+
sourceClient,
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
if (msgIndex === null) {
|
|
373
|
+
console.warn(
|
|
374
|
+
"Could not find withdrawal in receipt events",
|
|
375
|
+
withdrawalInfo,
|
|
376
|
+
);
|
|
377
|
+
return {
|
|
378
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
hubToDstMessage = hubToDstMessages[msgIndex];
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (
|
|
386
|
+
hubToDstMessage.status.name === "INFLIGHT" ||
|
|
387
|
+
hubToDstMessage.status.name === "CONFIRMING"
|
|
388
|
+
) {
|
|
389
|
+
return {
|
|
390
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (hubToDstMessage.status.name !== "DELIVERED") {
|
|
395
|
+
return {
|
|
396
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
397
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Track dst chain transaction
|
|
402
|
+
const dstTxHash = hubToDstMessage.destination?.tx?.txHash as `0x${string}`;
|
|
403
|
+
if (!dstTxHash) {
|
|
404
|
+
return {
|
|
405
|
+
step: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const dstTx = await getTxStatus(dstTxHash, dstClient);
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
step: dstTx.success
|
|
413
|
+
? OVaultTransactionStep.COMPLETED
|
|
414
|
+
: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
415
|
+
refunded: false,
|
|
416
|
+
failureReason: dstTx.error,
|
|
417
|
+
destinationTxHash: dstTx.success ? dstTxHash : undefined,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async function trackABA(
|
|
422
|
+
txHash: `0x${string}`,
|
|
423
|
+
viemConfigs: TrackingChainConfigs,
|
|
424
|
+
withdrawalInfo?: OVaultWithdrawalInfo,
|
|
425
|
+
) {
|
|
426
|
+
const { sourceChain, hubChain, dstChain } = viemConfigs;
|
|
427
|
+
|
|
428
|
+
const sourceClient = createPublicClient({
|
|
429
|
+
chain: sourceChain,
|
|
430
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
const hubClient = createPublicClient({
|
|
434
|
+
chain: hubChain,
|
|
435
|
+
transport: http(viemConfigs.rpcUrls?.hubChain),
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const dstClient = createPublicClient({
|
|
439
|
+
chain: dstChain,
|
|
440
|
+
transport: http(viemConfigs.rpcUrls?.dstChain),
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
444
|
+
|
|
445
|
+
if (sourceTx.error) {
|
|
446
|
+
return {
|
|
447
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
448
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
449
|
+
};
|
|
450
|
+
} else if (!sourceTx.success) {
|
|
451
|
+
// Transaction is still in progress
|
|
452
|
+
return {
|
|
453
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const sourceToHubMessages = await getLzTxStatus(txHash);
|
|
458
|
+
|
|
459
|
+
if (sourceToHubMessages.length === 0) {
|
|
460
|
+
return {
|
|
461
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
let sourceToHubMessage: V2Types.ScanAPIMessage = sourceToHubMessages[0];
|
|
466
|
+
|
|
467
|
+
// For withdrawals, find which message index corresponds to this specific withdrawal
|
|
468
|
+
if (withdrawalInfo) {
|
|
469
|
+
const msgIndex = await findWithdrawalIndexInReceipt(
|
|
470
|
+
sourceToHubMessage,
|
|
471
|
+
withdrawalInfo,
|
|
472
|
+
sourceClient,
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
if (msgIndex === null) {
|
|
476
|
+
console.warn(
|
|
477
|
+
"Could not find withdrawal in receipt events",
|
|
478
|
+
withdrawalInfo,
|
|
479
|
+
);
|
|
480
|
+
return {
|
|
481
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
sourceToHubMessage = sourceToHubMessages[msgIndex];
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (
|
|
489
|
+
sourceToHubMessage.status.name === "INFLIGHT" ||
|
|
490
|
+
sourceToHubMessage.status.name === "CONFIRMING"
|
|
491
|
+
) {
|
|
492
|
+
return {
|
|
493
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (sourceToHubMessage.status.name !== "DELIVERED") {
|
|
498
|
+
return {
|
|
499
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
500
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Track hub chain transaction
|
|
505
|
+
const executorDst = sourceToHubMessage.destination as V2Types.ExecutorTx;
|
|
506
|
+
const composeTxHash = executorDst?.lzCompose?.txs?.[0]
|
|
507
|
+
?.txHash as `0x${string}`;
|
|
508
|
+
if (!composeTxHash) {
|
|
509
|
+
return {
|
|
510
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
const failedCompose = executorDst?.lzCompose?.failedTx?.[0]
|
|
514
|
+
?.txHash as `0x${string}`;
|
|
515
|
+
if (executorDst?.lzCompose?.status !== "SUCCEEDED" && failedCompose) {
|
|
516
|
+
return {
|
|
517
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
518
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
519
|
+
refunded: false,
|
|
520
|
+
hubTxHash: failedCompose,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
const hubTx = await getTxStatus(composeTxHash, hubClient);
|
|
524
|
+
|
|
525
|
+
const refunded = await isRefunded(composeTxHash, hubClient);
|
|
526
|
+
|
|
527
|
+
if (hubTx.success && refunded) {
|
|
528
|
+
// Something went wrong on the hub chain, but the funds were refunded.
|
|
529
|
+
return {
|
|
530
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
531
|
+
refunded: true,
|
|
532
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
533
|
+
hubTxHash: composeTxHash,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Track hub to dst chain transaction
|
|
538
|
+
const hubToDstLzMessages = await getLzTxStatus(composeTxHash);
|
|
539
|
+
if (hubToDstLzMessages.length === 0) {
|
|
540
|
+
return {
|
|
541
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
542
|
+
hubTxHash: composeTxHash,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const hubToDstMessage: V2Types.ScanAPIMessage = hubToDstLzMessages[0];
|
|
547
|
+
|
|
548
|
+
if (
|
|
549
|
+
hubToDstMessage.status.name === "INFLIGHT" ||
|
|
550
|
+
hubToDstMessage.status.name === "CONFIRMING"
|
|
551
|
+
) {
|
|
552
|
+
return {
|
|
553
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
554
|
+
hubTxHash: composeTxHash,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (hubToDstMessage.status.name !== "DELIVERED") {
|
|
559
|
+
return {
|
|
560
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
561
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
562
|
+
hubTxHash: composeTxHash,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Track dst chain transaction
|
|
567
|
+
const dstTxHash = hubToDstMessage.destination?.tx?.txHash as `0x${string}`;
|
|
568
|
+
if (!dstTxHash) {
|
|
569
|
+
// Waiting for the dst tx to be created
|
|
570
|
+
return {
|
|
571
|
+
step: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
572
|
+
hubTxHash: composeTxHash,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const dstTx = await getTxStatus(dstTxHash, dstClient);
|
|
577
|
+
|
|
578
|
+
return {
|
|
579
|
+
step: dstTx.success
|
|
580
|
+
? OVaultTransactionStep.COMPLETED
|
|
581
|
+
: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
582
|
+
refunded: false,
|
|
583
|
+
failureReason: dstTx.error,
|
|
584
|
+
destinationTxHash: dstTx.success ? dstTxHash : undefined,
|
|
585
|
+
hubTxHash: composeTxHash,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Track the OVault transaction
|
|
591
|
+
* There are 4 possible scenarios:
|
|
592
|
+
* 1. BBB - source chain, hub chain, dst chain are the same
|
|
593
|
+
* 2. BBA - source chain, hub chain are the same, dst chain is different
|
|
594
|
+
* 3. ABB - hub chain, dst chain are the same, source chain is different
|
|
595
|
+
* 4. ABA - source chain, hub chain, dst chain are different. Source chain can optionally be the same as the dst chain.
|
|
596
|
+
*
|
|
597
|
+
* @param txHash - The hash of the transaction to track on the source chain.
|
|
598
|
+
*/
|
|
599
|
+
export async function trackOVaultSyncTransaction(
|
|
600
|
+
txHash: `0x${string}`,
|
|
601
|
+
viemConfigs: TrackingChainConfigs,
|
|
602
|
+
withdrawalInfo?: OVaultWithdrawalInfo,
|
|
603
|
+
) {
|
|
604
|
+
const { sourceChain, hubChain, dstChain } = viemConfigs;
|
|
605
|
+
if (sourceChain.id === hubChain.id && sourceChain.id === dstChain.id) {
|
|
606
|
+
return trackBBB(txHash, viemConfigs);
|
|
607
|
+
} else if (sourceChain.id === hubChain.id && hubChain.id !== dstChain.id) {
|
|
608
|
+
return trackBBA(txHash, viemConfigs, withdrawalInfo);
|
|
609
|
+
} else if (sourceChain.id !== hubChain.id && hubChain.id === dstChain.id) {
|
|
610
|
+
return trackABB(txHash, viemConfigs, withdrawalInfo);
|
|
611
|
+
} else {
|
|
612
|
+
return trackABA(txHash, viemConfigs, withdrawalInfo);
|
|
613
|
+
}
|
|
614
|
+
}
|