Summary
When Single Address mode is unavailable, the Address Mode screen shows:
⚠ You can't switch to single address mode because other addresses in your wallet are already in use.
That sentence asserts a specific finding. But the flag behind it is also true when the check failed to run, so on that path we tell the user something we never actually determined.
The blocking behaviour is correct and should not change — only the message is wrong on one of the two paths that produce it.
Root cause — one boolean carries two states
AddressMode.js derives singleDisabled from hasTxOutside, which comes from:
async function detectTxOutsideFirstAddress(wallet, dispatch) {
try {
return await wallet.hasTxOutsideFirstAddress();
} catch (e) {
log.error('hasTxOutsideFirstAddress check failed', e);
dispatch(onExceptionCaptured(e, false));
return true; // fail closed
}
}
The return true on error is deliberate and right: if we cannot confirm the wallet has no activity past index 0, switching to single would hide funds on the other addresses, so we block. Failing closed is the correct default and this issue does not propose changing it.
The consequence is that hasTxOutside === true conflates two different situations:
- We checked, and found activity on addresses past index 0. The banner is accurate.
- We could not check —
hasTxOutsideFirstAddress() threw (network, storage, an unexpected wallet-lib state). The banner is a confident claim about something we never established.
A single boolean cannot express both, so the copy cannot be fixed by rewording alone.
Worth noting how reachable path 2 is: it covers any transient failure of the underlying call, and the user gets no hint that anything went wrong. onExceptionCaptured(e, false) reports the error to us, but the screen presents a definitive explanation to them.
Proposed direction
Replace the boolean with a tri-state — 'available' | 'blocked' | 'unknown' — and give each its own message:
blocked → keep today's wording; it is correct there.
unknown → something honest about not having been able to verify, e.g. "We couldn't check whether your other addresses are in use, so single address mode isn't available right now."
Exact copy is for UX to settle. The unknown path may also warrant a retry affordance, since unlike blocked it is likely transient — worth deciding alongside the wording rather than assuming.
Acceptance criteria
References
Summary
When Single Address mode is unavailable, the Address Mode screen shows:
That sentence asserts a specific finding. But the flag behind it is also
truewhen the check failed to run, so on that path we tell the user something we never actually determined.The blocking behaviour is correct and should not change — only the message is wrong on one of the two paths that produce it.
Root cause — one boolean carries two states
AddressMode.jsderivessingleDisabledfromhasTxOutside, which comes from:The
return trueon error is deliberate and right: if we cannot confirm the wallet has no activity past index 0, switching to single would hide funds on the other addresses, so we block. Failing closed is the correct default and this issue does not propose changing it.The consequence is that
hasTxOutside === trueconflates two different situations:hasTxOutsideFirstAddress()threw (network, storage, an unexpected wallet-lib state). The banner is a confident claim about something we never established.A single boolean cannot express both, so the copy cannot be fixed by rewording alone.
Worth noting how reachable path 2 is: it covers any transient failure of the underlying call, and the user gets no hint that anything went wrong.
onExceptionCaptured(e, false)reports the error to us, but the screen presents a definitive explanation to them.Proposed direction
Replace the boolean with a tri-state —
'available' | 'blocked' | 'unknown'— and give each its own message:blocked→ keep today's wording; it is correct there.unknown→ something honest about not having been able to verify, e.g. "We couldn't check whether your other addresses are in use, so single address mode isn't available right now."Exact copy is for UX to settle. The
unknownpath may also warrant a retry affordance, since unlikeblockedit is likely transient — worth deciding alongside the wording rather than assuming.Acceptance criteria
References
src/screens/AddressMode.js.