跳到主要内容

Solana 签名接入

本文说明如何在 UKey Wallet 硬件设备上完成 Solana 地址确认和交易签名。重点放在三件事:使用设备支持的派生路径、把交易序列化成设备可解析的 rawTx,以及在应用端完成签名回填和校验。

目录

  1. 原理
  2. 部署
  3. 启动
  4. 适用面
  5. 交互状态
  6. 示范
  7. 末尾核对

原理

应用通过 SDK 入口把待签名交易发送给设备端 Solana App。设备会根据序列化后的 rawTx 展示账户、转账目标、金额、费用等摘要,用户确认后才会返回签名。应用随后需要把签名写回 TransactionVersionedTransaction,并用 @solana/web3.js 校验签名者公钥。

接入时请先确认以下边界:

  • 派生路径必须是 4 段全硬化结构:m/44'/501'/account'/0',例如 m/44'/501'/3'/0'
  • rawTx 传入十六进制字符串即可,前缀 0x 可带可不带。
  • 如果手里是 TransactionVersionedTransaction 对象,先执行 Buffer.from(tx.serialize()).toString('hex') 再传给 SDK。
  • 应用负责构造交易、设置 recentBlockhash、序列化交易;签名只在设备确认后产生。
  • Versioned Transaction 需要固件版本满足 UKey Lite 24 / UKey Lite 25 / UKey Core 26 ≥ 1.1.0

部署

npm i @ukeyfe/hardware-core @ukeyfe/hardware-common-connect-sdk

启动

import ukeySdk from "@ukeyfe/hardware-common-connect-sdk";
await ukeySdk.init({ env: "webusb", fetchConfig: true, debug: false });
const [{ connectId }] = await ukeySdk.searchDevices();
const deviceId = (await ukeySdk.getFeatures(connectId)).payload?.device_id;

适用面

场景 1:读取并确认地址

const path = "m/44'/501'/3'/0'";
const opResult = await ukeySdk.solGetAddress(connectId, deviceId, {
path,
showOnUKey: true,
});
// 返回字段参考片段:opResult.payload.address, publicKey?, path

入参清单

  • path: Solana 账户路径,需保持 44'/501'/account'/0' 这种全硬化结构。
  • showOnUKey?: 需要用户在设备上核对地址时开启,例如首次绑定或敏感操作前确认。

返回

Promise<{ success; payload: { address; path; publicKey? } }>;

场景 2:确认提交交易给设备签名

const opResult = await ukeySdk.solSignTransaction(connectId, deviceId, {
path: "m/44'/501'/3'/0'",
rawTx,
keepSession: true,
});
// 返回值参考片段:opResult.payload.signature

入参清单

  • path: 与构造交易所用地址一致的 Solana 账户路径。
  • rawTx: 序列化后的交易十六进制字符串,0x 前缀可带可不带;如果来源是 Transaction.serialize(),请先转成 hex。
  • keepSession?: 保留当前会话,让连续签名过程更顺畅。

返回

Promise<{ success; payload: { signature } }>;

拿到签名后,将其附加回交易对象,完成本地校验后再广播。

交互状态

  • SDK 方法通过 Promise 返回最终结果;解锁设备、打开 Solana App、确认交易等中间步骤会通过 UI_REQUEST 事件通知应用展示提示。
  • 同一台设备请按顺序调用接口,不要并发发起多个签名请求。
  • 批量或连续签名时,可结合 keepSession 让交互更顺滑。

示范

参考片段:交易签名

import ukeySdk from "@ukeyfe/hardware-common-connect-sdk";

await ukeySdk.init({ env: "webusb", debug: false });

const [{ connectId }] = await ukeySdk.searchDevices();
const deviceId = (await ukeySdk.getFeatures(connectId)).payload?.device_id;

const path = "m/44'/501'/3'/0'";
await ukeySdk.solGetAddress(connectId, deviceId, {
path,
showOnUKey: true,
});

// 如果已经拿到 Transaction / VersionedTransaction,先转成十六进制再处理:
const rawTxFromObject = Buffer.from(transaction.serialize()).toString('hex');
// 下面这个例子里的 demoRawTx hex 已经序列化完成,可直接交给设备确认。
const demoRawTx =
"5f3b1d7a9c2e4f6081a3b5d7f90c2e4f6081a3b5d7f90c2e4f6081a3b5d7f90c2e4f6081a3b5d7f90c2e4f60";

const { success, payload } = await ukeySdk.solSignTransaction(
connectId,
deviceId,
{
path,
rawTx: demoRawTx,
keepSession: true,
},
);

if (success) {
console.info("signature:", payload.signature);
}

末尾核对

核验项建议处理
路径说明规则路径说明要维持 44'/501'/account'/0' 这种全硬化形式,其他写法可能会被设备拒绝。
交易材料先准备好有效的 recentBlockhash、完整账户列表和稳定的指令步骤。
屏幕一致性账户、目标地址、金额和费用摘要要和设备屏幕上的内容对得上。
签名回填@solana/web3.js 回填签名后,确认签名公钥与 solGetAddress 返回的地址一致。
负载控制交易太大或包含设备暂不支持的指令时,先拆分或简化。
交互结束用户拒绝或超时后,给出重新发起入口,不要在后台自动重播同一笔交易。

继续查看具体 API:solSignTransaction