当前位置: 首页 > news >正文

智能合约 -透明可升级合约[ hardhat、openzeppelin 、ethers ]的演示 demo

文章目录

  • 前言
    • 智能合约 -透明可升级合约[ hardhat、openzeppelin 、ethers ]的演示 demo
      • 1. 测试内容
      • 2. 合约源码
      • 3. 脚本部署测试
        • 3.1. 执行代理合约[逻辑合约BoxV1]的部署脚本
        • 3.2. 执行代理合约[逻辑合约BoxV2]的升级脚本:

前言

如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


智能合约 -透明可升级合约[ hardhat、openzeppelin 、ethers ]的演示 demo

版本:
solidity ^0.8.28、hardhat 2.28.4、openzeppelin 5.6.1 ethers 6.16.0

1. 测试内容

测试内容: BoxV2合约升级内容为覆盖BoxV1合约的call()函数。

注意的是升级实现合约时,不需要重新部署代理合约,代理合约地址始终不变,仅需将代理指向新的实现合约地址即可。

所以针对 TPUProxy 这类可升级代理,必须写两个核心脚本:初次部署脚本(代理 + 实现合约 V1 的绑定初始化)和升级脚本(部署实现合约 V2 + 让代理指向新实现)。

2. 合约源码

下面是两个逻辑合约和代理合约的源码:
BoxV1 合约:

// 声明代码遵循 MIT 开源许可证 // SPDX-License-Identifier: MIT pragma solidity ^0.8.28;import"@openzeppelin/contracts/proxy/utils/Initializable.sol";contract BoxV1 is Initializable{uint public x;// initialize 替代constructorfunctioninitialize(uint _val)external initializer{x=_val;}functioncall()external{x=x+1;}// 逻辑合约的初始化数据:供代理合约使用functionshowInvoke()external pure returns(bytes memory){returnabi.encodeWithSelector(this.initialize.selector,1);}}

BoxV2 合约:

// 声明代码遵循 MIT 开源许可证 // SPDX-License-Identifier: MITimport"@openzeppelin/contracts/proxy/utils/Initializable.sol";pragma solidity ^0.8.28;contract BoxV2 is Initializable{uint public x;// initialize 替代constructorfunctioninitialize(uint _val)external initializer{x=_val;}functioncall()external{x=x+2;}// 逻辑合约的初始化数据:供代理合约使用functionshowInvoke()external pure returns(bytes memory){returnabi.encodeWithSelector(this.initialize.selector,1);}}

TPUProxy 自定义透明可升级代理合约:

// 声明代码遵循 MIT 开源许可证,SPDX 标准许可证标识 // SPDX-License-Identifier: MIT // 透明可升级代理合约,继承 OpenZeppelin 官方透明代理基础合约 pragma solidity ^0.8.28;// 限定 Solidity 编译器版本为0.8.28 及兼容版本 // 引入 OpenZeppelin 官方透明可升级代理核心合约,提供代理底层逻辑import"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";// 自定义透明可升级代理合约,继承 TransparentUpgradeableProxy 实现功能扩展 contract TPUProxy is TransparentUpgradeableProxy{/** * @dev 构造函数,继承并调用父类 TransparentUpgradeableProxy 构造函数 * @param _logic 实现合约地址(代理指向的业务逻辑合约) * @param initialOwner 代理合约初始管理员地址-区块链账户地址(拥有代理升级、管理权限) * @param _data 部署时传递给实现合约的初始化数据(通常是初始化函数的编码数据) */ constructor(address _logic, address initialOwner, bytes memory _data)payable TransparentUpgradeableProxy(_logic, initialOwner, _data){// 无自定义逻辑,仅透传参数调用父类构造函数完成代理初始化}/** * @dev 外部只读方法,查询代理合约的管理员地址 * @return address 代理管理员地址(拥有 proxyAdmin 权限的账户) * 封装父类内部的 _proxyAdmin()方法,对外提供查询接口 */functionproxyAdmin()external view returns(address){return_proxyAdmin();}/** * @dev 外部只读方法,查询代理当前指向的实现合约地址 * @return address 业务逻辑实现合约的当前地址 * 封装父类内部的 _implementation()方法,对外提供查询接口 */functiongetImplementation()external view returns(address){return_implementation();}receive()external payable{revert("TPUProxy: do not send ETH directly");// 回滚交易并抛出明确错误信息}}

3. 脚本部署测试

3.1. 执行代理合约[逻辑合约BoxV1]的部署脚本

源码:

// Hardhat 和 ethers.js 的「桥梁」,负责注册插件,让两者能协同工作;importhre from"hardhat";import"@nomicfoundation/hardhat-ethers";import"@openzeppelin/hardhat-upgrades";const CONTRACT_NAME="BoxV1";// 部署合约 asyncfunctioncontract(){console.log(`开始部署 ${CONTRACT_NAME}代理合约...`);// 获取合约工厂 const factory=await hre.ethers.getContractFactory("BoxV1");const proxy=await hre.upgrades.deployProxy(factory,[1],{initializer:"initialize"});// 获取代理合约地址方式 const contractAddress=await proxy.getAddress();return{contractInstance: proxy, contractAddress};// 同时返回实例和地址,方便后续调用方法}asyncfunctiondeploy(){const{contractInstance, contractAddress}=await contract();console.log(`${CONTRACT_NAME}部署完成!`);console.log(`代理合约地址: ${contractAddress}`);console.log(`验证: 调用代理合约-${CONTRACT_NAME}的 call 方法`);try{await contractInstance.call();console.log(`验证: x:`, await contractInstance.x());}catch(error){console.error(`代理合约-${CONTRACT_NAME}的 方法调用失败:`, error);process.exit(1);}}// 启动 本地网络 npx hardhatnodedeploy().then(()=>process.exit(0)).catch((error)=>{console.error("部署失败:", error);process.exit(1);});

