Skip to content

Commit 02193a0

Browse files
authored
fix: show failure state for reverted L1 deposit transactions (#264)
1 parent f37b37b commit 02193a0

File tree

2 files changed

+59
-20
lines changed

2 files changed

+59
-20
lines changed

store/zksync/transactionStatus.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,8 @@ export const useZkSyncTransactionStatusStore = defineStore("zkSyncTransactionSta
5050
)
5151
);
5252

53-
const getDepositL2TransactionHash = async (l1TransactionHash: string) => {
54-
const publicClient = onboardStore.getPublicClient();
55-
const transaction = await retry(() =>
56-
publicClient.waitForTransactionReceipt({
57-
hash: l1TransactionHash as Hash,
58-
})
59-
);
60-
for (const log of transaction.logs) {
53+
const getDepositL2TransactionHash = (l1Receipt: any) => {
54+
for (const log of l1Receipt.logs) {
6155
try {
6256
const { args, eventName } = decodeEventLog({
6357
abi: IZkSyncHyperchain,
@@ -74,12 +68,50 @@ export const useZkSyncTransactionStatusStore = defineStore("zkSyncTransactionSta
7468
throw new Error("No L2 transaction hash found");
7569
};
7670
const getDepositStatus = async (transaction: TransactionInfo) => {
77-
const transactionHash = await getDepositL2TransactionHash(transaction.transactionHash);
78-
const transactionReceipt = await providerStore.requestProvider().getTransactionReceipt(transactionHash);
79-
if (!transactionReceipt) return transaction;
80-
transaction.info.toTransactionHash = transactionHash;
81-
transaction.info.completed = true;
82-
return transaction;
71+
try {
72+
// Get L1 transaction receipt with retry logic for consistency
73+
const publicClient = onboardStore.getPublicClient();
74+
const l1Receipt = await retry(() =>
75+
publicClient.waitForTransactionReceipt({
76+
hash: transaction.transactionHash as Hash,
77+
})
78+
);
79+
80+
// Create a copy to avoid mutating the input parameter
81+
const updatedTransaction = { ...transaction, info: { ...transaction.info } };
82+
83+
// If L1 transaction failed, mark the deposit as failed
84+
if (l1Receipt.status === "reverted") {
85+
updatedTransaction.info.failed = true;
86+
updatedTransaction.info.completed = true;
87+
return updatedTransaction;
88+
}
89+
90+
// L1 transaction succeeded, extract L2 transaction hash from the same receipt
91+
const l2TransactionHash = getDepositL2TransactionHash(l1Receipt);
92+
const l2TransactionReceipt = await providerStore.requestProvider().getTransactionReceipt(l2TransactionHash);
93+
if (!l2TransactionReceipt) return updatedTransaction;
94+
95+
updatedTransaction.info.toTransactionHash = l2TransactionHash;
96+
updatedTransaction.info.completed = true;
97+
return updatedTransaction;
98+
} catch (err) {
99+
// Only mark as failed for specific transaction-related errors
100+
// Network/RPC errors should be re-thrown to allow retry at higher level
101+
const error = err as Error;
102+
if (
103+
error.message.includes("transaction") ||
104+
error.message.includes("reverted") ||
105+
error.message.includes("failed")
106+
) {
107+
const updatedTransaction = { ...transaction, info: { ...transaction.info } };
108+
updatedTransaction.info.failed = true;
109+
updatedTransaction.info.completed = true;
110+
return updatedTransaction;
111+
}
112+
// Re-throw network/infrastructure errors for retry at higher level
113+
throw err;
114+
}
83115
};
84116
const getWithdrawalStatus = async (transaction: TransactionInfo) => {
85117
if (!transaction.info.withdrawalFinalizationAvailable) {

views/transactions/DepositSubmitted.vue

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
<template>
22
<div>
33
<h1 class="h1 mt-block-gap-1/2 text-center">
4-
{{ transaction.info.completed ? "Transaction completed" : "Transaction submitted" }}
4+
<template v-if="transaction.info.failed">Transaction failed</template>
5+
<template v-else>{{ transaction.info.completed ? "Transaction completed" : "Transaction submitted" }}</template>
56
</h1>
6-
<CommonHeightTransition :opened="!transaction.info.completed">
7+
<CommonHeightTransition :opened="!transaction.info.completed || transaction.info.failed">
78
<p class="mb-4 text-center">
8-
Your funds will be available after the transaction is committed on
9-
<span class="font-medium">{{ transaction.from.destination.label }}</span> and then processed on
10-
<span class="font-medium">{{ transaction.to.destination.label }}</span
11-
>. You are free to close this page.
9+
<template v-if="transaction.info.failed">
10+
The deposit transaction failed on <span class="font-medium">{{ transaction.from.destination.label }}</span>
11+
. Your funds remain in your wallet and were not bridged.
12+
</template>
13+
<template v-else>
14+
Your funds will be available after the transaction is committed on
15+
<span class="font-medium">{{ transaction.from.destination.label }}</span> and then processed on
16+
<span class="font-medium">{{ transaction.to.destination.label }}</span
17+
>. You are free to close this page.
18+
</template>
1219
</p>
1320
</CommonHeightTransition>
1421
<TransactionProgress

0 commit comments

Comments
 (0)