Skip to Content

Solana

UR registry types for Solana offline signing.

Data Types

  • Request UR: sol-sign-request (transaction/message bytes + BIP-44 path)
  • Response UR: sol-signature

Flow

  1. Prepare Solana transaction or message bytes and derive path
  2. Build sol-sign-request and show as animated QR
  3. Scan device response → decode sol-signature → attach to transaction
  4. Submit to the Solana network

Examples

Install @keystonehq/bc-ur-registry-sol and @ngraveio/bc-ur. The examples require a Buffer implementation. Registry encoding alone does not establish support on a device; verify the UR types accepted by the target firmware.

The wallet supplies the unsigned transaction data and the actual account path and master fingerprint exported by the device. The QR renderer should call nextFrame() on a timer and stop when the signing dialog closes. These snippets encode and decode the transport; they do not submit a transaction.

Build Solana sign request (UR)

import { SolSignRequest, SignType, CryptoKeypath, PathComponent } from '@keystonehq/bc-ur-registry-sol'; // BIP44: m/44'/501'/0' const keypath = new CryptoKeypath([ new PathComponent({ index: 44, hardened: true }), new PathComponent({ index: 501, hardened: true }), new PathComponent({ index: 0, hardened: true }), ], Buffer.from(masterFingerprintHex, 'hex')); const requestId = globalThis.crypto.randomUUID(); const requestIdBytes = Buffer.from(requestId.replace(/-/g, ''), 'hex'); const req = new SolSignRequest({ requestId: requestIdBytes, signData: Buffer.from(rawTxBytes), // transaction or message bytes derivationPath: keypath, signType: SignType.Transaction, // or SignType.Message }); const encoder = req.toUREncoder(200); const nextFrame = () => encoder.nextPart(); // Call from your QR animation timer.

Decode Solana signature (UR)

import { URDecoder } from '@ngraveio/bc-ur'; import { SolSignature } from '@keystonehq/bc-ur-registry-sol'; const dec = new URDecoder(); // dec.receivePart(frameString) for each scanned frame if (dec.isError()) throw new Error('QR decoding failed'); if (dec.isSuccess()) { const ur = dec.resultUR(); if (ur.type !== 'sol-signature') throw new Error('Expected sol-signature'); const sig = SolSignature.fromCBOR(ur.cbor); const returnedId = sig.getRequestId(); if (!returnedId || !returnedId.equals(requestIdBytes)) { throw new Error('Signature request ID does not match'); } const signature = sig.getSignature(); // Verify the signer and signature against the original payload before use. // Attach transaction signatures to the original transaction; return message signatures to the caller. }
Last updated on