Initializable.sol 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
  3. pragma solidity ^0.8.20;
  4. /**
  5. * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
  6. * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
  7. * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
  8. * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
  9. *
  10. * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
  11. * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
  12. * case an upgrade adds a module that needs to be initialized.
  13. *
  14. * For example:
  15. *
  16. * [.hljs-theme-light.nopadding]
  17. * ```solidity
  18. * contract MyToken is ERC20Upgradeable {
  19. * function initialize() initializer public {
  20. * __ERC20_init("MyToken", "MTK");
  21. * }
  22. * }
  23. *
  24. * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
  25. * function initializeV2() reinitializer(2) public {
  26. * __ERC20Permit_init("MyToken");
  27. * }
  28. * }
  29. * ```
  30. *
  31. * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
  32. * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
  33. *
  34. * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
  35. * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
  36. *
  37. * [CAUTION]
  38. * ====
  39. * Avoid leaving a contract uninitialized.
  40. *
  41. * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
  42. * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
  43. * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
  44. *
  45. * [.hljs-theme-light.nopadding]
  46. * ```
  47. * /// @custom:oz-upgrades-unsafe-allow constructor
  48. * constructor() {
  49. * _disableInitializers();
  50. * }
  51. * ```
  52. * ====
  53. */
  54. abstract contract Initializable {
  55. /**
  56. * @dev Storage of the initializable contract.
  57. *
  58. * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
  59. * when using with upgradeable contracts.
  60. *
  61. * @custom:storage-location erc7201:openzeppelin.storage.Initializable
  62. */
  63. struct InitializableStorage {
  64. /**
  65. * @dev Indicates that the contract has been initialized.
  66. */
  67. uint64 _initialized;
  68. /**
  69. * @dev Indicates that the contract is in the process of being initialized.
  70. */
  71. bool _initializing;
  72. }
  73. // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
  74. bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
  75. /**
  76. * @dev The contract is already initialized.
  77. */
  78. error InvalidInitialization();
  79. /**
  80. * @dev The contract is not initializing.
  81. */
  82. error NotInitializing();
  83. /**
  84. * @dev Triggered when the contract has been initialized or reinitialized.
  85. */
  86. event Initialized(uint64 version);
  87. /**
  88. * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
  89. * `onlyInitializing` functions can be used to initialize parent contracts.
  90. *
  91. * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
  92. * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
  93. * production.
  94. *
  95. * Emits an {Initialized} event.
  96. */
  97. modifier initializer() {
  98. // solhint-disable-next-line var-name-mixedcase
  99. InitializableStorage storage $ = _getInitializableStorage();
  100. // Cache values to avoid duplicated sloads
  101. bool isTopLevelCall = !$._initializing;
  102. uint64 initialized = $._initialized;
  103. // Allowed calls:
  104. // - initialSetup: the contract is not in the initializing state and no previous version was
  105. // initialized
  106. // - construction: the contract is initialized at version 1 (no reinitialization) and the
  107. // current contract is just being deployed
  108. bool initialSetup = initialized == 0 && isTopLevelCall;
  109. bool construction = initialized == 1 && address(this).code.length == 0;
  110. if (!initialSetup && !construction) {
  111. revert InvalidInitialization();
  112. }
  113. $._initialized = 1;
  114. if (isTopLevelCall) {
  115. $._initializing = true;
  116. }
  117. _;
  118. if (isTopLevelCall) {
  119. $._initializing = false;
  120. emit Initialized(1);
  121. }
  122. }
  123. /**
  124. * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
  125. * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
  126. * used to initialize parent contracts.
  127. *
  128. * A reinitializer may be used after the original initialization step. This is essential to configure modules that
  129. * are added through upgrades and that require initialization.
  130. *
  131. * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
  132. * cannot be nested. If one is invoked in the context of another, execution will revert.
  133. *
  134. * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
  135. * a contract, executing them in the right order is up to the developer or operator.
  136. *
  137. * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
  138. *
  139. * Emits an {Initialized} event.
  140. */
  141. modifier reinitializer(uint64 version) {
  142. // solhint-disable-next-line var-name-mixedcase
  143. InitializableStorage storage $ = _getInitializableStorage();
  144. if ($._initializing || $._initialized >= version) {
  145. revert InvalidInitialization();
  146. }
  147. $._initialized = version;
  148. $._initializing = true;
  149. _;
  150. $._initializing = false;
  151. emit Initialized(version);
  152. }
  153. /**
  154. * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
  155. * {initializer} and {reinitializer} modifiers, directly or indirectly.
  156. */
  157. modifier onlyInitializing() {
  158. _checkInitializing();
  159. _;
  160. }
  161. /**
  162. * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
  163. */
  164. function _checkInitializing() internal view virtual {
  165. if (!_isInitializing()) {
  166. revert NotInitializing();
  167. }
  168. }
  169. /**
  170. * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
  171. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
  172. * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
  173. * through proxies.
  174. *
  175. * Emits an {Initialized} event the first time it is successfully executed.
  176. */
  177. function _disableInitializers() internal virtual {
  178. // solhint-disable-next-line var-name-mixedcase
  179. InitializableStorage storage $ = _getInitializableStorage();
  180. if ($._initializing) {
  181. revert InvalidInitialization();
  182. }
  183. if ($._initialized != type(uint64).max) {
  184. $._initialized = type(uint64).max;
  185. emit Initialized(type(uint64).max);
  186. }
  187. }
  188. /**
  189. * @dev Returns the highest version that has been initialized. See {reinitializer}.
  190. */
  191. function _getInitializedVersion() internal view returns (uint64) {
  192. return _getInitializableStorage()._initialized;
  193. }
  194. /**
  195. * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
  196. */
  197. function _isInitializing() internal view returns (bool) {
  198. return _getInitializableStorage()._initializing;
  199. }
  200. /**
  201. * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
  202. *
  203. * NOTE: Consider following the ERC-7201 formula to derive storage locations.
  204. */
  205. function _initializableStorageSlot() internal pure virtual returns (bytes32) {
  206. return INITIALIZABLE_STORAGE;
  207. }
  208. /**
  209. * @dev Returns a pointer to the storage namespace.
  210. */
  211. // solhint-disable-next-line var-name-mixedcase
  212. function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
  213. bytes32 slot = _initializableStorageSlot();
  214. assembly {
  215. $.slot := slot
  216. }
  217. }
  218. }