Agent链上操作的技术挑战:从“能跑“到“安全运行“
Agent链上操作的技术挑战从能跑到安全运行AI Agent与区块链结合的核心命题不是能否让Agent发送交易——这是LangChain ethers.js组合在技术层面已经解决的问题。真正的挑战在于如何定义Agent在链上操作的权限边界如何在Agent被攻击或做出错误决策时限制损失以及如何协调多个Agent的链上协作而不引入新的安全漏洞。7月在AI Agent的安全研究方向上有几个重要进展OpenAI发布了对Agent系统安全评估的Preparedness Framework更新、a16z crypto发表了Agent自治许可Agent Authorization Framework的讨论稿、以及Safe Wallet团队开源了支持AI Agent多签操作的安全模块原型。本文将这些分散的信息整合为一套Agent链上操作的技术框架涵盖权限模型、安全边界和协作框架三个维度。二、Agent链上操作的权限模型架构权限控制层是Agent安全的核心防线。它不是简单地允许/禁止Agent操作而是一个多层次的过滤系统操作白名单规定了Agent可以调用的合约地址和函数选择器例如只允许调用特定DeFi协议的swap函数不允许调用任意合约的任意函数金额上限限制单次操作的最大资金量例如单次swap限额10 ETH时间窗口限制高频操作例如每小时最多3笔交易多签策略要求高影响操作需要至少m-of-n个Agent或人类签名三、Agent安全框架的代码实现Safe Wallet AI Agent多签模块// contracts/AgentSafeModule.sol // Safe Wallet的AI Agent安全模块 —— 继承Safe的模块体系 // // 设计决策 // 1. 模块化设计 —— 作为Safe的Module安装在多签钱包上, // 而非修改Safe核心合约。Agent的权限可以通过 // enableModule / disableModule 随时开启和关闭 // 2. 双重限制: 函数白名单 金额上限 —— // 操作白名单防御未知函数调用(approve恶意代币), // 金额上限防御Agent决策错误导致的资金损失, // 两者叠加形成纵深防御 // 3. 冷却期机制 —— 大额交易不是拒绝而是延迟, // 给人类操作者一个时间窗口审查和取消交易 // 采用ERC-4337风格的UserOperation队列实现 // 4. 执行窗口 —— Agent只能在指定时间段内操作, // 非窗口期所有交易拒绝,防止非工作时间无人监控 import {Safe} from safe-global/safe-contracts/contracts/Safe.sol; import {Enum} from safe-global/safe-contracts/contracts/common/Enum.sol; contract AgentSafeModule { // 权限定义 struct AgentPermissions { bool active; // 该Agent是否被授权 uint256 maxSingleTxValue; // 单笔交易最大ETH金额 uint256 maxDailyVolume; // 每日累计最大ETH金额 uint256 dailyVolumeUsed; // 当日已使用金额 uint256 lastDayReset; // 上次日重置的时间戳 uint256 cooldownThreshold; // 触发冷却期的金额阈值 uint256 cooldownDuration; // 冷却期时长(秒) mapping(bytes4 bool) allowedFunctions; // 函数选择器白名单 mapping(address bool) allowedContracts; // 合约地址白名单 } // Agent地址 → 权限配置 mapping(address AgentPermissions) public agentPermissions; // 执行窗口: startHour ~ endHour (UTC小时) uint256 public executionWindowStart 0; // 默认全天 uint256 public executionWindowEnd 24; // 待执行的冷却期交易 struct QueuedTransaction { address to; uint256 value; bytes data; uint256 queuedAt; uint256 expiresAt; } mapping(bytes32 QueuedTransaction) public cooldownQueue; // 事件 —— 链上审计追踪 event AgentTxProposed( address indexed agent, address indexed to, uint256 value, bytes4 selector, bytes32 queueId ); event AgentTxExecuted( address indexed agent, bytes32 queueId, bool success ); event AgentTxCancelled(bytes32 queueId, address canceller); event AgentSuspended(address indexed agent, string reason); /** * notice Agent提交交易 —— 经权限检查、冷却期检查、窗口期检查 */ function executeFromAgent( address to, uint256 value, bytes calldata data, Enum.Operation operation ) external returns (bool) { address agent msg.sender; AgentPermissions storage perm agentPermissions[agent]; // 检查1: Agent是否激活 require(perm.active, Agent not authorized); // 检查2: 执行窗口时间 uint256 hour (block.timestamp % 86400) / 3600; require( hour executionWindowStart hour executionWindowEnd, Outside execution window ); // 检查3: 合约白名单 require(perm.allowedContracts[to], Contract not in whitelist); // 检查4: 函数选择器白名单 bytes4 selector bytes4(data[:4]); require(perm.allowedFunctions[selector], Function not in whitelist); // 检查5: 金额上限 _resetDailyVolumeIfNeeded(perm); require( perm.dailyVolumeUsed value perm.maxDailyVolume, Daily volume exceeded ); // 检查6: 大额交易冷却期 if (value perm.cooldownThreshold) { bytes32 queueId keccak256( abi.encodePacked(agent, to, value, data, block.timestamp) ); cooldownQueue[queueId] QueuedTransaction({ to: to, value: value, data: data, queuedAt: block.timestamp, expiresAt: block.timestamp perm.cooldownDuration }); emit AgentTxProposed(agent, to, value, selector, queueId); return false; // 需要人工确认 } // 通过所有检查: 执行交易并更新日统计 perm.dailyVolumeUsed value; bool success Safe(msg.sender).execTransactionFromModule( to, value, data, operation ); emit AgentTxExecuted(agent, bytes32(0), success); return success; } /** * notice 人类操作者确认冷却期交易 */ function confirmCooldownTx(bytes32 queueId) external { QueuedTransaction storage tx_ cooldownQueue[queueId]; require(tx_.queuedAt 0, Transaction not found); require(block.timestamp tx_.expiresAt, Transaction expired); // 执行交易 Safe(msg.sender).execTransactionFromModule( tx_.to, tx_.value, tx_.data, Enum.Operation.Call ); emit AgentTxExecuted(msg.sender, queueId, true); delete cooldownQueue[queueId]; } /** * notice 任何人可以在冷却期内取消交易 */ function cancelCooldownTx(bytes32 queueId) external { require(cooldownQueue[queueId].queuedAt 0, Transaction not found); emit AgentTxCancelled(queueId, msg.sender); delete cooldownQueue[queueId]; } function _resetDailyVolumeIfNeeded(AgentPermissions storage perm) internal { if (block.timestamp - perm.lastDayReset 86400) { perm.dailyVolumeUsed 0; perm.lastDayReset block.timestamp; } } }Agent端的权限调用封装// agent/safe_client.ts // AI Agent → Safe Wallet 交互客户端 // // 设计决策 // 1. 使用 viem 的 WalletClient 发送交易 —— // viem 的 Account 抽象支持 private key / mnemonic / HSM // Agent使用独立的EOA作为签名者,而非共享人类操作者的账户 // 2. 交易模拟优先于实际执行 —— // 通过 Tenderly Simulation API 在 fork 环境中预执行交易, // 检查: 是否会revert、状态变化是否符合预期、Gas消耗是否异常 // 模拟失败的交易不会发送到mempool // 3. 决策记录上链 —— Agent的每次推理决策写入合约事件, // 作为不可篡改的审计日志 import { createWalletClient, http, encodeFunctionData, parseAbi } from viem; import { privateKeyToAccount } from viem/accounts; import { mainnet } from viem/chains; const SAFE_ADDRESS 0x...; const AGENT_MODULE_ADDRESS 0x...; const agentModuleAbi parseAbi([ function executeFromAgent(address to, uint256 value, bytes data, uint8 operation) returns (bool), ]); export class AgentSafeClient { private walletClient; private agentAccount; constructor(agentPrivateKey: 0x${string}, rpcUrl: string) { this.agentAccount privateKeyToAccount(agentPrivateKey); this.walletClient createWalletClient({ account: this.agentAccount, chain: mainnet, transport: http(rpcUrl), }); } /** * Agent调用Safe模块执行交易 * * param to - 目标合约地址 (必须在白名单中) * param value - ETH金额 (必须≤单笔上限) * param calldata - 编码后的函数调用 * returns 交易哈希或null(冷却期排队) */ async executeTransaction( to: 0x${string}, value: bigint, calldata: 0x${string} ): Promise0x${string} | null { // Step 1: Tenderly模拟交易 const simulationOk await this.simulateTransaction(to, value, calldata); if (!simulationOk) { throw new Error(Transaction simulation failed); } // Step 2: 调用Safe模块的executeFromAgent const txHash await this.walletClient.writeContract({ address: AGENT_MODULE_ADDRESS, abi: agentModuleAbi, functionName: executeFromAgent, args: [to, value, calldata, 0], // operation0 (Call) }); return txHash; } private async simulateTransaction( to: 0x${string}, value: bigint, calldata: 0x${string} ): Promiseboolean { // 调用Tenderly Simulation API const response await fetch( https://api.tenderly.co/api/v1/account/me/project/project/simulate, { method: POST, headers: { Content-Type: application/json, X-Access-Key: process.env.TENDERLY_ACCESS_KEY!, }, body: JSON.stringify({ network_id: 1, from: SAFE_ADDRESS, to, input: calldata, value: value.toString(), save: false, // 不保存模拟结果 save_if_fails: true, // 仅保存失败结果用于调试 }), } ); const result await response.json(); return result.simulation?.status true; } }四、安全边界Agent链上操作的反面模式反模式1——Agent拥有私钥的全部控制权架构上将Agent的私钥直接存储在运行环境的环境变量中Agent可以发送任意交易。这是最危险的模式——一旦Agent的推理被操纵例如prompt注入让Agent把所有ETH转给攻击者没有任何人工防线可以阻止。正确的做法是Agent永远无法直接签名交易——它只能向Safe模块提交交易提案由模块验证权限后再决定执行或排队等待人工确认。反模式2——多Agent共享同一Safe且无操作隔离如果有多个Agent例如一个Agent负责价格监控、一个负责自动调仓、一个负责收益收割共享同一个Safe钱包需要确保每个Agent的权限配置是独立的。一个Agent的每日限额被另一Agent的误操作消耗完毕会导致三个Agent同时停摆。为每个Agent分配独立的权限配置条目通过Agent地址区分是基础要求。反模式3——完全自动化的自动驾驶模式Agent全自动执行所有交易没有人工干预窗口。这在技术上可行让模块永不过期地缓存冷却期交易但在安全上危险。任何bug、攻击或异常市场条件都可能在几分钟内耗尽Safe中的全部资金。最小的人工干预窗口是必要的——至少对于超过一定金额的交易应该有12-24小时的冷却期。五、总结AI Agent在区块链上的操作安全性本质上是一个权限最小化问题——不是让Agent能做什么而是将Agent的权限精确限制在它确实需要做的那些事情上。7月的实践表明Solidity层面的Safe模块 函数白名单 金额上限 冷却期机制是一套足够健壮的防御体系它平衡了Agent自动化操作的效率和资金安全的底线要求。8月需要重点关注的方向跨链Agent的操作同步Agent在L1上做出的决策如何安全地在L2上执行、Agent决策的ZK证明让Agent的LLM推理过程附带一个ZK证明链上合约验证证明了推理的逻辑正确性、以及多Agent博弈场景下的协作协议多个Agent如何在DeFi中合作而不会被任何一个Agent的恶意行为拖垮整个系统。资料说明本文中的协议、版本、性能、成本和行业趋势应以可核验的一手资料为准。未标注统计口径的比例、时间表和预测仅作工程讨论不应视为行业事实。可参考 0731 资料来源索引并在发布前将具体来源贴到对应断言之后。