尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

使用OpenZeppelin编写可升级智能合约(代理) - all-in

使用OpenZeppelin编写可升级智能合约(代理) - all-in
📅 发布时间:2026/6/20 0:28:26

开发环境:VSCode + Foundry

一、创建项目

执行$forge init ProxyDemo 创建Foundry项目,并创建2个版本的逻辑合约:

  • LogicV1.sol

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.30;import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";contract LogicV1 is Initializable {uint256 public number;function initialize(uint256 initialValue) public initializer {number = initialValue;}function changeNumber() public {number++;}
    }
    
  • LogicV2.sol

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.30;import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";contract LogicV2 is Initializable {uint256 public number;function setNumber(uint256 newValue) public {number = newValue;}function changeNumber() public {number += 10;}
    }
    

普通合同和可升级合同的最大区别在于,可升级合同没有constructor()

二、使用OpenZeppelin Upgrades 插件部署LogicV1

2.1 安装库

安装OpenZeppelin可升级合约库:

forge install OpenZeppelin/openzeppelin-foundry-upgrades
forge install OpenZeppelin/openzeppelin-contracts-upgradeable

然后更新remappings.txt文件:forge remappings > remappings.txt

如果你想在升级或部署时,运行OpenZeppelin自带的升级安全检查,请执行:

  1. 安装node.js

  2. 在foundry.toml里配置ffi、 ast、 build info和storage layout:

[profile.default]
ffi = true
ast = true
build_info = true
extra_output = ["storageLayout"]

2.2 编写部署脚本

在 script/LogicV1.s.sol 中编写 LogicV1 合约的部署脚本

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;import {Script} from "forge-std/Script.sol";
import {LogicV1} from "../src/LogicV1.sol";
import {console} from "forge-std/console.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";contract LogicV1Script is Script {function setUp() public {}function run() public {// 部署的账户私钥uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");vm.startBroadcast(deployerPrivateKey);// Deploy the upgradeable proxy and its first implementationaddress proxy = Upgrades.deployTransparentProxy("LogicV1.sol",vm.envAddress("ADMIN_ADDRESS"),abi.encodeCall(LogicV1.initialize, (22)));console.log("Proxy deployed at:", proxy);console.log("Implementation deployed at:", Upgrades.getImplementationAddress(proxy));console.log("Admin address at:", Upgrades.getAdminAddress(proxy));vm.stopBroadcast();}
}

执行 forge script 进行部署:

$ forge script script/LogicV1.s.sol --rpc-url https://sepolia.gateway.tenderly.co --broadcast --verify[⠒] Compiling...
No files changed, compilation skipped
Script ran successfully.== Logs ==Proxy deployed at: 0xDDDb96d38096Bc2acB1a43a0c5A29d4162ac0CB7Implementation deployed at: 0xF401a5f6E69bDC1c4BDa51e9Be7719338dB61096Admin address at: 0xCF5a9750169b0DA9408AEa6757912211692F1FCf

通过OpenZeppelin Upgrades 插件,我们部署了三个合约:

  1. Logic 合约:也叫 Implementation 合约,即LogicV1。

  2. Proxy 合约:透明代理合约,即TransparentUpgradeableProxy。

  3. ProxyAdmin 合约:代理管理员合约,ProxyAdmin。

对应地址:

  1. https://repo.sourcify.dev/11155111/0xF401a5f6E69bDC1c4BDa51e9Be7719338dB61096

  2. https://repo.sourcify.dev/11155111/0xDDDb96d38096Bc2acB1a43a0c5A29d4162ac0CB7

  3. https://repo.sourcify.dev/11155111/0xCF5a9750169b0DA9408AEa6757912211692F1FCf

这三个合约之间的关系如下:
image

管理员只能通过 ProxyAdmin 合约去调用 Proxy 合约的 upgradeToAndCall() 函数进行升级。

三、使用OpenZeppelin Upgrades 插件升级LogicV2

在 script/LogicV2.s.sol 中编写 LogicV1 -> LogicV2 的升级脚本:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;import {Script} from "forge-std/Script.sol";
import {LogicV2} from "../src/LogicV2.sol";
import {console} from "forge-std/console.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {Options} from "openzeppelin-foundry-upgrades/Options.sol";contract LogicV2Script is Script {function setUp() public {}function run() public {// 部署的账户私钥uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");// 代理合约地址address proxyAddress = vm.envAddress("PROXY_ADDRESS");// 升级选项,指定旧合约Options memory opts;opts.referenceContract = "LogicV1.sol";vm.startBroadcast(deployerPrivateKey);// 升级代理合约到 LogicV2,并调用 setNumber 函数设置新的值Upgrades.upgradeProxy(proxyAddress,"LogicV2.sol", // 要升级的合约abi.encodeCall(LogicV2.setNumber, (50)), // 调用新合约的函数opts);console.log("Proxy deployed at:", proxyAddress);console.log("New implementation deployed at:", Upgrades.getImplementationAddress(proxyAddress));vm.stopBroadcast();}
}

执行 forge script 进行升级:

$ forge script script/LogicV2.s.sol --rpc-url https://sepolia.gateway.tenderly.co --broadcast --verify[⠒] Compiling...
No files changed, compilation skipped
Script ran successfully.== Logs ==Proxy deployed at: 0xDDDb96d38096Bc2acB1a43a0c5A29d4162ac0CB7New implementation deployed at: 0x964D52fd3c94CA379Ab1ED3411f01EeFF8e99Bf5

新部署的LogicV2合约地址:https://repo.sourcify.dev/11155111/0x964D52fd3c94CA379Ab1ED3411f01EeFF8e99Bf5

查看Proxy合约的日志,可以看到有一次Upgraded调用更新了逻辑合约地址:
image

相关新闻

  • vuepress2.x支持vue2吗?
  • 【IO多路转接】IO 多路复用之 select:从接口解析到服务器实战 - 详解
  • java sql注入的危害有哪些

最新新闻

  • 论文写作进阶:构建清晰一致的数学符号系统
  • MC9S12VR ATD模块高精度设计:从手册规范到电路实战
  • 2026全球化仓储软件(WMS)哪家好?行业选型参考 - 品牌排行榜
  • 告别臃肿:3个理由让你立即切换到GHelper控制华硕笔记本
  • 2026苏州擅长协议离婚谈判的律师推荐 - 品牌排行榜
  • MCU系统时钟与复位机制深度解析:从MC68HC908到嵌入式稳定运行

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号