fix: WaitTx timeout no longer overwrites a rendered success screen (closes #155)
All checks were successful
check / check (push) Successful in 29s
All checks were successful
check / check (push) Successful in 29s
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.
This commit is contained in:
17
README.md
17
README.md
@@ -688,10 +688,23 @@ of it.
|
||||
- To: color dot + full address + etherscan link
|
||||
- Transaction hash: full hash (tap to copy) + etherscan link
|
||||
- Count-up timer: "Waiting for confirmation... Ns"
|
||||
- **Behavior**: Polls `getTransactionReceipt` every 10 seconds.
|
||||
- **Behavior**: Polls `getTransactionReceipt` every 10 seconds. The wait is
|
||||
persisted: closing and reopening the popup resumes the poll, with the elapsed
|
||||
counter and the timeout deadline still measured from the original broadcast. A
|
||||
lookup that fails is retried on the next tick rather than counted as a missing
|
||||
receipt, because a failed lookup says nothing about the transaction; but six
|
||||
failures in a row (60 seconds at the poll cadence) end the wait, so an RPC
|
||||
that never answers cannot leave it running indefinitely. Any lookup that
|
||||
answers resets that count.
|
||||
- **Transitions**:
|
||||
- Receipt found → **SuccessTx**
|
||||
- 60 seconds without confirmation → **ErrorTx** (timeout message)
|
||||
- A lookup that answers "no receipt" 60 seconds or more after broadcast →
|
||||
**ErrorTx** (timeout message)
|
||||
- Six consecutive failed lookups → **ErrorTx**, with a message naming the
|
||||
unreachable network and pointing at the RPC URL in Settings. This is a
|
||||
different fact from the timeout — the chain was never asked — and says so
|
||||
- Exactly one outcome: a receipt found on the tick that crosses the deadline
|
||||
wins, and no outcome can be rendered over another
|
||||
|
||||
#### SuccessTx (`success-tx`)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user