Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move upgradeToAndCallUUPS to UUPSUpgradeable #4356

Merged
merged 14 commits into from
Jun 17, 2023
33 changes: 0 additions & 33 deletions contracts/proxy/ERC1967/ERC1967Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pragma solidity ^0.8.20;

import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
ernestognw marked this conversation as resolved.
Show resolved Hide resolved
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";

Expand Down Expand Up @@ -33,9 +32,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
Expand All @@ -59,11 +55,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.
*/
Expand Down Expand Up @@ -103,30 +94,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
Expand Down
26 changes: 24 additions & 2 deletions contracts/proxy/utils/UUPSUpgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -81,7 +86,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);
}

/**
Expand All @@ -96,7 +101,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);
}

/**
Expand All @@ -110,4 +115,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);
}
}
}
6 changes: 0 additions & 6 deletions test/proxy/utils/UUPSUpgradeable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,6 @@ contract('UUPSUpgradeable', function () {
);

const receipt = await legacyInstance.upgradeTo(this.implInitial.address);

const UpgradedEvents = receipt.logs.filter(
({ address, event }) => address === legacyInstance.address && event === 'Upgraded',
);
expect(UpgradedEvents.length).to.be.equal(1);
frangio marked this conversation as resolved.
Show resolved Hide resolved

expectEvent(receipt, 'Upgraded', { implementation: this.implInitial.address });

const implementationSlot = await getSlot(legacyInstance, ImplementationSlot);
Expand Down