function _authorizeUpgrade(address newImplementation) internal override {}
关于重写该函数的原因,在 OpenZeppelin 库中给出了原因:
1 2 3 4 5 6 7 8 9 10 11
/** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual;
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity ^0.8.18;
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract BoxV1 is Initializable, UUPSUpgradeable, OwnableUpgradeable { uint256 internal number;
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity ^0.8.18;
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract BoxV2 is Initializable, UUPSUpgradeable, OwnableUpgradeable { uint256 internal number;
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity ^0.8.18;
import {Script} from "forge-std/Script.sol"; import {BoxV1} from "../src/BoxV1.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract DeployBox is Script { function run() external returns (address) { address proxy = deployBox(); return proxy; }
function deployBox() public returns (address) { vm.startBroadcast(); BoxV1 box = new BoxV1(); // implementation (Logic) // here we will use ERC1967 Proxy Contract ERC1967Proxy proxy = new ERC1967Proxy(address(box), ""); vm.stopBroadcast(); return address(proxy); } }
将 V1 合约升级到 V2
对合约进行升级时,涉及到这么一个过程:
deploy V2 -> call function upgradeToAndCall(V2address, "") (in Proxy) -> 升级成功。
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity ^0.8.18;
import {Script} from "forge-std/Script.sol"; import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol"; import {BoxV2} from "../src/BoxV2.sol"; import {BoxV1} from "../src/BoxV1.sol";
contract UpgradeBox is Script { function run() external returns (address) { address mostRecentlyDeployed = DevOpsTools.get_most_recent_deployment("ERC1967Proxy", block.chainid);
// SPDX-License-Identifier: SEE LICENSE IN LICENSE pragma solidity ^0.8.18;
import {Test} from "forge-std/Test.sol"; import {DeployBox} from "../script/DeployBox.s.sol"; import {UpgradeBox} from "../script/UpgradeBox.s.sol"; import {BoxV1} from "../src/BoxV1.sol"; import {BoxV2} from "../src/BoxV2.sol";
contract DeployAndUpgradeTest is Test { DeployBox public deployer; UpgradeBox public upgrader; address public OWNER = makeAddr("owner");
address public proxy;
function setUp() public { deployer = new DeployBox(); upgrader = new UpgradeBox(); proxy = deployer.run(); // right now, Proxy point to V1 }
function testProxyStartAsBoxV1() public { vm.expectRevert(); BoxV2(proxy).setNumber(7); }
function testUpgrades() public { BoxV2 box2 = new BoxV2();