Skip to main content

BTC PSBT

PSBT data handling for offline signing with animated UR codes.

Type Map

  • Request/response UR type: crypto-psbt
  • See also: Basic API (UR primitives and structures)

Steps

  1. Build an unsigned PSBT with your wallet backend
  2. Encode PSBT → UR (crypto-psbt) and display as animated QR
  3. Device scans → returns signed PSBT as crypto-psbt
  4. Finalize and broadcast

Tip: Keep PSBT size within practical QR limits; split across frames as needed.

Samples

Encode unsigned PSBT → animated QR

import { CryptoPSBT } from "@keystonehq/bc-ur-registry-btc";
import { airGapUrUtils } from "@keystonehq/keystone-sdk";

const psbtBytes = Buffer.from(unsignedPsbtBase64, "base64");
const req = CryptoPSBT.fromPSBT(psbtBytes); // 也可以写成 new CryptoPSBT(psbtBytes)
const ur = req.toUR();
const frames = airGapUrUtils.urToQrcode(ur); // Render the frames in your UI

Decode animated QR → signed PSBT

import { URDecoder } from "@ngraveio/bc-ur";
import { CryptoPSBT } from "@keystonehq/bc-ur-registry-btc";

const dec = new URDecoder();
// For each frame string scanned by the camera:
// hand frameString to dec.receivePart for each frame

if (dec.isComplete()) {
const ur = dec.resultUR(); // the UR type should resolve to 'crypto-psbt'
const psbt = CryptoPSBT.fromCBOR(ur.cbor);
const signedPsbt = psbt.getPSBT(); // PSBT buffer after full or partial signing
// Finalize and broadcast it through your backend
}