Transaction Hash:
Block:
19011779 at Jan-15-2024 10:46:59 AM +UTC
Transaction Fee:
0.00198916299598545 ETH
$4.84
Gas Used:
86,850 Gas / 22.903431157 Gwei
Emitted Events:
247 |
Proxy.0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2( 0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2, 0x1dc88ef759e14ba0ccac2423479781c1d8cd6d3cd1f767c476bca097337868f7, 0x0000000000000000000000000000000000000000000000000000000000002419, 0x000000000000000000000000000000000000000000000000000000000010ec30, 0000000000000000000000000000000000000000000000000000000065a50d23 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1f9090aa...8e676c326
Miner
| 4.228520818640758885 Eth | 4.228521687276244885 Eth | 0.000000868635486 | ||
0x30c78967...19EA05C1D | |||||
0x853bDfF7...651f90aCa | (Manta Pacific: Proposer) |
1.512104781009054778 Eth
Nonce: 9241
|
1.510115618013069328 Eth
Nonce: 9242
| 0.00198916299598545 |
Execution Trace
Proxy.9aaab648( )
-
L2OutputOracle.proposeL2Output( _outputRoot=1DC88EF759E14BA0CCAC2423479781C1D8CD6D3CD1F767C476BCA097337868F7, _l2BlockNumber=1109040, _l1BlockHash=B6888A9D93A8F22FC59A478B8FBF301AC398F9FDE33AE002F7F38E2448D5E155, _l1BlockNumber=19011767 )
proposeL2Output[L2OutputOracle (ln:156)]
nextBlockNumber[L2OutputOracle (ln:167)]
latestBlockNumber[L2OutputOracle (ln:298)]
computeL2Timestamp[L2OutputOracle (ln:171)]
blockhash[L2OutputOracle (ln:188)]
OutputProposed[L2OutputOracle (ln:192)]
nextOutputIndex[L2OutputOracle (ln:192)]
push[L2OutputOracle (ln:193)]
OutputProposal[L2OutputOracle (ln:194)]
File 1 of 2: Proxy
File 2 of 2: L2OutputOracle
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; /** * @title Proxy * @notice Proxy is a transparent proxy that passes through the call if the caller is the owner or * if the caller is address(0), meaning that the call originated from an off-chain * simulation. */ contract Proxy { /** * @notice The storage slot that holds the address of the implementation. * bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) */ bytes32 internal constant IMPLEMENTATION_KEY = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @notice The storage slot that holds the address of the owner. * bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1) */ bytes32 internal constant OWNER_KEY = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @notice An event that is emitted each time the implementation is changed. This event is part * of the EIP-1967 specification. * * @param implementation The address of the implementation contract */ event Upgraded(address indexed implementation); /** * @notice An event that is emitted each time the owner is upgraded. This event is part of the * EIP-1967 specification. * * @param previousAdmin The previous owner of the contract * @param newAdmin The new owner of the contract */ event AdminChanged(address previousAdmin, address newAdmin); /** * @notice A modifier that reverts if not called by the owner or by address(0) to allow * eth_call to interact with this proxy without needing to use low-level storage * inspection. We assume that nobody is able to trigger calls from address(0) during * normal EVM execution. */ modifier proxyCallIfNotAdmin() { if (msg.sender == _getAdmin() || msg.sender == address(0)) { _; } else { // This WILL halt the call frame on completion. _doProxyCall(); } } /** * @notice Sets the initial admin during contract deployment. Admin address is stored at the * EIP-1967 admin storage slot so that accidental storage collision with the * implementation is not possible. * * @param _admin Address of the initial contract admin. Admin as the ability to access the * transparent proxy interface. */ constructor(address _admin) { _changeAdmin(_admin); } // slither-disable-next-line locked-ether receive() external payable { // Proxy call by default. _doProxyCall(); } // slither-disable-next-line locked-ether fallback() external payable { // Proxy call by default. _doProxyCall(); } /** * @notice Set the implementation contract address. The code at the given address will execute * when this contract is called. * * @param _implementation Address of the implementation contract. */ function upgradeTo(address _implementation) public virtual proxyCallIfNotAdmin { _setImplementation(_implementation); } /** * @notice Set the implementation and call a function in a single transaction. Useful to ensure * atomic execution of initialization-based upgrades. * * @param _implementation Address of the implementation contract. * @param _data Calldata to delegatecall the new implementation with. */ function upgradeToAndCall(address _implementation, bytes calldata _data) public payable virtual proxyCallIfNotAdmin returns (bytes memory) { _setImplementation(_implementation); (bool success, bytes memory returndata) = _implementation.delegatecall(_data); require(success, "Proxy: delegatecall to new implementation contract failed"); return returndata; } /** * @notice Changes the owner of the proxy contract. Only callable by the owner. * * @param _admin New owner of the proxy contract. */ function changeAdmin(address _admin) public virtual proxyCallIfNotAdmin { _changeAdmin(_admin); } /** * @notice Gets the owner of the proxy contract. * * @return Owner address. */ function admin() public virtual proxyCallIfNotAdmin returns (address) { return _getAdmin(); } /** * @notice Queries the implementation address. * * @return Implementation address. */ function implementation() public virtual proxyCallIfNotAdmin returns (address) { return _getImplementation(); } /** * @notice Sets the implementation address. * * @param _implementation New implementation address. */ function _setImplementation(address _implementation) internal { assembly { sstore(IMPLEMENTATION_KEY, _implementation) } emit Upgraded(_implementation); } /** * @notice Changes the owner of the proxy contract. * * @param _admin New owner of the proxy contract. */ function _changeAdmin(address _admin) internal { address previous = _getAdmin(); assembly { sstore(OWNER_KEY, _admin) } emit AdminChanged(previous, _admin); } /** * @notice Performs the proxy call via a delegatecall. */ function _doProxyCall() internal { address impl = _getImplementation(); require(impl != address(0), "Proxy: implementation not initialized"); assembly { // Copy calldata into memory at 0x0....calldatasize. calldatacopy(0x0, 0x0, calldatasize()) // Perform the delegatecall, make sure to pass all available gas. let success := delegatecall(gas(), impl, 0x0, calldatasize(), 0x0, 0x0) // Copy returndata into memory at 0x0....returndatasize. Note that this *will* // overwrite the calldata that we just copied into memory but that doesn't really // matter because we'll be returning in a second anyway. returndatacopy(0x0, 0x0, returndatasize()) // Success == 0 means a revert. We'll revert too and pass the data up. if iszero(success) { revert(0x0, returndatasize()) } // Otherwise we'll just return and pass the data up. return(0x0, returndatasize()) } } /** * @notice Queries the implementation address. * * @return Implementation address. */ function _getImplementation() internal view returns (address) { address impl; assembly { impl := sload(IMPLEMENTATION_KEY) } return impl; } /** * @notice Queries the owner of the proxy contract. * * @return Owner address. */ function _getAdmin() internal view returns (address) { address owner; assembly { owner := sload(OWNER_KEY) } return owner; } }
File 2 of 2: L2OutputOracle
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { Semver } from "../universal/Semver.sol"; import { Types } from "../libraries/Types.sol"; /** * @custom:proxied * @title L2OutputOracle * @notice The L2OutputOracle contains an array of L2 state outputs, where each output is a * commitment to the state of the L2 chain. Other contracts like the OptimismPortal use * these outputs to verify information about the state of L2. */ contract L2OutputOracle is Initializable, Semver { /** * @notice The interval in L2 blocks at which checkpoints must be submitted. Although this is * immutable, it can safely be modified by upgrading the implementation contract. */ uint256 public immutable SUBMISSION_INTERVAL; /** * @notice The time between L2 blocks in seconds. Once set, this value MUST NOT be modified. */ uint256 public immutable L2_BLOCK_TIME; /** * @notice The address of the challenger. Can be updated via upgrade. */ address public immutable CHALLENGER; /** * @notice The address of the proposer. Can be updated via upgrade. */ address public immutable PROPOSER; /** * @notice Minimum time (in seconds) that must elapse before a withdrawal can be finalized. */ uint256 public immutable FINALIZATION_PERIOD_SECONDS; /** * @notice The number of the first L2 block recorded in this contract. */ uint256 public startingBlockNumber; /** * @notice The timestamp of the first L2 block recorded in this contract. */ uint256 public startingTimestamp; /** * @notice Array of L2 output proposals. */ Types.OutputProposal[] internal l2Outputs; /** * @notice Emitted when an output is proposed. * * @param outputRoot The output root. * @param l2OutputIndex The index of the output in the l2Outputs array. * @param l2BlockNumber The L2 block number of the output root. * @param l1Timestamp The L1 timestamp when proposed. */ event OutputProposed( bytes32 indexed outputRoot, uint256 indexed l2OutputIndex, uint256 indexed l2BlockNumber, uint256 l1Timestamp ); /** * @notice Emitted when outputs are deleted. * * @param prevNextOutputIndex Next L2 output index before the deletion. * @param newNextOutputIndex Next L2 output index after the deletion. */ event OutputsDeleted(uint256 indexed prevNextOutputIndex, uint256 indexed newNextOutputIndex); /** * @custom:semver 1.2.0 * * @param _submissionInterval Interval in blocks at which checkpoints must be submitted. * @param _l2BlockTime The time per L2 block, in seconds. * @param _startingBlockNumber The number of the first L2 block. * @param _startingTimestamp The timestamp of the first L2 block. * @param _proposer The address of the proposer. * @param _challenger The address of the challenger. */ constructor( uint256 _submissionInterval, uint256 _l2BlockTime, uint256 _startingBlockNumber, uint256 _startingTimestamp, address _proposer, address _challenger, uint256 _finalizationPeriodSeconds ) Semver(1, 2, 0) { require(_l2BlockTime > 0, "L2OutputOracle: L2 block time must be greater than 0"); require( _submissionInterval > _l2BlockTime, "L2OutputOracle: submission interval must be greater than L2 block time" ); SUBMISSION_INTERVAL = _submissionInterval; L2_BLOCK_TIME = _l2BlockTime; PROPOSER = _proposer; CHALLENGER = _challenger; FINALIZATION_PERIOD_SECONDS = _finalizationPeriodSeconds; initialize(_startingBlockNumber, _startingTimestamp); } /** * @notice Initializer. * * @param _startingBlockNumber Block number for the first recoded L2 block. * @param _startingTimestamp Timestamp for the first recoded L2 block. */ function initialize(uint256 _startingBlockNumber, uint256 _startingTimestamp) public initializer { require( _startingTimestamp <= block.timestamp, "L2OutputOracle: starting L2 timestamp must be less than current time" ); startingTimestamp = _startingTimestamp; startingBlockNumber = _startingBlockNumber; } /** * @notice Deletes all output proposals after and including the proposal that corresponds to * the given output index. Only the challenger address can delete outputs. * * @param _l2OutputIndex Index of the first L2 output to be deleted. All outputs after this * output will also be deleted. */ // solhint-disable-next-line ordering function deleteL2Outputs(uint256 _l2OutputIndex) external { require( msg.sender == CHALLENGER, "L2OutputOracle: only the challenger address can delete outputs" ); // Make sure we're not *increasing* the length of the array. require( _l2OutputIndex < l2Outputs.length, "L2OutputOracle: cannot delete outputs after the latest output index" ); // Do not allow deleting any outputs that have already been finalized. require( block.timestamp - l2Outputs[_l2OutputIndex].timestamp < FINALIZATION_PERIOD_SECONDS, "L2OutputOracle: cannot delete outputs that have already been finalized" ); uint256 prevNextL2OutputIndex = nextOutputIndex(); // Use assembly to delete the array elements because Solidity doesn't allow it. assembly { sstore(l2Outputs.slot, _l2OutputIndex) } emit OutputsDeleted(prevNextL2OutputIndex, _l2OutputIndex); } /** * @notice Accepts an outputRoot and the timestamp of the corresponding L2 block. The timestamp * must be equal to the current value returned by `nextTimestamp()` in order to be * accepted. This function may only be called by the Proposer. * * @param _outputRoot The L2 output of the checkpoint block. * @param _l2BlockNumber The L2 block number that resulted in _outputRoot. * @param _l1BlockHash A block hash which must be included in the current chain. * @param _l1BlockNumber The block number with the specified block hash. */ function proposeL2Output( bytes32 _outputRoot, uint256 _l2BlockNumber, bytes32 _l1BlockHash, uint256 _l1BlockNumber ) external payable { require( msg.sender == PROPOSER, "L2OutputOracle: only the proposer address can propose new outputs" ); require( _l2BlockNumber == nextBlockNumber(), "L2OutputOracle: block number must be equal to next expected block number" ); require( computeL2Timestamp(_l2BlockNumber) < block.timestamp, "L2OutputOracle: cannot propose L2 output in the future" ); require( _outputRoot != bytes32(0), "L2OutputOracle: L2 output proposal cannot be the zero hash" ); if (_l1BlockHash != bytes32(0)) { // This check allows the proposer to propose an output based on a given L1 block, // without fear that it will be reorged out. // It will also revert if the blockheight provided is more than 256 blocks behind the // chain tip (as the hash will return as zero). This does open the door to a griefing // attack in which the proposer's submission is censored until the block is no longer // retrievable, if the proposer is experiencing this attack it can simply leave out the // blockhash value, and delay submission until it is confident that the L1 block is // finalized. require( blockhash(_l1BlockNumber) == _l1BlockHash, "L2OutputOracle: block hash does not match the hash at the expected height" ); } emit OutputProposed(_outputRoot, nextOutputIndex(), _l2BlockNumber, block.timestamp); l2Outputs.push( Types.OutputProposal({ outputRoot: _outputRoot, timestamp: uint128(block.timestamp), l2BlockNumber: uint128(_l2BlockNumber) }) ); } /** * @notice Returns an output by index. Exists because Solidity's array access will return a * tuple instead of a struct. * * @param _l2OutputIndex Index of the output to return. * * @return The output at the given index. */ function getL2Output(uint256 _l2OutputIndex) external view returns (Types.OutputProposal memory) { return l2Outputs[_l2OutputIndex]; } /** * @notice Returns the index of the L2 output that checkpoints a given L2 block number. Uses a * binary search to find the first output greater than or equal to the given block. * * @param _l2BlockNumber L2 block number to find a checkpoint for. * * @return Index of the first checkpoint that commits to the given L2 block number. */ function getL2OutputIndexAfter(uint256 _l2BlockNumber) public view returns (uint256) { // Make sure an output for this block number has actually been proposed. require( _l2BlockNumber <= latestBlockNumber(), "L2OutputOracle: cannot get output for a block that has not been proposed" ); // Make sure there's at least one output proposed. require( l2Outputs.length > 0, "L2OutputOracle: cannot get output as no outputs have been proposed yet" ); // Find the output via binary search, guaranteed to exist. uint256 lo = 0; uint256 hi = l2Outputs.length; while (lo < hi) { uint256 mid = (lo + hi) / 2; if (l2Outputs[mid].l2BlockNumber < _l2BlockNumber) { lo = mid + 1; } else { hi = mid; } } return lo; } /** * @notice Returns the L2 output proposal that checkpoints a given L2 block number. Uses a * binary search to find the first output greater than or equal to the given block. * * @param _l2BlockNumber L2 block number to find a checkpoint for. * * @return First checkpoint that commits to the given L2 block number. */ function getL2OutputAfter(uint256 _l2BlockNumber) external view returns (Types.OutputProposal memory) { return l2Outputs[getL2OutputIndexAfter(_l2BlockNumber)]; } /** * @notice Returns the number of outputs that have been proposed. Will revert if no outputs * have been proposed yet. * * @return The number of outputs that have been proposed. */ function latestOutputIndex() external view returns (uint256) { return l2Outputs.length - 1; } /** * @notice Returns the index of the next output to be proposed. * * @return The index of the next output to be proposed. */ function nextOutputIndex() public view returns (uint256) { return l2Outputs.length; } /** * @notice Returns the block number of the latest submitted L2 output proposal. If no proposals * been submitted yet then this function will return the starting block number. * * @return Latest submitted L2 block number. */ function latestBlockNumber() public view returns (uint256) { return l2Outputs.length == 0 ? startingBlockNumber : l2Outputs[l2Outputs.length - 1].l2BlockNumber; } /** * @notice Computes the block number of the next L2 block that needs to be checkpointed. * * @return Next L2 block number. */ function nextBlockNumber() public view returns (uint256) { return latestBlockNumber() + SUBMISSION_INTERVAL; } /** * @notice Returns the L2 timestamp corresponding to a given L2 block number. * * @param _l2BlockNumber The L2 block number of the target block. * * @return L2 timestamp of the given block. */ function computeL2Timestamp(uint256 _l2BlockNumber) public view returns (uint256) { return startingTimestamp + ((_l2BlockNumber - startingBlockNumber) * L2_BLOCK_TIME); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Types * @notice Contains various types used throughout the Optimism contract system. */ library Types { /** * @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1 * timestamp that the output root is posted. This timestamp is used to verify that the * finalization period has passed since the output root was submitted. * * @custom:field outputRoot Hash of the L2 output. * @custom:field timestamp Timestamp of the L1 block that the output root was submitted in. * @custom:field l2BlockNumber L2 block number that the output corresponds to. */ struct OutputProposal { bytes32 outputRoot; uint128 timestamp; uint128 l2BlockNumber; } /** * @notice Struct representing the elements that are hashed together to generate an output root * which itself represents a snapshot of the L2 state. * * @custom:field version Version of the output root. * @custom:field stateRoot Root of the state trie at the block of this output. * @custom:field messagePasserStorageRoot Root of the message passer storage trie. * @custom:field latestBlockhash Hash of the block this output was generated from. */ struct OutputRootProof { bytes32 version; bytes32 stateRoot; bytes32 messagePasserStorageRoot; bytes32 latestBlockhash; } /** * @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end * user (as opposed to a system deposit transaction generated by the system). * * @custom:field from Address of the sender of the transaction. * @custom:field to Address of the recipient of the transaction. * @custom:field isCreation True if the transaction is a contract creation. * @custom:field value Value to send to the recipient. * @custom:field mint Amount of ETH to mint. * @custom:field gasLimit Gas limit of the transaction. * @custom:field data Data of the transaction. * @custom:field l1BlockHash Hash of the block the transaction was submitted in. * @custom:field logIndex Index of the log in the block the transaction was submitted in. */ struct UserDepositTransaction { address from; address to; bool isCreation; uint256 value; uint256 mint; uint64 gasLimit; bytes data; bytes32 l1BlockHash; uint256 logIndex; } /** * @notice Struct representing a withdrawal transaction. * * @custom:field nonce Nonce of the withdrawal transaction * @custom:field sender Address of the sender of the transaction. * @custom:field target Address of the recipient of the transaction. * @custom:field value Value to send to the recipient. * @custom:field gasLimit Gas limit of the transaction. * @custom:field data Data of the transaction. */ struct WithdrawalTransaction { uint256 nonce; address sender; address target; uint256 value; uint256 gasLimit; bytes data; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; /** * @title Semver * @notice Semver is a simple contract for managing contract versions. */ contract Semver { /** * @notice Contract version number (major). */ uint256 private immutable MAJOR_VERSION; /** * @notice Contract version number (minor). */ uint256 private immutable MINOR_VERSION; /** * @notice Contract version number (patch). */ uint256 private immutable PATCH_VERSION; /** * @param _major Version number (major). * @param _minor Version number (minor). * @param _patch Version number (patch). */ constructor( uint256 _major, uint256 _minor, uint256 _patch ) { MAJOR_VERSION = _major; MINOR_VERSION = _minor; PATCH_VERSION = _patch; } /** * @notice Returns the full semver contract version. * * @return Semver contract version as a string. */ function version() public view returns (string memory) { return string( abi.encodePacked( Strings.toString(MAJOR_VERSION), ".", Strings.toString(MINOR_VERSION), ".", Strings.toString(PATCH_VERSION) ) ); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/Address.sol"; /** * @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] * ``` * 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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 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. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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. * * `initializer` is equivalent to `reinitializer(1)`, so 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. * * 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. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @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. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }