Skip to content

fix(btc): read the vault's scriptType so dApps get the segwit address - #161

Open
BitHighlander wants to merge 1 commit into
masterfrom
fix/btc-script-type
Open

BitHighlander wants to merge 1 commit into
masterfrom
fix/btc-script-type

Conversation

@BitHighlander

Copy link
Copy Markdown
Collaborator

Problem

KeepKey Desktop's /api/pubkeys/batch returns UTXO rows as { pubkey: '<xpub>', address: '', scriptType: 'p2wpkh' } (camelCase; projects/keepkey-vault/src/bun/rest-api.ts, the batch handler). The SDK passes them through unchanged. The extension reads script_type (snake_case) everywhere, so every UTXO row looked like it had no script type:

  • utxoAccountFromPubkeyRow fell back to p2pkh, so request_accounts handed dApps the legacy encoding of the native-segwit key. On swaps.pro, a USDC → BTC swap's recipient was 1JaUQDVN…c54Hso (the legacy encoding of bc1qcr8te4… for the BIP-39 test wallet). BTC sent there doesn't show in KeepKey Desktop's accounts; only Desktop's sweeper recovers it.
  • The pk.script_type lookups in background/index.ts (preferred-account choice, send context, receive address) compared against undefined for the same reason.

The existing tests built rows with script_type, which isn't the shape the vault sends, so this never showed up in CI.

Fix

  • normalizePubkeyRows (in utxoDerive.ts) copies scriptType into script_type when it's missing. wallet.ts applies it to the fresh batch and to cached rows (caches written before this fix lack script_type). Rows that already have script_type, and non-UTXO rows, are left as they are.
  • utxoAccountFromPubkeyRow also accepts either name.
  • Regression tests use the vault's real row shape: a vault BIP84 row → bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu.

Verified

  • make type-check ✅ · make test ✅ (146 pass) · make lint ✅ (no new warnings) · prettier ✅
  • End to end in a studio build of 0.0.38 with this patch, against a stub that answers in the vault's row shape, on the live www.swaps.pro (250,000 USDC → BTC review): recipient was 1JaUQDVN…c54Hso before and is bc1qcr8t…306fyu after. Nothing signed or broadcast. Not yet exercised against a real device and Desktop.

Follow-up worth considering

Anyone who swapped into BTC through the extension with a SegWit account may hold BTC on the legacy encoding of their key. Desktop's sweeper handles it; a support note could point people there.

🤖 Generated with Claude Code

KeepKey Desktop's /api/pubkeys/batch returns rows with `scriptType`
(camelCase) and an empty address. The extension reads `script_type`
everywhere, so every UTXO row looked script-less and derived as p2pkh.
A native-segwit account was handed to dApps as the legacy encoding of
the same key: swaps.pro showed recipient 1JaUQDVN...c54Hso for
bc1qcr8te4..., and BTC swapped there didn't show in Desktop's accounts
(recoverable only through Desktop's sweeper).

Normalize rows at ingestion (fresh batch and cached) so script_type is
set, and let utxoAccountFromPubkeyRow accept either name. Regression
tests use the vault's real row shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant