Hi,
I'm using UUPS proxies in some of my projects and I was thinking about a pattern to make a proxy not upgradeable anymore. Because of the _upgradeToAndCallSecure
function with the secure pattern I think a good way is to make it upgradeable and have the ability to stop the upgradeability afterwards. I dont know if there is any other official pattern, I propose those two and ask for a review. Any improvement is appreciated.
First proposal:
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.9;
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "../utils/AccessControlProxyPausable.sol";
contract UUPSNotUpgradeable is AccessControlProxyPausable, UUPSUpgradeable {
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
function endUpgradeability() public onlyRole(UPGRADER_ROLE) {
StorageSlot.getBooleanSlot(bytes32(uint256(keccak256("eip1967.proxy.upgradeabilityEnded")) - 1)).value = true;
}
function upgradeabilityEnded() public view returns(bool) {
return StorageSlot.getBooleanSlot(bytes32(uint256(keccak256("eip1967.proxy.upgradeabilityEnded")) - 1)).value;
}
function _authorizeUpgrade(address newImplementation)
internal
onlyRole(UPGRADER_ROLE)
override
{
require(!upgradeabilityEnded(), "UUPSNotUpgradeable: not upgradeable anymore");
}
}
Second proposal:
// SPDX-License-Identifier: Unlicensed
pragma solidity 0.8.9;
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "../utils/AccessControlProxyPausable.sol";
contract UUPSNotUpgradeable is AccessControlProxyPausable, UUPSUpgradeable {
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
function _authorizeUpgrade(address newImplementation)
internal
onlyRole(UPGRADER_ROLE)
override
{
require(StorageSlot.getBooleanSlot(bytes32(uint256(keccak256("eip1967.proxy.rollback")) - 1)).value, "UUPSNotUpgradeable: not upgradeable anymore");
}
}