mcpField
W
wallet-cli-usage

wallet-cli-usage

github.com/ledgerhq其他7119 次安装2 周前更新
代码仓库

关于 wallet-cli-usage

用于 Ledger 钱包操作的 USB 命令行技能,支持 Bitcoin、Ethereum 和 Solana 网络。它涵盖账户与交易、质押、兑换、加密及 Agent 意图提案,并强调设备安全规则。

主要功能

  1. 01管理 Ledger 钱包会话和账户
  2. 02查看余额与交易记录
  3. 03发送、接收、兑换和质押资产
  4. 04使用 Ledger Key Ring 加密数据
  5. 05提交 Agent 意图以供审批

适用场景

  1. 01检查钱包余额和活动
  2. 02转账或兑换支持的资产
  3. 03管理质押仓位
  4. 04使用 Ledger 设备加密机密信息
  5. 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 …
  • 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.5 ETH、1000 USDC),绝不舍入。小数位数超过资产精度、金额为零、带符号或使用指数表示,都会报错。报价中的接收金额会向下舍入至所购资产的精度。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 解锁设备。

评论

支持 Markdown