On this page
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
- How it works
- Installation
- Initialization
- Common scenarios
- Interaction & Status
- Examples
- Validation & Troubleshooting
How it works
OneKey BTC signer uses HardwareSDK and the OneKey protocol to request UTXO review and signing on the device.
- Paths must match script purpose (44/49/84/86).
- Provide complete previous transactions requested by the signing flow in
refTxs; the requirements depend on input type and firmware. - 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-sdkInitialization
The examples use the standard wallet consistently. For a hidden wallet, replace useEmptyPassphrase: true with the verified passphraseState on every address and signing call. Register UI handlers before protected calls, and check success before using any payload. Examples containing declared transaction inputs are preparation fragments, not standalone runnable applications.
import HardwareSDK from '@onekeyfe/hd-common-connect-sdk';
const initialized = await HardwareSDK.init({ env: 'webusb', fetchConfig: true, debug: false });
if (!initialized) throw new Error('SDK initialization failed');
const devices = await HardwareSDK.searchDevices();
if (!devices.success) throw new Error(devices.payload.error);
if (!devices.payload.length) throw new Error("No device");
// Select explicitly in the application when more than one device is available.
if (devices.payload.length !== 1) throw new Error('Select exactly one device before continuing');
const { connectId } = devices.payload[0];
if (!connectId) throw new Error("Missing connectId");
const state = await HardwareSDK.getDeviceState(connectId);
if (!state.success) throw new Error(state.payload.error);
const deviceId = state.payload.identity.deviceId;
if (!deviceId) throw new Error("Device has no wallet identity");Common scenarios
Scenario 1: Get Address
const res = await HardwareSDK.btcGetAddress(connectId, deviceId, {
useEmptyPassphrase: true,
path: "m/84'/0'/0'/0/0",
coin: 'btc',
showOnOneKey: true,
});
if (!res.success) throw new Error(res.payload.error);
// res.payload.address and res.payload.path are strings.Parameters
path: required; must match purpose.coin: optional for address requests; e.g.,btc,test.showOnOneKey?: optional; display and confirm on device.
Returns
type AddressResult =
| { success: true; payload: { address: string; path: string } }
| { success: false; payload: { error: string; code?: string | number } };Scenario 2: Sign Transaction
const { success, payload } = await HardwareSDK.btcSignTransaction(connectId, deviceId, {
useEmptyPassphrase: true,
coin: 'btc',
inputs,
outputs,
refTxs,
locktime: 0,
});
if (!success) throw new Error(payload.error);
// Verify payload.serializedTx and payload.signatures before broadcasting.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_typealigned to purpose
- Recipient:
refTxs: required array; supply all previous transactions requested by firmware. Use an empty array only when the signing flow needs none.locktime?: optional.
Returns
type SignResult =
| { success: true; payload: { serializedTx: string; signatures: string[]; txid?: string } }
| { success: false; payload: { error: string; code?: string | number } };Interaction & Status
- APIs resolve on completion; user prompts arrive via
UI_REQUEST(unlock device, confirm inputs/outputs/change/fee). - Run calls serially per device; use
showOnOneKeyto confirm receive/change paths before signing.
Examples
P2SH-P2WPKH transaction
This is a preparation fragment. Replace the illustrative UTXO/output data with your transaction and load matching complete refTxs before calling the SDK.
import HardwareSDK from '@onekeyfe/hd-common-connect-sdk';
import type { BTCSignTransactionParams } from '@onekeyfe/hd-core';
const initialized = await HardwareSDK.init({ env: 'webusb', debug: false });
if (!initialized) throw new Error('SDK initialization failed');
const devices = await HardwareSDK.searchDevices();
if (!devices.success) throw new Error(devices.payload.error);
if (!devices.payload.length) throw new Error("No device");
// Select explicitly in the application when more than one device is available.
if (devices.payload.length !== 1) throw new Error('Select exactly one device before continuing');
const { connectId } = devices.payload[0];
if (!connectId) throw new Error("Missing connectId");
const state = await HardwareSDK.getDeviceState(connectId);
if (!state.success) throw new Error(state.payload.error);
const deviceId = state.payload.identity.deviceId;
if (!deviceId) throw new Error("Device has no wallet identity");
const path49 = [(49 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, 0, 0];
const confirmedAddress = await HardwareSDK.btcGetAddress(connectId, deviceId, {
path: path49, coin: 'btc',
showOnOneKey: true,
useEmptyPassphrase: true,
});
if (!confirmedAddress.success) throw new Error(confirmedAddress.payload.error);
const inputs: BTCSignTransactionParams['inputs'] = [
{
address_n: path49,
prev_index: 0,
prev_hash: 'b035d89d4543ce5713c553d69431698116a822c57c03ddacf3f04b763d1999ac',
amount: '3382047',
script_type: 'SPENDP2SHWITNESS',
},
];
const outputs: BTCSignTransactionParams['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
},
];
// Load complete previous transactions matching each requested prev_hash.
declare const refTxs: BTCSignTransactionParams['refTxs'];
const { success, payload } = await HardwareSDK.btcSignTransaction(connectId, deviceId, {
useEmptyPassphrase: true,
coin: 'btc',
inputs,
outputs,
refTxs,
locktime: 0,
});
if (!success) throw new Error(payload.error);
// Verify the signed transaction before submitting it through your Bitcoin client.Validation & Troubleshooting
- Path ↔ script:
44'→P2PKH,49'→P2SH-P2WPKH,84'→P2WPKH,86'→P2TR. refTxsmust contain every previous transaction requested by the firmware; missing requested 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, checkserializedTx/txid and signatures. - Common issues:
- Too many inputs: report the limit. Splitting or simplifying a transaction requires rebuilding it and obtaining a new user review.
- Fee anomaly: stop signing. Recalculate outputs, change, and dust limits with the user; do not silently alter a reviewed transaction.
- User reject/timeout: offer retry/cancel; no auto-resubmission.
See method docs: btcSignTransaction · btcGetAddress.