MINARA
安全

资金确认机制

每个涉及资金移动的工具都经过「预览再执行」门控。本文介绍其设计原因、覆盖范围,以及唯一的例外情形。

你告诉 Agent:"把 100 USDC 兑换成 ETH。"Agent 不会直接执行,而是先弹出一张确认卡片,展示交易细节:

Sell: 100 USDC (Ethereum)
Buy:  ~0.0286 ETH (estimated, 0.5% slippage)
Route: Uniswap V3
Gas estimate: ~$1.20

确认内容符合你的意图后,点接受。此时 Agent 才会广播交易。

为什么 Agent 不直接执行? 因为 LLM 会误读输入。"100 USDC"可能变成"1000 USDC",你输入的地址可能偏移一个字符,链也可能悄悄从 Ethereum 切换到 Base。一旦广播,这些错误都无法撤回。因此,每个涉及资金的工具在结构上都分为两步:先预览,再执行。

合约约定

每个涉及资金移动的工具都在 ToolEntry 上声明 controlPolicy.confirm。控制策略门在工具调用否决点运行预览、收集同意,然后才把调用交给只负责执行的 handler。这由运行时强制执行,不靠提示词,也不在 handler 内部。

为什么用硬约束,而不是提示词层面的软性要求? 因为在提示词注入、恶意技能的障眼法,或 LLM 将恶意工具结果视为指令等情况下,LLM 可能"遗忘"提示词级别的规则。模型只需带着操作参数调用一次工具。没有确认证据时,门返回预览信封,绝不会发起交易。客户端渲染确认卡片;模型看不到预览,也没有第二次工具调用。

策略定义在 tool-control-policy.ts。 解释它的钩子在 tier-gate.ts。 每个新增的涉及资金的工具都必须声明 controlPolicy.confirm;未声明的 PR 会被 code review 拒绝。带 isFundMoving 却没有确认路径的条目会 fail-closed。

覆盖范围

工具在工具注册表中标记为 isFundMoving: true。以下按用途分组列出:

代币交易

  • swap_tokens:跨链 DEX 闪兑
  • buy_token / sell_token:显式买入 / 卖出
  • transfer_token:钱包到地址的转账

永续合约

  • open_perps_position / close_perps_position
  • minara_perps_wallet_sweep:子账户间余额划转
  • minara_perps_wallet_transfer:永续合约余额转账
  • minara_wallet_fund_perp:从现货向永续合约账户充值(存入 USDC)

Autopilot:开启或关闭自动交易

  • minara_autopilot_enable / minara_autopilot_disable

Autopilot 开关属于资金类操作,因为开启它即代表操作员授权 Agent 自主交易。一旦启用,后续每笔 Autopilot 交易均继承该授权,不会对每笔交易单独提示确认。

工作流

  • workflow_activate / workflow_deactivate

逻辑相同:激活工作流的那一刻,即代表你批准该自动化流程独立运行。

Strategy Studio:自有策略

  • strategy-codegen 技能的 deploy.sh

部署是一次性授权,详见下文策略部署是一次性授权

运行他人创建的策略

  • minara_top_strategies_apply_start:运行精选 Top Strategies 策略

这些操作会使用用户资金启动或停止自主交易,且不存在作者授权时机,因此与 Autopilot 一样走确认门(apply_start / sub_startMANUAL_ONLYsub_stopALWAYS_CONFIRM)。

直接下单到交易所

  • 所有 hyperliquid_* 下单 / 撤单 / 提现接口

如需新增涉及资金的工具,请标记 isFundMoving: true 并声明 controlPolicy.confirm。未声明的 PR 会被 code review 拒绝。

实际流程

从 Agent 调用到你点接受:

LLM: swap_tokens({
  sell_token: "USDC",
  sell_amount: 100,
  buy_token: "ETH",
  chain: "ethereum"
})

→ 门:没有确认证据
→ 运行声明的 preview(模拟),以 minara-confirm 信封拦住调用
→ 客户端渲染预览卡片;模型看不到它

你在卡片上点接受

→ 同一次调用进入只负责执行的 handler
→ handler 签名并广播
→ 返回 {tx_hash: "0x...", executed: true}

调用方传入的 confirm: true 仍可作为交互式同意证据。检查是宽松的(true"true"1"yes""on"),因为部分工具调用协议会把布尔值序列化成字符串。界面路径并不依赖模型传入该标志。

