You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hardhat升级OpenZeppelin可升级合约后owner变为0x0问题求助

问题根因及修复步骤

1. 核心错误:错误读取逻辑合约的状态

upgrades.prepareUpgrade的作用仅为校验V2合约兼容性、部署V2逻辑合约,返回的是逻辑合约地址,不会修改原代理合约的指向。你当前是直接读取逻辑合约的owner,可升级合约的逻辑合约本身不会执行初始化方法,所有状态都存储在代理合约侧,因此逻辑合约的owner默认就是0x0。
升级完成后应当始终和原V1代理合约地址交互,不要直接和逻辑合约交互。

2. 缺失代理升级步骤

你只完成了V2逻辑合约的部署,还没有执行代理指向升级的操作,完整的升级流程可根据需求二选一:

  • 单步完成升级,直接用upgrades.upgradeProxy方法代替prepareUpgrade:
const { ethers } = require("hardhat");

async function main() {
  const [deployer] = await ethers.getSigners();

  const myContractProxyAddress = "0x64291acc5af4B9DAF59C04412b987DEe9EA167E0"; // 原V1代理合约地址
  const MyContractV2 = await ethers.getContractFactory("MyContractV2");

  console.log("Deploying contracts with the account:", deployer.address);
  console.log("Upgrading to V2...");

  // 自动校验兼容性、部署V2逻辑、升级代理指向
  const myContractV2 = await upgrades.upgradeProxy(
    myContractProxyAddress,
    MyContractV2
  );
  
  await myContractV2.setVersion("2");
  // 读取代理合约存储的owner值,和V1一致
  const owner = await myContractV2.owner();
  console.log("Current owner: ", owner);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });
  • 若需要分开部署逻辑和执行升级(比如多签审批升级场景),prepareUpgrade部署完逻辑合约后,还需要调用代理管理员的upgrade方法把代理指向新的逻辑合约,后续仍然和原代理地址交互即可。

3. 额外检查项(避免后续异常)

  • 确认V2合约没有修改V1已经声明的存储变量顺序,新增变量必须放在原有存储变量的后面,存储布局错乱也会导致owner读取异常
  • 确认V2没有新增initialize方法覆盖原有初始化逻辑,若需要在升级时执行一次性初始化逻辑,要预留__gap存储位,且用onlyInitializing修饰升级调用的初始化函数,通过upgrades.upgradeProxy的第三个参数指定调用的初始化方法

内容的提问来源于stack exchange,提问作者Ruham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 02:54:04