En esta página
Firmante BTC
Guía de firma de UTXO de Bitcoin. Cubre la confirmación de direcciones y la firma P2PKH / P2SH-P2WPKH / P2WPKH / Taproot con coincidencia estricta entre ruta y script y refTxs completas. El comportamiento coincide con hardware-js-sdk (respuestas Promise + eventos de interfaz).
Índice
- Cómo funciona
- Instalación
- Inicialización
- Casos habituales
- Interacción y estado
- Ejemplos
- Validación y resolución de problemas
Cómo funciona
El firmante BTC de OneKey usa HardwareSDK y el protocolo OneKey para solicitar la revisión y firma de UTXO en el dispositivo.
- Las rutas deben coincidir con el propósito del script (44/49/84/86).
- Proporciona las transacciones anteriores completas que solicite el flujo de firma en
refTxs; los requisitos dependen del tipo de entrada y del firmware. - El dispositivo muestra entradas, salidas, cambio y comisión; tras la confirmación devuelve firmas o una transacción serializada.
Instalación
npm i @onekeyfe/hd-core @onekeyfe/hd-common-connect-sdkInicialización
Los ejemplos usan la cartera estándar de forma coherente. Para una cartera oculta, sustituye useEmptyPassphrase: true por el valor verificado de passphraseState en cada llamada de dirección y firma. Registra los controladores de interfaz antes de las llamadas protegidas y comprueba success antes de usar cualquier carga de datos. Los ejemplos con entradas de transacción declaradas son fragmentos de preparación, no aplicaciones ejecutables independientes.
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");Casos habituales
Caso 1: Obtener dirección
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.Parámetros
path: obligatorio; debe coincidir con el propósito.coin: opcional para solicitudes de dirección; por ejemplo,btc,test.showOnOneKey?: opcional; mostrar y confirmar en el dispositivo.
Devuelve
type AddressResult =
| { success: true; payload: { address: string; path: string } }
| { success: false; payload: { error: string; code?: string | number } };Caso 2: Firmar transacción
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.Parámetros
coin: obligatorio; selecciona las reglas de la red.inputs: array obligatorio con:address_n(ruta correspondiente al script)prev_hash(txid hexadecimal)prev_index(vout)amount(satoshis como cadena)script_type(SPENDADDRESS/SPENDP2SHWITNESS/SPENDWITNESS/SPENDTAPROOT)
outputs: array obligatorio con:- Destinatario:
address+amount+script_type(por ejemplo,PAYTOADDRESS) - Cambio:
address_n+amount+script_typecoherente con el propósito
- Destinatario:
refTxs: array obligatorio; incluye todas las transacciones anteriores que solicite el firmware. Usa un array vacío solo si el flujo de firma no necesita ninguna.locktime?: opcional.
Devuelve
type SignResult =
| { success: true; payload: { serializedTx: string; signatures: string[]; txid?: string } }
| { success: false; payload: { error: string; code?: string | number } };Interacción y estado
- Las API se resuelven al finalizar; los avisos al usuario llegan mediante
UI_REQUEST(desbloquear el dispositivo, confirmar entradas/salidas/cambio/comisión). - Ejecuta las llamadas en serie por dispositivo; usa
showOnOneKeypara confirmar las rutas de recepción y cambio antes de firmar.
Ejemplos
Transacción P2SH-P2WPKH
Este es un fragmento de preparación. Sustituye los datos ilustrativos de UTXO y salidas por los de tu transacción y carga las refTxs completas correspondientes antes de llamar al 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.Validación y resolución de problemas
- Ruta ↔ script:
44'→P2PKH,49'→P2SH-P2WPKH,84'→P2WPKH,86'→P2TR. refTxsdebe contener todas las transacciones anteriores solicitadas por el firmware; se rechaza la ausencia de datos solicitados.- La salida de cambio debe permanecer dentro de la misma ruta de cuenta.
- Comprueba en el dispositivo que entradas, salidas, cambio y comisión coincidan con tu interfaz.
- Comprobación en el host: reconstruye con
bitcoinjs-lib/@scure/btc-signer, compruebaserializedTx, el txid y las firmas. - Problemas habituales:
- Demasiadas entradas: informa del límite. Dividir o simplificar una transacción requiere reconstruirla y obtener una nueva revisión del usuario.
- Comisión anómala: detén la firma. Recalcula salidas, cambio y límites de dust con el usuario; no modifiques silenciosamente una transacción ya revisada.
- Rechazo del usuario o tiempo agotado: ofrece reintentar o cancelar; no vuelvas a enviarla automáticamente.
Consulta la documentación de los métodos: btcSignTransaction · btcGetAddress.