// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.6.12; /** * @title VersionedInitializable * * @dev Helper contract to implement versioned initializer functions. To use it, replace * the constructor with a function that has the `initializer` or `initializerRunAlways` modifier. * The revision number should be defined as a private constant, returned by getRevision() and used by initializer() modifier. * * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * * ATTN: When used with inheritance, parent initializers with `initializer` modifier are prevented by calling twice, * but can only be called in child-to-parent sequence. * * WARNING: When used with inheritance, parent initializers with `initializerRunAlways` modifier * are NOT protected from multiple calls by another initializer. */ abstract contract VersionedInitializable { /** * @dev Indicates that the contract has been initialized. */ uint256 private lastInitializedRevision = 0; /** * @dev Indicates that the contract is in the process of being initialized. */ uint256 private lastInitializingRevision = 0; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer(uint256 localRevision) { uint256 topRevision = getRevision(); (bool initializing, bool skip) = _preInitializer(localRevision, topRevision); if (!skip) { lastInitializingRevision = localRevision; _; lastInitializedRevision = localRevision; } if (!initializing) { lastInitializedRevision = topRevision; lastInitializingRevision = 0; } } modifier initializerRunAlways(uint256 localRevision) { uint256 topRevision = getRevision(); (bool initializing, bool skip) = _preInitializer(localRevision, topRevision); _; if (!skip) { lastInitializingRevision = localRevision; } _; if (!skip) { lastInitializedRevision = localRevision; } if (!initializing) { lastInitializedRevision = topRevision; lastInitializingRevision = 0; } } function _preInitializer(uint256 localRevision, uint256 topRevision) private returns (bool initializing, bool skip) { require(localRevision > 0, 'incorrect initializer revision'); require(localRevision <= topRevision, 'incorrect contract revision'); initializing = lastInitializingRevision > 0 && lastInitializedRevision < topRevision; require( initializing || isConstructor() || topRevision > lastInitializedRevision, 'Contract instance has already been initialized' ); if (initializing) { require(lastInitializingRevision > localRevision, 'incorrect order of calls to initializers'); } if (localRevision <= lastInitializedRevision) { // prevent calling of parent's initializer when it was called before if (initializing) { // Can't set zero yet, as it is not a top-level call, otherwise "initializing" will become false. // Further calls will fail with the 'incorrect order' assertion above. lastInitializingRevision = 1; } return (initializing, true); } return (initializing, false); } function isRevisionInitialized(uint256 localRevision) internal view returns (bool) { return lastInitializedRevision >= localRevision; } function REVISION() public pure returns (uint256) { return getRevision(); } /** * @dev returns the revision number of the contract * Needs to be defined in the inherited class as a constant. **/ function getRevision() internal pure virtual returns (uint256); /** * @dev Returns true if and only if the function is running in the constructor **/ function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. uint256 cs; //solium-disable-next-line assembly { cs := extcodesize(address()) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[4] private ______gap; }