fix(swap): make the AdvancedMode path an opt-in, and pin the routing - #419
Merged
Merged
Conversation
A user should never get a dead reject for a transaction AdvancedMode would allow. They should be offered the switch. That machinery already exists and I under-sold it in #417. SwapDialog.tsx:2307 routes on the error CONTENT: if (/AdvancedMode/i.test(raw)) { setBlindSignCause('device') setPhase('blind-signing-required') } which opens the panel whose Enable button calls applyPolicy. So #417's message was already reaching the opt-in, not a reject — the reject is the PRE-#417 path, where hdwallet flattens the firmware's "Blind signing disabled by policy" into a bare "Action cancelled" that matches nothing and falls through to the generic "Cancelled on device". Two things wrong with leaving it there. 1. The copy contradicted the affordance. It said "Enable AdvancedMode on your KeepKey, then try the swap again" — sending the user to device settings for something the dialog was about to offer as a button. Reworded to "Turn on AdvancedMode to continue", and it still states the setting dies on reboot (firmware #373 made it session state, which is why users hit this repeatedly). 2. The routing depended on an unpinned phrase inside prose. Rewording the copy is a normal, innocuous-looking edit that would silently turn the prompt back into a reject, with no test failing. So the message moves to evmAdvancedModeRequiredMessage() in shared/types.ts, beside SOLANA_BLIND_SIGNING_REQUIRED, documented as content-routed and load-bearing. __tests__/advanced-mode-routing.test.ts asserts it matches the SwapDialog predicate for every chain name, does NOT tell the user to go elsewhere, and mentions the reboot. It also pins the predicate from the other side: a bare "Action cancelled" must NOT match (that is the dead end), while firmware-worded refusals must. Content-based routing is deliberate, per the comment above that branch: it also catches refusals phrased by firmware versions this code has never seen. The tests protect the phrase without giving that up. make test-unit 488 pass, 0 fail across 33 files, +35 btc-backend, +10 cosmos tsc --noEmit 627, unchanged, 2 below baseline 629
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A user should never get a dead reject for a transaction AdvancedMode would
allow. They should be offered the switch.
That machinery already exists and I under-sold it in #417. SwapDialog.tsx:2307
routes on the error CONTENT:
which opens the panel whose Enable button calls applyPolicy. So #417's message
was already reaching the opt-in, not a reject — the reject is the PRE-#417 path,
where hdwallet flattens the firmware's "Blind signing disabled by policy" into a
bare "Action cancelled" that matches nothing and falls through to the generic
"Cancelled on device".
Two things wrong with leaving it there.
The copy contradicted the affordance. It said "Enable AdvancedMode on your
KeepKey, then try the swap again" — sending the user to device settings for
something the dialog was about to offer as a button. Reworded to "Turn on
AdvancedMode to continue", and it still states the setting dies on reboot
(firmware feat(hive): serialize limit_order_create / limit_order_cancel #373 made it session state, which is why users hit this repeatedly).
The routing depended on an unpinned phrase inside prose. Rewording the copy
is a normal, innocuous-looking edit that would silently turn the prompt back
into a reject, with no test failing.
So the message moves to evmAdvancedModeRequiredMessage() in shared/types.ts,
beside SOLANA_BLIND_SIGNING_REQUIRED, documented as content-routed and
load-bearing. tests/advanced-mode-routing.test.ts asserts it matches the
SwapDialog predicate for every chain name, does NOT tell the user to go
elsewhere, and mentions the reboot. It also pins the predicate from the other
side: a bare "Action cancelled" must NOT match (that is the dead end), while
firmware-worded refusals must.
Content-based routing is deliberate, per the comment above that branch: it also
catches refusals phrased by firmware versions this code has never seen. The
tests protect the phrase without giving that up.
make test-unit 488 pass, 0 fail across 33 files, +35 btc-backend, +10 cosmos
tsc --noEmit 627, unchanged, 2 below baseline 629