Repository navigation
fix(view): offer the review shortcut once, only when blind signing, and make it work - #234
Merged
Merged
Conversation
0xPxt
added a commit
to Zondax/ledger-stacks
that referenced
this pull request
Sep 4, 2026
Picks up the two commits this branch depends on: the skip offered once rather than after every item, keyed on a blind-signed review and working when one is being signed, and the same shortcut on the touch devices through NBGL's Skip control. Without them the progressive review this branch turns on is worse than what it replaces -- the old skip menu, which interrupts every item and does nothing at all when blind signing. Points at Zondax/ledger-zxlib#234, which is not merged. Re-point at the merge commit before this leaves draft. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PzJ2P5pR4becLUiDTm17HN
chcmedeiros
marked this pull request as ready for review
September 16, 2026 06:19
chcmedeiros
self-requested a review
September 16, 2026 06:19
chcmedeiros
approved these changes
Sep 16, 2026
The skip menu had three problems, and they compound. It was offered after every item. On a 27-item review that is 25 copies of a screen whose purpose is to shorten the review, so taking the offer at the first opportunity was the only way it ever saved anything. It is now an ordinary step at a fixed slot in the flow, straight after the review title and before the first item: offered once, up front, with reading uninterrupted afterwards. Walking back onto it works, because it is a position in the ring rather than something injected and withdrawn while the review runs. That also retires the custom button callback the interstitial needed -- left and right are the flow engine's job again. Taking it did nothing at all when blind signing. The flow builder and the skip handler each chose the approval step, and disagreed: the builder uses the blind-signing variant, the handler always asked ux_flow_init to start at the plain one, which is absent from that flow, so nothing moved. Both now go through approval_step(), which makes the mismatch impossible rather than merely fixed. It was offered on any review. That is the important one. A shortcut on an ordinary review is a way to approve without reading -- blind signing in all but name, reached without the warning that names it and without the setting the user had to turn on first. h_review_is_skippable() now requires app_mode_blindsign_required(), and a review long enough to be worth skipping at all; short ones spend a screen to save two clicks. Skipping also leaves the paging one index past the last item, as reading to the end does, so stepping back from the approval shows the end of the transaction rather than restarting it. MAX_REVIEW_UX_SCREENS goes 10 -> 12. The added step makes the worst-case flow eleven entries, and that array is a global: overrunning it would have corrupted whatever follows rather than failing where you could see it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PzJ2P5pR4becLUiDTm17HN
NBGL draws its "Skip" control only for an operation that asks for it, and nothing here ever did, so a touch review had no way to the approval short of tapping through every page. The same reviews the Nano now offers a skip on ask for it: blind signed, and long enough to be worth skipping. Deliberately the platform's control rather than the Nano's screen. On touch the header button costs no page and no extra tap, and the SDK already asks "Skip review?" before honouring it, so the shortcut cannot be taken by accident. Reproducing the Nano's single offer page would mean rebuilding the review out of nbgl_useCaseGenericReview and hand-writing the blind-signing intro and the "Accept risk and sign" page, which are the SDK's to own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PzJ2P5pR4becLUiDTm17HN
The review shortcut changes behaviour for every consumer that draws a review: it is now offered once instead of after every item, only on a blind-signed review past REVIEW_SKIP_MIN_ITEMS, and on touch devices it appears at all for the first time. An app pinning zxlib needs a version to move to in order to pick that up. Minor rather than major because nothing in include/ changed shape -- the new predicate and REVIEW_SKIP_MIN_ITEMS live in view_internal.h, so no consumer has to touch its own code to keep building.
0xPxt
force-pushed
the
feat/review-fast-path
branch
from
September 16, 2026 06:54
3f986b2 to
dae3f4a
Compare
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.
Value
A user who has turned blind signing on, and who signs the same call repeatedly,
had no way to reach the approval except by tapping or clicking through every
screen. A wide DeFi withdrawal is 27 display items; the device has already told
them it cannot fully explain one of the arguments, so most of that paging buys
nothing.
The skip menu was meant to be that way out. It did not work.
screen whose whole purpose is to shorten the review.
wanted most. Pressing both buttons left the screen exactly where it was.
there is a way to approve without reading, reached without the blind-signing
warning and without the setting the user had to turn on.
Technical
h_review_is_skippable()is the single predicate all three UIs share: blindsigned, and past
REVIEW_SKIP_MIN_ITEMS. Counting the transaction's own displayitems rather than the screens wrapped around them keeps the answer the same on
every device.
On bagl the skip becomes an ordinary
UX_STEP_CBat a fixed slot before the firstitem, so it is a position in the ring rather than something injected and withdrawn
mid-review. The custom button callback the interstitial needed is gone — left and
right are the flow engine's job again, which is most of the diff in
view_x.c.The blind-signing failure was a disagreement:
run_ux_review_flowputux_review_flow_3_step_blindsignin the flow while the skip handler always askedux_flow_initto start atux_review_flow_3_step, which that flow does notcontain. Both now call
approval_step(), so the mismatch cannot come back.Skipping leaves the paging one index past the last item, as reading to the end
does, so stepping back from the approval shows the end of the transaction.
MAX_REVIEW_UX_SCREENSgoes 10 → 12: the added step makes the worst-case floweleven entries in a global array.
On NBGL the same reviews now set
SKIPPABLE_OPERATION. That is the platform's owncontrol, and deliberately not a copy of the Nano screen — reproducing that would
mean rebuilding the review from
nbgl_useCaseGenericReviewand hand-writing theblind-signing intro and the "Accept risk and sign" page, which are the SDK's to
own.
Verification
Exercised through
Zondax/ledger-stacks#246, which turns the progressive review on:and sign", never the plain approval.
past it uninterrupted, back-navigation lands on the last item, and a long
transaction that is not blind signed offers nothing.
Notes for review
main, andzxversion.hnow goes to 52.3.0 so apps have aversion to move to. Minor rather than major: nothing in
include/changedshape, since
h_review_is_skippable()andREVIEW_SKIP_MIN_ITEMSboth live inview_internal.h, so a consumer picks this up without touching its own code.view_s.c(Nano S) gets the same gate but is not compile-checked — the app Iverified against cannot build that target at all.
REVIEW_SKIP_MIN_ITEMS = 12is a judgement call; apps can override it.APP_BLINDSIGN_MODE_ENABLEDnow get no shortcut at all, since thereis no opted-in state to key it on. Deliberate, but it is a behaviour change for
any such app using the progressive review.
https://claude.ai/code/session_01PzJ2P5pR4becLUiDTm17HN