Skip to Content

BTC Signer

Bitcoin UTXO signing guide. Covers address confirmation and P2PKH / P2SH-P2WPKH / P2WPKH / Taproot signing with strict path–script matching and complete refTxs. Behavior aligned with hardware-js-sdk (Promise responses + UI events).

Index

  1. How it works
  2. Installation
  3. Initialization
  4. Common scenarios
  5. Interaction & Status
  6. Examples
  7. Validation & Troubleshooting

How it works

OneKey BTC signer talks to the device app via HardwareSDK, wraps APDUs into UTXO review and signing tasks.

  • Paths must match script purpose (44/49/84/86).
  • Each input needs a full previous transaction (refTxs), otherwise the device rejects.
  • The device shows inputs, outputs, change, and fee; after confirmation it returns signatures or a serialized tx.

Installation

npm i @onekeyfe/hd-core @onekeyfe/hd-common-connect-sdk

Initialization

import HardwareSDK from '@onekeyfe/hd-common-connect-sdk'; await HardwareSDK.init({ env: 'webusb', fetchConfig: true, debug: false }); const [{ connectId }] = await HardwareSDK.searchDevices(); const deviceId = (await HardwareSDK.getFeatures(connectId)).payload?.device_id;

Common scenarios

Scenario 1: Get Address

const res = await HardwareSDK.btcGetAddress(connectId, deviceId, { path: "m/84'/0'/0'/0/0", coin: 'btc', showOnOneKey: true, }); // res.payload.address, publicKey?, path

Parameters

  • path / address_n: required; must match purpose.
  • coin: required; e.g., btc, test.
  • showOnOneKey?: optional; display and confirm on device.

Returns

Promise<{ success, payload: { address, path, publicKey?, chainCode? } }>

Scenario 2: Sign Transaction

const { success, payload } = await HardwareSDK.btcSignTransaction(connectId, deviceId, { coin: 'btc', inputs, outputs, refTxs, locktime: 0, }); // payload.serializedTx (ready to broadcast)

Parameters

  • coin: required; selects network rules.
  • inputs: required array with:
    • address_n (path matched to script)
    • prev_hash (txid hex)
    • prev_index (vout)
    • amount (string satoshi)
    • script_type (SPENDADDRESS / SPENDP2SHWITNESS / SPENDWITNESS / SPENDTAPROOT)
  • outputs: required array with:
    • Recipient: address + amount + script_type (e.g., PAYTOADDRESS)
    • Change: address_n + amount + script_type aligned to purpose
  • refTxs: required; full previous transactions for every input.
  • locktime?: optional.

Returns

Promise<{ success, payload: { serializedTx, signatures?: any } }>

Interaction & Status

  • APIs resolve on completion; user prompts arrive via UI_REQUEST (unlock device, open BTC app, confirm inputs/outputs/change/fee).
  • Run calls serially per device; use showOnOneKey to confirm receive/change paths before signing.

Examples

P2SH-P2WPKH transaction

import HardwareSDK from '@onekeyfe/hd-common-connect-sdk'; await HardwareSDK.init({ env: 'webusb', debug: false }); const [{ connectId }] = await HardwareSDK.searchDevices(); const deviceId = (await HardwareSDK.getFeatures(connectId)).payload?.device_id; const path49 = [(49 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, 0, 0]; await HardwareSDK.btcGetAddress(connectId, deviceId, { path: path49, coin: 'btc', showOnOneKey: true }); const inputs = [ { address_n: path49, prev_index: 0, prev_hash: 'b035d89d4543ce5713c553d69431698116a822c57c03ddacf3f04b763d1999ac', amount: '3382047', script_type: 'SPENDP2SHWITNESS', }, ]; const outputs = [ { address_n: [(49 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, 1, 1], amount: '3181747', script_type: 'PAYTOP2SHWITNESS', // change }, { address: '18WL2iZKmpDYWk1oFavJapdLALxwSjcSk2', amount: '200000', script_type: 'PAYTOADDRESS', // recipient }, ]; const refTxs = [ { hash: 'b035d89d4543ce5713c553d69431698116a822c57c03ddacf3f04b763d1999ac', version: 1, lock_time: 0, inputs: [/* previous tx inputs */], bin_outputs: [/* previous tx outputs */], }, ]; const { success, payload } = await HardwareSDK.btcSignTransaction(connectId, deviceId, { coin: 'btc', inputs, outputs, refTxs, locktime: 0, }); if (success) { console.info('signed tx:', payload.serializedTx); // ready to broadcast }

Validation & Troubleshooting

  • Path ↔ script: 44'→P2PKH, 49'→P2SH-P2WPKH, 84'→P2WPKH, 86'→P2TR.
  • refTxs must cover every input; missing data is rejected.
  • Change output should stay within the same account path.
  • Verify on device: inputs, outputs, change, fee must match your UI.
  • Host verify: rebuild with bitcoinjs-lib / @scure/btc-signer, check serializedTx/txid and signatures.
  • Common issues:
    • Too many inputs: split transactions or simplify.
    • Fee anomalies: recalc outputs/change; respect dust rules.
    • User reject/timeout: offer retry/cancel; no auto-resubmission.

See method docs: btcSignTransaction · btcGetAddress.

Last updated on