123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- // SPDX-License-Identifier: MIT
- // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
- pragma solidity ^0.8.20;
- /**
- * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
- * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
- * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
- * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
- *
- * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
- * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
- * case an upgrade adds a module that needs to be initialized.
- *
- * For example:
- *
- * [.hljs-theme-light.nopadding]
- * ```solidity
- * contract MyToken is ERC20Upgradeable {
- * function initialize() initializer public {
- * __ERC20_init("MyToken", "MTK");
- * }
- * }
- *
- * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
- * function initializeV2() reinitializer(2) public {
- * __ERC20Permit_init("MyToken");
- * }
- * }
- * ```
- *
- * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
- * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
- *
- * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
- * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
- *
- * [CAUTION]
- * ====
- * Avoid leaving a contract uninitialized.
- *
- * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
- * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
- * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
- *
- * [.hljs-theme-light.nopadding]
- * ```
- * /// @custom:oz-upgrades-unsafe-allow constructor
- * constructor() {
- * _disableInitializers();
- * }
- * ```
- * ====
- */
- abstract contract Initializable {
- /**
- * @dev Storage of the initializable contract.
- *
- * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
- * when using with upgradeable contracts.
- *
- * @custom:storage-location erc7201:openzeppelin.storage.Initializable
- */
- struct InitializableStorage {
- /**
- * @dev Indicates that the contract has been initialized.
- */
- uint64 _initialized;
- /**
- * @dev Indicates that the contract is in the process of being initialized.
- */
- bool _initializing;
- }
- // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
- bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
- /**
- * @dev The contract is already initialized.
- */
- error InvalidInitialization();
- /**
- * @dev The contract is not initializing.
- */
- error NotInitializing();
- /**
- * @dev Triggered when the contract has been initialized or reinitialized.
- */
- event Initialized(uint64 version);
- /**
- * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
- * `onlyInitializing` functions can be used to initialize parent contracts.
- *
- * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
- * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
- * production.
- *
- * Emits an {Initialized} event.
- */
- modifier initializer() {
- // solhint-disable-next-line var-name-mixedcase
- InitializableStorage storage $ = _getInitializableStorage();
- // Cache values to avoid duplicated sloads
- bool isTopLevelCall = !$._initializing;
- uint64 initialized = $._initialized;
- // Allowed calls:
- // - initialSetup: the contract is not in the initializing state and no previous version was
- // initialized
- // - construction: the contract is initialized at version 1 (no reinitialization) and the
- // current contract is just being deployed
- bool initialSetup = initialized == 0 && isTopLevelCall;
- bool construction = initialized == 1 && address(this).code.length == 0;
- if (!initialSetup && !construction) {
- revert InvalidInitialization();
- }
- $._initialized = 1;
- if (isTopLevelCall) {
- $._initializing = true;
- }
- _;
- if (isTopLevelCall) {
- $._initializing = false;
- emit Initialized(1);
- }
- }
- /**
- * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
- * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
- * used to initialize parent contracts.
- *
- * A reinitializer may be used after the original initialization step. This is essential to configure modules that
- * are added through upgrades and that require initialization.
- *
- * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
- * cannot be nested. If one is invoked in the context of another, execution will revert.
- *
- * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
- * a contract, executing them in the right order is up to the developer or operator.
- *
- * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
- *
- * Emits an {Initialized} event.
- */
- modifier reinitializer(uint64 version) {
- // solhint-disable-next-line var-name-mixedcase
- InitializableStorage storage $ = _getInitializableStorage();
- if ($._initializing || $._initialized >= version) {
- revert InvalidInitialization();
- }
- $._initialized = version;
- $._initializing = true;
- _;
- $._initializing = false;
- emit Initialized(version);
- }
- /**
- * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
- * {initializer} and {reinitializer} modifiers, directly or indirectly.
- */
- modifier onlyInitializing() {
- _checkInitializing();
- _;
- }
- /**
- * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
- */
- function _checkInitializing() internal view virtual {
- if (!_isInitializing()) {
- revert NotInitializing();
- }
- }
- /**
- * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
- * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
- * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
- * through proxies.
- *
- * Emits an {Initialized} event the first time it is successfully executed.
- */
- function _disableInitializers() internal virtual {
- // solhint-disable-next-line var-name-mixedcase
- InitializableStorage storage $ = _getInitializableStorage();
- if ($._initializing) {
- revert InvalidInitialization();
- }
- if ($._initialized != type(uint64).max) {
- $._initialized = type(uint64).max;
- emit Initialized(type(uint64).max);
- }
- }
- /**
- * @dev Returns the highest version that has been initialized. See {reinitializer}.
- */
- function _getInitializedVersion() internal view returns (uint64) {
- return _getInitializableStorage()._initialized;
- }
- /**
- * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
- */
- function _isInitializing() internal view returns (bool) {
- return _getInitializableStorage()._initializing;
- }
- /**
- * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
- *
- * NOTE: Consider following the ERC-7201 formula to derive storage locations.
- */
- function _initializableStorageSlot() internal pure virtual returns (bytes32) {
- return INITIALIZABLE_STORAGE;
- }
- /**
- * @dev Returns a pointer to the storage namespace.
- */
- // solhint-disable-next-line var-name-mixedcase
- function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
- bytes32 slot = _initializableStorageSlot();
- assembly {
- $.slot := slot
- }
- }
- }
|