Initializable.sol 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
  3. pragma solidity ^0.8.0;
  4. import "../../utils/Address.sol";
  5. /**
  6. * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
  7. * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
  8. * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
  9. * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
  10. *
  11. * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
  12. * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
  13. * case an upgrade adds a module that needs to be initialized.
  14. *
  15. * For example:
  16. *
  17. * [.hljs-theme-light.nopadding]
  18. * ```
  19. * contract MyToken is ERC20Upgradeable {
  20. * function initialize() initializer public {
  21. * __ERC20_init("MyToken", "MTK");
  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 Indicates that the contract has been initialized.
  57. * @custom:oz-retyped-from bool
  58. */
  59. uint8 private _initialized;
  60. /**
  61. * @dev Indicates that the contract is in the process of being initialized.
  62. */
  63. bool private _initializing;
  64. /**
  65. * @dev Triggered when the contract has been initialized or reinitialized.
  66. */
  67. event Initialized(uint8 version);
  68. /**
  69. * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
  70. * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
  71. */
  72. modifier initializer() {
  73. bool isTopLevelCall = _setInitializedVersion(1);
  74. if (isTopLevelCall) {
  75. _initializing = true;
  76. }
  77. _;
  78. if (isTopLevelCall) {
  79. _initializing = false;
  80. emit Initialized(1);
  81. }
  82. }
  83. /**
  84. * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
  85. * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
  86. * used to initialize parent contracts.
  87. *
  88. * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
  89. * initialization step. This is essential to configure modules that are added through upgrades and that require
  90. * initialization.
  91. *
  92. * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
  93. * a contract, executing them in the right order is up to the developer or operator.
  94. */
  95. modifier reinitializer(uint8 version) {
  96. bool isTopLevelCall = _setInitializedVersion(version);
  97. if (isTopLevelCall) {
  98. _initializing = true;
  99. }
  100. _;
  101. if (isTopLevelCall) {
  102. _initializing = false;
  103. emit Initialized(version);
  104. }
  105. }
  106. /**
  107. * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
  108. * {initializer} and {reinitializer} modifiers, directly or indirectly.
  109. */
  110. modifier onlyInitializing() {
  111. require(_initializing, "Initializable: contract is not initializing");
  112. _;
  113. }
  114. /**
  115. * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
  116. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
  117. * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
  118. * through proxies.
  119. */
  120. function _disableInitializers() internal virtual {
  121. _setInitializedVersion(type(uint8).max);
  122. }
  123. function _setInitializedVersion(uint8 version) private returns (bool) {
  124. // If the contract is initializing we ignore whether _initialized is set in order to support multiple
  125. // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
  126. // of initializers, because in other contexts the contract may have been reentered.
  127. if (_initializing) {
  128. require(
  129. version == 1 && !Address.isContract(address(this)),
  130. "Initializable: contract is already initialized"
  131. );
  132. return false;
  133. } else {
  134. require(_initialized < version, "Initializable: contract is already initialized");
  135. _initialized = version;
  136. return true;
  137. }
  138. }
  139. }