hec-ovi/blockchain-skill
GitHub: hec-ovi/blockchain-skill
为 AI agent 打造的非托管链上钱包与 Solidity 合约开发工具包,覆盖 EVM 和 Bitcoin 上的钱包管理、交易、兑换、合约部署及本地沙盒验证全流程。
Stars: 2 | Forks: 0
# agent-wallet (blockchain-skill)
这是一款允许任何 AI agent 直接在链上操作钱包的工具包:创建钱包、接收、发送、兑换(swap)、包装(wrap)、签名、部署和验证 Solidity 合约,以及了解已部署合约的工作原理。密钥会在你自己的机器上生成并存储(加密的 keystore v3),并且交易会直接发送到公共 RPC endpoint。无需 MetaMask,无需交易所,无需任何托管。
一个引擎,两副面孔:一个自包含的 CLI(`agent-wallet <动词>`)以及复制到所有发现规范(repo 根目录、`skills/`、Claude 和 Codex 插件目录)的丰富 agent 技能。到处都是相同的动词,相同的 JSON 封装。
包中附带了两个技能。`agent-wallet` 是下方的钱包和链表面。`agent-solidity` 是一个用于编写和审计合约的受限工作流,带有一个可在本地 EVM 上证明合约的环境。参见 [Solidity 工作流](#solidity-workflow)。
## 安装
### Agent CLI(即插即用)
```
/skills add hec-ovi/blockchain-skill
```
这会将技能包(包括位于 `dist/agent-wallet.mjs` 的捆绑 CLI)复制到工作区中。然后 agent 会解析 CLI,运行一次 `agent-wallet init`,并使用这些动词。无需第二个引导脚本。
其他技能安装程序:`npx skills add hec-ovi/blockchain-skill`,Claude `/plugin marketplace add hec-ovi/blockchain-skill`。
### 宿主机 CLI(可选)
需要 Node >= 22.18。
```
npm install
npm run build
./agent-wallet init
./agent-wallet help
```
备用宿主机引导:`bash bin/init.sh` 或
`curl -fsSL https://raw.githubusercontent.com/hec-ovi/blockchain-skill/HEAD/bin/init.sh | bash`。
将密钥放入被 git 忽略的 `.env` 中(参见 `.env.example`);CLI 会自动加载它。至少需要设置 `AGENT_WALLET_PASSPHRASE`(用于加密 keystore)。
## Agent 如何使用它
1. 解析 CLI(在 PATH、`.noob/skills/agent-wallet/agent-wallet` 或 `node …/dist/agent-wallet.mjs` 中)。
2. 每个会话执行一次 `agent-wallet init`(体检 + 数据目录)。
3. 动词:`wallet-create`、`wallet-export`、`balance`、`send`、`swap`、`wrap`、`contract-*`,……
每个动词都是一个独立的进程:在 stdout 上输出 JSON 封装,然后退出。它不是长时间运行的服务器。
通过从外部钱包或公共测试网水龙头网站发送来为测试网提供资金。此工具包不提供水龙头 gas。
## 功能
| 领域 | 动词 | 网络 |
|---|---|---|
| 钱包 | wallet-create, wallet-import, wallet-list, wallet-addresses, wallet-export | EVM + Bitcoin |
| 读取 | balance, utxos, fees, tx | EVM + Bitcoin |
| 发送 | send (native, ERC-20, BTC, sweep) | EVM + Bitcoin |
| 兑换 | swap-quote, swap (CoW, Kyber, Uniswap), wrap, unwrap | EVM |
| 合约 | contract-compile, contract-deploy, contract-call, contract-write, contract-learn, contract-verify | EVM |
| Solidity 工作流 | contract-step, sandbox-run | local |
| 会话 | init, version, help | local |
每个默认后端都是无密钥的。可选的 Etherscan 密钥仅用于提高 contract-learn 的限制。
## Solidity 工作流
部署的代码是不可变的并且持有资金,因此合约工作作为一个流程运行,每次交给 agent 一个步骤,并且在当前步骤生成文件之前拒绝继续推进。
```
agent-wallet contract-step # the mode picker
agent-wallet contract-step --mode build # spec, threat model, design, implement,
# compile, test plan, sandbox, audit gate,
# fix, gas, docs, deploy plan, deploy, handoff
agent-wallet contract-step --mode review # audit existing source or an on-chain address
agent-wallet contract-step --mode ship # deploy already-reviewed source
agent-wallet contract-step --status # where the walk stands, what blocks it
```
产物会存放在 `./.contract-work` 中。跳过某个步骤会返回 `WALK_BLOCKED` 并指出你缺失的步骤;在一个步骤上循环六次会返回 `WALK_LOOPING` 并告知 agent 将控制权交还给人类。步骤主体位于 `layers/workflow/prompts/` 中,并在构建时被内联到 bundle 中,因此它们是每次加载一个,而不是一次全部加载。
`sandbox-run` 是 CLI 进程内的一个真实 EVM(`@ethereumjs/vm` v10,包含直至 Amsterdam 的硬分叉)。它使用 solc 0.8.36 进行编译、部署、从命名账户发送交易、解码事件和 revert 原因(按名称分类的自定义错误,带有其含义的 `Panic` 代码)、测量 gas、报告针对 EIP-170 限制的 runtime 大小,并检查你声明的 invariant。
```
agent-wallet sandbox-run --plan ./plan.json
```
```
{
"accounts": { "alice": "10 ether", "mallory": "5 ether" },
"sources": [{ "path": "Vault.sol", "file": "contract.sol" }],
"deploy": [{ "as": "vault", "contract": "Vault", "from": "deployer" }],
"steps": [
{ "to": "vault", "from": "alice", "fn": "deposit", "value": "2 ether" },
{ "to": "vault", "from": "mallory", "fn": "sweep", "expect": "revert", "revert": "NotOwner" }
],
"invariants": [{ "name": "solvency", "to": "vault", "fn": "totalHeld", "op": "gte", "value": "2 ether" }]
}
```
无需 Foundry,无需 Hardhat,无需 anvil,无需 node,无需测试网资金,无需 `npm install`。它是确定性的(固定的区块,零 base fee,从账户名称派生的密钥),因此失败是可重现的,而通过即是证据。Gas 会被计量但永远不会被扣除,这使得余额断言极其精确。
审计步骤根据 EEA EthTrust 安全级别和 OWASP 智能合约 Top 10(2026)对十个维度进行评分,并以所有十个维度全部通过且没有未解决的关键或高危发现作为准入条件。这是一次带有可运行证明的自动审查,而非独立的专业审计。
## 此工作流无法解决的问题
### 模型才是瓶颈,而非工作流
Solidity 对小错误的惩罚方式是大多数代码所没有的。Bytecode 是公开的、不可变的、持有资金的,地球上的任何人都可以调用它。没有补丁发布,也没有回滚,因此在 Web 服务中只需周一早上提个工单的缺陷,在这里就是永久性的损失。
前沿模型也会在这方面犯错。工作流缩小了错误可能藏匿的空间:它迫使在任何代码存在之前进行威胁建模,在审计之前进行可执行证明,并在任何东西上链之前进行审计。它无法做到的是将一个弱模型变成一名合格的 Solidity 工程师。它只是让错误在更早、成本更低的时候显现,并在人类能够看到的地方暴露出来。
在我们自己的基准测试中,可见的失败都属于简单类型。35B 模型在自定义错误上写了 `indexed`,Solidity 拒绝了它,编译器捕获了它。它部署了两次但只报告了一次,链上显示了这一点。真正重要的失败是那些能够编译通过、在沙盒中通过测试并且在审计中读起来没问题的合约,因为流水线中没有任何东西在检查它们。
所以:对于本地模型,请将输出视为供人类审查的草稿,而不是完成的合约。当十个维度通过且没有未解决的关键或高危发现时,审计步骤会报告 PASS。这是一次带有可运行证明的自动审查。它不是独立审计,不是形式化验证,并且它不应成为涉及真实资金之前的最后一道工序。
### 为什么小模型会陷入循环,以及为什么这不是门限的错
小模型会原地打转。我们的模型两次在同一步骤触发了 50 轮上限,重复提供同一个步骤而不是继续推进,并且有一次保存了一个满足门限的产物,却没有执行该门限所代表的实际工作。人们很容易将此理解为工作流困住了 agent。但事实恰恰相反。门限是一段确定性的代码,它只问一个问题:文件存在吗?如果一个模型不断尝试但始终没有带着文件出现,那说明它未能制定计划,而不是被阻挡了。
产物门限、访问上限和单步提供机制的意义在于,将不可见的失败转化为可见的停止。`WALK_LOOPING` 不是工具包中的错误;它是工作流拒绝让 agent 陷入死循环一下午,并将问题交还给人类。一个没有这些检查的流水线并不会更少循环,它只是在静默地循环。
还有一种更微妙的失败是门限无法捕捉的。面对一个内容丰富的 prompt,模型会生成该 prompt 所要求的结构,无论其背后的内容是否真实。一份五 KB 的威胁模型列出了每一种攻击类别,却没有将其中任何一种应用于面前的合约,这与一份真正进行了工作的五 KB 威胁模型看起来一模一样。门限只检查产物是否存在,而不检查它是否优秀。工作流中只有两样东西检查实质内容:编译器,它会拒绝错误的代码;以及沙盒,它运行漏洞利用并报告其是否耗尽了合约。这两者的分量远远超过任何文字步骤,审查者也应以同样的方式权衡它们。
这对于任何进行测量的人来说都有一个结论。我们在一次基准测试期间更改了三次技能,每一次更改都改变了 agent 的行为。在调整 prompt 期间收集的数据描述的是调整本身,而不是技能。冻结流程,然后再测量它,最后更改它。同时进行这三项操作产生的结果将无法与任何事物进行比较,包括它们自己。
## 安全性
默认允许主网和测试网。要锁定主网,请在 `~/.agent-wallet/config.json` 中设置 `{"gate":{"allowMainnet":false}}`(可选的按链允许列表和按笔交易上限)。每个状态更改操作在签名前仍然会通过门限检查;读取操作永远不会受限。
## 我们验证了什么
**自动化测试套件。** `npm test` 构建 bundle,然后运行每一层的合约测试、BIP-86/BIP-84 向量、币种选择、封装验证、真实的 CLI e2e(源码 + bundle),以及 `tests/check_skill.sh`(技能副本按字节比对一致,版本锁步,启动器 + `dist/agent-wallet.mjs` 存在)。
**沙盒真实基准。** 测试夹具是一对故意设计成可重入的 `Vault` 及其 `Attacker`。该套件断言漏洞利用确实耗尽了金库(攻击者存入 1 ETH,拿走 3 ETH,invariant 被打破),并且 checks-effects-interactions 版本在未更改的情况下阻止了相同的计划。它在从 London 到 Osaka 的每个已公布的硬分叉上运行。
**实时公共网络检查**(通过 `RUN_LIVE=1` 选择加入):Sepolia 和 Bitcoin signet 读取、Sourcify ABI 获取、CoW / Kyber 报价。
**Agent 基准测试:** Sepolia 上的两个对等节点,测量了 26 个 CLI 动词中的 25 个(参见本 README 底部)。涵盖钱包创建、agent 间支付、兑换以及从规范到部署合约的完整 Solidity 路径,然后由另一个 agent 进行调用。
## 架构
`layers/` 下的各层分别拥有 `CONTRACT.md`、`schema/`、`src/` 和 `tests/`。跨层 TypeScript 导入仅限于已发布的模块(导入边界测试);CLI 组合根是 `agentio`。出站 agent I/O 是一个 JSON 封装。参见 `docs/ARCHITECTURE.md` 和 `docs/INDEX.md`。
层级顺序:core、keys、chains、read、sign、gate、send、learn、contracts、swap、sandbox、workflow、agentio(CLI + init)。
发布产物:`npm run build` 写入 `dist/agent-wallet.mjs`(单个 Node ESM 文件)。技能安装和包都会附带该文件,因此 agent 只需要 Node。
## Agent 基准测试:Sepolia 上的两个对等节点,钱包与 Solidity
**agent-wallet 0.5.0** 的实时端到端测试:两个独立的 agent 工作区,两个钱包,普通的英文 prompt。没有为 agent 选择任何动词。在 agent 阅读技能后,下面的每一条命令都是 agent 自己挑选并输入的。
### 设置
| 项目 | 选择 | 原因 |
|---|---|---|
| 运行时 | noob CLI `0.5.1`(`noob exec -p ... --yolo`) | 真实 agent 循环:加载技能,解析 CLI,运行动词,读取 JSON 封装 |
| 安装 | 将此 repo `git clone` 到 `.noob/skills/`,即 `/skills add` 所走的路径 | 仅需 Node,agent 工作区中无需 `npm install` |
| 模型(主体) | **Qwen3.6-35B-A3B**,GGUF **Q8_0**,本地 | 小型 MoE,约 3B 激活参数。问题不在于它能否编写出优秀的 Solidity;而在于该技能能否引导弱模型完成任务 |
| 模型(尾部) | **Claude Haiku 4.5** | 在同一技能上使用第二个模型系列,用于最后几个动词 |
| 服务器 | llama.cpp Vulkan,AMD Strix Halo (gfx1151),**64K 上下文,单插槽** | 刻意紧凑:一次一个请求,在 48K 时进行压缩 |
| 网络 | Ethereum Sepolia (`11155111`) | 公共测试网,真实的 RPC,真实的 gas,真实的 Uniswap 池 |
| 对等节点 | 地址 |
|---|---|
| A | `0x0C694913133AF426Dbb25504d3c13C0849C7F60b` |
| B | `0x9B2947f510034A6A5EE02a7e9f508CCF9171477` |
每个 agent 都根据简单的请求创建了自己的钱包。对等节点 A 从外部接收了一次资金;此后的每一次转账都是由 agent 驱动的。
### 动词覆盖范围
**26 个动词中的 25 个,已被测量。** 每个工作区中捆绑 CLI 上的 shim 记录了模型实际调用的每一个动词,所以这是被计数出来的,而不是断言出来的。
```
init version wallet-create wallet-import wallet-list
wallet-addresses wallet-export balance fees tx
utxos chain-resolve chain-check send wrap
unwrap swap-quote swap contract-learn contract-compile
contract-deploy contract-call contract-write contract-step sandbox-run
```
`contract-verify` 是唯一一个没有 agent 练习的动词:它是在此基准测试运行之后才被接入 CLI 的,而且它需要 `forge` 二进制文件,这是工具包的其余部分刻意避免使用的。
### 链上矩阵(agent 驱动)
| 区块 | 发送方 | 操作 | 交易 |
|---|---|---|---|
| 11368256 | (外部) | 为对等节点 A 注资,0.009 ETH | [0xe311e2f5…](https://sepolia.etherscan.io/tx/0xe311e2f5f9014dd41161b97f86bef8fe4efdb6dc4884b5b4517ffccb21fc5ce1) |
| 11368267 | 对等节点 A | **支付给对等节点 B** 0.002 ETH | [0x350f2f7f…](https://sepolia.etherscan.io/tx/0x350f2f7ff73c5aace4bb6e9f3d2eb14576cd8e0877847c7124bab06d86168c63) |
| 11368345 | 对等节点 A | 将 0.001 ETH 包装(wrap)为 WETH | [0x95d31902…](https://sepolia.etherscan.io/tx/0x95d31902382fd3a9f97f765bfe1f45692be98edbe09490b70535a91a461dc646) |
| 11368350 | 对等节点 A | 批准路由 | [0x778253c4…](https://sepolia.etherscan.io/tx/0x778253c46fa128e7c051c45342c741d65b94f7f8aefe1408adfb5077e8f50e6f) |
| 11368351 | 对等节点 A | **兑换(swap)** WETH 为 USDC (Uniswap) | [0x6bdd23dd…](https://sepolia.etherscan.io/tx/0x6bdd23dd6c0359d9834131bfe1750224cf4a07e28aa457441cfaf25e0c832a5b) |
| 11368687 | 对等节点 B | **调用对等节点 A 部署的合约** | [0x2e732600…](https://sepolia.etherscan.io/tx/0x2e7326005cb56deb1c7af0dba745e0c1775153d06f0f7e72dc1d5cbcad6520b6) |
| 11368697 | 对等节点 A | **部署** `Ping` | [0x7d4cc4f9…](https://sepolia.etherscan.io/tx/0x7d4cc4f9829d5c8806ab72b7bb4f8ef34b7d37fdb51c73bb222bea05505b5c0e) |
| 11368699 | 对等节点 A | 解包(unwrap)0.0002 WETH | [0xcd4316c9…](https://sepolia.etherscan.io/tx/0xcd4316c9644c4068747be5f91b0abf10560d6e61ccb219a3b17429eb584ace1d) |
Sepolia WETH `0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9`,USDC `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238`。
### Solidity 方面
从“制作一个包含 ping 函数的合约,并将其部署在 sepolia 上”开始,仅凭此指令,本地 35B 模型根据其描述加载了工作流技能,将 14 个步骤镜像到自己的待办事项列表中,并按顺序执行。无需提示,它生成了自定义错误、两步所有权、一个 indexed 事件、NatSpec 以及用于重入证明的攻击者合约。在此过程中:
- 编译门限捕获了一个真实的错误(在自定义错误上使用了 `indexed`,被 Solidity 拒绝),agent 修复了它。
- 沙盒运行了 17 个步骤,其中 5 个访问控制否定测试全部 revert `OwnableNotOwner()`,3 个 invariant 保持不变,零编译器警告,899 字节的 runtime 代码。
- 产物门限发挥了真实作用:agent 试图在未保存 `sandbox.json` 的情况下进入审计,得到了 `WALK_BLOCKED`,随后予以配合。
- 审计门限在重新冷读源码后通过了所有十个维度的检查。
- 该工作流在 64K 窗口的 75% 处经历了一次上下文压缩,且没有丢失其位置。
部署的合约是经过独立检查的,而不是直接采用 agent 的报告:重新编译 runtime bytecode 并逐字节比较(剥离了元数据),确认每个 ABI 选择器都存在于部署的代码中,回读 `owner()`,并执行了真实的 `ping()` 写入。
### 本次运行的成本
钱包层面很快:创建钱包需 20 秒,发送需 50 秒,包装和兑换需 137 秒,解包需 48 秒。整个双对等节点钱包和兑换序列耗时 27 分钟。
合约工作流并不快。在 35B 模型上以 43 t/s 的速度生成,一次完整的流程大约需要 8 分钟,因为这些步骤要求生成大量的书面产物(规范、威胁模型和设计每份都有 3 到 5 KB)。有两个限制值得说明,而不是隐瞒:
- noob 将单次输入的上限设定为 50 轮。14 个步骤的工作流在该模型上需要的轮次超过了这个限制,连续两次停在了第 11 步。工作流被设计为可以跨输入恢复,所以这只是节奏问题,而不是失败。
- 每次压缩都会迫使服务器重新处理整个重写的上下文,在 40K token 时大约需要 50 秒。整个会话期间发生了 31 次这样的操作。
Claude Haiku 4.5 使用相同的技能针对相同的 CLI 运行,在 115 秒内完成了四个动词,并在 80 秒内又完成了两个。
### Agent 发现了什么
四个缺陷,每一个都是由 agent 在执行普通工作时发现的,并且都在 0.5.0 版本中得到了修复:
- `.env` 只能从确切的工作目录中读取,而相对的 `AGENT_WALLET_HOME` 是相对于它进行解析的,因此一个空的 keystore 被悄悄地创建在了临时文件旁边。合约工作流告诉 agent 在一个临时子目录中工作,因此钱包在它这么做的那一刻似乎就消失了。
- Agent 在每条命令上都内联了 `AGENT_WALLET_PASSPHRASE=...`,将密钥暴露在了记录和 shell 历史记录中。在技能被更改为禁止此操作后,重新运行显示出现次数为零。
- `contract-step --mode ` 清空了工作目录,而这恰好是 agent 尝试恢复被中断的工作流时会用到的命令。它现在会在第一个未保存的步骤处恢复。
- `wallet-import` 只接受 `--mnemonic "twelve words"`,因此助记词必然会进入 shell 历史记录。现在有了 `--mnemonic-file` 和 `--mnemonic -`。
有一个弱点尚未修复,值得一提:在不指定链的情况下被要求解包时,模型假设是主网,读取到那里的零余额并报告钱包为空。它停止并询问而不是采取行动,而且无论何种情况门限都会拒绝未经授权的写入,但是先询问哪个网络的指令并没有被传达下去。
**本次运行不在范围内:** Bitcoin 花费(只读)、主网、浏览器源码验证。
**日期:** 2026-07-28 · agent-wallet **0.5.0** · noob **0.5.1** · 本地 **Qwen3.6-35B-A3B Q8_0** 和 **Claude Haiku 4.5**。
标签:Homebrew安装, MITM代理, Solidity, Web3, 人工智能代理, 加密货币钱包, 区块链, 智能合约, 自动化攻击