Files
AutistMask/tests
clawbot e32d6896f2
All checks were successful
check / check (push) Successful in 34s
fix: WaitTx timeout no longer overwrites a rendered success screen (closes #155)
A poll tick that found a receipt called showSuccess() and then fell through
to the elapsed check, so on the tick crossing the 60-second deadline the
"Transaction Confirmed" screen was immediately replaced by "not confirmed
within 60 seconds" — the user is told a confirmed transaction failed.

The wait now has an explicit lifecycle. A wait id is bumped by endWait(),
which is called on receipt, on timeout, when a new wait starts and when the
user navigates away; every timer callback and every post-await continuation
checks it, so exactly one outcome can be rendered per wait and no stale
timer or in-flight receipt lookup can touch a view it no longer owns.

A receipt lookup that throws is treated as "no answer this tick" rather than
"no receipt": the poll returns before the deadline check and keeps running,
so one transient RPC failure cannot declare a timeout. This matters most on
a resumed wait, whose first poll is immediate and may already be past the
deadline, where a single error would otherwise be terminal. Retrying is
bounded: six consecutive failed lookups — 60 seconds at the poll cadence,
the same patience the confirmation deadline gets — end the wait and report
that the network could not be reached, pointing at the RPC URL in Settings.
That is a different fact from the timeout, because the chain was never
asked, and it says so rather than claiming the transaction did not confirm.
Any lookup that answers, with a receipt or with null, resets the count. An
unbounded retry would be worse than the bug it avoids: the wait is persisted,
so a mistyped RPC URL would leave a wait that every popup open resumes and
nothing ever ends, on a view with no exit control of its own.

The wait is also persisted (state.viewData.pendingWait) and "wait-tx" is now
restorable: reopening the popup resumes the poll with the elapsed counter
and the deadline still measured from the original broadcast, instead of
silently abandoning the wait. restoreWait() validates every field startWait()
goes on to use, not just the presence of the containers — hash, a non-array
object txInfo carrying a string to and a string amount, and a finite numeric
broadcastTime — and returns false otherwise. txInfo.to reaches addressTitle(),
which calls address.toLowerCase(), so a payload merely missing that one field
would throw a TypeError out of restoreView(), which init() does not guard:
the rest of popup init is skipped and wait-tx stays on screen with no back
control. A non-numeric broadcastTime leaves an unexitable wait counting
"NaNs". Polling stays in the popup rather than moving to the background,
which would depend on setInterval surviving in an MV3 service worker.

"wait-tx" is added to src/popup/restorableViews.js, and a test pins its
membership. restoreView() refuses any view outside that set, so dropping the
entry would kill the resume feature silently — the other tests call
restoreWait() directly and never read the set.

The 60-second threshold and the timeout copy are unchanged.
2026-08-12 08:37:32 +00:00
..