Transaction Hash:
Block:
21671364 at Jan-21-2025 07:26:47 AM +UTC
Transaction Fee:
0.009855069383584531 ETH
$18.34
Gas Used:
1,279,613 Gas / 7.701601487 Gwei
Emitted Events:
347 |
DelayedWETH.OwnershipTransferred( previousOwner=0x00000000...000000000, newOwner=[Receiver] 0x4e59b44847b379578588920ca78fbf26c0b4956c )
|
348 |
DelayedWETH.OwnershipTransferred( previousOwner=[Receiver] 0x4e59b44847b379578588920ca78fbf26c0b4956c, newOwner=0x00000000...000000000 )
|
349 |
DelayedWETH.Initialized( version=1 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 12.213980659525644541 Eth | 12.214067033403144541 Eth | 0.0000863738775 | |
0x4e59b448...6c0B4956C | |||||
0x837eB124...4051de395 |
1.772325994237859454 Eth
Nonce: 31
|
1.762470924854274923 Eth
Nonce: 32
| 0.009855069383584531 | ||
0xdAF8E8cd...74A13a8EB |
0 Eth
Nonce: 0
|
0 Eth
Nonce: 1
|
Execution Trace
Deterministic Deployer .704de1ba( )

-
DelayedWETH.60a06040( )
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { ISemver } from "src/universal/ISemver.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IWETH } from "src/dispute/interfaces/IWETH.sol"; import { WETH98 } from "src/dispute/weth/WETH98.sol"; import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; /// @title DelayedWETH /// @notice DelayedWETH is an extension to WETH9 that allows for delayed withdrawals. Accounts must trigger an unlock /// function before they can withdraw WETH. Accounts must trigger unlock by specifying a sub-account and an /// amount of WETH to unlock. Accounts can trigger the unlock function at any time, but must wait a delay /// period before they can withdraw after the unlock function is triggered. DelayedWETH is designed to be used /// by the DisputeGame contracts where unlock will only be triggered after a dispute is resolved. DelayedWETH /// is meant to sit behind a proxy contract and has an owner address that can pull WETH from any account and /// can recover ETH from the contract itself. Variable and function naming vaguely follows the vibe of WETH9. /// Not the prettiest contract in the world, but it gets the job done. contract DelayedWETH is OwnableUpgradeable, WETH98, IDelayedWETH, ISemver { /// @notice Semantic version. /// @custom:semver 1.0.0 string public constant version = "1.0.0"; /// @inheritdoc IDelayedWETH mapping(address => mapping(address => WithdrawalRequest)) public withdrawals; /// @notice Withdrawal delay in seconds. uint256 internal immutable DELAY_SECONDS; /// @notice Address of the SuperchainConfig contract. SuperchainConfig public config; /// @param _delay The delay for withdrawals in seconds. constructor(uint256 _delay) { DELAY_SECONDS = _delay; initialize({ _owner: address(0), _config: SuperchainConfig(address(0)) }); } /// @notice Initializes the contract. /// @param _owner The address of the owner. /// @param _config Address of the SuperchainConfig contract. function initialize(address _owner, SuperchainConfig _config) public initializer { __Ownable_init(); _transferOwnership(_owner); config = _config; } /// @inheritdoc IDelayedWETH function delay() external view returns (uint256) { return DELAY_SECONDS; } /// @inheritdoc IDelayedWETH function unlock(address _guy, uint256 _wad) external { // Note that the unlock function can be called by any address, but the actual unlocking capability still only // gives the msg.sender the ability to withdraw from the account. As long as the unlock and withdraw functions // are called with the proper recipient addresses, this will be safe. Could be made safer by having external // accounts execute withdrawals themselves but that would have added extra complexity and made DelayedWETH a // leaky abstraction, so we chose this instead. WithdrawalRequest storage wd = withdrawals[msg.sender][_guy]; wd.timestamp = block.timestamp; wd.amount += _wad; } /// @inheritdoc IWETH function withdraw(uint256 _wad) public override(WETH98, IWETH) { withdraw(msg.sender, _wad); } /// @inheritdoc IDelayedWETH function withdraw(address _guy, uint256 _wad) public { require(!config.paused(), "DelayedWETH: contract is paused"); WithdrawalRequest storage wd = withdrawals[msg.sender][_guy]; require(wd.amount >= _wad, "DelayedWETH: insufficient unlocked withdrawal"); require(wd.timestamp > 0, "DelayedWETH: withdrawal not unlocked"); require(wd.timestamp + DELAY_SECONDS <= block.timestamp, "DelayedWETH: withdrawal delay not met"); wd.amount -= _wad; super.withdraw(_wad); } /// @inheritdoc IDelayedWETH function recover(uint256 _wad) external { require(msg.sender == owner(), "DelayedWETH: not owner"); uint256 amount = _wad < address(this).balance ? _wad : address(this).balance; payable(msg.sender).transfer(amount); } /// @inheritdoc IDelayedWETH function hold(address _guy, uint256 _wad) external { require(msg.sender == owner(), "DelayedWETH: not owner"); allowance[_guy][msg.sender] = _wad; emit Approval(_guy, msg.sender, _wad); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ISemver /// @notice ISemver is a simple contract for ensuring that contracts are /// versioned using semantic versioning. interface ISemver { /// @notice Getter for the semantic version of the contract. This is not /// meant to be used onchain but instead meant to be used by offchain /// tooling. /// @return Semver contract version as a string. function version() external view returns (string memory); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IWETH } from "src/dispute/interfaces/IWETH.sol"; /// @title IDelayedWETH /// @notice Interface for the DelayedWETH contract. interface IDelayedWETH is IWETH { /// @notice Represents a withdrawal request. struct WithdrawalRequest { uint256 amount; uint256 timestamp; } /// @notice Emitted when an unwrap is started. /// @param src The address that started the unwrap. /// @param wad The amount of WETH that was unwrapped. event Unwrap(address indexed src, uint256 wad); /// @notice Returns the withdrawal delay in seconds. /// @return The withdrawal delay in seconds. function delay() external view returns (uint256); /// @notice Returns a withdrawal request for the given address. /// @param _owner The address to query the withdrawal request of. /// @param _guy Sub-account to query the withdrawal request of. /// @return The withdrawal request for the given address-subaccount pair. function withdrawals(address _owner, address _guy) external view returns (uint256, uint256); /// @notice Unlocks withdrawals for the sender's account, after a time delay. /// @param _guy Sub-account to unlock. /// @param _wad The amount of WETH to unlock. function unlock(address _guy, uint256 _wad) external; /// @notice Extension to withdrawal, must provide a sub-account to withdraw from. /// @param _guy Sub-account to withdraw from. /// @param _wad The amount of WETH to withdraw. function withdraw(address _guy, uint256 _wad) external; /// @notice Allows the owner to recover from error cases by pulling ETH out of the contract. /// @param _wad The amount of WETH to recover. function recover(uint256 _wad) external; /// @notice Allows the owner to recover from error cases by pulling ETH from a specific owner. /// @param _guy The address to recover the WETH from. /// @param _wad The amount of WETH to recover. function hold(address _guy, uint256 _wad) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title IWETH /// @notice Interface for WETH9. interface IWETH { /// @notice Emitted when an approval is made. /// @param src The address that approved the transfer. /// @param guy The address that was approved to transfer. /// @param wad The amount that was approved to transfer. event Approval(address indexed src, address indexed guy, uint256 wad); /// @notice Emitted when a transfer is made. /// @param src The address that transferred the WETH. /// @param dst The address that received the WETH. /// @param wad The amount of WETH that was transferred. event Transfer(address indexed src, address indexed dst, uint256 wad); /// @notice Emitted when a deposit is made. /// @param dst The address that deposited the WETH. /// @param wad The amount of WETH that was deposited. event Deposit(address indexed dst, uint256 wad); /// @notice Emitted when a withdrawal is made. /// @param src The address that withdrew the WETH. /// @param wad The amount of WETH that was withdrawn. event Withdrawal(address indexed src, uint256 wad); /// @notice Returns the name of the token. /// @return The name of the token. function name() external view returns (string memory); /// @notice Returns the symbol of the token. /// @return The symbol of the token. function symbol() external view returns (string memory); /// @notice Returns the number of decimals the token uses. /// @return The number of decimals the token uses. function decimals() external pure returns (uint8); /// @notice Returns the balance of the given address. /// @param owner The address to query the balance of. /// @return The balance of the given address. function balanceOf(address owner) external view returns (uint256); /// @notice Returns the amount of WETH that the spender can transfer on behalf of the owner. /// @param owner The address that owns the WETH. /// @param spender The address that is approved to transfer the WETH. /// @return The amount of WETH that the spender can transfer on behalf of the owner. function allowance(address owner, address spender) external view returns (uint256); /// @notice Allows WETH to be deposited by sending ether to the contract. function deposit() external payable; /// @notice Withdraws an amount of ETH. /// @param wad The amount of ETH to withdraw. function withdraw(uint256 wad) external; /// @notice Returns the total supply of WETH. /// @return The total supply of WETH. function totalSupply() external view returns (uint256); /// @notice Approves the given address to transfer the WETH on behalf of the caller. /// @param guy The address that is approved to transfer the WETH. /// @param wad The amount that is approved to transfer. /// @return True if the approval was successful. function approve(address guy, uint256 wad) external returns (bool); /// @notice Transfers the given amount of WETH to the given address. /// @param dst The address to transfer the WETH to. /// @param wad The amount of WETH to transfer. /// @return True if the transfer was successful. function transfer(address dst, uint256 wad) external returns (bool); /// @notice Transfers the given amount of WETH from the given address to the given address. /// @param src The address to transfer the WETH from. /// @param dst The address to transfer the WETH to. /// @param wad The amount of WETH to transfer. /// @return True if the transfer was successful. function transferFrom(address src, address dst, uint256 wad) external returns (bool); } // SPDX-License-Identifier: GPL-3.0 // Copyright (C) 2015, 2016, 2017 Dapphub // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // Based on WETH9 by Dapphub. // Modified by OP Labs. pragma solidity 0.8.15; import { IWETH } from "src/dispute/interfaces/IWETH.sol"; /// @title WETH98 /// @notice WETH98 is a version of WETH9 upgraded for Solidity 0.8.x. contract WETH98 is IWETH { uint8 public constant decimals = 18; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /// @notice Pipes to deposit. receive() external payable { deposit(); } /// @notice Pipes to deposit. fallback() external payable { deposit(); } /// @inheritdoc IWETH function name() external view virtual override returns (string memory) { return "Wrapped Ether"; } /// @inheritdoc IWETH function symbol() external view virtual override returns (string memory) { return "WETH"; } /// @inheritdoc IWETH function deposit() public payable { balanceOf[msg.sender] += msg.value; emit Deposit(msg.sender, msg.value); } /// @inheritdoc IWETH function withdraw(uint256 wad) public virtual { require(balanceOf[msg.sender] >= wad); balanceOf[msg.sender] -= wad; payable(msg.sender).transfer(wad); emit Withdrawal(msg.sender, wad); } /// @inheritdoc IWETH function totalSupply() external view returns (uint256) { return address(this).balance; } /// @inheritdoc IWETH function approve(address guy, uint256 wad) external returns (bool) { allowance[msg.sender][guy] = wad; emit Approval(msg.sender, guy, wad); return true; } /// @inheritdoc IWETH function transfer(address dst, uint256 wad) external returns (bool) { return transferFrom(msg.sender, dst, wad); } /// @inheritdoc IWETH function transferFrom(address src, address dst, uint256 wad) public returns (bool) { require(balanceOf[src] >= wad); if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { require(allowance[src][msg.sender] >= wad); allowance[src][msg.sender] -= wad; } balanceOf[src] -= wad; balanceOf[dst] += wad; emit Transfer(src, dst, wad); return true; } } // SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { ISemver } from "src/universal/ISemver.sol"; import { Storage } from "src/libraries/Storage.sol"; /// @custom:audit none This contracts is not yet audited. /// @title SuperchainConfig /// @notice The SuperchainConfig contract is used to manage configuration of global superchain values. contract SuperchainConfig is Initializable, ISemver { /// @notice Enum representing different types of updates. /// @custom:value GUARDIAN Represents an update to the guardian. enum UpdateType { GUARDIAN } /// @notice Whether or not the Superchain is paused. bytes32 public constant PAUSED_SLOT = bytes32(uint256(keccak256("superchainConfig.paused")) - 1); /// @notice The address of the guardian, which can pause withdrawals from the System. /// It can only be modified by an upgrade. bytes32 public constant GUARDIAN_SLOT = bytes32(uint256(keccak256("superchainConfig.guardian")) - 1); /// @notice Emitted when the pause is triggered. /// @param identifier A string helping to identify provenance of the pause transaction. event Paused(string identifier); /// @notice Emitted when the pause is lifted. event Unpaused(); /// @notice Emitted when configuration is updated. /// @param updateType Type of update. /// @param data Encoded update data. event ConfigUpdate(UpdateType indexed updateType, bytes data); /// @notice Semantic version. /// @custom:semver 1.1.0 string public constant version = "1.1.0"; /// @notice Constructs the SuperchainConfig contract. constructor() { initialize({ _guardian: address(0), _paused: false }); } /// @notice Initializer. /// @param _guardian Address of the guardian, can pause the OptimismPortal. /// @param _paused Initial paused status. function initialize(address _guardian, bool _paused) public initializer { _setGuardian(_guardian); if (_paused) { _pause("Initializer paused"); } } /// @notice Getter for the guardian address. function guardian() public view returns (address guardian_) { guardian_ = Storage.getAddress(GUARDIAN_SLOT); } /// @notice Getter for the current paused status. function paused() public view returns (bool paused_) { paused_ = Storage.getBool(PAUSED_SLOT); } /// @notice Pauses withdrawals. /// @param _identifier (Optional) A string to identify provenance of the pause transaction. function pause(string memory _identifier) external { require(msg.sender == guardian(), "SuperchainConfig: only guardian can pause"); _pause(_identifier); } /// @notice Pauses withdrawals. /// @param _identifier (Optional) A string to identify provenance of the pause transaction. function _pause(string memory _identifier) internal { Storage.setBool(PAUSED_SLOT, true); emit Paused(_identifier); } /// @notice Unpauses withdrawals. function unpause() external { require(msg.sender == guardian(), "SuperchainConfig: only guardian can unpause"); Storage.setBool(PAUSED_SLOT, false); emit Unpaused(); } /// @notice Sets the guardian address. This is only callable during initialization, so an upgrade /// will be required to change the guardian. /// @param _guardian The new guardian address. function _setGuardian(address _guardian) internal { Storage.setAddress(GUARDIAN_SLOT, _guardian); emit ConfigUpdate(UpdateType.GUARDIAN, abi.encode(_guardian)); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.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) || (!AddressUpgradeable.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) (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 pragma solidity ^0.8.0; /// @title Storage /// @notice Storage handles reading and writing to arbitary storage locations library Storage { /// @notice Returns an address stored in an arbitrary storage slot. /// These storage slots decouple the storage layout from /// solc's automation. /// @param _slot The storage slot to retrieve the address from. function getAddress(bytes32 _slot) internal view returns (address addr_) { assembly { addr_ := sload(_slot) } } /// @notice Stores an address in an arbitrary storage slot, `_slot`. /// @param _slot The storage slot to store the address in. /// @param _address The protocol version to store /// @dev WARNING! This function must be used cautiously, as it allows for overwriting addresses /// in arbitrary storage slots. function setAddress(bytes32 _slot, address _address) internal { assembly { sstore(_slot, _address) } } /// @notice Returns a uint256 stored in an arbitrary storage slot. /// These storage slots decouple the storage layout from /// solc's automation. /// @param _slot The storage slot to retrieve the address from. function getUint(bytes32 _slot) internal view returns (uint256 value_) { assembly { value_ := sload(_slot) } } /// @notice Stores a value in an arbitrary storage slot, `_slot`. /// @param _slot The storage slot to store the address in. /// @param _value The protocol version to store /// @dev WARNING! This function must be used cautiously, as it allows for overwriting values /// in arbitrary storage slots. function setUint(bytes32 _slot, uint256 _value) internal { assembly { sstore(_slot, _value) } } /// @notice Returns a bytes32 stored in an arbitrary storage slot. /// These storage slots decouple the storage layout from /// solc's automation. /// @param _slot The storage slot to retrieve the address from. function getBytes32(bytes32 _slot) internal view returns (bytes32 value_) { assembly { value_ := sload(_slot) } } /// @notice Stores a bytes32 value in an arbitrary storage slot, `_slot`. /// @param _slot The storage slot to store the address in. /// @param _value The bytes32 value to store. /// @dev WARNING! This function must be used cautiously, as it allows for overwriting values /// in arbitrary storage slots. function setBytes32(bytes32 _slot, bytes32 _value) internal { assembly { sstore(_slot, _value) } } /// @notice Stores a bool value in an arbitrary storage slot, `_slot`. /// @param _slot The storage slot to store the bool in. /// @param _value The bool value to store /// @dev WARNING! This function must be used cautiously, as it allows for overwriting values /// in arbitrary storage slots. function setBool(bytes32 _slot, bool _value) internal { assembly { sstore(_slot, _value) } } /// @notice Returns a bool stored in an arbitrary storage slot. /// @param _slot The storage slot to retrieve the bool from. function getBool(bytes32 _slot) internal view returns (bool value_) { assembly { value_ := sload(_slot) } } } // 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 AddressUpgradeable { /** * @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 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/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); } } } }