关于 wallet-cli-usage
用于 Ledger 钱包操作的 USB 命令行技能,支持 Bitcoin、Ethereum 和 Solana 网络。它涵盖账户与交易、质押、兑换、加密及 Agent 意图提案,并强调设备安全规则。
主要功能
- 01管理 Ledger 钱包会话和账户
- 02查看余额与交易记录
- 03发送、接收、兑换和质押资产
- 04使用 Ledger Key Ring 加密数据
- 05提交 Agent 意图以供审批
适用场景
- 01检查钱包余额和活动
- 02转账或兑换支持的资产
- 03管理质押仓位
- 04使用 Ledger 设备加密机密信息
- 05请求批准 Agent 付款或兑换
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ledgerhq/ agent-skills --skill wallet-cli-usage安装后在 Claude Code 中输入/wallet-cli-usage确认已加载。
附带文件references/business-logic.md
详细介绍
wallet-cli
基于 USB 的 Ledger 钱包流程命令行工具。支持的网络:bitcoin、ethereum、solana(主网 + 测试网)。
使用你偏好的包管理器进行全局安装——npm i -g @ledgerhq/wallet-cli、pnpm add -g @ledgerhq/wallet-cli、yarn global add @ledgerhq/wallet-cli 或 bun add -g @ledgerhq/wallet-cli。运行:wallet-cli [flags]。
概念与设计依据: 如果想了解某条命令为何如此运行,或查看本技能简要说明的安全规则(真实设备检查、接收地址验证、会话、沙盒、设备争用),请阅读
references/business-logic.md。
先查看会话: 如果未指定具体任务,立即运行
session view——不要先询问用户要做什么。显示结果,然后询问接下来要做什么。如果已有标签,则跳过account discover。
沙盒:
account discover、receive(不带--no-verify)、send(不带--dry-run)、genuine-check、swap execute、earn deposit(不带--dry-run)、earn withdraw(不带--dry-run)、ring init必须使用dangerouslyDisableSandbox: true——这些命令会通过 node-webusb DMK 传输层经由 USB 打开设备,因此会受到 USB 限制而被阻止。ring encrypt、ring decrypt、ring destroy、agent-intent enroll、agent-intent recover、agent-intent sync、agent-intent send和agent-intent swap(不带--dry-run)、agent-intent intents、agent-intent status、agent-intent cancel不会打开设备,但同样需要绕过限制——它们会受到操作系统钥匙串访问限制而被阻止(agent-intent enroll/recover还会与 Trustchain 中继保持 WebSocket 连接)。ring keys不需要此设置,agent-intent list/show也不需要:它们只读取本地会话文件,因此无需绕过限制即可运行。
设备争用: 绝不要并行运行两条设备命令——它们会失败并显示
[object Object]或乱码 APDU。请按顺序运行。
设备就绪状态: 运行设备命令前,简要说明你即将执行的操作。CLI 会自行提示与设备交互——不要超时或终止命令。例外: 如果有任何币种应用处于打开状态,
genuine-check会立即退出(显示[✖] Wrong app. Open Ledger dashboard.,退出代码为 4);与其他设备命令不同,它针对的是仪表盘,且不会自动启动应用。运行前请确保设备处于仪表盘界面;如果命令退出,请让用户返回仪表盘,然后重新运行。
请求含糊时——先询问,不要猜测。 如果缺少必需参数或参数不明确(
send未指定接收方、account discover未指定网络、金额未指定币种代码),请停止并询问。硬件钱包操作中猜错参数可能导致资金无法挽回地丢失。
意图映射
将非正式说法映射到命令。账户引用使用会话标签(例如 ethereum-1)。
| 用户说 | 命令 |
|---|---|
| “显示我的钱包”、“我有什么”、“开始吧”,没有具体任务 | session view(立即运行,在询问任何问题之前) |
| “查找我的账户”、“扫描我的钱包”、“导入我的钱包”、“设置 Ethereum/Bitcoin” | account discover <network> |
| “我该把资金发送到哪里”、“给我我的地址”、“存款地址” | receive <account> |
| “我有多少钱”、“余额”、“我的 ETH 余额是多少” | balances <account> |
| “我发送了什么”、“交易历史”、“近期活动” | operations <account> |
| “向 Y 发送 X”、“转账”、“付款”、“提现到交易所” | send <account> --to <address> --amount '<amount> <ticker>' |
| “将 A 兑换为 B”、“转换”、“用 ETH 交易 BTC”、“兑换” | swap quote -> swap execute -> swap status |
| “在哪里可以赚取收益”、“质押利率”、“收益率/APY”、“我的 ETH/SOL 的最佳回报” | earn yields [-n <network>] |
| “我在质押什么”、“我的质押头寸”、“收益余额” | earn positions <account> |
| “质押我的 SOL”、“存入金库”、“通过我的 USDC 赚取收益”、“委托” | earn deposit <account> --product <id> --amount '<amount>' |
| “取消质押”、“提取我的质押资产”、“从金库赎回”、“停止赚取收益” | earn withdraw <account> … |
| “这台 Ledger 是真品吗”、“验证真伪”、“我是在 eBay 上买的” | genuine-check |
| “加密此文件/这些环境变量/发布令牌”、“GPG 替代方案”、“密钥管理器”、“用我的 Ledger 在任何地方解密” | ring init -> ring encrypt --key <name> / ring decrypt --key <name> |
| “我的密钥环里有哪些密钥”、“列出我加密时使用过的域/项目” | ring keys |
| “清除我的密钥环”、“销毁密钥环”、“拆除 LKRP 成员资格” | ring destroy |
| “注册此 Agent”、“让一个 Agent 提议意图”、“为机器人设置 Agent Intent” | agent-intent enroll --profile <id> --name <name> --source <runtime>(无需设备;会阻塞,直到获批) |
| “恢复此 Agent”、“将 Agent 重新注册到其信任链中” | agent-intent recover --profile <id>(无需设备;会阻塞,直到获批) |
| “有哪些 Agent 已注册”、“列出 Agent 配置文件” | agent-intent list |
| “显示该 Agent 配置文件”、“这个 Agent 的指纹是什么” | agent-intent show --profile <id> |
| “拉取我已同步的账户”、“从 Ledger Sync 导入”、“同步该 Agent 的账户” | agent-intent sync --profile <id>(无需设备) |
| “让 Agent 请求付款”、“提议向 Y 发送 X 以供审批” | agent-intent send --profile <id> --account <label> --to <address> --amount '<amount> <ticker>'(无需设备,绝不广播) |
| “让 Agent 提议兑换”、“提议将 X ETH 兑换为 USDC 以供审批” | agent-intent swap --profile <id> --account <label> --from ethereum --to <currency id> --amount <amount>(无需设备,绝不广播) |
| “Agent 提议了什么”、“列出 Agent 的意图” | agent-intent intents --profile <id>(无需设备;使用 --status signed,broadcast、--cursor 获取下一页) |
| “我的意图获批了吗”、“意图 X 的状态是什么”、“等待它签署” | agent-intent status --profile <id> --intent <id>(无需设备;轮询 JSON 中的 intent.status 获取当前状态,terminal 表示最终状态) |
| “取消意图 X”、“撤回提议”、“Agent 改变主意了” | agent-intent cancel --profile <id> --intent <id> --yes(无需设备;仅限用户签署前;不可撤销) |
| “重新开始”、“清除我的会话”、“我换了设备” | session reset |
暂不支持的功能——直接说明,不要自行编造
如果用户要求执行以下任何操作,请说明 wallet-cli 目前尚不支持,而不是自行构造命令:
- NFT(铸造、转账、查看)。
- 与 OpenPGP 兼容的输出或密钥共享/多接收方加密(
ring命令使用每位用户各自的 Ledger 密钥环进行加密,不使用可共享的密钥)。 - 在测试网和二层网络(例如 Base)上执行
send、receive、operations或swap execute。 - 上方 Networks 行中未列出的自定义链。
会话与标签
account discover 会持久化账户。每个账户都会获得一个标签:<network>[-derivation][-env]-<n>(例如:ethereum-1、bitcoin-native-1、ethereum-sepolia-1)。
所有 --account 标志都接受会话标签(例如:ethereum-1)。先运行 account discover 以填充会话。
命令
| 命令 | 设备 | 沙盒 | TTY† | 网络 |
|---|---|---|---|---|
session view | 否 | 否 | 否 | 否 |
session reset | 否 | 否 | 否 | 否 |
account discover | 是 | 必需 | 否 | 是 |
receive | 是* | 必需 | 否 | 否 |
send | 是* | 必需 | 否 | 是 |
genuine-check | 是 | 必需 | 否 | 是 |
balances | 否 | 否 | 否 | 是 |
operations | 否 | 否 | 否 | 是 |
swap quote | 否 | 否 | 否 | 是 |
swap execute | 是 | 必需 | 否 | 是 |
swap status | 否 | 否 | 否 | 是 |
assets token | 否 | 否 | 否 | 否 |
assets token-by-id | 否 | 否 | 否 | 否 |
earn yields | 否 | 否 | 否 | 是 |
earn positions | 否 | 否 | 否 | 是 |
earn deposit | 是* | 必需 | 否 | 是 |
earn withdraw | 是* | 必需 | 否 | 是 |
ring init | 是 | 必需 | 必需‡ | 是 |
ring encrypt | 否 | 必需 | 否 | 是 |
ring decrypt | 否 | 必需 | 否 | 是 |
ring keys | 否 | 否 | 否 | 否 |
ring destroy | 否 | 必需 | 必需‡‡ | 是 |
agent-intent enroll | 否 | 必需 | 否 | 是 |
agent-intent recover | 否 | 必需 | 否 | 是 |
agent-intent list | 否 | 否 | 否 | 否 |
agent-intent show | 否 | 否 | 否 | 否 |
agent-intent sync | 否 | 必需 | 否 | 是 |
agent-intent intents | 否 | 必需 | 否 | 是 |
agent-intent status | 否 | 必需 | 否 | 是 |
agent-intent cancel | 否 | 必需 | 否§§ | 是 |
*receive 使用 --no-verify、send 使用 --dry-run,以及 earn deposit/earn withdraw 使用 --dry-run 时,无需设备,也无需绕过沙盒。
†TTY:该命令是否需要交互式终端来接收用户输入。
§§agent-intent cancel 会在终端上请求确认;没有终端时(例如脚本、AI Agent)需要使用 --yes。
‡ring init 需要密码来保护 ring。开发者/用户必须在命令运行前,预先在环境中提供 WALLET_PASS——Agent 不会设置或注入该值(参见非 TTY 密码注入)。
‡‡ring destroy 会提示输入确认文本("destroy")。在非交互式 shell 中通过管道传入:echo "destroy" | wallet-cli ring destroy。如果已设置密码,WALLET_PASS 必须已存在于环境中(由开发者提供,而非 Agent)。
session view / reset
wallet-cli session view
wallet-cli session reset
account discover
wallet-cli account discover ethereum
wallet-cli account discover bitcoin
wallet-cli account discover ethereum:sepolia
网络:bitcoin(主网)、ethereum、solana、ethereum:sepolia、bitcoin:testnet、solana:devnet。
receive
wallet-cli receive ethereum-1
wallet-cli receive ethereum-1 --no-verify # skip device confirmation
**如果屏幕上显示的地址与终端中的地址不同:**请勿分享或使用该地址。请用户断开设备连接并运行 genuine-check,然后再重试。背景信息请参阅 references/business-logic.md § 接收地址验证。
genuine-check
wallet-cli genuine-check
wallet-cli genuine-check --output json # only if a downstream caller needs to parse the result
**前提条件:**设备已解锁并处于仪表盘界面(退出所有已打开的应用);主机可以访问互联网(安全通道需要连接 Ledger 的后端——离线运行会失败)。
balances
wallet-cli balances ethereum-1
wallet-cli balances ethereum-1 --output json
operations
wallet-cli operations ethereum-1
wallet-cli operations ethereum-1 --limit 20 --cursor <cursor>
分页:下一页游标通过 stderr(人类可读)或 JSON 中的 nextCursor 返回。
send
wallet-cli send ethereum-1 --to 0xDEF... --amount '0.5 ETH'
wallet-cli send ethereum-1 --to 0xDEF... --amount '100 USDT' # ERC-20
wallet-cli send bitcoin-native-1 --to bc1q... --amount '0.001 BTC' --fee-per-byte 15 --rbf
wallet-cli send ethereum-1 --to 0xDEF... --amount '0.5 ETH' --dry-run
--amount 中必须指定币种代码。没有 --token 标志——币种代码用于解析资产。
Bitcoin 标志: --fee-per-byte <sats>、--rbf
Solana 标志: --mode send|stake.createAccount|stake.delegate|stake.undelegate|stake.withdraw、--validator <addr>、--stake-account <addr>、--memo <text>
EVM 标志: --data <hex> — 合约调用的原始 calldata(带 0x 前缀的十六进制数,位数必须为偶数)。用于 CLI 没有专用命令的合约交互(例如下文的 WETH 包装/解包)。普通原生资产或代币转账时省略。
使用 --data 进行合约调用(包装/解包示例)
标准模式:WETH 包装/解包。deposit()(包装 ETH → WETH,无参数)的选择器为 0xd0e30db0,通过 --amount 将 ETH 作为交易金额发送。withdraw(uint256)(解包 WETH → ETH,一个 uint256 参数,即以 wei 为单位的金额)的选择器为 0x2e1a7d4d,后接左侧补零至 32 字节的金额。
# wrap 0.5 ETH into WETH
wallet-cli send ethereum-1 --to <WETH_CONTRACT_ADDRESS> --amount '0.5 ETH' --data 0xd0e30db0
# unwrap 0.5 WETH back to ETH (0.5 ETH = 500000000000000000 wei = 6f05b59d3b20000 hex, padded to 32 bytes)
wallet-cli send ethereum-1 --to <WETH_CONTRACT_ADDRESS> --amount '0 ETH' --data 0x2e1a7d4d00000000000000000000000000000000000000000000000006f05b59d3b20000
始终先使用 --dry-run 运行,以验证 calldata,然后再签名。CLI 无法验证手动提供的 --data 在语义上是否正确——设备屏幕是最后一道防线,因此请在设备上检查解码后的调用,再予以批准。
swap quote
并行获取内置提供商列表中的报价(无需设备;地址从会话账户解析)。
币种: --from / -f 和 --to / -t 是 Ledger 币种 ID——原生资产(例如 ethereum、bitcoin、solana),或当代币的父链是受支持的原生兑换币种时使用代币 ID(与 CLI 允许兑换的 ID 相同)。它们不是会话账户标签——账户请使用 --from-account / --to-account。
swap quote 默认查询且 swap execute 可使用的提供商: changelly、changelly_v2、cic、cic_v2、exodus、lifi、nearintents、okx、oneinch、swapsxyz、uniswap、velora。其中一些是通过旧版 Exchange 应用流程运行的 CEX/聚合器;DEX 提供商(uniswap、oneinch、velora、okx)则在合作伙伴嵌入式币种应用中执行——请参阅 swap execute — DEX 提供商。
账户: --from-account 和 --to-account 仅接受会话标签;CLI 会像 receive 一样,从账户解析新的收款地址。
wallet-cli swap quote --from ethereum --to bitcoin --amount 0.1 --from-account ethereum-1 --to-account bitcoin-native-1
wallet-cli swap quote -f ethereum -t bitcoin --amount 0.1 --from-account ethereum-1 --to-account bitcoin-native-1 --output json
必填项:--from、--to、--from-account、--to-account、--amount。
swap execute
货币: --from / -f 和 --to / -t 是 Ledger 货币 ID(与 swap quote 相同):允许的主链上的原生资产或代币。它们必须分别与源 --account 和 --to-account 的资产匹配。
提供商: 有效的 --provider 值包括 changelly、changelly_v2、cic、cic_v2、exodus、lifi、nearintents、okx、oneinch、swapsxyz、uniswap、velora。别名:changelly → changelly_v2,1inch → oneinch。请使用从 swap quote 中选取的报价行上显示的提供商 ID。
DEX 提供商(uniswap、oneinch、velora、okx): 这些提供商会在设备上的合作伙伴嵌入式币种应用中端到端运行(通过 Device Intent Executor),而不是使用旧版 Exchange 应用。此流程会为所选提供商重新获取报价,然后在设备上执行授权和兑换序列(sign-approval / sign-permit2 / sign-swap / 广播),并根据需要切换设备应用——请在设备上确认每个 Open <app> 提示和签名提示。
- 仅限 EVM。DEX 执行要求源账户为 EVM 账户(例如
ethereum);非 EVM 的--account将回退到旧版流程。 - CLI 不支持 RFQ 报价。如果选取的报价解析为 RFQ 计划(
rfq-order/approval-then-rfq-order),则会跳过嵌入式流程,执行回退到旧版 Exchange 应用流程(你会看到一行falling back to legacy Exchange-app pipeline进度信息)。
所有其他提供商(changelly、cic、exodus、nearintents、swapsxyz、lifi、……)都会运行旧版 Exchange 应用流程(nonce → payload → 完成兑换 → 签名/广播)。
手续费策略: --fee-strategy 接受 slow、medium(默认值)或 fast。在旧版流程中,它用于设置退款链交易手续费。
wallet-cli swap execute --from ethereum --to bitcoin --account ethereum-1 --to-account bitcoin-native-1 --provider changelly --amount 0.1
wallet-cli swap execute -f ethereum -t bitcoin --account ethereum-1 --to-account bitcoin-native-1 --provider changelly --amount 0.1 --fee-strategy fast
wallet-cli swap execute --from ethereum --to bitcoin --account ethereum-1 --to-account bitcoin-native-1 --provider changelly --amount 0.1 --output json
# DEX (embedded coin app): EVM-only, source and destination on an EVM chain
wallet-cli swap execute --from ethereum --to ethereum/erc20/usd_tether__erc20_ --account ethereum-1 --to-account ethereum-1 --provider uniswap --amount 0.1
必需标志:--from、--to、--account、--to-account、--provider、--amount。请使用与从 swap quote 中选取的报价行上提供商 ID 匹配的 --provider 值。
swap status
wallet-cli swap status --swap-id <swapId> --provider changelly
wallet-cli swap status --swap-id <swapId> --provider changelly --output json
必需标志:--swap-id、--provider
assets token / token-by-id
从 cryptoassets 存储中解析代币元数据。无需设备或会话。
wallet-cli assets token ethereum 0xdac17f958d2ee523a2206206994597c13d831ec7
wallet-cli assets token-by-id ethereum/erc20/usd_tether__erc20_
有合约地址时使用 token;有 ID 时使用 token-by-id。如果未找到,则以非零状态退出。
对于非 EVM 链,请传入 --identifier。
此处打印的 id 与 swap quote --from / --to 和 swap execute --from / --to 接受的 ID 相同。
ring — Ledger Key Ring(LKRP)
为文件和文本提供无信任、以硬件为根的加密。密钥环只需通过 Ledger Sync 应用在 Ledger 上配置一次;之后,encrypt/decrypt 无需设备即可运行——密钥通过 HKDF-SHA256 从 LKRP 共享根确定性派生,且绝不会离开 AES-256-GCM。encrypt/decrypt 仍会在每次调用时访问 LKRP 后端以恢复信任链,因此需要网络连接。你可以在任何新机器上通过助记词恢复密钥环。
# One-time provisioning (device required). Password comes from WALLET_PASS in the environment (see below); name the machine with --name.
wallet-cli ring init
wallet-cli ring init --name my-laptop
# File round-trip (no device after init):
wallet-cli ring encrypt --key my-oss-project -i .publish-tokens -o .publish-tokens.enc
wallet-cli ring decrypt --key my-oss-project -i .publish-tokens.enc -o .publish-tokens
# Text via stdin/stdout (clipboard pattern):
pbpaste | wallet-cli ring encrypt --key personal-notes | pbcopy
pbpaste | wallet-cli ring decrypt --key personal-notes | pbcopy
# List the keys this machine has used; tear down the ring:
wallet-cli ring keys
wallet-cli ring destroy
始终使用密码进行配置。 密钥环必须受密码保护。用户应在运行
ring init前通过环境变量中的WALLET_PASS提供密码(参见非 TTY 密码注入)——Agent 绝不会在没有密码的情况下配置密钥环。
解密后的输出属于敏感信息。
ring decrypt会输出机密信息——绝不要将其打印到终端、对解密后的文件执行cat,或以其他方式暴露解密内容,因为这些内容会进入 Agent 对话记录、日志和终端滚屏缓冲区。将decrypt的输出直接传送到目标位置(通过-o写入文件、传给另一个进程,或如上所示复制到剪贴板),或将其捕获到环境变量中;避免使用可能会回显内容的--output/日志输出目标。
--key <name> 会派生一个按名称区分的 AES-256-GCM 密钥;解密时必须使用相同的名称。名称可自由填写(最长 253 个字符,不能包含空白字符)——常见模式包括项目代号(my-oss-project)、环境标签(openClaw-prod)、笔记本名称(personal-notes)。
**非 TTY(CI / Agent 式)密码注入:**没有 TTY 时,ring 命令会从 WALLET_PASS 环境变量读取密码。密码本身必须由开发者/用户配置(导出到环境变量中或存储在操作系统钥匙串中)——Agent 绝不会选择、输入或以其他方式处理机密值;它只会引用用户已配置的值。
- 绝不要将密码明文写入命令(例如
WALLET_PASS=hunter2 wallet-cli …,或通过标志传入)。明文会泄露到 shell 历史记录、ps输出、CI 日志中;如果命令由 Agent 运行,还会泄露到Agent 对话记录中。此规则同样适用于临时/测试密码:养成这个习惯,因为相同的命令形式也会用于真实机密。 - 始终通过命令替换注入,这样机密就不会出现在你输入的命令文本中:
- macOS:
WALLET_PASS=$(security find-generic-password -a default -s ledger-wallet-cli -w) wallet-cli ring encrypt … - Linux:
WALLET_PASS=$(secret-tool lookup service ledger-wallet-cli account default) wallet-cli ring encrypt …
- macOS:
- Agent 绝不能处理机密本身。 请用户将密码存入操作系统钥匙串一次,然后只引用
$(…)替换表达式。如果测试或ring init需要密码,先将临时值存入钥匙串(security add-generic-password -a default -s ledger-wallet-cli -w),再用同样的方式注入——绝不要在工具调用中输入明文。 - 即使使用命令替换,密码值仍会存在于子进程环境中(同一用户可以通过
ps eww读取)——这是可接受的,但应优先使用钥匙串方式,并避免使用可能会回显密码的--output json输出目标或日志。
轮换限制:域密钥由密钥环的钱包同步加密密钥派生,而 LKRP 协议会在移除密钥环成员时轮换该密钥。轮换后,之前加密的数据将无法解密(解密会因“错误的密钥名称、数据损坏或 Ledger Key Ring 已轮换”而失败,并且 CLI 会打印 ⚠ Ledger Key Ring rotated 警告)。移除成员后,请使用新密钥环重新加密受影响的数据。输入错误密码时,ring destroy 会中止(不作任何更改);如果设置了 WALLET_PASS,但其值为空(钥匙串查询失败),也会中止——这会被视为错误,而不是跳过,因此不会导致远程密钥环成为孤立项。若要有意跳过远程拆除,只清除本地凭据,请在交互式密码提示处按 Enter。
Agent 意图
将信任模型与
ring分开。 Agent 是纯软件的 LKRP 成员:它加入自己的 Agent Intent(App-18)Trustchain,并获准访问用户的 Ledger Sync(App-16)流, 但它绝不会打开设备,也不会接收ring(App-17)的域密钥。
Agent Intent 会将远程 Agent(为人工审核提交交易意图的机器人)注册为本机上的软件身份 — 注册、恢复、列出、查看和同步均无需设备。每个配置都有自己的 secp256k1 密钥对;私钥不会离开操作系统密钥链,也绝不会被打印、记录日志或包含在任何命令的输出中(包括人工可读输出和 --output json)。
# Create a pending profile, print its signed enrollment URL + fingerprint, then BLOCK until the
# human approves in the Agent Intent frontend (default environment: production):
wallet-cli agent-intent enroll --profile my-bot --name "My Bot" --source claude-code
wallet-cli agent-intent enroll --profile my-bot --name "My Bot" --source other \
--environment staging --expires-in 2h
# Re-enroll an enrolled profile's existing key into its previous Trustchain, then
# BLOCK until approved (environment/keycloak come from the profile):
wallet-cli agent-intent recover --profile my-bot
# List/inspect local profiles (never reveals the secret key):
wallet-cli agent-intent list
wallet-cli agent-intent show --profile my-bot
# Import the Ledger Sync accounts the agent was granted into the session (explicit, never automatic):
wallet-cli agent-intent sync --profile my-bot
wallet-cli agent-intent sync --profile my-bot --output json
始终传入 --source。 它表示 Agent 运行所在的运行时或执行环境(而非其模型提供商):
openclaw、hermes、claude-code、codex、cursor、muse、grok-bot,或者在均不匹配时使用 other。省略该参数时默认为 other。前端会将其显示为 Agent 的来源;传入的值必须属于此列表。
一个阻塞命令,无需复制粘贴。 enroll 会先打印 URL(使用 --output json 时会发出 enrollment-pending NDJSON 事件),然后等待加密的 Trustchain 中继通道;该通道已绑定到签名请求中。前端会通过此通道传回完成结果;没有 complete 命令,也没有手动 JSON 后备方案。请保持进程运行,直到它打印最终的 enrolled 结果(json:status: "success"、enrolled: true、trustchainId、accountAccessEnvironment)。等待时间受 --expires-in 限制(默认为 30m)。
不能仅凭中继内容建立信任。 保存前,enroll 会验证完成结果:Agent 密钥必须能针对所声明的 Trustchain 获取 App-18 访问令牌(Keycloak),并且必须以完全符合预期的权限向所声明的 App-16 流进行身份验证。只有通过这两项检查后,才会将 trustchainId 和(非机密的)accountAccess 引用写入配置。
超时、按下 Ctrl+C 或检查失败时,配置会保持 pending(之后变为 expired),且无法恢复 — 请使用新的 --profile ID 重新开始注册。
恢复会复用同一密钥。 recover --profile <id> 会使用该配置现有的密钥和 Trustchain 签署恢复请求(不会生成新密钥,也不会改动 accountAccess),然后像 enroll 一样等待中继(json:先发出 recovery-pending 事件,然后返回 status: "success"、recovered: true、trustchainId)。任何密钥链密钥与记录的公钥匹配的已注册配置都可以恢复,无论其 --source 是什么。完成结果必须指明同一 Agent 密钥、同一签名请求和同一 Trustchain,并且 Agent 密钥必须能为其获取 App-18 令牌(不会重新检查 App-16)。等待期间,list/show 会报告 recovering;超时、按下 Ctrl+C 或检查失败时,标记会被清除,配置会保留为 enrolled 且数据不变 — 再次运行 recover 即可重试。
指纹是安全检查手段。 enroll 会在注册 URL 旁打印公钥指纹,之后 show 也会为任何配置打印相同指纹 — 批准前,请将其与 Agent Intent 前端/设备上显示的指纹进行比对。指纹不匹配表示注册请求遭到篡改,或被发送给了错误的 Agent。
重复项保护: 如果会话中已记录 --profile ID,enroll 会拒绝复用该 ID;如果密钥链中存在该 ID 的条目,但没有匹配的会话记录(这属于不一致状态,必须先手动清除才能使用相同 ID 重新注册),enroll 也会单独拒绝。
需要密钥链: enroll 需要可用的操作系统密钥链——macOS Keychain、Windows Credential
Manager,或 Linux 上正在运行且已解锁集合的 Secret Service 提供程序(例如 gnome-keyring 或 KeePassXC)。如果没有密钥链(无头 Linux、容器、某些 CI 运行器),enroll 会失败,并显示
Could not store the agent's secret key in the OS keychain (…),且不会保存任何内容——修复密钥链后重新运行相同命令;此设计不提供基于文件的回退方案。
环境隔离: 每个配置文件都会记录其注册时所用的环境(staging/production)。如果完成信息中的 accountAccess.environment 不匹配,就会被拒绝,因此为 staging 注册的配置文件绝不会持有 production Trustchain ID。--bff-url 和 --keycloak-url 可覆盖该环境的默认值(仅限 http(s),不允许使用 user:pass@)。
状态为计算所得,不会存储: list/show 会根据 trustchainId、enrollmentExpiresAt 和任何未过期的恢复标记计算 pending / enrolled / recovering /
expired,并在注册后显示获准的账户访问权限(环境 +
App-16 应用路径)。
同步 Ledger Sync 账户
agent-intent sync --profile <id> 会导入从你其他 Ledger Wallet 实例(桌面端、移动端)同步的账户,以便按标签引用这些账户。它使用 Agent 自己的密钥(来自操作系统密钥链)进行身份验证;前端已在注册时将该密钥添加到 App-16 流中——它不会打开设备,也无需单独注册 Ledger Sync。环境取自配置文件的 accountAccess。
- 需要已注册的配置文件:
pending/expired配置文件(没有accountAccess)或缺少密钥链密钥时,会显示明确错误并失败。 - 报告访问权限丢失,不会修复: 如果 Agent 已从 Ledger Sync 中移除,
sync会报告 "no longer has Ledger Sync access",不会删除任何内容。 - 跟随密钥轮换: 如果 Ledger Sync 轮换了密钥(某个成员被移除),配置文件的
accountAccess会更新为新的应用路径,然后继续同步。 - 仅增量添加且具幂等性: 不会删除或重新标记会话账户,也不会上传任何内容;重复运行时会报告
unchanged条目或 "Up to date"。 - 隔离不支持或格式错误的条目: 对于 wallet-cli 不支持的货币系列账户(仅支持 bitcoin/evm/solana),状态为
skipped;格式错误的账户状态为invalid——导入其余账户的流程仍会继续,而存在invalid条目时,下一次同步不会将数据视为最新。
提议付款(agent-intent send)
agent-intent send 会提议一笔 Ethereum 或 Solana 转账,供人审核——它绝不会签名或广播任何内容,也不需要设备。它使用配置文件的密钥为提议签名,将其提交到 Agent Intent 服务,并打印审核链接;只有人在 Ledger 设备上打开该链接并批准后,付款才会发生。
# Native ETH, sender from a session label:
wallet-cli agent-intent send --profile my-bot --account ethereum-1 \
--to 0xRecipient --amount '0.01 ETH' --description "Invoice #42"
# ERC-20: pass the token contract; the ticker in --amount must match it:
wallet-cli agent-intent send --profile my-bot --from 0xSender \
--to 0xRecipient --amount '25 USDC' --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
# Native SOL: the 'SOL' ticker makes it a Solana send; base58 addresses, optional on-chain memo:
wallet-cli agent-intent send --profile my-bot --account solana-1 \
--to RecipientBase58 --amount '0.5 SOL' --memo "Invoice 42"
# SPL token: a base58 --token is the mint, so the send is on Solana:
wallet-cli agent-intent send --profile my-bot --account solana-1 \
--to RecipientBase58 --amount '25 USDC' --token EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
# Validate everything and print the proposal without submitting (no keychain, no sign-in):
wallet-cli agent-intent send --profile my-bot --account ethereum-1 \
--to 0xRecipient --amount '0.01 ETH' --dry-run
- 仅限已注册的配置文件(其
agent-intent enroll审批已通过)。它使用配置文件的环境、注册时记录的 BFF 和 Keycloak URL(因此注册时的--bff-url/--keycloak-url覆盖设置会沿用),以及其在操作系统密钥链中的密钥。 - **仅限主网:**Ethereum 用于 ETH 和 ERC-20,Solana 用于 SOL 和 SPL 代币。
--token根据格式选择网络(0x合约 → Ethereum,base58 铸币地址 → Solana);不指定时,SOL→ Solana,其他任何代币代码 → Ethereum。--account标签必须对应该网络的主网账户。Agent Intent SDK 不支持测试网,因此 staging 配置文件也会提议主网转账。 - **地址:**在 Ethereum 上,
--from、--to和--token必须是0x加 40 位十六进制字符;混合大小写的输入必须通过其 EIP-55 校验和检查,该检查可以发现复制地址时的拼写错误。在 Solana 上,--from和--to必须是规范的 base58 32 字节地址。 - 代币会在 CAL 中查询(
assets token ethereum|solana <address>),且--amount中的代币代码必须匹配。目前 Agent Intent 还无法发送 Token-2022 铸币,因此会拒绝此类铸币。 - Solana 不接受
--fee-strategy,因为服务会设置优先费。--memo(1–280 个字符;表情符号计为两个字符;仅限 Solana)会与转账一起上链。 - **金额精确,绝不舍入。**小数位数超过资产支持的位数、金额为零,或金额超过 uint256(Solana 上为 u64 lamports)都会报错。JSON 输出中的
amount以基本单位(wei、代币单位或 lamports)表示,为字符串;信封中的network为ethereum:main或solana:main。 --fee-strategy slow|medium|fast(仅限 Ethereum,默认为medium)是要求人类批准的费用等级。wallet-cli 不会检查发送方余额;审核该意图的人需自行负责确认余额。- **不要盲目重试。**如果服务已接受请求(例如发生超时或链接无法读取),意图可能已经创建。请先检查前端再重新运行,否则会提议重复转账。服务拒绝请求时会说明原因及下一步操作(例如,发行方不匹配时需重新注册)。
提议兑换(agent-intent swap)
agent-intent swap 会提议一笔 Ethereum 兑换,供人工审核,方式与
agent-intent send 相同:它不会签名或广播,无需设备,并会打印一个审核链接。
它会先向 Swap API 请求报价,然后对最佳报价的交易对、金额和提供商进行签名,以便 Agent Intent 前端准备交易。
人工打开链接后,前端会获取最新报价并构建交易。
# Sell 0.5 ETH for USDC at the best quote (currency ids, as in `swap quote`):
wallet-cli agent-intent swap --profile my-bot --account ethereum-1 \
--from ethereum --to ethereum/erc20/usd__coin --amount 0.5 --description "Rebalance"
# Quote one provider only:
wallet-cli agent-intent swap --profile my-bot --sender 0xSender \
--from ethereum/erc20/usd__coin --to ethereum --amount 1000 --provider oneinch
# Quote and validate without submitting (doesn't read the agent key or sign in):
wallet-cli agent-intent swap --profile my-bot --account ethereum-1 \
--from ethereum --to ethereum/erc20/usd__coin --amount 0.5 --dry-run
- 仅限已注册的配置文件,与
agent-intent send相同。仅限 Ethereum 主网:--from和--to必须是ethereum或 Ethereum ERC-20 货币 ID(运行assets token ethereum <contract>可查看),发送方必须是--account标签或--sender地址。 - 金额使用人类可读单位(
0.5ETH、1000USDC),绝不舍入。小数位数超过资产精度、金额为零、带符号或使用指数表示,都会报错。报价中的接收金额会向下舍入至所购资产的精度。JSON 输出中的fromAmount和toAmount为字符串。 - **提供商:**仅支持
oneinch、velora、okx和lifi,也就是前端目前能够转换为交易的提供商(1inch会被接受为oneinch)。如果报价需要代币授权或 Permit2 签名,则会跳过,因为前端尚无法准备这些内容,意图会因此一直卡在审核阶段。 --to-amount会对你指定的预期金额进行签名,而不是对报价金额进行签名。兑换仍会请求报价,因此提供商始终是前端能够准备交易的提供商。- 不要盲目重试,与
agent-intent send相同:如果服务已接受请求,意图可能已经创建。
列出 Agent 的意图(agent-intent intents)
agent-intent intents 会按时间从近到远列出已注册配置文件提议的意图。它会像 send 一样使用配置文件密钥登录;服务只会返回该 Agent 自己的意图,即使在同一 Trustchain 上,也不会返回其他 Agent 的意图。
wallet-cli agent-intent intents --profile my-bot
wallet-cli agent-intent intents --profile my-bot --status signed,broadcast --page-size 50
# Next page: pass the previous page's nextCursor (filters and page size carry over):
wallet-cli agent-intent intents --profile my-bot --cursor <nextCursor> --output json
- 每次运行只返回一页。
--page-size可设为 1、5、10、50 或 100(默认值为 10)。如果还有更多意图,JSON 中会包含nextCursor(人类可读输出会打印后续命令);最后一页的值为null。使用--cursor时,--status和--page-size会被忽略。 --status接受以逗号分隔的状态:created、crafted、signed、broadcast、success、failed、rejected、cancelled、expired。未知状态会在登录前被拒绝。- JSON(
--output json):包含profileId、count、nextCursor,以及intents[],其中包含id、status、type、network、sender、recipient、amount(精确的基础单位,字符串)、displayAmount(例如"0.01 ETH",资产未知时为null)、asset、feeStrategy、description、failureReason、createdAt和updatedAt。空页也算成功,且count: 0。 - **只读:**它不会创建、批准或取消任何内容,因此失败后始终可以安全地重新运行。
检查单个意图(agent-intent status)
agent-intent status 会根据 agent-intent send 打印的 ID(或 agent-intent intents 列出的 ID),读取该配置文件提议的单个意图的当前状态和详情。
ID=0192f7a4-0000-7000-8000-000000000001
wallet-cli agent-intent status --profile my-bot --intent "$ID"
# Poll while the intent is known to be in progress; stop on a final state (terminal: true),
# an unknown one (terminal: null) or an error, then read the status:
while wallet-cli agent-intent status --profile my-bot --intent "$ID" --output json | jq -e '.terminal == false' >/dev/null; do sleep 30; done
# To wait for one state, e.g. until the user signs, poll intent.status instead (signed is not final):
while wallet-cli agent-intent status --profile my-bot --intent "$ID" --output json | jq -e '.intent.status == "created" or .intent.status == "crafted"' >/dev/null; do sleep 30; done
- 状态:
created、crafted、signed、broadcast表示正在进行(terminal: false);success、failed、rejected、cancelled、expired表示已结束(terminal: true)。如果此 wallet-cli 版本不识别某个状态,会按原样显示,并将terminal设为null:不要将其视为已结束状态或错误。 - JSON(
--output json):包含profileId、terminal,以及intent;其字段与agent-intent intents条目相同(精确的基础单位amount为字符串,还包括displayAmount、失败意图的failureReason和时间戳)。 - **未找到:**未知 ID 和其他 Agent 的意图会返回相同结果,因此错误信息无法区分两者。格式错误的 ID 会在登录前被拒绝。
- 需要使用允许 Agent 读取单个意图的服务;较旧的服务会说明这一点,并指向
agent-intent intents。
取消意图(agent-intent cancel)
agent-intent cancel 会撤回配置文件提出的意图,前提是用户尚未签署。意图无法编辑:如果要在用户签署前更改提案,请先取消,再发送新的提案。
wallet-cli agent-intent cancel --profile my-bot --intent 0192f7a4-0000-7000-8000-000000000001 --yes
- 适用时机: 只有处于
created或crafted状态的意图才能取消。此版本 wallet-cli 不认识的状态会发送给服务,由服务决定如何处理。其他任何已知状态(包括signed,因为其交易仍可能上链)都会失败,并返回当前状态,不作任何更改。取消操作不可逆。 - 确认: 在终端中,命令会显示意图,并在 stderr 上询问
[y/N]。在没有终端的情况下(脚本、AI Agent、管道输入),除非提供--yes,否则命令会在签名之前拒绝操作。作为 Agent,只有在用户要求取消此意图时才传入--yes。 - 重复操作: 取消已取消的意图会成功,并报告
alreadyCancelled: true;即使另一条取消请求先到达,也一样。如果用户在此期间签署了意图,命令会失败并报告新状态。 - JSON(
--output json):返回profileId、cancelled: true、alreadyCancelled、readBack,以及服务在取消后报告的intent(字段与agent-intent status相同)。readBack: false表示读取失败:intent是较早读取到的意图,并标记为cancelled。如果用户拒绝确认提示,则会输出cancelled: false和declined: true,并附上intentId(与ring destroy不同,后者的cancelled: true表示用户拒绝了提示)。 - 未找到: 对于未知 ID 和其他 Agent 的意图,返回相同的结果,与
agent-intent status一致。
earn(质押与 DeFi 收益)
Earn 涵盖两种流程:Ethereum ERC-4626 DeFi 金库(存入/赎回)和 Solana 原生质押(委托/取消委托)。yields 和 positions 为只读操作(无需设备);deposit 和 withdraw 需要在设备上签名。
只有 ethereum 和 solana 支持
deposit/withdraw。其他网络会显示在earn yields中(仅供参考),但无法通过 CLI 向其存入资产。
earn yields
列出收益机会(无需设备)。不指定 --network 时,会显示每个网络的主要收益率。指定 -n ethereum 或 -n solana 时,还会显示具体的存入目标,每个目标末尾都会提供要传给 earn deposit 的确切 → --product <id> 值:
- ethereum → ERC-4626 金库 ID(例如
1_0x7daeba3f217614e409f85d3014d33923a6b03630)。 - solana → 验证者投票账户。CLI 会将由 Ledger 运营的验证者(“Ledger by Figment”、“Ledger by Bitwise”)列为推荐目标;任何其他有效的投票账户也可用作
--product。
wallet-cli earn yields
wallet-cli earn yields -n solana
wallet-cli earn yields -n ethereum --output json
没有单独的“列出验证者 / 金库”命令——earn yields -n <network> 就是查找有效 --product 的方式。在 JSON 中,该值是每行的 vaultId(ETH)或 validator(SOL)字段。
earn positions
列出账户的活跃 Earn 仓位(无需设备)。仅支持基于账户的网络(solana、ethereum)。
wallet-cli earn positions solana-1
wallet-cli earn positions solana-1 --fresh # request a background refresh
--fresh 会将过时的行标记为需要异步后端刷新;刷新后的数据会在重新运行命令时显示,而不会出现在同一响应中。请留意 (stale) 标记。
Solana 质押账户: 对于 Solana 账户,命令还会读取链上质押账户,并为每个账户打印 → --stake-account <address>、其 state(active / inactive / activating / deactivating)、余额和验证者。这是获取 earn withdraw 所需 --stake-account 值的途径。 在 JSON 中,这些账户会作为与 positions 并列的顶层 stakes[] 数组返回(每个条目包含:stakeAccount、validator、state、stakeBalance、withdrawable);如果没有质押账户,则完全省略 stakes 键。即使后端快照仍为空,存入后质押账户也会立即显示在此处。(需要进行链同步;如果无法连接,仍会打印后端快照,并附带警告。)
earn deposit
在 Solana 上质押,或在 Ethereum 上存入金库。需要操作设备进行签名——绕过沙箱。--product 的值来自 earn yields -n <network>(见上文)。--amount 必须包含资产代码。
# Solana: --product is a validator vote account
wallet-cli earn deposit solana-1 --product 26pV97Ce83ZQ6Kz9XT4td8tdoUFPTng8Fb8gPyc53dJx --amount '1.5 SOL'
# Ethereum: --product is a vault id
wallet-cli earn deposit ethereum-1 --product 1_0x7daeba3f217614e409f85d3014d33923a6b03630 --amount '100 USDC'
# Validate without signing (no device, no sandbox bypass)
wallet-cli earn deposit solana-1 --product 26pV97… --amount '1.5 SOL' --dry-run
Solana 的 stake.createAccount 会在一笔交易中创建并委托质押账户。Ethereum 存款可能需要执行两笔交易(ERC-20 的 approve,然后是 deposit)。
首次存入 ETH 金库——试运行无法验证存款步骤。 首次向你从未使用过的金库存款时,需要执行 approve → deposit,且只有链上存在非零授权额度后,才能构建存款交易。在 --dry-run 模式下不会广播任何交易,因此如果仍需执行 approve,CLI 会验证 approve 并跳过存款交易的构建(状态为 not-simulated …,整体结果为 dry-run: approve validated; deposit needs an on-chain allowance to simulate),而不是显示后端含糊的 500 错误。这是预期行为——不是余额错误。验证存款步骤的唯一方式是实际运行(广播 approve,等待确认,然后执行 deposit)。此时应将试运行成功视为“approve 没问题”;实际运行前请先向用户确认,因为这需要在设备上签署不可逆操作。授权额度存在后,再次运行 --dry-run 就能正常模拟存款。
earn withdraw
取消质押(Solana),或从金库赎回(Ethereum)。需要操作设备——绕过沙箱。
- Ethereum: 必须提供
--product <vault-id>;--amount可选。金额使用金库的资产单位(例如'50 USDC');如果指定了资产代码,则必须与金库资产相符。如需全部退出,请省略--amount: CLI 会发送amount:"max",后端将赎回全部份额余额,不留零头(全部退出时不要自行计算资产金额——份额→资产的汇率会变化)。 - Solana: 必须提供
--stake-account <address>。分两阶段操作: 先运行一次以执行undelegate(停用),等待停用纪元边界(约 2–3 天),然后再次运行并添加--finalize,将现已停用的 lamports 提取回主账户。coin-solana 会在链上计算可提取金额,因此 finalize 时会忽略--amount。
# Ethereum vault redeem
wallet-cli earn withdraw ethereum-1 --product 1_0x7daeba3f… --amount '50 USDC'
# Solana phase 1: deactivate
wallet-cli earn withdraw solana-1 --stake-account <stakeAccountAddr>
# Solana phase 2 (after ~2–3 days): withdraw
wallet-cli earn withdraw solana-1 --stake-account <stakeAccountAddr> --finalize
可通过 earn positions <account> 获取 Solana 的 --stake-account 地址(查看其 stakes[] / → --stake-account 行)——这就是你之前运行 earn deposit 时创建的质押账户。
常见错误
| 错误 | 原因 | 解决方法 |
|---|---|---|
Amount must include a ticker | --amount 缺少代币代码 | 询问用户指的是哪种资产——不要猜测。然后将代币代码内联传入,例如 --amount '0.5 ETH'。 |
Ticker UNKN not found in account | 账户余额中没有该代币代码 | 运行 balances <account>,并向用户显示此账户持有的代币代码。询问用户要使用哪个代币代码,或他们是否指的是其他账户——不要擅自替换为其他代币代码。 |
[✖] Wrong app. Open Ledger dashboard. (exit code 4) | 在打开货币应用时调用了 genuine-check。与其他设备命令不同,genuine-check 针对的是仪表板,且不会自动启动应用。 | 请用户退出设备上正在运行的应用(在应用主屏幕上短按两个按钮,直到显示 Quit,然后确认),再重新运行 genuine-check。其他设备命令(account discover、receive、send、swap execute)不会遇到此问题——它们会自动提示启动正确的应用。 |
[✖] Rejected on device. No action taken. | 用户在设备上拒绝了签名请求 | 用户是有意拒绝的。询问用户是要重试还是中止——不要自动重试。如果用户选择重试,请让他们先在设备屏幕上检查金额、收款人和费用,再批准。 |
[✖] Rejected on device. App was not opened. | 用户在设备上拒绝了打开应用的提示 | 请用户在设备上确认打开应用的提示,然后重新运行命令。 |
[✖] Timed out talking to the Ledger over USB. The device may be busy or locked. Retry the command. | 沙盒阻止了 USB 连接,或设备正忙/已锁定 | 告知用户该命令需要设置 dangerouslyDisableSandbox: true,并在使用绕过设置重新运行前征求确认。设备命令(account discover、receive、send、genuine-check、swap execute、earn deposit、earn withdraw、ring init)预期需要此绕过设置;如果其他命令触发此错误,应先调查,再决定是否绕过,而不是不加思索地禁用沙盒。 |
[object Object] 或乱码 APDU 输出 | 两条设备命令并行运行(发生争用) | 依次运行会操作设备的命令——绝不要通过并行工具调用运行。 |
[✖] Ledger not detected. Plug in, unlock, retry. (exit code 3) | 设备已关机或未连接 | 请用户开启设备、解锁设备并通过 USB 连接,然后重新运行命令。 |
device-state … awaiting_approval … reason: unlock(JSON 流) | 设备已锁定 | 保持命令运行——解锁后,CLI 会自动继续。请用户使用 PIN 解锁设备。 |