feat(emu): expand the confirm dialog to cover the Hive operations#374
Merged
Conversation
/hive/sign-operations hands the device a pre-serialized Graphene blob, so
unlike every other chain the emulator confirm dialog had no params to read
an amount or a counterparty out of. It passed a bare
{ operation: 'hiveSignOperations', chain: 'HIVE' }, which rendered as
Hive Sign Operations
Chain: HIVE
[Confirm] [Reject]
for a transaction that may carry up to four distinct operations. Claiming
rewards, cancelling a market order and powering down all produced the same
prompt, so the dialog told the user nothing about what they were approving.
/hive/sign-message was equally bare — no indication of which login message a
dApp had asked for.
hiveConfirmDetails() expands the condenser-style op array the caller already
serialized into the existing EmulatorConfirmDetails shape, following
evmConfirmDetails: DISPLAY ONLY, never feeding the serializer. A single op
gets its label, counterparty and amount; a batch names the count and lists
the ops rather than claiming one recipient for four operations.
It keeps this module's honesty contract, so it declines to assert what it
does not know:
- no "To:" row for claim_reward_balance / limit_order_cancel /
account_update2, which act on the signer's own account — a recipient
there would be a claim the operation does not make
- a self power-up (to: "") says "self" instead of an empty row
- zero rewards are dropped from a claim so the real amount is not buried
beside "0.000 HBD"
- an absent or unparseable op array falls back to the bare header rather
than guessing; the OLED behind it is still authoritative
hiveMessagePreview() shows the signBuffer payload, round-tripping the UTF-8
decode so a binary Buffer payload is reported as a byte count instead of
rendered as mojibake.
Multi-screen ops (claim_reward_balance is 2 screens, limit_order_create 2,
comment_options 2 + one per beneficiary) raise one prompt per firmware
ButtonRequest, so the same summary shows on each press. That is intended —
the OLED behind it is what advances.
Scope note: this makes the prompt informative, it does NOT add a recovery
path. A confirm that is never answered still leaves confirm_helper blocked
on the poll thread, which wedges the emulator so that every subsequent
request from any chain fails with "Malformed tiny packet" until the emulator
is force-quit. Cancel is a legal tiny message, so the vault can unwedge
itself; that belongs in its own change.
11 new tests; 129 pass across the deterministic units (this file,
txbuilder/hive-ops, rest-sign-gating). The live-device integration tests in
this suite vary run to run independently of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… payloads
Two review findings on this PR:
1. toFixed(0) misreported fractional vote weights. Weight is basis points, so
1bp = 0.01%: a 1 showed as "0%", a 50 (0.5%) as "1%", a -50 as "-1%". The
dialog was stating a value different from the one being signed. Now keeps
up to two decimals and drops trailing zeros, so 10000 still reads "100%".
2. hiveMessagePreview's UTF-8 round-trip only catches MALFORMED UTF-8. Bytes
00 01 02 03, embedded NULs, and bidi/zero-width controls are all valid
UTF-8, so they passed the check and rendered as invisible or reordered
"text" — U+202E can make the displayed string differ from the bytes
signed, which is the exact misrepresentation this module exists to avoid.
Adds a \p{C} control/format check (tab/newline/CR exempted as ordinary
whitespace) and treats whitespace-only payloads as binary rather than
showing an empty dialog.
+6 regression tests covering both. Suite 17/17.
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.
The gap
Every chain family has a
*ConfirmDetails()expander that turns a signing payload into the emulator's confirm dialog —evmConfirmDetails,cosmosConfirmDetails. Hive had none./hive/sign-operationshands the device a pre-serialized Graphene blob, so unlike every other chain the dialog has nothing to read an amount or counterparty out of. It passed a bare{ operation: 'hiveSignOperations', chain: 'HIVE' }:…for a transaction that may carry up to four distinct operations. Claiming rewards, cancelling a market order and powering down all produced the same prompt.
/hive/sign-messagewas equally bare — no indication which login message a dApp had asked to sign.The change
Hive Sign OperationsClaim Rewards·1.500 HIVE + 1000.000000 VESTSHive Sign OperationsMarket Order·1.500 HIVE → 0.400 HBDHive Sign OperationsDelegate HP·Delegatee: @bob·1000.000000 VESTSHive Sign Operations2 Hive operations·Post / Comment · Payout OptionsHive Sign MessageSign Message·{login: "bithighlander22"}hiveConfirmDetails()expands the condenser-style op array the caller already serialized, followingevmConfirmDetails. Display only — it never feeds the serializer.Honesty contract
This module's stated job is "not to MISREPRESENT," so the expander declines to assert what it doesn't know:
To:row.claim_reward_balance,limit_order_cancelandaccount_update2act on the signer's own account. A recipient row there would be a claim the operation does not make.to: "") saysself, not an empty row.0.000 HBD.hiveMessagePreview()round-trips the UTF-8 decode, so a binary Buffer payload reports as4 bytes (binary)instead of rendering as mojibake.Multi-screen behaviour
claim_reward_balanceis 2 screens,limit_order_create2,comment_options2 + one per beneficiary. One prompt fires per firmware ButtonRequest, so the same summary shows on each press. Intended — the OLED behind it is what advances.Scope: this does NOT fix the wedge
Worth being explicit, because the two are related. A confirm that is never answered leaves
confirm_helperblocked on the poll thread, which wedges the emulator: every subsequent request, on every chain, then fails withMalformed tiny packetuntil the emulator is force-quit. That was observed in the field — an EVM sign and a HivesignBufferboth failing that way, cleared by restarting the emulator.An uninformative prompt makes that wedge more likely to be reached, which is why this is worth landing. But it is not the fix.
Cancelis one of the legal tiny messages (msg_tiny's static_asserts name it), so the vault can unwedge the device itself instead of requiring a force-quit. That belongs in its own change.Verification
emulator-confirm-details.test.ts.txbuilder/hive-ops,__tests__/rest-sign-gating.origin/develop.Branched from
origin/develop, so it does not include the three unpushed local commits on that branch.🤖 Generated with Claude Code