On this page
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
- How it works
- Installation
- Initialization
- Common scenarios
- Interaction & Status
- Example
- 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-sdkInitialization
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 is44'/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: passpassphraseState.
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
passphraseStateoruseEmptyPassphrase: true.keepSessionstill 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 equalssolGetAddressresult. - 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.