本页目录
Solana Signer
Solana 硬件签名全链路指南,覆盖地址确认与交易/消息签名,强调受支持的硬化路径、序列化消息签名与设备可验证。
目录
工作原理
通过 HardwareSDK 将序列化消息发送给设备。设备解析支持的内容并请求用户确认,具体可展示字段取决于请求、设备与固件。应用将返回签名附加到交易(@solana/web3.js),并验证签名及账户公钥。
关键点:
- 使用固件支持的全硬化路径,例如:
m/44'/501'/account'/0'(如m/44'/501'/0'/0')。 rawTx只接受十六进制字符串,若使用Transaction,编码serializeMessage()的结果;若使用VersionedTransaction,编码message.serialize()的结果。不要传包含签名区的整笔交易序列化结果。- 应用需自行构造并序列化消息(含 recent blockhash);Versioned Transaction 的支持情况应按目标机型、固件与对应链方法的要求验证。
安装
npm i @onekeyfe/hd-core @onekeyfe/hd-common-connect-sdk初始化
示例统一使用标准钱包。隐藏钱包应在每次地址和签名调用中,以经过确认的 passphraseState 替代 useEmptyPassphrase: true。受保护调用前先注册 UI 处理器,使用返回数据前检查 success。含待提供交易参数的代码是接入片段,应用仍需实现 UI、设备选择与网络数据获取。
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");适用场景
场景 1:获取地址
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.参数
path: 必填,推荐使用44'/501'/account'/0'的全硬化结构。showOnOneKey?: 可选,是否在设备上展示并确认。
返回
type AddressResult =
| { success: true; payload: { address: string; path: string } }
| { success: false; payload: { error: string; code?: string | number } };场景 2:签名交易
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.参数
path: 必填,同上。rawTx: 必填,仅包含签名消息的序列化字节(hex,0x可选),不包含交易的签名区。运行时要求提供该字段。useEmptyPassphrase?: 可选,强制标准钱包。隐藏钱包请带passphraseState。
返回
type SignResult =
| { success: true; payload: { signature: string; path: string } }
| { success: false; payload: { error: string; code?: string | number } };可附加到 Transaction 后广播。
交互与状态
- 接口以 Promise 结束;用户提示通过
UI_REQUEST事件触发(解锁设备、确认交易)。 - 同一设备串行调用。复用
passphraseState或useEmptyPassphrase: true。keepSession仍是传输持有,不是钱包绑定。
示例
示例:交易签名
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.验签与排障
- 路径:SDK 校验至少 3 级,固件进一步限制受支持的派生路径。示例使用
m/44'/501'/account'/0'。 - 消息/交易:确保包含最新
recentBlockhash、正确的账户列表和指令顺序。 - 设备核对:路径/账户、公链币金额、目标账户、费用摘要需与前端一致。
- 验签:用
@solana/web3.js将签名附加到Transaction,验证签名公钥对应solGetAddress返回的 base58address。 - 常见问题:
- 超大消息或不支持的指令:报告限制并终止当前请求;如需精简或拆分交易,重新构造请求并取得用户确认,不自动改写后重签。
- 会话交互:同一设备串行调用;
openWalletSession一次后带上passphraseState。keepSession仍是传输持有,不是钱包绑定。 - 拒签/超时:提供重试/取消,不要自动重播。
参见方法文档:solSignTransaction。
最后更新于