关于 dmk-business-logic
为使用 Ledger Device Management Kit(DMK)的开发者提供参考,解释 API 设计概念、设备交互、传输限制、签名及安全相关行为。
主要功能
- 01清晰签名与盲签概念
- 02安全通道要求
- 03设备操作与命令
- 04会话生命周期与传输方式
- 05派生路径指导
- 06设备真伪检查
适用场景
- 01选择设备操作或命令
- 02设计交易签名流程
- 03管理 Ledger 连接会话
- 04设置链的派生路径
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ledgerhq/ agent-skills --skill dmk-business-logic安装后在 Claude Code 中输入/dmk-business-logic确认已加载。
详细介绍
DMK 业务逻辑与概念
本技能解释 DMK API 设计决策背后的原因——领域模型、安全限制和权衡取舍——帮助开发者理解其设计缘由,而不仅仅是调用方法。在实现过程中需要澄清某个术语或概念时,ledger-dmk-implementation/SKILL.md 也会将其作为连接器加载。
明文签名与盲签名
含义
盲签名是指用户在 Ledger 屏幕上看到原始十六进制字节——一长串无法阅读、无法验证的字符。用户需要批准一项自己无法有意义地审查的操作。
明文签名是指用户在设备屏幕上看到人类可读的交易详情——收款地址、金额、代币名称、合约名称、费用。按下按钮前,用户可以核实自己实际批准的内容。
重要性
设备屏幕是唯一可信的显示界面。被入侵的主机(恶意软件、钓鱼网站)可以在浏览器或桌面 UI 上向用户显示任何内容。设备屏幕无法伪造。明文签名让设备屏幕发挥作用,而盲签名则让它失去意义。
在 DMK 中的工作方式
即使没有明文签名,DMK 也能正常工作——明文签名是增强功能,并非前提条件。要为 Ethereum 启用明文签名:
@ledgerhq/context-module无论如何都必须安装——它是 ETH 签名器工具包的强制同级依赖,负责获取设备显示人类可读字段所需的元数据(ABI、代币信息、NFT 详情)。originToken是传递给SignerEthBuilder的可选合作伙伴令牌。没有它,签名器仍可工作,但设备会显示原始十六进制内容——体验会悄然退化为盲签名,且不会出现运行时错误。要获取令牌,请加入 Ledger 合作伙伴计划:https://developers.ledger.com/docs/clear-signing/for-wallets。
// Clear Signing enabled (requires partner token):
new SignerEthBuilder({ dmk, sessionId, originToken: "your-partner-token" }).build();
// Blind signing — works but users see raw hex on device:
new SignerEthBuilder({ dmk, sessionId }).build();
对于 Bitcoin 和 Solana,明文签名由应用处理——无需 originToken,但设备上的 Ledger 应用必须支持相应的交易类型。
开发者检查清单
originToken是可选的——可以先集成并发布,准备好在生产环境启用明文签名后,再加入 Ledger 合作伙伴计划- 使用 ETH 签名器工具包时,始终安装
@ledgerhq/context-module,开发期间也不例外 - 对
getAddress()流程始终使用checkOnDevice: true——对于接收流程,这是与明文签名等效的地址验证方式
安全通道
定义
安全通道是 Ledger 设备与 Ledger 的 HSM(硬件安全模块)后端之间的加密、经身份验证的连接。它允许后端在设备上执行无法本地完成的特权操作。
哪些操作需要安全通道
| 操作 | 是否需要安全通道 |
|---|---|
GenuineCheckDeviceAction | 是 |
ListInstalledAppsDeviceAction | 是 |
InstallAppDeviceAction | 是 |
UninstallAppDeviceAction | 是 |
| 所有签名器操作(签名、获取地址) | 否 |
OpenAppDeviceAction | 否 |
工作方式
- DMK 与 Ledger 的 HSM 建立 WebSocket 连接,地址为
wss://manager.live.ledger.com - 设备与 HSM 执行双向身份验证握手
- 设备屏幕会提示用户执行
AllowSecureConnection——用户必须在设备上亲自批准连接 - 批准后,该会话在设备本次重启期间始终可信
实际影响
- 需要互联网。 安全通道操作在离线状态下会失败——没有本地备用方案。
设备操作与命令
两级 API
DMK 提供两级设备交互方式:
命令(dmk.sendCommand())是底层的单次 APDU 往返操作。它们向设备发送一条指令,并同步返回结果。不处理任何用户交互——调用方需要负责其他所有事项。
设备操作(dmk.executeDeviceAction() 或签名器套件方法)是高级编排流程。它们通过单个可观察对象处理完整流程:检测解锁状态、打开应用、发出用户确认提示、重试以及发出终止状态。
何时使用哪种方式
| 使用场景 | 使用方式 |
|---|---|
| 签署交易、获取地址 | 签名器套件设备操作(通过签名器构建器) |
| 真伪检查、安装/卸载应用 | 使用相应的 DeviceAction 类调用 dmk.executeDeviceAction() |
| 打开应用并显示用户确认界面 | 通过 dmk.executeDeviceAction() 调用 OpenAppDeviceAction |
| 检查固件版本、获取当前应用名称 | sendCommand()——操作简单,无需用户交互 |
| 自定义/不受支持的链、原始 APDU | 使用 ApduBuilder 调用 sendCommand()——仅在没有签名器套件时使用 |
设备操作的作用
如果没有设备操作,每位开发者都必须重新实现以下功能:
- 检测并等待设备解锁
- 检测并切换当前活动应用
- 处理
ConfirmOpenApp提示 - 将状态字错误映射为面向用户的消息
- 管理超时和取消
设备操作封装了所有这些功能。它们返回的可观察对象会发出可直接对应到 UI 提示的状态——UserInteractionRequired.SignTransaction 表示“向用户显示提示”,DeviceActionStatus.Completed 表示“已完成,提取输出”。
会话和 SessionId
什么是会话
会话表示与特定 Ledger 设备之间的活动 USB/BLE 连接。它由 dmk.connect() 创建,并由 dmk.disconnect() 销毁。sessionId 是一个不透明字符串,用于在 DMK 实例中标识会话。
什么不是会话
- 它不是按链区分的。相同的
sessionId可用于 ETH、BTC、SOL 以及任何其他签名器,无需重新连接。 - 它不是授权。设备仍会针对每次签名操作提示用户——会话纯粹是一个传输句柄。
- 它不会在页面加载之间持久保留。刷新浏览器会销毁会话。
会话生命周期
会话在以下情况下有效:
- 调用
dmk.disconnect({ sessionId }) - 拔下 USB 线缆(会话状态变为
Disconnected) - 关闭浏览器标签页
不要尝试使用现有的 sessionId 重新连接——一旦变为 Disconnected,就从 startDiscovering() 开始新的流程。
会话刷新器
DMK 会定期轮询设备,以更新会话状态(当前应用、设备状态)。这就是会话刷新器。在多个标签页共享同一台实体设备的场景中,请禁用它,以避免轮询冲突:
dmk.connect({ device, sessionRefresherOptions: { isRefresherDisabled: true } });
传输
抽象的内容
传输层处理主机与 Ledger 设备之间的物理通信协议。无论使用哪种传输方式,DMK 的 API 都相同——只有初始化方式不同。
| 传输方式 | 协议 | 环境 |
|---|---|---|
| WebHID | USB HID,64 字节帧 | 浏览器(仅限 Chromium) |
| WebBLE | Bluetooth GATT | 浏览器 |
| Node-HID | 通过原生插件使用 USB HID | Node.js、Electron |
| React Native HID | USB HID | React Native |
| React Native BLE | Bluetooth | React Native |
| Speculos | 连接模拟器的 TCP 套接字 | 仅限开发/CI |
浏览器限制
WebHID 要求:
- 基于 Chromium 的浏览器(Chrome、Edge、Brave)——Firefox 和 Safari 不支持 WebHID
- HTTPS 或 localhost——WebHID 在普通 HTTP 上会被阻止
- 用户操作——必须通过按钮点击或等效操作调用
startDiscovering()和connect()。如果在页面加载时调用,则会静默失败。
每个 DMK 实例使用一种传输方式
每个 DeviceManagementKitBuilder 接受一种或多种传输方式。实际使用中,请使用一种。DMK 会按注册顺序尝试传输方式。
派生路径
定义
派生路径是一系列索引,用于指定从设备上存储的根种子派生哪个密钥。给定相同的助记词,相同的路径始终会生成相同的密钥;不同的路径则会生成完全不同的密钥,且不会出现运行时错误。
为什么它们是开发者常量,而不是用户输入
从设备的角度看,不存在“错误路径”——每条路径都会生成有效密钥。如果用户输入的路径哪怕只有一个片段不同,得到的地址也会不同。发送到该地址的资金将无法访问,除非知道正确的路径。这是一个悄无声息且无法挽回的错误。
路径必须在应用代码中硬编码为常量,并与用户钱包采用的标准一致。
路径格式规则
- 不要添加
m/前缀。DerivationPathUtils.splitPath会解析由/分隔的片段。开头的m不是有效片段——parseInt("m")会返回NaN并抛出“提供了无效数字”错误。请使用"44'/60'/0'/0/0",而不是"m/44'/60'/0'/0/0"。 - 强化片段使用
'后缀(例如44')。这是在索引上加上0x80000000的简写形式。 - 账户和索引是不同的概念。
account用于选择钱包(大多数用户使用0)。index用于选择该钱包中的地址。
各链的标准路径
| 链 | Ledger Live 路径 | 备注 |
|---|---|---|
| Ethereum | 44'/60'/0'/0/0 | BIP44,账户 0,索引 0 |
| Bitcoin Native SegWit | 84'/0'/0' | BIP84,传递给钱包策略 |
| Solana | 44'/501'/0'/0' | 社区标准 |
| Cosmos | 44'/118'/0'/0/0 | BIP44 |
对于未列出的链:SLIP-0044 定义了币种类型(github.com/satoshilabs/slips/blob/master/slip-0044.md)。
BOLOS
BOLOS(Blockchain Open Ledger Operating System),现称为 Ledger OS,是 Ledger 设备的操作系统。当没有应用打开且设备处于主屏幕(仪表板)时,state.currentApp.name 会返回 "BOLOS"。
以下是检测当前没有应用打开的方法:
const isOnDashboard =
state.currentApp.name === "BOLOS" || state.currentApp.name === "Dashboard";
使用 signer kit 设备操作时,无需显式检测这一状态——它们会自动处理应用切换。此检测适用于操作前的 UX 提示(“当前没有应用打开,继续后将打开正确的应用”)。
真伪验证
真伪验证用于确认实体 Ledger 设备是 Ledger 制造的正版硬件,而非仿冒品。设备会证明其持有私钥,该私钥对应的证书由 Ledger 的根 CA 签名,并通过 Secure Channel 验证。
它会返回 output.isGenuine: boolean。
使用时机: 在继续操作前必须确认设备真伪的高安全性流程中,例如企业密钥管理设置或首次设备接入流程。常规签名操作不需要进行真伪验证。
无法证明的事项: 它无法证明设备在制造后未遭篡改,也无法证明助记词已正确备份。
Ledger Wallet / Ledger Live
Ledger Live 是 Ledger Wallet 的旧称——两者指的是同一个桌面和移动应用。文档、技能文件和 SDK 参考资料可能会使用其中任一名称;请将它们视为相同名称。
设备操作中使用的应用名称(OpenAppDeviceAction、InstallAppDeviceAction、UninstallAppDeviceAction)必须与 Ledger 应用目录中的名称完全一致——也就是 Ledger Wallet 中显示的名称。拼写或大小写有误会导致静默失败,或出现无法说明具体原因的晦涩错误。