Cover photo

UUPS在hardhat中的实现

1、创建两个文件UUPSV1和UUPSV2

//  SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract UUPSV1 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
    uint public x;

    function _authorizeUpgrade(address implementation) internal override {}

    function initialize(uint _var) external initializer {
        x = _var;

        __Ownable_init(msg.sender);
    }

    function cal() external {
        x = x + 1;
    }
}
//  SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract UUPSV2 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
    uint public x;

    function _authorizeUpgrade(address implementation) internal override {}

    function initialize(uint _var) external initializer {
        x = _var;

        __Ownable_init(msg.sender);
    }

    function cal() external {
        x = x * 2;
    }
}

解释一下:

UUPSV1: 逻辑合约,第一个版本

UUPSV2: 升级合约,升级版本

import {
    time,
    loadFixture,
} from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import { expect } from "chai";
import hre from "hardhat";

describe("UUPS", function () {

    it("test_UUPS", async function () {
        const UUPSV1 = await hre.ethers.getContractFactory("UUPSV1");
        const v1 = await hre.upgrades.deployProxy(UUPSV1, [1], {
            initializer: "initialize",
            kind: 'uups'
        });
        await v1.waitForDeployment();

        // 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
        console.log(await v1.getAddress());
        console.log(await v1.x());
        await v1.cal();
        console.log(await v1.x());

        // UUPS升级
        const UUPSV2 = await hre.ethers.getContractFactory("UUPSV2");
        await hre.upgrades.upgradeProxy(
            await v1.getAddress(),
            UUPSV2
        );
        // 当前状态 
        console.log(await v1.x());
        await v1.cal();
        console.log(await v1.x());
    });

});

总结:

1、还是继承了delegatecall的基本原理

2、还是UUPSV2中的x保留了UUPSV1中的状态

3、UUPS的proxy只是起到了代理合约,而决定是否升级则是由逻辑合约自己决定,这是与透明可升级合约最大的区别,在整个过程中没有了proxyAdmin