-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce
UUPSExtUpgradeable
base contract (#32)
* feat: introduce the UUPSExtUpgradeable base contract * chore: fix comments * chore: remove empty line * fix: move errors, add tests * fix: eslint * feat: update version
- Loading branch information
1 parent
880dba4
commit 9b28e54
Showing
27 changed files
with
263 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | ||
|
||
/** | ||
* @title UUPSExtUpgradeable base contract | ||
* @author CloudWalk Inc. (See https://www.cloudwalk.io) | ||
* @dev Extends the OpenZeppelin's {UUPSUpgradeable} contract by adding additional checks for | ||
* the new implementation address. | ||
* | ||
* This contract is used through inheritance. It introduces the virtual `_validateUpgrade()` function that must be | ||
* implemented in the parent contract. | ||
*/ | ||
abstract contract UUPSExtUpgradeable is UUPSUpgradeable { | ||
// ------------------ Errors ---------------------------------- // | ||
|
||
/// @dev Thrown if the provided new implementation address is not a contract. | ||
error UUPSExtUpgradeable_ImplementationAddressNotContract(); | ||
|
||
/// @dev Thrown if the provided new implementation contract address is zero. | ||
error UUPSExtUpgradeable_ImplementationAddressZero(); | ||
|
||
// ------------------ Internal functions ---------------------- // | ||
|
||
/** | ||
* @dev The upgrade authorization function for UUPSProxy. | ||
* @param newImplementation The address of the new implementation. | ||
*/ | ||
function _authorizeUpgrade(address newImplementation) internal override { | ||
if (newImplementation == address(0)) { | ||
revert UUPSExtUpgradeable_ImplementationAddressZero(); | ||
} | ||
|
||
if (newImplementation.code.length == 0) { | ||
revert UUPSExtUpgradeable_ImplementationAddressNotContract(); | ||
} | ||
|
||
_validateUpgrade(newImplementation); | ||
} | ||
|
||
/** | ||
* @dev Executes further validation steps of the upgrade including authorization and implementation address checks. | ||
* @param newImplementation The address of the new implementation. | ||
*/ | ||
function _validateUpgrade(address newImplementation) internal virtual; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
import { UUPSExtUpgradeable } from "../common/UUPSExtUpgradeable.sol"; | ||
|
||
/** | ||
* @title UUPSExtUpgradableMock contract | ||
* @author CloudWalk Inc. (See https://www.cloudwalk.io) | ||
* @dev An implementation of the {UUPSExtUpgradable} contract for test purposes. | ||
*/ | ||
contract UUPSExtUpgradeableMock is UUPSExtUpgradeable { | ||
/// @dev Emitted when the internal `_validateUpgrade()` function is called with the parameters of the function. | ||
event MockValidateUpgradeCall(address newImplementation); | ||
|
||
/** | ||
* @dev Executes further validation steps of the upgrade including authorization and implementation address checks. | ||
* @param newImplementation The address of the new implementation. | ||
*/ | ||
function _validateUpgrade(address newImplementation) internal virtual override { | ||
emit MockValidateUpgradeCall(newImplementation); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { ethers, network, upgrades } from "hardhat"; | ||
import { expect } from "chai"; | ||
import { Contract, ContractFactory } from "ethers"; | ||
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; | ||
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; | ||
import { connect } from "../../test-utils/eth"; | ||
|
||
const ADDRESS_ZERO = ethers.ZeroAddress; | ||
|
||
async function setUpFixture<T>(func: () => Promise<T>): Promise<T> { | ||
if (network.name === "hardhat") { | ||
return loadFixture(func); | ||
} else { | ||
return func(); | ||
} | ||
} | ||
|
||
describe("Contracts 'UUPSExtUpgradeable'", async () => { | ||
// Errors of the lib contracts | ||
const REVERT_ERROR_IMPLEMENTATION_ADDRESS_NOT_CONTRACT = "UUPSExtUpgradeable_ImplementationAddressNotContract"; | ||
const REVERT_ERROR_IMPLEMENTATION_ADDRESS_ZERO = "UUPSExtUpgradeable_ImplementationAddressZero"; | ||
|
||
// Events of the contracts under test | ||
const EVENT_NAME_MOCK_VALIDATE_UPGRADE_CALL = "MockValidateUpgradeCall"; | ||
|
||
let uupsExtensionFactory: ContractFactory; | ||
let deployer: HardhatEthersSigner; | ||
|
||
before(async () => { | ||
[deployer] = await ethers.getSigners(); | ||
|
||
// The contract factory with the explicitly specified deployer account | ||
uupsExtensionFactory = await ethers.getContractFactory("UUPSExtUpgradeableMock"); | ||
uupsExtensionFactory = uupsExtensionFactory.connect(deployer); | ||
}); | ||
|
||
async function deployContract(): Promise<{ uupsExtension: Contract }> { | ||
let uupsExtension: Contract = await upgrades.deployProxy(uupsExtensionFactory, [], { initializer: false }); | ||
await uupsExtension.waitForDeployment(); | ||
uupsExtension = connect(uupsExtension, deployer); // Explicitly specifying the initial account | ||
|
||
return { uupsExtension }; | ||
} | ||
|
||
describe("Function 'upgradeToAndCall()'", async () => { | ||
it("Executes as expected", async () => { | ||
const { uupsExtension } = await setUpFixture(deployContract); | ||
|
||
const newImplementation = await uupsExtensionFactory.deploy(); | ||
await newImplementation.waitForDeployment(); | ||
const newImplementationAddress = await newImplementation.getAddress(); | ||
|
||
await expect(uupsExtension.upgradeToAndCall(newImplementationAddress, "0x")) | ||
.to.emit(uupsExtension, EVENT_NAME_MOCK_VALIDATE_UPGRADE_CALL) | ||
.withArgs(newImplementationAddress); | ||
}); | ||
|
||
it("Is reverted if the new implementation address is zero", async () => { | ||
const { uupsExtension } = await setUpFixture(deployContract); | ||
await expect(uupsExtension.upgradeToAndCall(ADDRESS_ZERO, "0x")) | ||
.to.be.revertedWithCustomError(uupsExtension, REVERT_ERROR_IMPLEMENTATION_ADDRESS_ZERO); | ||
}); | ||
|
||
it("Is reverted if the new implementation address is not a contract", async () => { | ||
const { uupsExtension } = await setUpFixture(deployContract); | ||
await expect(uupsExtension.upgradeToAndCall(deployer.address, "0x")) | ||
.to.be.revertedWithCustomError(uupsExtension, REVERT_ERROR_IMPLEMENTATION_ADDRESS_NOT_CONTRACT); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.