Skip to content

Commit 5d03c64

Browse files
ggonzalez94claude
andcommitted
fix(dao-ui): verify bridge message status after L2 tx and filter logs by address
- After processMessage tx confirms, re-poll messageStatus on L2 bridge to verify the message actually reached DONE status (inner execution can fail, leaving it RETRIABLE) - Filter L1 tx receipt logs by bridge address before decoding events Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e8ce293 commit 5d03c64

1 file changed

Lines changed: 34 additions & 20 deletions

File tree

packages/ui/src/hooks/useL2LegExecution.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ export function useL2LegExecution(
8080
.then((receipt) => {
8181
if (cancelled) return;
8282
let found = false;
83+
const bridgeAddr = PUB_TAIKO_BRIDGE_ADDRESS.toLowerCase();
8384
for (const log of receipt.logs) {
85+
if (log.address.toLowerCase() !== bridgeAddr) continue;
8486
try {
8587
const decoded = decodeEventLog({
8688
abi: TaikoBridgeL1EventsAbi,
@@ -113,19 +115,7 @@ export function useL2LegExecution(
113115
};
114116
}, [l1TxHash, l1Client, message]);
115117

116-
// Step 2: Check if already processed on L2
117-
const { data: messageStatusResult } = useReadContract({
118-
address: TAIKO_L2_BRIDGE_ADDRESS,
119-
abi: TaikoBridgeL2Abi,
120-
chainId: TAIKO_L2_CHAIN_ID,
121-
functionName: "messageStatus",
122-
args: msgHash ? [msgHash] : undefined,
123-
query: { enabled: !!msgHash },
124-
});
125-
126-
const isAlreadyProcessed = messageStatusResult === MESSAGE_STATUS_DONE;
127-
128-
// Step 3: Write contract for processMessage
118+
// Step 2: Write contract setup (declared early so l2TxHash is available for status polling)
129119
const {
130120
writeContract,
131121
data: l2TxHash,
@@ -137,6 +127,24 @@ export function useL2LegExecution(
137127
const { isLoading: isL2Confirming, isSuccess: isL2Confirmed } =
138128
useWaitForTransactionReceipt({ hash: l2TxHash });
139129

130+
// Step 3: Check message status on L2 (re-polls after processMessage tx until DONE)
131+
const { data: messageStatusResult } = useReadContract({
132+
address: TAIKO_L2_BRIDGE_ADDRESS,
133+
abi: TaikoBridgeL2Abi,
134+
chainId: TAIKO_L2_CHAIN_ID,
135+
functionName: "messageStatus",
136+
args: msgHash ? [msgHash] : undefined,
137+
query: {
138+
enabled: !!msgHash,
139+
refetchInterval: (query) => {
140+
if (l2TxHash && query.state.data !== MESSAGE_STATUS_DONE) return 5_000;
141+
return false;
142+
},
143+
},
144+
});
145+
146+
const isMessageDone = messageStatusResult === MESSAGE_STATUS_DONE;
147+
140148
// Step 4: Build proof and execute
141149
const executeL2 = useCallback(async () => {
142150
if (!message || !msgHash || !l1Client || !isSynced || !anchorBlockNumber) {
@@ -238,21 +246,27 @@ export function useL2LegExecution(
238246
return;
239247
}
240248
if (isL2Confirmed) {
241-
addAlert("L2 leg executed successfully", {
242-
description: "The cross-chain proposal actions have been executed on L2",
243-
type: "success",
244-
});
249+
if (isMessageDone) {
250+
addAlert("L2 leg executed successfully", {
251+
description: "The cross-chain proposal actions have been executed on L2",
252+
type: "success",
253+
});
254+
} else {
255+
addAlert("L2 transaction confirmed but message not yet processed", {
256+
description: "The inner L2 execution may have failed. Check the transaction and retry if needed.",
257+
type: "error",
258+
});
259+
}
245260
}
246-
}, [writeStatus, writeError, l2TxHash, isL2Confirming, isL2Confirmed, addAlert, resetWrite]);
261+
}, [writeStatus, writeError, l2TxHash, isL2Confirming, isL2Confirmed, isMessageDone, addAlert, resetWrite]);
247262

248263
return {
249264
message,
250265
msgHash,
251266
isExtracting,
252267
extractError,
253-
isAlreadyProcessed,
254268
executeL2,
255269
isL2Confirming: writeStatus === "pending" || isL2Confirming,
256-
isL2Confirmed: isL2Confirmed || isAlreadyProcessed,
270+
isL2Confirmed: isMessageDone,
257271
};
258272
}

0 commit comments

Comments
 (0)