如何使用 OpenZeppelin Contracts Upgradeable 包:以 initializer 替换构造函数并部署代理合约?

发布时间:2026/9/13 22:13:18

如何使用 OpenZeppelin Contracts Upgradeable 包:以 initializer 替换构造函数并部署代理合约? 如何使用 OpenZeppelin Contracts Upgradeable 包以 initializer 替换构造函数并部署代理合约【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts如果你要把合约部署成可升级的例如配合 OpenZeppelin Upgrades Plugins 使用就不能直接用openzeppelin/contracts里的普通合约而要改用专门的 Upgradeable 变体包openzeppelin/contracts-upgradeable。这个任务包含三步安装 Upgradeable 包、把构造函数改写为 initializer 函数、用 Upgrades Plugins 部署代理合约。本文基于仓库中的 upgradeable 文档、Initializable 源码 和 Proxy 模块说明 给出完整的操作路径。一个必须先知道的前提OpenZeppelin Contracts 用语义化版本来承诺 API 与存储布局的向后兼容不同大版本之间的存储布局应视为不兼容例如从 4.9.3 升级到 5.0.0 是不安全的见 index 文档。所以升级前先在文档中确认版本约束。安装 Upgradeable 包Upgradeable 变体是独立发布的 npm 包openzeppelin/contracts-upgradeable并且以openzeppelin/contracts作为 peer dependency因此两个包要一起安装$ npm install openzeppelin/contracts-upgradeable openzeppelin/contracts包的结构与主包一致只是每个文件和合约名都带Upgradeable后缀。唯一的例外接口interface和库library不包含在 Upgradeable 包里仍从主包openzeppelin/contracts导入。把构造函数替换为 initializer 函数改写分两部分导入与继承以及构造函数改写成 initializer。以 ERC721 为例导入和继承的改动是-import {ERC721} from openzeppelin/contracts/token/ERC721/ERC721.sol; import {ERC721Upgradeable} from openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol; -contract MyCollectible is ERC721 { contract MyCollectible is ERC721Upgradeable {构造函数的改写遵循固定命名约定Upgradeable 包中每个合约的构造函数对应一个内部函数__{ContractName}_init。因为它是internal的你必须在自己的合约里定义一个public的 initializer 函数并调用父合约的 init 函数- constructor() ERC721(MyCollectible, MCO) { function initialize() initializer public { __ERC721_init(MyCollectible, MCO); }initializer修饰符保证该函数最多只能被成功调用一次这是代理部署替代构造函数的核心保护机制见 Initializable.sol。为什么部署前建议锁定实现合约Initializable 源码 的文档明确警告未初始化的合约可能被攻击者接管这对代理和它背后的实现合约都适用。为防止实现合约本身被误初始化推荐在构造器中调用_disableInitializers()自动上锁/// custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); }_disableInitializers()会把合约锁定阻止其被初始化到任何版本文档建议用于设计为通过代理调用的实现合约。用 Upgrades Plugins 部署代理合约合约写好并编译后用 OpenZeppelin Upgrades Plugins 部署代理。Proxy 模块说明 指出正确使用升级代理需要深入理解代理模式、Solidity 和 EVM除非你想做低层控制否则推荐直接使用 Hardhat 和 Foundry 的 Upgrades Plugins。以下是 upgradeable 文档 给出的 Hardhat 部署脚本示例放在scripts/目录下// scripts/deploy-my-collectible.js const { ethers, upgrades } require(hardhat); async function main() { const MyCollectible await ethers.getContractFactory(MyCollectible); const mc await upgrades.deployProxy(MyCollectible); await mc.waitForDeployment(); console.log(MyCollectible deployed to:, await mc.getAddress()); } main();执行脚本后终端会打印代理地址上面console.log输出的MyCollectible deployed to:即为代理合约地址这是文档给出的部署完成标志。部署后如何验证初始化成功两个来自文档的验证依据Initialized事件。initializer修饰符在成功初始化后会发出event Initialized(uint64 version)事件见 Initializable.sol。在部署交易的回执中确认该事件版本为 1说明initialize()已成功执行过一次。重复调用应失败。initializer修饰符的语义是最多调用一次重复调用会 revertInvalidInitialization()。如果意外发现还能再次调用成功说明保护机制没有生效属于异常情况。另外注意底层代理的行为如果不用 Upgrades Plugins 而直接使用 ERC1967Proxy其构造函数要求传入_data即编码好的初始化调用_data为空时构造会失败——文档建议把initialize的编码调用作为_data尽早传入以避免代理停留在未初始化状态。使用deployProxy时插件会自动处理这一步。限制与边界多继承需要特别注意。initializer 函数不像构造函数那样由编译器线性化每个__{ContractName}_init内嵌了对所有父合约 initializer 的线性化调用因此两个init函数可能把同一个合约初始化两次。每个合约都提供__{ContractName}_init_unchained即去掉父调用后的 initializer可以手动规避双重初始化但文档不推荐手动这么做。命名空间存储ERC-7201。Upgradeable 包中的合约用带custom:storage-location erc7201:NAMESPACE_ID注解的 struct 存放状态变量每个合约拥有独立的存储命名空间。这使得日后新增状态变量不会推移继承链中下方变量的存储位置从而保持存储布局兼容。大版本存储不兼容。跨大版本如 4.x 到 5.0.0升级前按 Backwards Compatibility 文档确认存储布局并使用 Upgrades Plugins 检查存储兼容性。完成以上步骤后你就有了一个已完成初始化、地址可从部署日志或Initialized事件中确认的代理合约。后续的升级操作如upgradeProxy到新版本实现、用reinitializer(n)初始化新增模块属于 OpenZeppelin Upgrades Plugins 文档的范畴本仓库 upgradeable 文档 将其列为延伸阅读。【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/13 22:13:17

脑电伪迹识别:从原理到临床实操的全流程指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 22:13:17

双层规划与雨流计数法在电力系统优化中的应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 22:58:20

AI芯片设计新人避坑指南:从物理极限到系统协同

1. 这不是劝退帖,是芯片设计新人的真实生存图谱“AI芯片设计从入门到放弃”——看到这个标题,你可能已经笑出声,也可能心头一紧。别急,这不是段子,也不是泄愤帖,而是我带过7届校招工程师、参与过4款边缘AI芯…

2026/9/13 22:58:20

MATLAB手写数字识别:SVM图像预处理与嵌入式部署实战

简介:本资源是一份面向机器学习初学者与MATLAB实践者的手写数字识别完整实现方案,聚焦支持向量机(SVM)算法在图像分类任务中的落地应用,适用于课程设计、竞赛备赛及AI入门项目开发。压缩包共159个文件,含15…

2026/9/13 22:58:20

智能体记忆能否在模型升级后存活?记忆可移植性对照研究

智能体记忆能否在模型升级后存活?记忆可移植性对照研究 论文来源:arXiv:2609.05339v1 摘要 大语言模型驱动的智能体(Agent)普遍依赖外部记忆模块(RAG向量索引、记忆数据库)保存历史上下文、工具调用记录、任务知识。工程实践中经常发生基座模型版本升级:将同一个Agent后…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码