Skip to Content

Solana Signer

Solana hardware signing guide. Covers address confirmation and message/transaction signing with supported hardened path and serialized rawTx. Aligned with hardware-js-sdk (Promise responses + UI events).

Index

  1. How it works
  2. Installation
  3. Initialization
  4. Common scenarios
  5. Interaction & Status
  6. Example
  7. Validation & Troubleshooting

How it works

OneKey Solana signer uses HardwareSDK to talk to the device. You pass a hex-encoded Solana message bytes in rawTx; the device displays source/destination, amount, and fee summary, then returns a signature. Host attaches the signature with @solana/web3.js and verifies against the public key decoded from the base58 address returned by solGetAddress.

  • Use a firmware-supported hardened path, for example: m/44'/501'/account'/0'.
  • Ensure the message/tx includes a fresh recent blockhash.

Installation

npm i @onekeyfe/hd-core @onekeyfe/hd-common-connect-sdk

Initialization

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.solGetAddress(connectId, deviceId, { useEmptyPassphrase: true, path: "m/44'/501'/0'/0'", showOnOneKey: true, }); if (!res.success) throw new Error(res.payload.error); // res.payload.address and res.payload.path are strings.

Parameters

  • path: required; a recommended path is 44'/501'/account'/0'.
  • 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 res = await HardwareSDK.solSignTransaction(connectId, deviceId, { path: "m/44'/501'/0'/0'", rawTx, useEmptyPassphrase: true, }); if (!res.success) throw new Error(res.payload.error); // res.payload.signature is hex; res.payload.path is the serialized path.

Parameters

  • path: required; SDK minimum length is 3, subject to firmware path policy.
  • rawTx: required; hex-encoded serialized message bytes, excluding the transaction signature envelope. The runtime requires this field.
  • useEmptyPassphrase?: optional; force the standard wallet. Hidden wallet: pass passphraseState.

Returns

type SignResult = | { success: true; payload: { signature: string; path: string } } | { success: false; payload: { error: string; code?: string | number } };

Interaction & Status

  • APIs resolve on completion; user prompts surface via UI_REQUEST (unlock device, confirm transaction).
  • Run calls serially per device. Reuse passphraseState or useEmptyPassphrase: true. keepSession still holds the transport; it is not a wallet binding.

Example

import HardwareSDK from '@onekeyfe/hd-common-connect-sdk'; 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 path = "m/44'/501'/0'/0'"; const confirmedAddress = await HardwareSDK.solGetAddress(connectId, deviceId, { path, showOnOneKey: true, useEmptyPassphrase: true, }); if (!confirmedAddress.success) throw new Error(confirmedAddress.payload.error); // Obtain these bytes from Transaction.serializeMessage() or // VersionedTransaction.message.serialize(), with a fresh recent blockhash. declare const messageBytes: Uint8Array; const rawTx = Array.from(messageBytes, byte => byte.toString(16).padStart(2, '0')).join(''); const { success, payload } = await HardwareSDK.solSignTransaction(connectId, deviceId, { path, rawTx, useEmptyPassphrase: true, }); if (!success) throw new Error(payload.error); // Attach the signature and verify it against the confirmed address before broadcasting.

Validation & Troubleshooting

  • Path: the SDK checks a minimum of 3 components; firmware enforces the supported derivation paths. The examples use m/44'/501'/account'/0'.
  • Message/tx: include fresh recentBlockhash, correct accounts, and instruction order.
  • Device review: path/account, destination, amount, fee summary must match your UI.
  • Host verify: attach signature with @solana/web3.js, confirm the signer equals solGetAddress result.
  • Oversized messages or unsupported instructions: report the error and stop the current request. Splitting or adjusting a transaction requires rebuilding it and obtaining a new user review. Serialize calls per device; offer retry/cancel on rejection or timeout without automatic replay.

See method doc: solSignTransaction.

Last updated on