feat(rpc,sdk,rest): expose 5 new message-signing methods#140
Merged
Conversation
Pairs with keepkey/hdwallet#38 (merged) which added the underlying hdwallet methods and firmware PRs #221-#224 / #217 on the integration release/7.14.1 branch. New surface exposed at every layer: shared/rpc-schema.ts: 5 new request entries - tronSignMessage, tronVerifyMessage, tronSignTypedHash - tonSignMessage - solanaSignOffchainMessage bun/index.ts: 5 RPC handlers (engine.wallet.X pass-through with emuSigningOp wrapper for emulator runs, hex-encoding for transport) bun/schemas.ts: 5 zod request schemas with hex/text encoding selectors, domain/message hash length regex (TIP-712 must be exactly 32 bytes each), version + format range constraints (Solana off-chain spec) bun/rest-api.ts: 5 REST endpoints - POST /tron/sign-message (TIP-191 personal_sign) - POST /tron/verify-message (TIP-191 verify, returns {verified}) - POST /tron/sign-typed-hash (TIP-712 hash mode) - POST /ton/sign-message (bare Ed25519, AdvancedMode-gated firmware) - POST /solana/sign-offchain-message (domain-separated envelope) keepkey-sdk/src/types.ts: 9 new TypeScript interfaces keepkey-sdk/src/index.ts: 5 new SDK methods on solana / tron / ton namespaces modules/hdwallet bumped to bf76b0a4 (PR #38 merge commit on master) which provides the underlying tronSignMessage / tronVerifyMessage / tronSignTypedHash / tonSignMessage / solanaSignOffchainMessage methods. Verified locally: hdwallet builds clean, vault tsc --noEmit shows no new errors (1 pre-existing minimatch type config issue unchanged). Live signing requires firmware 7.14.1+; with stock 7.14.0 the device will return Failure_UnknownMessage.
1. Schema doc comments inverted is_text semantics (the implementation
was correct, the comments said the opposite). Fixed all 5 schemas to
match the SDK type docs:
'Default: encoded as UTF-8 bytes. If is_text=false, expect hex'
This matters because zod schema doc comments are what surface in any
auto-generated OpenAPI / type-derived docs.
2. Empty-message handling was inconsistent: TRON sign/verify used min(0)
while TON / Solana off-chain used min(1). Aligned to min(1) across all
five — empty signing payloads are almost always a caller bug, and
firmware-level zero-length support remains exercisable via the SDK
directly if needed.
3. Strict hex parsing: Buffer.from(str, 'hex') silently truncates on
non-hex chars or odd length, which surfaces downstream as confusing
wrong-length errors. Added a parseHex(input, label, expectedBytes?)
helper that throws a clear 400 up front. Replaced inline hex parsing
in all 5 endpoints. Also added a HEX_SIG_65 regex on
TronVerifyMessageRequest.signature so zod rejects malformed sigs
before the handler runs.
4. Added decodeMessageBody() helper to centralize the
is_text-defaults-true / hex-when-false decoding pattern that was
duplicated in 4 of 5 handlers.
Pre-existing review nit (RPC layer accepts only camelCase addressNList,
not snake_case address_n) deliberately left as-is for parity with the
existing solanaSignTx / tonSignTx handlers — would be a fork of an
existing convention rather than a fix.
5. Solana off-chain 1212-byte ceiling now enforced at two layers:
- Schema: SolanaSignOffchainMessageRequest.message capped at 2424
chars (worst case = hex bytes). Defense-in-depth + DoS protection.
- Handler: post-decodeMessageBody check against 1212 bytes (the
actual spec ceiling for formats 0/1). Surfaces with a clear 400
pre-USB-roundtrip and points at the off-chain spec, instead of the
opaque firmware Failure that was the only signal before.
6. toHex helper consolidates the
v instanceof Uint8Array ? Buffer.from(v).toString('hex') : v
pattern in rest-api.ts (4 sites in the new handlers) and a parallel
bytesToHex helper in bun/index.ts (4 sites). Pre-existing inline
patterns elsewhere in both files left untouched per the
surgical-changes rule — this PR only consolidates its own duplicates.
Both flagged as 'Style only' / optional cleanups in the review;
applying both since the user asked for the touch-up before merge.
Item 4 (signature/message hex truncation) is already covered by the
parseHex helper added in 4a8937c — the runtime check rejects garbage
hex with a clear 400 across all 5 endpoints. The hex-mode 'message'
field can't easily get a zod regex since its semantics are conditional
on is_text, but the runtime check covers the same ground.
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.
Summary
Wires the new firmware 7.14.1 message-signing methods through every vault layer — RPC schema, Bun handlers, REST endpoints, SDK types, SDK methods.
Pairs with keepkey/hdwallet#38 (merged), which added the underlying `tronSignMessage` / `tronVerifyMessage` / `tronSignTypedHash` / `tonSignMessage` / `solanaSignOffchainMessage` methods, and firmware integration branch `BitHighlander/keepkey-firmware:release/7.14.1` (PRs #221-#224, #217).
New API surface
REST endpoints
SDK methods
Files changed
Test plan
Known caveats