BTC Flow
This guide walks through BTC address confirmation and UTXO transaction signing with UKey Wallet. The fragile parts of a Bitcoin flow are usually mismatched paths, script types, previous transactions, or change outputs, so the focus here is how those fields are reviewed and verified on the device.
Table of contents
How It Works
BTC related methods are invoked through the SDK entry, and the device reviews inputs, outputs, change, and fees according to the UTXO model. The app needs to provide enough complete transaction context that the device can confirm that what the user sees is consistent with the final transaction.
- The HD path must correspond to the script purpose, such as 44, 49, 84, 86.
- Each input should find the complete preceding transaction in
refTxs. - The change output must use the correct path and script type, otherwise the device cannot safely determine whether it belongs to the user.
- After the user confirms, the SDK returns results such as a signature, serialized transaction, or transaction ID.
Setup
npm i @ukeyfe/hardware-core @ukeyfe/hardware-common-connect-sdk
Init
import ukeySdk from "@ukeyfe/hardware-common-connect-sdk";
await ukeySdk.init({ env: "webusb", fetchConfig: true, debug: false });
const [{ connectId }] = await ukeySdk.searchDevices();
const deviceId = (await ukeySdk.getFeatures(connectId)).payload?.device_id;
Best For
Scenario 1: Read address
Read the BTC address under the specified path. When displaying it to users for the first time, saving payment addresses, or configuring change paths, enable device-side confirmation.
const path84 = "m/84'/0'/1'/0/0";
const opResult = await ukeySdk.btcGetAddress(connectId, deviceId, {
path: path84,
coin: "btc",
showOnUKey: true,
});
// Example data: opResult.payload.address, publicKey?, path
Input Fields
path/address_n: BIP44-style path, either as a string or number array, aligned with the script purpose.coin: Network selector, for instancebtcortest.showOnUKey?: Enable device-side address review before returning the result.
return
Promise<{ success; payload: { address; path; publicKey?; chainCode? } }>;
Scenario 2: Sign transaction
Before signing the transaction, please confirm that input, output, change and handling fees can be calculated independently by the application. The content displayed on the device should be consistent with the transaction ultimately broadcast on the front end.
const { success, payload } = await ukeySdk.btcSignTransaction(
connectId,
deviceId,
{
coin: "btc",
inputs,
outputs,
refTxs,
locktime: 0,
},
);
// 返回结构大致为: { serializedTx, signatures?, txid? }
Input Fields
coin: Selects the Bitcoin network rules and address prefixes.inputs: Transaction inputs. Include these fields;amountis mandatory for SegWit/Taproot and still preferred for Legacy:address_n(path, matches script)prev_hash(UTXO txid,hex)prev_index(UTXO vout)amount(String satoshi)script_type(SPENDADDRESS/SPENDP2SHWITNESS/SPENDWITNESS/SPENDTAPROOT)
outputs: Transaction outputs. Describe both recipient and change outputs:- Payment address output:
address+amount+script_type(such asPAYTOADDRESS) - Change output:
address_n+amount+script_typeCorresponding script
- Payment address output:
refTxs: Full previous transactions for every input, includinghash,version,lock_time,inputs, andbin_outputsoroutputsaccording to the source transaction format.locktime?: Numeric locktime value when the transaction uses one.
return
Promise<{
success;
payload: { serializedTx; signatures?: string[]; txid?: string };
}>;
Flow & State
- The method returns the result through Promise; interactions such as unlocking, opening BTC App, confirming input/output/change/handling fee are triggered through
UI_REQUESTevent. - Sign serially on the same device to avoid multiple requests waiting for user confirmation at the same time.
- Available before signing
showOnUKeyallows the user to confirm the address and path, especially the change path.
Demo
Example: P2SH-P2WPKH transaction (nested SegWit)
import ukeySdk from "@ukeyfe/hardware-common-connect-sdk";
await ukeySdk.init({ env: "webusb", debug: false });
const [{ connectId }] = await ukeySdk.searchDevices();
const deviceId = (await ukeySdk.getFeatures(connectId)).payload?.device_id;
const path49 = [
(49 | 0x80000000) >>> 0,
(0 | 0x80000000) >>> 0,
(0 | 0x80000000) >>> 0,
0,
0,
];
await ukeySdk.btcGetAddress(connectId, deviceId, {
path: path49,
coin: "btc",
showOnUKey: true,
});
const inputs = [
{
address_n: path49,
prev_index: 0,
prev_hash:
"d29e7c4b1a0f3d5e6c7b8a99112233445566778899aabbccddeeff0012345678",
amount: "3471185",
script_type: "SPENDWITNESS",
},
];
const outputs = [
{
address_n: [
(49 | 0x80000000) >>> 0,
(0 | 0x80000000) >>> 0,
(0 | 0x80000000) >>> 0,
1,
1,
],
amount: "3265985",
script_type: "PAYTOWITNESS", // Note: change
},
{
address: "1FfmbHfnpaZjKFvyi1okTjJJusN455paPH",
amount: "205200",
script_type: "PAYTOADDRESS", // Note: Payee
},
];
const refTxs = [
{
hash: "d29e7c4b1a0f3d5e6c7b8a99112233445566778899aabbccddeeff0012345678",
version: 1,
lock_time: 0,
inputs: [
/* 这里填写前序交易的 inputs */
],
bin_outputs: [
/* 这里填写前序交易的 outputs */
],
},
];
const { success, payload } = await ukeySdk.btcSignTransaction(
connectId,
deviceId,
{
coin: "btc",
inputs,
outputs,
refTxs,
locktime: 0,
},
);
if (success) {
console.info("Signed transaction payload:", payload.serializedTx); // Note: Can be broadcast directly
}
Final Checks
| Checkpoint | What to do |
|---|---|
| Path and script | 44' maps to P2PKH, 49' to P2SH-P2WPKH, 84' to P2WPKH, and 86' to P2TR. |
| Previous transactions | Fill refTxs completely for every input or the device will reject the request. |
| Change address | Keep address_n for change inside the same account path so it is not confused with a recipient output. |
| Screen review | Input, output, change, and fee summaries should match what the device shows. |
| Result check | Rebuild the transaction with bitcoinjs-lib or @scure/btc-signer, then compare txid and serializedTx. |
| Usual blockers | Split oversized inputs, tune outputs and dust handling when fees look off, and expose retry/cancel when the user rejects or times out. |
Continue with the API pages: btcSignTransaction · btcGetAddress.