UUPS Example
EIP-1822
Proxy
UUPS proxy is fairly minimal compared to the transparent proxy setup.
Using OZ's implementation library, you don't need to do anything else other than simply deploying the
ERC1967Proxy.solcontract and linking your implementation.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {StakingPoolStorage} from "./StakingPoolStorage.sol";
import {ERC1967Proxy} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol";
/// @title Proxy for UUPS implementation
/// @author Calnix
contract StakingPoolProxy is ERC1967Proxy {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializing the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) ERC1967Proxy(_logic, _data){
}
/// @dev Returns the current implementation address.
function implementation() external view returns (address impl) {
return _implementation();
}
}Implementation
We will need to have our implementation contract inherit UUPSUpgradeable, which defines the upgradeability mechanism to be included in the implementation contract.
Inheriting from UUPSUpgradeable (and overriding the _authorizeUpgrade function with the relevant access control mechanism) will turn your contract into a UUPS compliant implementation.
Disable Initializer
_disableInitializer() is called inside the constructor; prevents any further initialization. This is done so that in the context of the logic contract the initializer is locked.
Therefore an attacker will not able to call the initalizer() function in the state of the logic contract and perform any malicious activity (like self-destruct)
Note that the proxy contract state will still be able to call this function, this is because the constructor does not effect the state of the proxy contract.
When you upgrade your contract you need to follow the convention of inheriting the previous version and then adding any modifications.
It is not expected that you will need to initialize something every time. So, if you shouldn’t confuse this as preventing any upgrades.
Need to use reinitializer() in subsequent upgrades for the initializer function
Last updated