Solidity 0.8.28 + OpenZeppelin v5:实现 AI Agent 链上共有平台
引言
在人工智能(AI)呈指数级爆发的今天,AI Agent(智能体)正在从单纯的工具演变为具有独立经济行为的数字实体。然而,传统的 AI 开发与运营高度中心化,普通用户只能作为消费者,无法分享 AI 商业化带来的红利。
Virtuals Protocol ($VIRTUAL) 的出现打破了这一僵局。它通过将每一个 AI Agent 资产化、代币化,开创了 AI Agent 的共同拥有权与娱乐平台(Co-ownership Platform) 。本文将带领大家深入剖析其底层逻辑,并基于最新 Solidity 0.8.28 与 OpenZeppelin v5 标准,从零构建并测试一个精简而完备的核心智能合约系统。
一、 项目背景与核心痛点
1. 行业背景
传统的 AI 智能体(如虚拟主播、自动化交易 Bot、NPC 等)通常由单一公司或开发者掌控,其收益也完全归属于中心化实体。这导致了两个痛点:
- 资金冷启动难:优秀的 AI 模型和娱乐 Agent 早期缺乏研发与运营资金。
- 用户参与度低:社区用户空有热情,无法通过支持或推广特定的 AI Agent 来获得经济回报。
2. Virtuals Protocol 如何解决问题?
Virtuals Protocol 引入了 IAO(Initial Agent Offering,初始智能体发行) 机制:
- 资产化(Assetization) :每一个独立的 AI Agent 都会在链上发行其专属的 ERC-20 共同所有权代币。
- 代币经济绑定:所有 Agent 代币均与核心生态代币
$VIRTUAL紧密挂钩,形成去中心化的流动性与价值捕获闭环。 - 社区共治:持有 Agent 代币的用户不仅拥有情感或娱乐上的共鸣,更享有该 AI Agent 未来产生商业收益的分红权与治理权。
二、 系统架构设计
整个核心合约架构主要由两部分组成,严格遵循现代化安全规范:
-
AgentToken.sol(AI Agent 资产代币) :- 代表特定 AI Agent 共同所有权的标准 ERC-20 代币。
- 采用固定供应量设计(默认 10 亿枚),杜绝暗箱增发,保障公平发行。
- 记录有 AI 模型的元数据链上指针(
agentURI),用于挂载其特征、行为或 IPFS 描述。
-
AgentFactory.sol(智能体工厂与 IAO 启动器) :- 负责免许可(Permissionless)地创建新的 AI Agent 实例。
- 集中管理基础结算资产
$VIRTUAL的全局引用。 - 提供统一的注册表与索引机制(
allAgents与agents映射),方便前端和生态查询。
三、 核心智能合约代码实现
1. Agent 资产代币合约 (AgentToken.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title AgentToken
* @notice Virtuals Protocol 中代表特定 AI Agent 共同所有权的 ERC-20 代币
*/
contract AgentToken is ERC20, Ownable {
uint256 public constant INITIAL_SUPPLY = 1_000_000_000 * 10**18; // 10亿固定供应量
// 关联的 AI Agent 元数据或 URI
string public agentURI;
event AgentURIUpdated(string newURI);
constructor(
string memory name,
string memory symbol,
string memory _agentURI,
address creator
) ERC20(name, symbol) Ownable(creator) {
agentURI = _agentURI;
// 初始代币全部铸造给创建者/流动性池
_mint(creator, INITIAL_SUPPLY);
}
function updateAgentURI(string calldata newURI) external onlyOwner {
agentURI = newURI;
emit AgentURIUpdated(newURI);
}
}
2. 工厂与 IAO 启动合约 (AgentFactory.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {AgentToken} from "./AgentToken.sol";
/**
* @title AgentFactory
* @notice 模拟 Virtuals Protocol 的 IAO(Initial Agent Offering)与 Agent 生成器
*/
contract AgentFactory is Ownable, ReentrancyGuard {
// 基础资产 $VIRTUAL 的合约地址
IERC20 public immutable virtualToken;
// 记录所有已创建的 Agent 信息
struct AgentInfo {
address agentTokenAddress;
address creator;
uint256 createdAt;
}
mapping(address => AgentInfo) public agents;
address[] public allAgents;
event AgentCreated(
address indexed agentToken,
address indexed creator,
string name,
string symbol,
uint256 timestamp
);
constructor(address _virtualToken) Ownable(msg.sender) {
require(_virtualToken != address(0), "Invalid virtual token");
virtualToken = IERC20(_virtualToken);
}
/**
* @notice 创建一个新的 AI Agent 及其共同所有权代币
* @param name Agent 名称 (例如: "AI Waifu")
* @param symbol Agent 代号 (例如: "WAIFU")
* @param agentURI AI 模型的具体行为特征或 IPFS 描述链接
*/
function createAgent(
string calldata name,
string calldata symbol,
string calldata agentURI
) external nonReentrant returns (address agentTokenAddress) {
// 1. 部署新的 Agent 资产代币
AgentToken newToken = new AgentToken(
name,
symbol,
agentURI,
msg.sender
);
agentTokenAddress = address(newToken);
// 2. 记录注册表
agents[agentTokenAddress] = AgentInfo({
agentTokenAddress: agentTokenAddress,
creator: msg.sender,
createdAt: block.timestamp
});
allAgents.push(agentTokenAddress);
// 3. 触发事件
emit AgentCreated(
agentTokenAddress,
msg.sender,
name,
symbol,
block.timestamp
);
}
function totalAgents() external view returns (uint256) {
return allAgents.length;
}
}
四、 自动化集成测试实现 (Viem + Node.js 原生测试)
为了保障系统的高可靠性,我们使用现代化的 viem 与 Node.js 原生断言编写了完整的集成测试脚本:test/AgentFactory.ts。
- 测试用例:Virtuals Protocol AgentFactory & AgentToken Integration
- 初始化验证:Factory 应正确记录 $VIRTUAL 地址
- IAO 发行:创建者应能成功铸造新的 AI Agent 资产代币
- 权限控制:只有所有者或特权方法能更新 Agent URI
- 多 Agent 支持:工厂应能批量注册并索引多个不同 Agent
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { parseEther, getAddress, zeroAddress } from "viem";
import { network } from "hardhat";
describe("Virtuals Protocol AgentFactory & AgentToken Integration", function () {
async function deployFixture() {
const { viem } = await (network as any).connect();
const [owner, creator, otherAccount] = await viem.getWalletClients();
const publicClient = await viem.getPublicClient();
// 1. 部署一个用于测试的 Mock $VIRTUAL 代币合约
const virtualToken = await viem.deployContract("AgentToken", [
"Virtual Protocol",
"VIRTUAL",
"ipfs://virtual-core",
owner.account.address
]);
// 2. 部署 AgentFactory 合约
const agentFactory = await viem.deployContract("AgentFactory", [
virtualToken.address
]);
return {
viem,
virtualToken,
agentFactory,
owner,
creator,
otherAccount,
publicClient
};
}
it("初始化验证:Factory 应正确记录 $VIRTUAL 地址", async function () {
const { agentFactory, virtualToken } = await deployFixture();
const boundVirtual = await agentFactory.read.virtualToken();
assert.equal(
getAddress(boundVirtual),
getAddress(virtualToken.address),
"Factory 绑定的 $VIRTUAL 地址不匹配"
);
assert.equal(await agentFactory.read.totalAgents(), 0n, "初始 Agent 数量应为 0");
});
it("IAO 发行:创建者应能成功铸造新的 AI Agent 资产代币", async function () {
const { viem, agentFactory, creator } = await deployFixture();
const name = "AI Waifu Agent";
const symbol = "WAIFU";
const agentURI = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi";
const txHash = await agentFactory.write.createAgent(
[name, symbol, agentURI],
{ account: creator.account }
);
assert.ok(txHash, "交易应成功发出");
assert.equal(await agentFactory.read.totalAgents(), 1n, "Agent 总数应变为 1");
const agentTokenAddress = await agentFactory.read.allAgents([0n]);
assert.notEqual(getAddress(agentTokenAddress), getAddress(zeroAddress), "Agent 代币地址无效");
const agentToken = await viem.getContractAt("AgentToken", agentTokenAddress);
assert.equal(await agentToken.read.name(), name, "代币名称不匹配");
assert.equal(await agentToken.read.symbol(), symbol, "代币符号不匹配");
assert.equal(await agentToken.read.agentURI(), agentURI, "Agent URI 不匹配");
const expectedSupply = parseEther("1000000000");
assert.equal(await agentToken.read.totalSupply(), expectedSupply, "总供应量应为 10 亿");
assert.equal(await agentToken.read.balanceOf([creator.account.address]), expectedSupply, "创建者应持有全部初始代币");
});
it("权限控制:只有所有者或特权方法能更新 Agent URI", async function () {
// 修复点:正确解构出 viem
const { viem, agentFactory, creator, otherAccount } = await deployFixture();
await agentFactory.write.createAgent(
["Crypto Analyst", "ANALYST", "ipfs://v1"],
{ account: creator.account }
);
const agentTokenAddress = await agentFactory.read.allAgents([0n]);
const agentToken = await viem.getContractAt("AgentToken", agentTokenAddress);
await assert.rejects(
async () => {
await agentToken.write.updateAgentURI(["ipfs://v2-hack"], {
account: otherAccount.account
});
},
/OwnableUnauthorizedAccount/,
"非代币拥有者不应被允许修改 Agent URI"
);
await agentToken.write.updateAgentURI(["ipfs://v2-official"], {
account: creator.account
});
assert.equal(
await agentToken.read.agentURI(),
"ipfs://v2-official",
"Agent URI 应成功更新"
);
});
it("多 Agent 支持:工厂应能批量注册并索引多个不同 Agent", async function () {
const { agentFactory, creator } = await deployFixture();
await agentFactory.write.createAgent(["Agent Alpha", "ALPHA", "uri_1"], {
account: creator.account
});
await agentFactory.write.createAgent(["Agent Beta", "BETA", "uri_2"], {
account: creator.account
});
assert.equal(await agentFactory.read.totalAgents(), 2n, "总数应为 2");
const addr1 = await agentFactory.read.allAgents([0n]);
const addr2 = await agentFactory.read.allAgents([1n]);
// 在 viem 中,合约结构体返回通常为数组或对象,采用安全索引访问
const info1 = await agentFactory.read.agents([addr1]);
const info2 = await agentFactory.read.agents([addr2]);
const creator1 = Array.isArray(info1) ? info1[1] : (info1 as any).creator;
const creator2 = Array.isArray(info2) ? info2[1] : (info2 as any).creator;
assert.equal(getAddress(creator1), getAddress(creator.account.address));
assert.equal(getAddress(creator2), getAddress(creator.account.address));
assert.notEqual(getAddress(addr1), getAddress(addr2), "不同 Agent 的合约地址应当独立");
});
});
五、部署脚本
// scripts/deploy.js
import { network, artifacts } from "hardhat";
async function main() {
// 连接网络
const { viem } = await network.connect({ network: network.name });//指定网络进行链接
// 获取客户端
const [deployer] = await viem.getWalletClients();
const publicClient = await viem.getPublicClient();
const deployerAddress = deployer.account.address;
console.log("部署者的地址:", deployerAddress);
// 加载合约
const AgentTokenArtifact = await artifacts.readArtifact("AgentToken");
const AgentFactoryArtifact = await artifacts.readArtifact("AgentFactory");
// 部署(构造函数参数:recipient, initialOwner)
const AgentTokenHash = await deployer.deployContract({
abi: AgentTokenArtifact.abi,//获取abi
bytecode: AgentTokenArtifact.bytecode,//硬编码
args: ["Virtual Protocol",
"VIRTUAL",
"ipfs://virtual-core",
deployer.account.address
],//process.env.RECIPIENT, process.env.OWNER
});
// 等待确认并打印地址
const AgentTokenReceipt = await publicClient.waitForTransactionReceipt({ hash: AgentTokenHash });
console.log("AgentToken合约地址:", AgentTokenReceipt.contractAddress);
const AgentFactoryHash = await deployer.deployContract({
abi: AgentFactoryArtifact.abi,//获取abi
bytecode: AgentFactoryArtifact.bytecode,//硬编码
args: [AgentTokenReceipt.contractAddress],//process.env.RECIPIENT, process.env.OWNER
});
const AgentFactoryReceipt = await publicClient.waitForTransactionReceipt({ hash: AgentFactoryHash });
console.log("AgentFactory合约地址:", AgentFactoryReceipt.contractAddress);
}
main().catch(console.error);
总结
至此,通过结合 OpenZeppelin v5 与 Solidity 0.8.28,本项目构建了一个高安全、低耦合的 AI Agent 启动平台核心,既保障了底层资产的防重入与权限安全,又通过工厂与代币的解耦设计为未来的流动性扩展奠定了良好基础。
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
鸿途知科网
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。