-
-
Notifications
You must be signed in to change notification settings - Fork 2
Comparing changes
Open a pull request
base repository: keepkey/keepkey-client
base: master
head repository: keepkey/keepkey-client
compare: develop
- 7 commits
- 23 files changed
- 3 contributors
Commits on Jul 18, 2026
-
Merge pull request #128 from keepkey/master
chore: sync master back into develop (0.0.37 drop-scripting)
Configuration menu - View commit details
-
Copy full SHA for 5be0b82 - Browse repository at this point
Copy the full SHA 5be0b82View commit details
Commits on Jul 20, 2026
-
feat(hive): limit_order_create / limit_order_cancel clear-sign gate (#…
…130) * docs(hive): handoff for vault limit_order_create/cancel serializer Firmware clear-signs both ops (PR #315). Vault has no serializer for them, so Hive internal-market swaps still fail at hive_broadcast. Doc pins the byte layout the firmware parser expects. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * feat(hive): allow limit_order_create / limit_order_cancel Opens the client clear-sign gate now that the vault serializer exists (keepkey-vault #373) and the firmware parses both ops (keepkey-firmware #315). Adds an approval-screen summary line for each. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 2b191ab - Browse repository at this point
Copy the full SHA 2b191abView commit details -
feat(bex): every page-touching MCP tool shows UI in the page (#129)
The driving overlay fired only from showThen(), which has three callers — click, type and select. Every other tool that touches a page ran with no indication to the user at all: bex_snapshot, bex_find and bex_read_page read the DOM, bex_console/bex_network/bex_perf read page state, bex_storage reads localStorage, and bex_screenshot captures the tab. Reading and capturing a user's page are precisely the operations that most need to be visible. Enforce it at the dispatcher instead of per call site. executeBrowserTool() announces before the switch, so a tool added later is covered by construction rather than by remembering. Each tool is either in ANNOUNCE_CAPTIONS or in NO_ANNOUNCE with a stated reason; announceContract.test.ts fails the build on any tool that is in neither, so a silent tool cannot ship. Exempt, with reasons: bex_panel is the UI itself; bex_tabs touches no page; bex_navigate and bex_bring_to_front are self-evident (the user watches their own tab move); click/type/select are already announced page-side by showThen, which additionally points at the target. bex_screenshot now refuses a tab whose content script is missing. Reaching the content script is what proves the tab CAN show the indicator, and it is already required to hide the overlay out of the capture — so a capture that cannot be announced is no longer taken. The remedy is the page reload the no_content_script error already names. Banner lifetime: BANNER_IDLE_MS was 8s, so the "MCP is driving this tab" banner vanished during any quiet stretch — including while waiting on a hardware-wallet confirmation, the longest silence and the highest stakes in the whole flow. It now stays up until the agent says it is done (panel 'done' or hide), with a 5 minute safety net for an agent that dies mid-session. No new permissions. The overlay is plain DOM in the content script that is already declaratively injected on <all_urls>; the scripting permission dropped in b3e3126 was only ever for executeScript into pre-existing tabs.
Configuration menu - View commit details
-
Copy full SHA for 09e4ca8 - Browse repository at this point
Copy the full SHA 09e4ca8View commit details -
fix(hive): render op summaries in the approval card (#131)
* fix(hive): render op summaries in the approval card hiveHandler built a one-line summary per operation (opSummary) into unsignedTx.operations and no component ever read it. Grepping pages/side-panel/src/approval for `.operations` returned zero hits, so a Hive batch fell through to the generic amount table, which has no destination or amount to show for an op batch and rendered "N/A" and "0". The summaries surfaced only inside RequestDataCard's collapsed raw-JSON dump. That matters most for the four ops the extension does not construct itself — claim_reward_balance, account_update2, limit_order_create and limit_order_cancel reach the device via requestBroadcast, so a dApp composes them and the panel was the user's only look at them before the device screen. The OLED is authoritative and was always correct, so this was never a signing hole; but the clear-sign table exists so the user can compare the screen against what the dApp asked for, and half of that comparison was an unreadable blob. RequestDetailsCard now renders the account plus one row per op, falling back to the op name rather than blanking a row — an unsummarized op must stay visible, not disappear. SUPPORTED_OPS and opSummary move to hiveOps.ts, a leaf module. hiveHandler.ts imports @extension/storage, which touches chrome.* at import time and throws under vitest ("chrome is not defined"), so the table was untestable where it lived. No logic changed in the move. hiveOpSummary.test.ts pins the contract the card depends on: every op in SUPPORTED_OPS must summarize to something other than its own bare name (opSummary's default arm returns `name`, which is exactly the unreadable render this fixes) and must carry a test payload. It also pins the details a user has to check against the OLED — amounts with their symbols, the counterparty account, the '0.000000 VESTS' sentinels that mean stop/remove rather than "send zero", and comment_options beneficiary names and percentages, since a payout redirect is the one thing in the table an attacker would most want unreadable. Differential-verified: deleting the limit_order_create case fails with "limit_order_create falls through to the default arm — add a case to opSummary()". 121 tests pass, up from 116. type-check clean across all 15 packages. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * fix(hive): show the signed payload, not a lossy render of it Review of #131 found three ways the approval could differ from what the device signs. custom_json rendered String(p.json). The vault serializes `typeof json === 'string' ? json : JSON.stringify(json ?? {})` (hive-ops.ts:151), so a dApp passing an object got "[object Object]" in the panel while the object's real contents went to the device — the approval showed neither the value nor that it was hiding one. Mirror the vault's own expression instead. Truncation at 120 chars was unmarked, so two payloads sharing a prefix rendered as the same string. The cut now carries the dropped length. comment_options showed only the post and its beneficiaries, omitting max_accepted_payout, percent_hbd, allow_votes and allow_curation_rewards. A declined payout, an all-HIVE split and a votes-disabled post therefore had identical browser approvals. Every control that differs from the Hive default is now named; defaults stay quiet so the common case remains a one-liner. percent_steem_dollars is read as the alias the vault also accepts (hive-ops.ts:225) — ignoring it would have shown the default while a non-default value was signed. unsignedTx.operations kept only {op, summary}, so the Raw tab could not recover what the summary elides. It now carries `params` verbatim. RequestDataCard renders transaction.unsignedTx and nothing else — the event's own `request` is never displayed in any tab — so this is the only surface on which the operation body appears at all. The approval also opened on the Raw tab (defaultIndex={1}), whose data section is useState(false) and so renders a collapsed chevron with no transaction facts on it. A user could approve having seen nothing. Basic is now the default. This affects all five chains routed to OtherTransaction (ripple, solana, ton, tron, hive), and is an improvement or a wash for each: Hive, Ripple and Tron contract-calls gain a populated table, and the chains that render N/A in Basic were previously landing on an empty panel anyway, so the cost is one click to reach Raw and no fact became less visible. Differential-verified: restoring String(p.json) fails with "expected 'follow: [object Object]' not to contain '[object Object]'"; dropping the payout controls fails with "expected 'Payout options for @alice/a-post' to contain '0.000 HBD'". 125 tests pass, up from 121. type-check, prettier and build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>Configuration menu - View commit details
-
Copy full SHA for e2a0e57 - Browse repository at this point
Copy the full SHA e2a0e57View commit details
Commits on Jul 31, 2026
-
fix(injected): reject with an Error, not a bare string
Closes #132. The background sends failures across postMessage as a plain string (`sendResponse({ error: formatUserError(error) })`), and every injected provider rejected with that string untouched. EIP-1193 requires rejecting with an object carrying `code` and `message`, and dApp libraries rely on it: wagmi/viem/ethers inspect the rejection value, `in` throws on a primitive, and the user gets TypeError: Cannot use 'in' operator to search for 'data' in KeepKey Vault is not running. Open the KeepKey Vault desktop app... instead of the instruction we wrote for exactly that situation. The message we most want read is the one we made unreadable. Nothing about that message is special — every error from the extension rejected as a primitive. It is just long enough to make the TypeError absurd. Add toProviderError() and apply it at all five reject sites: injected.ts (EVM), solana-provider, tron-provider, solana-wallet-standard. It keeps an existing Error by reference so stacks are not discarded, preserves a `code` when one is already set, rebuilds structured errors that lost their prototype crossing postMessage, and never throws — a normalizer that can fail is worse than the bug it fixes. Follow-up (deliberately not in this change): formatUserError() flattens errors to a string, so the 4900 "provider disconnected" code from createVaultRequiredError() is dropped before it reaches the dApp. Sending `{ message, code }` would preserve it — toProviderError already handles that shape — but it changes what every consumer of `response.error` receives and wants a side-panel audit first. Co-Authored-By: Claude Opus 5 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 8f6d961 - Browse repository at this point
Copy the full SHA 8f6d961View commit details
Commits on Aug 15, 2026
-
fix(evm): fail over on Chrome network errors instead of claiming the …
…vault is down (#134) A dApp eth_sendTransaction failed with "KeepKey Vault is not running" while the vault was running. Two message-text classifiers combined to turn a dead Ethereum RPC into a false claim about the vault: isTransientRpcError("Failed to fetch") -> false => failover aborts isVaultUnreachableError("Failed to fetch") -> true => "Vault not running" Chrome throws byte-identical text for an unreachable RPC and a closed vault, so no regex can separate them. - isTransientRpcError now covers browser connection-level wording (failed to fetch / load failed / err_ / aborted). It was written against Firefox/Node wording, so the same dead RPC failed over on Firefox and hard-threw on Chrome. The loop now tries the remaining URLs. - Collapse the two copies of the classifier (ethereumHandler + rpcFailover) into one export; they had already drifted. - Log the URL before both definitive throws. That branch was silent while the transient branch logged, so the failing RPC never appeared in the console — the single biggest reason this was misdiagnosed as a vault problem. - formatUserError probes localhost:1646 before blaming the vault, instead of inferring vault state from an arbitrary error string in a catch-all. Tests: browser error strings in rpcFailover.test.ts; utils.test.ts asserts an RPC-origin "Failed to fetch" does NOT produce VAULT_REQUIRED_MESSAGE when the vault answers. Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for b17f979 - Browse repository at this point
Copy the full SHA b17f979View commit details
Commits on Sep 11, 2026
-
Merge pull request #133 from sktbrd/fix/eip1193-reject-with-error
fix(injected): reject with an Error, not a bare string
Configuration menu - View commit details
-
Copy full SHA for 5596fa4 - Browse repository at this point
Copy the full SHA 5596fa4View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff master...develop