Move upgradeToAndCallUUPS to UUPSUpgradeable (#4356)
Co-authored-by: ernestognw <ernestognw@gmail.com>
This commit is contained in:
@ -4,8 +4,6 @@
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "../beacon/IBeacon.sol";
|
||||
import "../../interfaces/IERC1967.sol";
|
||||
import "../../interfaces/draft-IERC1822.sol";
|
||||
import "../../utils/Address.sol";
|
||||
import "../../utils/StorageSlot.sol";
|
||||
|
||||
@ -33,9 +31,6 @@ library ERC1967Utils {
|
||||
*/
|
||||
event BeaconUpgraded(address indexed beacon);
|
||||
|
||||
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
|
||||
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
|
||||
|
||||
/**
|
||||
* @dev Storage slot with the address of the current implementation.
|
||||
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
|
||||
@ -59,11 +54,6 @@ library ERC1967Utils {
|
||||
*/
|
||||
error ERC1967InvalidBeacon(address beacon);
|
||||
|
||||
/**
|
||||
* @dev The storage `slot` is unsupported as a UUID.
|
||||
*/
|
||||
error ERC1967UnsupportedProxiableUUID(bytes32 slot);
|
||||
|
||||
/**
|
||||
* @dev Returns the current implementation address.
|
||||
*/
|
||||
@ -103,30 +93,6 @@ library ERC1967Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
|
||||
*
|
||||
* Emits an {IERC1967-Upgraded} event.
|
||||
*/
|
||||
function upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
|
||||
// Upgrades from old implementations will perform a rollback test. This test requires the new
|
||||
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
|
||||
// this special case will break upgrade paths from old UUPS implementation to new ones.
|
||||
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
|
||||
_setImplementation(newImplementation);
|
||||
} else {
|
||||
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
|
||||
if (slot != IMPLEMENTATION_SLOT) {
|
||||
revert ERC1967UnsupportedProxiableUUID(slot);
|
||||
}
|
||||
} catch {
|
||||
// The implementation is not UUPS
|
||||
revert ERC1967InvalidImplementation(newImplementation);
|
||||
}
|
||||
upgradeToAndCall(newImplementation, data, forceCall);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Storage slot with the admin of the contract.
|
||||
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "../ERC1967/ERC1967Proxy.sol";
|
||||
import "../../interfaces/IERC1967.sol";
|
||||
|
||||
/**
|
||||
* @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
|
||||
|
||||
@ -27,6 +27,11 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable {
|
||||
*/
|
||||
error UUPSUnauthorizedCallContext();
|
||||
|
||||
/**
|
||||
* @dev The storage `slot` is unsupported as a UUID.
|
||||
*/
|
||||
error UUPSUnsupportedProxiableUUID(bytes32 slot);
|
||||
|
||||
/**
|
||||
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
|
||||
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
|
||||
@ -35,12 +40,10 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable {
|
||||
* fail.
|
||||
*/
|
||||
modifier onlyProxy() {
|
||||
if (address(this) == __self) {
|
||||
// Must be called through delegatecall
|
||||
revert UUPSUnauthorizedCallContext();
|
||||
}
|
||||
if (ERC1967Utils.getImplementation() != __self) {
|
||||
// Must be called through an active proxy
|
||||
if (
|
||||
address(this) == __self || // Must be called through delegatecall
|
||||
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
|
||||
) {
|
||||
revert UUPSUnauthorizedCallContext();
|
||||
}
|
||||
_;
|
||||
@ -81,7 +84,7 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable {
|
||||
*/
|
||||
function upgradeTo(address newImplementation) public virtual onlyProxy {
|
||||
_authorizeUpgrade(newImplementation);
|
||||
ERC1967Utils.upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
|
||||
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +99,7 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable {
|
||||
*/
|
||||
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
|
||||
_authorizeUpgrade(newImplementation);
|
||||
ERC1967Utils.upgradeToAndCallUUPS(newImplementation, data, true);
|
||||
_upgradeToAndCallUUPS(newImplementation, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,4 +113,21 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable {
|
||||
* ```
|
||||
*/
|
||||
function _authorizeUpgrade(address newImplementation) internal virtual;
|
||||
|
||||
/**
|
||||
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
|
||||
*
|
||||
* Emits an {IERC1967-Upgraded} event.
|
||||
*/
|
||||
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) private {
|
||||
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
|
||||
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
|
||||
revert UUPSUnsupportedProxiableUUID(slot);
|
||||
}
|
||||
ERC1967Utils.upgradeToAndCall(newImplementation, data, forceCall);
|
||||
} catch {
|
||||
// The implementation is not UUPS
|
||||
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user