执行脚本。

npx hardhat run scripts/upgradable/deploy-BoxV1Proxy.ts --network localhost


0x0165878A594ca255338adfa4d48449f69242Eb8F 是合约代理地址,记下来,这个会在升级脚本的时候会用到。
下面是call合约的方法:

functioncall()external{x=x+1;}

初始化的x为1,调用call函数后,加1,最后得出x为2,正确。

3.2. 执行代理合约[逻辑合约BoxV2]的升级脚本:

源码:

// Hardhat 和 ethers.js 的「桥梁」,负责注册插件,让两者能协同工作;importhre from"hardhat";import"@nomicfoundation/hardhat-ethers";import"@openzeppelin/hardhat-upgrades";const CONTRACT_NAME="BoxV2";const PROXY_ADDRESS="0x0165878A594ca255338adfa4d48449f69242Eb8F";// 部署合约 asyncfunctioncontract(){console.log(`开始升级 ${CONTRACT_NAME}代理合约...`);// 获取合约工厂 const factory=await hre.ethers.getContractFactory("BoxV2");const proxy=await hre.upgrades.upgradeProxy(PROXY_ADDRESS,factory);// 获取代理合约地址方式 const contractAddress=await proxy.getAddress();return{contractInstance: proxy, contractAddress};// 同时返回实例和地址,方便后续调用方法}asyncfunctiondeploy(){const{contractInstance, contractAddress}=await contract();console.log(`${CONTRACT_NAME}部署完成!`);console.log(`代理合约地址: ${contractAddress}`);console.log(`验证: 调用代理合约-${CONTRACT_NAME}的 call 方法`);try{await contractInstance.call();console.log(`验证: x:`, await contractInstance.x());}catch(error){console.error(`代理合约-${CONTRACT_NAME}的 方法调用失败:`, error);process.exit(1);}}// 启动 本地网络 npx hardhatnodedeploy().then(()=>process.exit(0)).catch((error)=>{console.error("部署失败:", error);process.exit(1);});

执行脚本:

npx hardhat run scripts/upgradable/upgrade-TPUProxy.ts --network localhost


因为原来的x=2,看一下BoxV2合约的call方法:

functioncall()external{x=x+2;}

调用call()函数后,加2,最后得出x=4,验证通过。

http://www.jsqmd.com/news/495429/

相关文章:

  • useMemo vs useCallback:核心区别与使用场景
  • ACDC变换器:单相PFC_Boost+后级半桥LLC,功率因素矫正及软开关技术实现(300W...
  • 2026年AI搜索优化公司深度测评:从技术到效果的客观分析与选型指南 - 小白条111
  • 麟智产业通,为您的企业数字化需求保驾护航
  • HCIP 路由控制 实验一
  • 2026年全国园林景观工程公司Top10,源石石业产品种类丰富吗 - myqiye
  • 2026年ASOC SCI2区TOP,基于人工蜂群算法和自适应大邻域搜索的星环网络设计问题求解方法,深度解析+性能实测
  • 论文排版之参考文献
  • KVM切换总黑屏、分辨率乱跳?问题可能出在EDID上|TESmart用这项技术彻底解决
  • 拖延症福音!全行业通用降AIGC工具 千笔·降AIGC助手 VS 灵感风暴AI
  • wsl安装包
  • 欧意注册okxz.run复制打开-2026年最新版V5.6.12.5.317安卓/苹果版
  • 2026必备!10个降AI率软件降AIGC网站评测:开源免费必看,学术降重全维度推荐
  • 看看众合食品包装吗,东三省食品包装口碑哪家好 - mypinpai
  • 热门的重庆包装袋制作制造企业
  • 2026年苏州纸箱加工优质厂家,定制适配方案兼顾多方面 - 工业设备
  • Kama缓存系统结果分析
  • 华硕电脑键盘全部失灵
  • 【Rust日报】 ry(o3) - Python的Rust封装库
  • hive—1.1、执行优化
  • 2026年镇江AI搜索优化公司推荐——从技术实力到效果落地的深度测评 - 小白条111
  • 程序员小白必看,三个月从零基础到实战,轻松转型大模型开发者!!
  • K8s Pod 网络策略与安全组配置
  • 2026年湖南光石传媒口碑TOP10,专业服务备受认可 - 工业推荐榜
  • 多尺度特征提取块改进YOLOv26空洞卷积与自适应权重融合双重突破
  • 2026 年 AI 产品经理薪资曝光:程序员转型能涨 40%?附完整学习体系 + 成功案例
  • 刘教链|比特观察:一个极致轻量的比特币观察钱包,带你回归聪本位
  • 2026年3月浙江浴室柜厂家权威评测:镱朗实业综合实力领跑 - 2026年企业推荐榜
  • 传统 A*算法与改进 A*算法性能大比拼及融合 DWA 避障仿真
  • WSL2+Ubuntu22.04+VScode开发环境