策略部署是一次性授权

策略部署的工作方式有所不同。strategy-codegen 技能的 deploy.sh 在部署时执行一次两步确认:不带 --confirm 运行时只打印完整的部署预览(标的、K 线周期、杠杆、子账户、最大回撤上限),你查看后做出一次性决策,再用同一条命令加 --confirm 重新执行。

之后,策略的生命周期脚本(start.shstop.shreconfig.sh)各自走同样的「预览 → --confirm」两步流程,其中 stop 默认会市价平掉未平仓位。这些是对已授权策略的调度操作,而非新的资金移动。

运行他人创建的策略则不同:不存在作者授权时机,因此 Top Strategies 的 minara_top_strategies_apply_start 确实会走确认门,与启用 Autopilot 的逻辑相同。

为什么有这个例外? 如果每笔算法交易都需要人工确认,策略就只是手动交易脚本。Strategy Studio 的意义在于在你预先设定的约束范围内委托执行。部署是你授权策略运行空间的时机;此后,策略受回撤上限、资产配置上限和部署配置中的标的白名单约束,而非逐笔交易的提示词约束。

这个例外仅适用于 Strategy Studio。不要在其他地方模仿该模式。工具层面的其他部分都走统一确认门。

MINARA_SKIP_FUND_CONFIRM:操作员级旁路

在非交互式场景下,有一个逃生口:环境变量 MINARA_SKIP_FUND_CONFIRM=1(或偏好 safety.skipFundConfirm)会让确认门把该调用视为已有证据。以下说明何时可用、何时绝对不可用:

合理用途(少数合法场景):

  • 回测。 调用方是 Python 测试框架,没有人工读取预览,且运行环境已针对历史数据进行沙盒隔离。
  • 工作流引擎执行。 工作流已在激活时获得批准,执行循环是在已授权工作流上调度,而非要求用户逐步确认。
  • CI 冒烟测试。 目的就是驱动涉及资金的路径并验证接口调用。

绝对不可用的场景:

  • 交互式 REPL 会话。 这会绕过保护你的最后一道防线。
  • "每次确认太烦了"的生产环境。 这等于把安全机制关掉。
  • Shell rc 文件。 不要把 export MINARA_SKIP_FUND_CONFIRM=1 写进 .zshrc 后忘掉。下次启动 Agent 时,它将在无防护状态下运行。

完整的环境变量参考文档见 环境变量 → MINARA_SKIP_FUND_CONFIRM

第 3 层与第 4 层各自拦截什么

最常见的疑惑:拦截行为属于第 3 层(本页)还是第 4 层(脚本风险闸门)?快速参考如下:

你的请求拦截层
"把 100 USDC 兑换成 ETH"(直接交易请求)第 3 层:控制策略门先预览,再确认
运行包含 subprocess.run(["minara","swap",…]) 的 Python 脚本第 4 层:脚本风险闸门检测到涉及资金的 CLI 调用,触发 YELLOW 提示
terminal 中运行 cast send 0x… 1ether第 4 层:闸门检查 shell 命令,触发 YELLOW 提示
修改文件,导致其内容包含 minara swap第 4 层:闸门扫描应用后的内容,触发 YELLOW 提示
通过 codegen 技能的 deploy.sh 部署策略脚本级两步确认:不带 --confirm 只出预览,带上才执行;后端风控层兜底

简而言之:第 3 层拦截 Agent 直接发起的涉及资金的工具调用;第 4 层拦截 Agent 运行的脚本和命令中包含的涉及资金的代码。 两者覆盖同一威胁的不同维度,并行运作。

操作员检查清单

  • ✅ 看到预览时,务必仔细阅读。核对目标地址、链、金额和滑点是否与你的意图一致。两步确认的存在,也是为了让你发现自己的失误。
  • ✅ 部署策略时,仔细审查部署配置。这是唯一一次被要求确认的机会。
  • ✅ 激活工作流时,在点击确认前从头到尾阅读工作流定义。后续执行不会再次询问。
  • ❌ 不要在交互式 REPL 会话中设置 MINARA_SKIP_FUND_CONFIRM=1,也不要写入 .zshrc.envrc
  • ❌ 不要接受你没读过的预览。确认依赖的是你的判断,而非 Agent。

本页目录