区块链 区块链技术 比特币公众号手机端

Solidity 0.8.28 + OpenZeppelin v5:实现 AI Agent 链上共有平台

liumuhui 4小时前 阅读数 1 #区块链

引言

在人工智能(AI)呈指数级爆发的今天,AI Agent(智能体)正在从单纯的工具演变为具有独立经济行为的数字实体。然而,传统的 AI 开发与运营高度中心化,普通用户只能作为消费者,无法分享 AI 商业化带来的红利。

Virtuals Protocol ($VIRTUAL) 的出现打破了这一僵局。它通过将每一个 AI Agent 资产化、代币化,开创了 AI Agent 的共同拥有权与娱乐平台(Co-ownership Platform) 。本文将带领大家深入剖析其底层逻辑,并基于最新 Solidity 0.8.28OpenZeppelin 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 未来产生商业收益的分红权与治理权。

二、 系统架构设计

整个核心合约架构主要由两部分组成,严格遵循现代化安全规范:

  1. AgentToken.sol(AI Agent 资产代币)

    • 代表特定 AI Agent 共同所有权的标准 ERC-20 代币。
    • 采用固定供应量设计(默认 10 亿枚),杜绝暗箱增发,保障公平发行。
    • 记录有 AI 模型的元数据链上指针(agentURI),用于挂载其特征、行为或 IPFS 描述。
  2. AgentFactory.sol(智能体工厂与 IAO 启动器)

    • 负责免许可(Permissionless)地创建新的 AI Agent 实例。
    • 集中管理基础结算资产 $VIRTUAL 的全局引用。
    • 提供统一的注册表与索引机制(allAgentsagents 映射),方便前端和生态查询。

三、 核心智能合约代码实现

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 启动平台核心,既保障了底层资产的防重入与权限安全,又通过工厂与代币的解耦设计为未来的流动性扩展奠定了良好基础。

版权声明

本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门