ETH Price: $3,361.68 (-1.75%)

Contract

0x24Ae2dA0f361AA4BE46b48EB19C91e02c5e4f27E
 

Overview

ETH Balance

1.773 ETH

Eth Value

$5,960.25 (@ $3,361.68/ETH)

Multichain Info

1 address found via
Transaction Hash
Method
Block
From
To
Withdraw Queue212702022024-11-26 6:42:1121 hrs ago1732603331IN
MEV LST Protocol: mevETH Token
0 ETH0.00086798.23193723
Approve212685842024-11-26 1:17:1126 hrs ago1732583831IN
MEV LST Protocol: mevETH Token
0 ETH0.00036657.91269471
Withdraw Queue212427372024-11-22 10:40:594 days ago1732272059IN
MEV LST Protocol: mevETH Token
0 ETH0.0012367411.72899344
Withdraw Queue212369972024-11-21 15:27:475 days ago1732202867IN
MEV LST Protocol: mevETH Token
0 ETH0.0038386526.09752593
Withdraw Queue212166072024-11-18 19:10:358 days ago1731957035IN
MEV LST Protocol: mevETH Token
0 ETH0.0006756717.2528555
Withdraw Queue212166072024-11-18 19:10:358 days ago1731957035IN
MEV LST Protocol: mevETH Token
0 ETH0.0018189817.2528555
Approve212134982024-11-18 8:46:358 days ago1731919595IN
MEV LST Protocol: mevETH Token
0 ETH0.000469210.19883308
Withdraw Queue211984612024-11-16 6:27:4710 days ago1731738467IN
MEV LST Protocol: mevETH Token
0 ETH0.0016225515.38970965
Withdraw Queue211766842024-11-13 5:29:2313 days ago1731475763IN
MEV LST Protocol: mevETH Token
0 ETH0.0029832520.28365333
Approve211766342024-11-13 5:19:2313 days ago1731475163IN
MEV LST Protocol: mevETH Token
0 ETH0.0010745623.34491031
Withdraw Queue211612382024-11-11 1:45:2316 days ago1731289523IN
MEV LST Protocol: mevETH Token
0 ETH0.0016902416.0317962
Withdraw Queue211557782024-11-10 7:29:4716 days ago1731223787IN
MEV LST Protocol: mevETH Token
0 ETH0.0012292811.65961386
Approve211557722024-11-10 7:28:3516 days ago1731223715IN
MEV LST Protocol: mevETH Token
0 ETH0.000572612.43978982
Approve211523172024-11-09 19:54:3517 days ago1731182075IN
MEV LST Protocol: mevETH Token
0 ETH0.000410948.93717847
Withdraw Queue211503632024-11-09 13:21:3517 days ago1731158495IN
MEV LST Protocol: mevETH Token
0 ETH0.0011126410.55333524
Withdraw Queue211407022024-11-08 5:01:5918 days ago1731042119IN
MEV LST Protocol: mevETH Token
0 ETH0.000922158.74557096
Withdraw Queue211381472024-11-07 20:26:1119 days ago1731011171IN
MEV LST Protocol: mevETH Token
0 ETH0.002752726.1061415
Withdraw Queue211378392024-11-07 19:24:2319 days ago1731007463IN
MEV LST Protocol: mevETH Token
0 ETH0.0028042221.57281294
Approve211378292024-11-07 19:22:2319 days ago1731007343IN
MEV LST Protocol: mevETH Token
0 ETH0.0010231522.2221527
Approve211317052024-11-06 22:50:3520 days ago1730933435IN
MEV LST Protocol: mevETH Token
0 ETH0.0009503120.64554789
Transfer210858602024-10-31 13:16:4726 days ago1730380607IN
MEV LST Protocol: mevETH Token
0 ETH0.000650079.09955535
Withdraw Queue210642272024-10-28 12:47:2329 days ago1730119643IN
MEV LST Protocol: mevETH Token
0 ETH0.0012927813.94212097
Withdraw Queue210479522024-10-26 6:16:5931 days ago1729923419IN
MEV LST Protocol: mevETH Token
0 ETH0.000378163.58686217
Withdraw Queue210454412024-10-25 21:52:4732 days ago1729893167IN
MEV LST Protocol: mevETH Token
0 ETH0.000457444.3388359
Approve210429852024-10-25 13:39:3532 days ago1729863575IN
MEV LST Protocol: mevETH Token
0 ETH0.000186097.74284674
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
212708222024-11-26 8:46:5919 hrs ago1732610819
MEV LST Protocol: mevETH Token
1.773 ETH
212369972024-11-21 15:27:475 days ago1732202867
MEV LST Protocol: mevETH Token
0.05436784 ETH
212369882024-11-21 15:25:595 days ago1732202759
MEV LST Protocol: mevETH Token
6.47055845 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
9.65442258 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
50.04621432 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
0.55496955 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
12.50118185 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
0.35246536 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
0.5209149 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
31.54212221 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
124.31346591 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
19.98931698 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212200522024-11-19 6:41:597 days ago1731998519
MEV LST Protocol: mevETH Token
32 ETH
212132042024-11-18 7:47:238 days ago1731916043
MEV LST Protocol: mevETH Token
1.9251 ETH
212119082024-11-18 3:27:359 days ago1731900455
MEV LST Protocol: mevETH Token
1.9251 ETH
211766842024-11-13 5:29:2313 days ago1731475763
MEV LST Protocol: mevETH Token
0.49079875 ETH
211633252024-11-11 8:43:4715 days ago1731314627
MEV LST Protocol: mevETH Token
5.89420858 ETH
211633242024-11-11 8:43:3515 days ago1731314615
MEV LST Protocol: mevETH Token
1.12062011 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MevEth

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 512 runs

Other Settings:
paris EvmVersion
File 1 of 11 : MevEth.sol
/// SPDX-License-Identifier: SSPL-1.-0

pragma solidity ^0.8.19;

/*///////////// Mev Protocol ///////////////////////
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣷⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣷⣤⣀⠀⠀⠀⠀⠀⠉⠑⣶⣤⣄⣀⣠⣤⣶⣶⣿⣿⣿⣿⡇⠀⠀⠀
⠀⠀⠀⠀⣀⣴⣶⣿⣷⡄⠀⠀⠀⠀⢹⣿⣿⣿⣿⠏⠁⠀⢀⠄⠀⠀⠈⢀⠄⠀⢀⡖⠁⠀⢀⠀⠈⠻⣿⣿⣿⣿⡏⠀⠀⠀⠀
⠀⠀⢠⣾⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⢸⣿⣿⠏⠀⠀⢀⡴⠁⠀⠀⣠⠖⠁⢀⠞⠋⠀⢠⡇⢸⡄⠀⠀⠈⢻⣿⣿⠁⠀⠀⠀⠀
⠀⣠⣿⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⢸⡿⠁⠀⠀⢀⡞⠀⠀⢀⡴⠃⠀⣰⠋⠀⠀⣰⡿⠀⡜⢳⡀⠘⣦⠀⢿⡇⠀⠀⠀⠀⠀
⢠⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⢰⣿⠃⠀⢀⠆⡞⡄⠀⣠⡞⠁⣀⢾⠃⠀⣀⡜⢱⠇⣰⠁⠈⣷⠂⢸⡇⠸⣵⠀⠀⠀⠀⠀
⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⢠⣿⠇⠀⠀⡜⣸⡟⢀⣴⡏⢠⣾⠋⡎⢀⣼⠋⢀⡎⡰⠃⠀⠀⣿⣓⢒⡇⠀⣿⠀⠀⠀⠀⠀
⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠴⢻⣟⢀⣀⢀⣧⡇⢨⠟⢾⣔⡿⠃⢸⢀⠞⠃⢀⣾⡜⠁⠀⠀⠀⡏⠁⢠⠃⠀⢹⠀⠀⠀⠀⠀
⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⢸⣼⢸⣿⡟⢻⣿⠿⣶⣿⣿⣿⣶⣾⣏⣀⣠⣾⣿⠔⠒⠉⠉⢠⠁⡆⡸⠀⡈⣸⠀⠀⠀⠀⠀
⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⣸⣿⣸⣿⣇⢸⠃⡄⢻⠃⣾⣿⢋⠘⣿⣿⠏⣿⡟⣛⡛⢻⣿⢿⣶⣷⣿⣶⢃⣿⠀⠀⠀⠀⠀
⢸⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⣰⠃⣿⣿⣿⣿⠀⣸⣧⠈⣸⣿⠃⠘⠃⢹⣿⠀⣿⠃⠛⠛⣿⡇⢸⣿⡇⢸⣿⡿⣿⡀⠀⠀⠀⠀
⠀⠻⣿⣿⣿⣿⣦⡀⠀⢀⡔⣹⣼⡟⡟⣿⣿⣿⠛⠻⠶⠿⠷⣾⣿⣿⣬⣿⣠⣿⣀⣿⣿⣿⡇⠸⡿⠀⣾⡏⢠⣿⣇⠀⠀⠀⠀
⠀⠀⠙⢿⣿⣿⣿⣿⣷⡞⢠⣿⢿⡇⣿⡹⡝⢿⡷⣄⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠙⠛⠛⠻⠿⣶⣶⣾⣿⣇⣾⠉⢯⠃⠀⠀⠀
⠀⠀⠀⠀⠙⠿⣿⣿⣿⠇⢸⠇⠘⣇⠸⡇⣿⣮⣳⡀⠉⠂⠀⠀⣀⣤⡤⢤⣀⠀⠀⠀⠀⠀⢈⣿⠟⣠⣾⠿⣿⡆⡄⣧⡀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠙⠻⡘⠾⣄⠀⠘⢦⣿⠃⠹⣿⣿⣶⠤⠀⠀⣿⠋⠉⠻⣿⠁⠀⠠⣀⣤⣾⣵⣾⡿⠃⣾⠏⣿⣧⠋⡇⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣠⠖⠳⣄⡈⠃⠀⠼⠋⠙⢷⣞⢻⣿⣿⣀⡀⠈⠤⣀⠬⠟⠀⢀⣠⣶⠿⢛⡽⠋⣠⣾⣏⣠⡿⣃⣞⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣧⠀⠀⠀⠉⠛⠓⠢⠶⣶⡤⠺⡟⢺⣿⠿⣿⣶⣤⣀⣠⣴⣾⡿⠿⢵⠋⠙⠲⣏⡝⠁⠀⣹⢿⡣⣌⠒⠄⠀
⠀⠀⠀⠀⠀⠀⢸⠈⡄⠀⠇⠀⠀⡖⠁⢢⡞⠀⢰⠻⣆⡏⣇⠙⠻⣿⣿⣿⣿⠋⢀⡴⣪⢷⡀⠀⡘⠀⢀⠜⠁⢀⠟⢆⠑⢄⠀
⠀⠀⠀⠀⠀⠀⠘⡄⠱⠀⠸⡀⠄⠳⡀⠀⢳⡀⢰⠀⢸⢇⡟⠑⠦⢈⡉⠁⢼⢠⡏⣴⠟⢙⠇⠀⡇⢠⠃⢀⡴⠁⠀⠘⠀⠈⡆
⠀⠀⠀⠀⠀⠀⠀⠇⠀⠣⠀⡗⢣⡀⠘⢄⠀⢧⠀⢳⡟⠛⠙⣧⣧⣠⣄⣀⣠⢿⣶⠁⠀⠸⡀⠀⠓⠚⢴⣋⣠⠔⠀⠀⠀⠀⠁
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠧⡤⠙⢤⡈⣦⡼⠀⠀⠧⢶⠚⡇⠈⠁⠈⠃⠀⡰⢿⣄⠀⠀⠑⢤⣀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
///////////////////////////////////////////////////*/

import { Auth } from "./libraries/Auth.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { IERC4626 } from "./interfaces/IERC4626.sol";
import { WETH } from "solmate/tokens/WETH.sol";
import { MevEthErrors } from "./interfaces/Errors.sol";
import { IStakingModule } from "./interfaces/IStakingModule.sol";
import { IERC20Burnable } from "./interfaces/IERC20Burnable.sol";
import { ITinyMevEth } from "./interfaces/ITinyMevEth.sol";

/// @title MevEth
/// @author CommodityStream, Inc.
/// @dev Contract that allows deposit of ETH, for a Liquid Staking Receipt (LSR) in return.
/// @dev LSR is represented through an ERC4626 token and interface.
contract MevEth is Auth, ERC20, IERC4626, ITinyMevEth {
    using SafeTransferLib for WETH;
    using FixedPointMathLib for uint256;

    /*//////////////////////////////////////////////////////////////
                            Configuration Variables
    //////////////////////////////////////////////////////////////*/

    /// @notice Inidicates if staking is paused.
    bool public stakingPaused;
    /// @notice Indicates if contract is initialized.
    bool public initialized;
    /// @notice withdraw fee denominator
    uint16 internal constant feeDenominator = 10_000;
    /// @notice Timestamp when pending staking module update can be finalized.
    uint64 public pendingStakingModuleCommittedTimestamp;
    /// @notice Timestamp when pending mevEthShareVault update can be finalized.
    uint64 public pendingMevEthShareVaultCommittedTimestamp;
    /// @notice Time delay before staking module or share vault can be finalized.
    uint64 internal constant MODULE_UPDATE_TIME_DELAY = 7 days;
    /// @notice Max amount of ETH that can be deposited.
    uint128 internal constant MAX_DEPOSIT = type(uint128).max;
    /// @notice Min amount of ETH that can be deposited.
    uint128 public constant MIN_DEPOSIT = 0.01 ether;
    /// @notice Min amount of ETH that can be withdrawn via the queue.
    uint128 public MIN_WITHDRAWAL;
    /// @notice The address of the MevEthShareVault.
    address public mevEthShareVault;
    /// @notice The address of the pending MevEthShareVault when a new vault has been committed but not finalized.
    address public pendingMevEthShareVault;
    /// @notice The staking module used to stake Ether.
    IStakingModule public stakingModule;
    /// @notice The pending staking module when a new module has been committed but not finalized.
    IStakingModule public pendingStakingModule;
    /// @notice WETH Implementation used by MevEth.
    WETH public immutable WETH9;
    /// @notice Last rewards payment by block number
    uint256 internal lastRewards;
    /// @notice Struct used to accounting the ETH staked within MevEth.
    Fraction public fraction;
    /// @notice The percent out of 1000 crETH2 can be redeemed for as mevEth
    uint256 public constant CREAM_TO_MEV_ETH_PERCENT = 1130;
    /// @notice The canonical address of the crETH2 address
    address public constant creamToken = 0x49D72e3973900A195A155a46441F0C08179FdB64;
    /// @notice Sandwich protection mapping of last user deposits by block number
    mapping(address => uint256) lastDeposit;
    /// @notice Deposited validators mapping to prevent double deposits
    mapping(bytes => bool) depositedValidators;

    /// @notice Central struct used for share accounting + math.
    /// @custom:field elastic   Represents total amount of staked ether, including rewards accrued / slashed.
    /// @custom:field base      Represents claims to ownership of the staked ether.
    struct Fraction {
        uint128 elastic;
        uint128 base;
    }

    /*//////////////////////////////////////////////////////////////
                                Setup
    //////////////////////////////////////////////////////////////*/

    /// @notice Construction creates mevETH token, sets authority and weth address.
    /// @dev Pending staking module and committed timestamp will both be zero on deployment.
    /// @param authority Address of the controlling admin authority.
    /// @param weth Address of the WETH contract to use for deposits.
    constructor(address authority, address weth) Auth(authority) ERC20("Mev Liquid Staking Receipt", "mevETH", 18) {
        WETH9 = WETH(payable(weth));
        MIN_WITHDRAWAL = MIN_DEPOSIT;
    }

    /// @notice Calculate the needed Ether buffer required when creating a new validator.
    /// @return uint256 The required Ether buffer.
    function calculateNeededEtherBuffer() public view returns (uint256) {
        unchecked {
            return max(withdrawalAmountQueued, (stakingModule.VALIDATOR_DEPOSIT_SIZE() / 100) * 90);
        }
    }

    /*//////////////////////////////////////////////////////////////
                            Admin Control Panel
    //////////////////////////////////////////////////////////////*/

    /// @notice Event emitted when the MevEth is successfully initialized.
    event MevEthInitialized(address indexed mevEthShareVault, address indexed stakingModule);

    /// @notice Initializes the MevEth contract, setting the staking module and share vault addresses.
    /// @param initialShareVault The initial share vault set during initialization.
    /// @param initialStakingModule The initial staking module set during initialization.
    /// @dev This function can only be called once and is protected by the onlyAdmin modifier.
    function init(address initialShareVault, address initialStakingModule) external onlyAdmin {
        // Revert if the initial share vault or staking module is the zero address.
        if (initialShareVault == address(0)) {
            revert MevEthErrors.ZeroAddress();
        }

        if (initialStakingModule == address(0)) {
            revert MevEthErrors.ZeroAddress();
        }

        // Revert if the contract has already been initialized.
        if (initialized) {
            revert MevEthErrors.AlreadyInitialized();
        }

        // Update state variables and emit event to notify offchain listeners that the contract has been initialized.
        initialized = true;
        mevEthShareVault = initialShareVault;
        stakingModule = IStakingModule(initialStakingModule);
        emit MevEthInitialized(initialShareVault, initialStakingModule);
    }

    /// @notice Emitted when staking is paused.
    event StakingPaused();
    /// @notice Emitted when staking is unpaused.
    event StakingUnpaused();

    /// @notice Ensures that staking is not paused when invoking a specific function.
    /// @dev This check is used on the createValidator, deposit and mint functions.
    function _stakingUnpaused() internal view {
        if (stakingPaused) revert MevEthErrors.StakingPaused();
    }

    /// @notice Pauses staking on the MevEth contract.
    /// @dev This function is only callable by addresses with the admin role.
    function pauseStaking() external onlyAdmin {
        stakingPaused = true;
        emit StakingPaused();
    }

    /// @notice Unauses staking on the MevEth contract.
    /// @dev This function is only callable by addresses with the admin role.
    function unpauseStaking() external onlyAdmin {
        stakingPaused = false;
        emit StakingUnpaused();
    }

    /// @notice Event emitted when a new staking module is committed.
    ///   The MODULE_UPDATE_TIME_DELAY must elapse before the staking module update can be finalized.
    event StakingModuleUpdateCommitted(address indexed oldModule, address indexed pendingModule, uint64 indexed eligibleForFinalization);

    /// @notice Event emitted when a new staking module is finalized.
    event StakingModuleUpdateFinalized(address indexed oldModule, address indexed newModule);

    /// @notice Event emitted when a new pending module update is canceled.
    event StakingModuleUpdateCanceled(address indexed oldModule, address indexed pendingModule);

    /// @notice Starts the process to update the staking module.
    ///   To finalize the update, the MODULE_UPDATE_TIME_DELAY must elapse
    ///   and thefinalizeUpdateStakingModule function must be called.
    /// @param newModule The new staking module.
    /// @dev This function is only callable by addresses with the admin role.
    function commitUpdateStakingModule(IStakingModule newModule) external onlyAdmin {
        if (address(newModule) == address(0)) {
            revert MevEthErrors.InvalidPendingStakingModule();
        }

        pendingStakingModule = newModule;
        pendingStakingModuleCommittedTimestamp = uint64(block.timestamp);
        emit StakingModuleUpdateCommitted(address(stakingModule), address(newModule), uint64(block.timestamp + MODULE_UPDATE_TIME_DELAY));
    }

    /// @notice Finalizes the staking module update if a pending staking module exists.
    /// @dev This function is only callable by addresses with the admin role.
    function finalizeUpdateStakingModule() external onlyAdmin {
        // Revert if there is no pending staking module or if the the staking module finalization is premature.
        uint64 committedTimestamp = pendingStakingModuleCommittedTimestamp;
        if (address(pendingStakingModule) == address(0) || committedTimestamp == 0) {
            revert MevEthErrors.InvalidPendingStakingModule();
        }

        if (uint64(block.timestamp) < committedTimestamp + MODULE_UPDATE_TIME_DELAY) {
            revert MevEthErrors.PrematureStakingModuleUpdateFinalization();
        }

        // Emit an event to notify offchain listeners that the staking module has been finalized.
        emit StakingModuleUpdateFinalized(address(stakingModule), address(pendingStakingModule));

        // Update the staking module
        stakingModule = pendingStakingModule;

        // Set the pending staking module variables to zero.
        pendingStakingModule = IStakingModule(address(0));
        pendingStakingModuleCommittedTimestamp = 0;
    }

    /// @notice Cancels a pending staking module update.
    /// @dev This function is only callable by addresses with the admin role.
    function cancelUpdateStakingModule() external onlyAdmin {
        // Revert if there is no pending staking module.
        if (address(pendingStakingModule) == address(0) || pendingStakingModuleCommittedTimestamp == 0) {
            revert MevEthErrors.InvalidPendingStakingModule();
        }

        // Emit an event to notify offchain listeners that the staking module has been canceled.
        emit StakingModuleUpdateCanceled(address(stakingModule), address(pendingStakingModule));

        // Set the pending staking module variables to zero.
        pendingStakingModule = IStakingModule(address(0));
        pendingStakingModuleCommittedTimestamp = 0;
    }

    /// @notice Event emitted when a new share vault is committed. To finalize the update, the MODULE_UPDATE_TIME_DELAY must elapse and the
    ///         finalizeUpdateMevEthShareVault function must be called.
    event MevEthShareVaultUpdateCommitted(address indexed oldVault, address indexed pendingVault, uint64 indexed eligibleForFinalization);
    /// @notice Event emitted when a new share vault is finalized.
    event MevEthShareVaultUpdateFinalized(address indexed oldVault, address indexed newVault);
    /// @notice Event emitted when a new pending share vault update is canceled.
    event MevEthShareVaultUpdateCanceled(address indexed oldVault, address indexed newVault);

    /// @notice Starts the process to update the share vault. To finalize the update, the MODULE_UPDATE_TIME_DELAY must elapse and the
    ///         finalizeUpdateStakingModule function must be called.
    /// @param newMevEthShareVault The new share vault
    /// @dev This function is only callable by addresses with the admin role
    function commitUpdateMevEthShareVault(address newMevEthShareVault) external onlyAdmin {
        if (newMevEthShareVault == address(0)) {
            revert MevEthErrors.ZeroAddress();
        }
        pendingMevEthShareVault = newMevEthShareVault;
        pendingMevEthShareVaultCommittedTimestamp = uint64(block.timestamp);
        emit MevEthShareVaultUpdateCommitted(mevEthShareVault, newMevEthShareVault, uint64(block.timestamp + MODULE_UPDATE_TIME_DELAY));
    }

    /// @notice Finalizes the share vault update if a pending share vault exists.
    /// @dev This function is only callable by addresses with the admin role.
    function finalizeUpdateMevEthShareVault() external onlyAdmin {
        // Revert if there is no pending share vault or if the the share vault finalization is premature.
        uint64 committedTimestamp = pendingMevEthShareVaultCommittedTimestamp;
        if (pendingMevEthShareVault == address(0) || committedTimestamp == 0) {
            revert MevEthErrors.InvalidPendingMevEthShareVault();
        }

        if (uint64(block.timestamp) < committedTimestamp + MODULE_UPDATE_TIME_DELAY) {
            revert MevEthErrors.PrematureMevEthShareVaultUpdateFinalization();
        }

        /// @custom:: When finalizing the update to the MevEthShareVault, make sure to grant any remaining rewards from the existing share vault.
        // Emit an event to notify offchain listeners that the share vault has been finalized.
        emit MevEthShareVaultUpdateFinalized(mevEthShareVault, address(pendingMevEthShareVault));

        // Update the mev share vault
        mevEthShareVault = pendingMevEthShareVault;

        // Set the pending vault variables to zero
        pendingMevEthShareVault = address(0);
        pendingMevEthShareVaultCommittedTimestamp = 0;
    }

    /// @notice Cancels a pending share vault update.
    /// @dev This function is only callable by addresses with the admin role.
    function cancelUpdateMevEthShareVault() external onlyAdmin {
        // Revert if there is no pending share vault.
        if (pendingMevEthShareVault == address(0) || pendingMevEthShareVaultCommittedTimestamp == 0) {
            revert MevEthErrors.InvalidPendingMevEthShareVault();
        }
        // Emit an event to notify offchain listeners that the share vault has been canceled.
        emit MevEthShareVaultUpdateCanceled(mevEthShareVault, pendingMevEthShareVault);

        //Set the pending vault variables to zero
        pendingMevEthShareVault = address(0);
        pendingMevEthShareVaultCommittedTimestamp = 0;
    }

    /*//////////////////////////////////////////////////////////////
                            Registry For Validators
    //////////////////////////////////////////////////////////////*/

    /// @notice Event emitted when a new validator is created
    event ValidatorCreated(address indexed stakingModule, IStakingModule.ValidatorData newValidator);

    /// @notice This function passes through the needed Ether to the Staking module, and the assosiated credentials with it
    /// @param newData The data needed to create a new validator
    /// @dev This function is only callable by addresses with the operator role and if staking is unpaused
    function createValidator(IStakingModule.ValidatorData calldata newData, bytes32 latestDepositRoot) external onlyOperator {
        // check if staking is paused
        _stakingUnpaused();
        // check validator does not already exist
        if (depositedValidators[newData.pubkey]) revert MevEthErrors.AlreadyDeposited();
        // set validator deposited to true
        depositedValidators[newData.pubkey] = true;
        IStakingModule _stakingModule = stakingModule;
        // check withdrawal address is correct
        if (address(_stakingModule) != address(uint160(uint256(newData.withdrawal_credentials)))) revert MevEthErrors.IncorrectWithdrawalCredentials();
        // Determine how big deposit is for the validator
        uint256 depositSize = _stakingModule.VALIDATOR_DEPOSIT_SIZE();

        if (address(this).balance < depositSize + calculateNeededEtherBuffer()) {
            revert MevEthErrors.NotEnoughEth();
        }

        // Deposit the Ether into the staking contract
        _stakingModule.deposit{ value: depositSize }(newData, latestDepositRoot);

        emit ValidatorCreated(address(_stakingModule), newData);
    }

    /// @notice Event emitted when rewards are granted.
    event Rewards(address sender, uint256 amount);

    /// @notice Grants rewards updating the fraction.elastic.
    /// @dev called from validator rewards updates
    function grantRewards() external payable {
        if (!(msg.sender == address(stakingModule) || msg.sender == mevEthShareVault)) revert MevEthErrors.UnAuthorizedCaller();
        if (msg.value == 0) revert MevEthErrors.ZeroValue();

        fraction.elastic += uint128(msg.value);
        lastRewards = block.number;
        emit Rewards(msg.sender, msg.value);
    }

    /// @notice  Emitted when validator withdraw funds are received.
    event ValidatorWithdraw(address sender, uint256 amount);

    /// @notice Allows the MevEthShareVault or the staking module to withdraw validator funds from the contract.
    /// @dev Before updating the fraction, the withdrawal queue is processed, which pays out any pending withdrawals.
    /// @dev This function is only callable by the MevEthShareVault or the staking module.
    function grantValidatorWithdraw() external payable {
        // Check that the sender is the staking module or the MevEthShareVault.
        if (!(msg.sender == address(stakingModule) || msg.sender == mevEthShareVault)) revert MevEthErrors.InvalidSender();

        // Check that the value is not zero
        if (msg.value != 32 ether) {
            revert MevEthErrors.WrongWithdrawAmount();
        }

        // Emit an event to notify offchain listeners that a validator has withdrawn funds.
        emit ValidatorWithdraw(msg.sender, msg.value);

        // Register our exit with the staking module
        stakingModule.registerExit();
    }

    /*//////////////////////////////////////////////////////////////
                            WITHDRAWAL QUEUE
    //////////////////////////////////////////////////////////////*/

    /// @notice Struct representing a withdrawal ticket which is added to the withdrawal queue.
    /// @custom:field claimed               True if this receiver has received ticket funds.
    /// @custom:field receiver              The receiever of the ETH specified in the WithdrawalTicket.
    /// @custom:field amount                The amount of ETH to send to the receiver when the ticket is processed.
    /// @custom:field accumulatedAmount     Keep a running sum of all requested ETH
    struct WithdrawalTicket {
        bool claimed;
        address receiver;
        uint128 amount;
        uint128 accumulatedAmount;
    }

    /// @notice Event emitted when a withdrawal ticket is added to the queue.
    event WithdrawalQueueOpened(address indexed recipient, uint256 indexed withdrawalId, uint256 assets);
    event WithdrawalQueueClosed(address indexed recipient, uint256 indexed withdrawalId, uint256 assets);

    /// @notice The length of the withdrawal queue.
    uint256 public queueLength;

    /// @notice  mark the latest withdrawal request that was finalised
    uint256 public requestsFinalisedUntil;

    /// @notice Withdrawal amount queued
    uint256 public withdrawalAmountQueued;

    /// @notice The mapping representing the withdrawal queue.
    /// @dev The index in the queue is the key, and the value is the WithdrawalTicket.
    mapping(uint256 ticketNumber => WithdrawalTicket ticket) public withdrawalQueue;

    /// @notice Claim Finalised Withdrawal Ticket
    /// @param withdrawalId Unique ID of the withdrawal ticket
    function claim(uint256 withdrawalId) external {
        if (withdrawalId > requestsFinalisedUntil) revert MevEthErrors.NotFinalised();
        WithdrawalTicket storage ticket = withdrawalQueue[withdrawalId];
        if (ticket.claimed) revert MevEthErrors.AlreadyClaimed();
        withdrawalQueue[withdrawalId].claimed = true;
        withdrawalAmountQueued -= uint256(ticket.amount);
        emit WithdrawalQueueClosed(ticket.receiver, withdrawalId, uint256(ticket.amount));
        WETH9.deposit{ value: uint256(ticket.amount) }();
        WETH9.safeTransfer(ticket.receiver, uint256(ticket.amount));
    }

    /// @notice Processes the withdrawal queue, reserving any pending withdrawals with the contract's available balance.
    function processWithdrawalQueue(uint256 newRequestsFinalisedUntil) external onlyOperator {
        if (newRequestsFinalisedUntil > queueLength) revert MevEthErrors.IndexExceedsQueueLength();
        uint256 balance = address(this).balance;
        if (withdrawalAmountQueued >= balance) revert MevEthErrors.NotEnoughEth();
        uint256 available = balance - withdrawalAmountQueued;

        uint256 finalised = requestsFinalisedUntil;
        if (newRequestsFinalisedUntil < finalised) revert MevEthErrors.AlreadyFinalised();

        uint256 delta = uint256(withdrawalQueue[newRequestsFinalisedUntil].accumulatedAmount - withdrawalQueue[finalised].accumulatedAmount);
        if (available < delta) revert MevEthErrors.NotEnoughEth();

        requestsFinalisedUntil = newRequestsFinalisedUntil;
        withdrawalAmountQueued += delta;
    }

    function setMinWithdrawal(uint128 newMinimum) public onlyAdmin {
        MIN_WITHDRAWAL = newMinimum;
    }

    /*//////////////////////////////////////////////////////////////
                            ERC4626 Support
    //////////////////////////////////////////////////////////////*/
    /// @notice The underlying asset of the mevEth contract
    /// @return assetTokenAddress The address of the asset token
    function asset() external view returns (address assetTokenAddress) {
        assetTokenAddress = address(WETH9);
    }

    /// @notice The total amount of assets controlled by the mevEth contract
    /// @return totalManagedAssets The amount of eth controlled by the mevEth contract
    function totalAssets() external view returns (uint256 totalManagedAssets) {
        // Should return the total amount of Ether managed by the contract
        totalManagedAssets = uint256(fraction.elastic);
    }

    /// @notice Function to convert a specified amount of assets to shares based on the elastic and base.
    /// @param assets The amount of assets to convert to shares
    /// @return shares The value of the given assets in shares
    function convertToShares(uint256 assets) public view returns (uint256 shares) {
        // So if there are no shares, then they will mint 1:1 with assets
        // Otherwise, shares will mint proportional to the amount of assets
        if ((uint256(fraction.elastic) == 0) || (uint256(fraction.base) == 0)) {
            shares = assets;
        } else {
            shares = (assets * uint256(fraction.base)) / uint256(fraction.elastic);
        }
    }

    /// @notice Function to convert a specified amount of shares to assets based on the elastic and base.
    /// @param shares The amount of shares to convert to assets
    /// @return assets The value of the given shares in assets
    function convertToAssets(uint256 shares) public view returns (uint256 assets) {
        // So if there are no shares, then they will mint 1:1 with assets
        // Otherwise, shares will mint proportional to the amount of assets
        if (uint256(fraction.elastic) == 0 || uint256(fraction.base) == 0) {
            assets = shares;
        } else {
            assets = (shares * uint256(fraction.elastic)) / uint256(fraction.base);
        }
    }

    /// @notice Function to indicate the maximum deposit possible.
    /// @return maxAssets The maximum amount of assets that can be deposited.
    function maxDeposit(address) external view returns (uint256 maxAssets) {
        // If staking is paused, then no deposits can be made
        if (stakingPaused) {
            return 0;
        }
        // No practical limit on deposit for Ether
        maxAssets = uint256(MAX_DEPOSIT);
    }

    /// @notice Function to simulate the amount of shares that would be minted for a given deposit at the current ratio.
    /// @param assets The amount of assets that would be deposited
    /// @return shares The amount of shares that would be minted, *under ideal conditions* only
    function previewDeposit(uint256 assets) external view returns (uint256 shares) {
        return convertToShares(assets);
    }

    /// @notice internal deposit function to process Weth or Eth deposits
    /// @param receiver The address user whom should receive the mevEth out
    /// @param assets The amount of assets to deposit
    /// @param shares The amount of shares that should be minted
    function _deposit(address receiver, uint256 assets, uint256 shares) internal {
        // If the deposit is less than the minimum deposit, revert
        if (assets < MIN_DEPOSIT) revert MevEthErrors.DepositTooSmall();

        fraction.elastic += uint128(assets);
        fraction.base += uint128(shares);

        // Update last deposit block for the user recorded for sandwich protection
        lastDeposit[msg.sender] = block.number;
        lastDeposit[receiver] = block.number;

        if (msg.value == 0) {
            WETH9.safeTransferFrom(msg.sender, address(this), assets);
            WETH9.withdraw(assets);
        } else {
            if (msg.value != assets) revert MevEthErrors.WrongDepositAmount();
        }

        // Mint MevEth shares to the receiver
        _mint(receiver, shares);

        // Emit the deposit event to notify offchain listeners that a deposit has occured
        emit Deposit(msg.sender, receiver, assets, shares);
    }

    /// @notice Function to deposit assets into the mevEth contract
    /// @param assets The amount of WETH which should be deposited
    /// @param receiver The address user whom should receive the mevEth out
    /// @return shares The amount of shares minted
    function deposit(uint256 assets, address receiver) external payable returns (uint256 shares) {
        _stakingUnpaused();

        // Convert the assets to shares and update the fraction elastic and base
        shares = convertToShares(assets);

        // Deposit the assets
        _deposit(receiver, assets, shares);
    }

    /// @notice Function to indicate the maximum amount of shares that can be minted at the current ratio.
    /// @return maxShares The maximum amount of shares that can be minted
    function maxMint(address) external view returns (uint256 maxShares) {
        // If staking is paused, no shares can be minted
        if (stakingPaused) {
            return 0;
        }
        // No practical limit on mint for Ether
        return MAX_DEPOSIT;
    }

    /// @notice Function to simulate the amount of assets that would be required to mint a given amount of shares at the current ratio.
    /// @param shares The amount of shares that would be minted
    /// @return assets The amount of assets that would be required, *under ideal conditions* only
    function previewMint(uint256 shares) external view returns (uint256 assets) {
        return convertToAssets(shares);
    }

    /// @notice Function to mint shares of the mevEth contract
    /// @param shares The amount of shares that should be minted
    /// @param receiver The address user whom should receive the mevEth out
    /// @return assets The amount of assets deposited
    function mint(uint256 shares, address receiver) external payable returns (uint256 assets) {
        _stakingUnpaused();

        // Convert the shares to assets and update the fraction elastic and base
        assets = convertToAssets(shares);

        // Deposit the assets
        _deposit(receiver, assets, shares);
    }

    /// @notice Function to indicate the maximum amount of assets that can be withdrawn at the current state.
    /// @param owner The address in question of who would be withdrawing
    /// @return maxAssets The maximum amount of assets that can be withdrawn
    function maxWithdraw(address owner) external view returns (uint256 maxAssets) {
        // Withdrawal is either their maximum balance, or the internal buffer
        maxAssets = min(address(this).balance, convertToAssets(balanceOf[owner]));
    }

    /// @notice Function to simulate the amount of shares that would be allocated for a specified amount of assets.
    /// @param assets The amount of assets that would be withdrawn
    /// @return shares The amount of shares that would be burned, *under ideal conditions* only
    function previewWithdraw(uint256 assets) external view returns (uint256 shares) {
        // withdraw fee fixed at 0.01%
        uint256 fee = assets / uint256(feeDenominator);
        shares = convertToShares(assets + fee);
    }

    ///@notice Function to withdraw assets from the mevEth contract
    /// @param useQueue Flag whether to use the withdrawal queue
    /// @param receiver The address user whom should receive the mevEth out
    /// @param owner The address of the owner of the mevEth
    /// @param assets The amount of assets that should be withdrawn
    /// @param shares shares that will be burned
    function _withdraw(bool useQueue, address receiver, address owner, uint256 assets, uint256 shares) internal {
        // If withdraw is less than the minimum deposit / withdraw amount, revert
        if (assets < MIN_WITHDRAWAL) revert MevEthErrors.WithdrawTooSmall();
        // Sandwich protection
        uint256 blockNumber = block.number;

        if (((blockNumber - lastDeposit[msg.sender]) == 0 || (blockNumber - lastDeposit[owner] == 0)) && (blockNumber - lastRewards) == 0) {
            revert MevEthErrors.SandwichProtection();
        }

        _updateAllowance(owner, shares);

        // Update the elastic and base
        fraction.elastic -= uint128(assets);
        fraction.base -= uint128(shares);

        // Burn the shares and emit a withdraw event for offchain listeners to know that a withdraw has occured
        _burn(owner, shares);

        uint256 availableBalance = address(this).balance - withdrawalAmountQueued; // available balance will be adjusted
        uint256 amountToSend = assets;
        if (availableBalance < assets) {
            if (!useQueue) revert MevEthErrors.NotEnoughEth();
            // Available balance is sent, and the remainder must be withdrawn via the queue
            uint256 amountOwed = assets - availableBalance;
            ++queueLength;
            withdrawalQueue[queueLength] = WithdrawalTicket({
                claimed: false,
                receiver: receiver,
                amount: uint128(amountOwed),
                accumulatedAmount: withdrawalQueue[queueLength - 1].accumulatedAmount + uint128(amountOwed)
            });
            emit WithdrawalQueueOpened(receiver, queueLength, amountOwed);
            amountToSend = availableBalance;
        }
        if (amountToSend != 0) {
            // As with ERC4626, we log assets and shares as if there is no queue, and everything has been withdrawn
            // as this most closely resembles what is happened
            emit Withdraw(msg.sender, owner, receiver, assets, shares);

            WETH9.deposit{ value: amountToSend }();
            WETH9.safeTransfer(receiver, amountToSend);
        }
    }

    /// @dev internal function to update allowance for withdraws if necessary
    /// @param owner owner of tokens
    /// @param shares amount of shares to update
    function _updateAllowance(address owner, uint256 shares) internal {
        uint256 allowed = allowance[owner][msg.sender];
        if (owner != msg.sender) {
            if (allowed < shares) revert MevEthErrors.TransferExceedsAllowance();
            if (allowed != type(uint256).max) {
                unchecked {
                    allowance[owner][msg.sender] -= shares;
                }
            }
        }
    }

    /// @notice Withdraw assets if balance is available
    /// @param assets The amount of assets that should be withdrawn
    /// @param receiver The address user whom should receive the mevEth out
    /// @param owner The address of the owner of the mevEth
    /// @return shares The amount of shares burned
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares) {
        // withdraw fee fixed at 0.01%
        uint256 fee = assets / uint256(feeDenominator);
        // Convert the assets to shares and check if the owner has the allowance to withdraw the shares.
        shares = convertToShares(assets + fee);

        // Withdraw the assets from the MevEth contract
        _withdraw(false, receiver, owner, assets, shares);
    }

    /// @notice Withdraw assets or open queue ticket for claim depending on balance available
    /// @param assets The amount of assets that should be withdrawn
    /// @param receiver The address user whom should receive the mevEth out
    /// @param owner The address of the owner of the mevEth
    /// @return shares The amount of shares burned
    function withdrawQueue(uint256 assets, address receiver, address owner) external returns (uint256 shares) {
        // withdraw fee fixed at 0.01%
        uint256 fee = assets / uint256(feeDenominator);
        // last shareholder has no fee
        if ((fraction.elastic - assets) == 0) fee = 0;
        // Convert the assets to shares and check if the owner has the allowance to withdraw the shares.
        shares = convertToShares(assets + fee);

        // Withdraw the assets from the MevEth contract
        _withdraw(true, receiver, owner, assets, shares);
    }

    ///@notice Function to simulate the maximum amount of shares that can be redeemed by the owner.
    /// @param owner The address in question of who would be redeeming their shares
    /// @return maxShares The maximum amount of shares they could redeem
    function maxRedeem(address owner) external view returns (uint256 maxShares) {
        maxShares = min(convertToShares(address(this).balance), balanceOf[owner]);
    }

    /// @notice Function to simulate the amount of assets that would be withdrawn for a specified amount of shares.
    /// @param shares The amount of shares that would be burned
    /// @return assets The amount of assets that would be withdrawn, *under ideal conditions* only
    function previewRedeem(uint256 shares) external view returns (uint256 assets) {
        // withdraw fee fixed at 0.01%
        uint256 fee = shares / uint256(feeDenominator);
        assets = convertToAssets(shares - fee);
    }

    /// @notice Function to redeem shares from the mevEth contract
    /// @param shares The amount of shares that should be burned
    /// @param receiver The address user whom should receive the wETH out
    /// @param owner The address of the owner of the mevEth
    /// @return assets The amount of assets withdrawn
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets) {
        // withdraw fee fixed at 0.01%
        uint256 fee = shares / uint256(feeDenominator);
        // last shareholder has no fee
        if ((totalSupply - shares) == 0) fee = 0;
        // Convert the shares to assets and check if the owner has the allowance to withdraw the shares.
        assets = convertToAssets(shares - fee);

        // Withdraw the assets from the MevEth contract
        _withdraw(false, receiver, owner, assets, shares);
    }

    /*//////////////////////////////////////////////////////////////
                            Utility Functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Returns the largest of two numbers.
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /// @dev Returns the smallest of two numbers.
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /*//////////////////////////////////////////////////////////////
             Special CreamEth2 redeem (from initial migration)
     //////////////////////////////////////////////////////////////*/

    /// @notice Redeem Cream staked eth tokens for mevETH at a fixed ratio
    /// @param creamAmount The amount of Cream tokens to redeem
    function redeemCream(uint256 creamAmount) external {
        _stakingUnpaused();
        if (creamAmount == 0) revert MevEthErrors.ZeroValue();

        // Calculate the equivalent mevETH to be redeemed based on the ratio
        uint256 assets = creamAmount * uint256(CREAM_TO_MEV_ETH_PERCENT) / 1000;
        if (assets < MIN_DEPOSIT) revert MevEthErrors.DepositTooSmall();

        // Convert the shares to assets and update the fraction elastic and base
        uint256 shares = convertToShares(assets);

        fraction.elastic += uint128(assets);
        fraction.base += uint128(shares);

        // Burn CreamEth2 tokens
        IERC20Burnable(creamToken).burnFrom(msg.sender, creamAmount);

        // Mint the equivalent mevETH
        _mint(msg.sender, shares);

        // Emit event
        emit CreamRedeemed(msg.sender, creamAmount, shares);
    }

    // Event emitted when Cream tokens are redeemed for mevETH
    event CreamRedeemed(address indexed redeemer, uint256 creamAmount, uint256 mevEthAmount);

    /// @dev Only Weth withdraw is defined for the behaviour. Deposits should be directed to deposit / mint. Rewards via grantRewards and validator withdraws
    /// via grantValidatorWithdraw.
    receive() external payable {
        if (msg.sender != address(WETH9)) revert MevEthErrors.InvalidSender();
    }

    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        uint256 lastDepositFrom = lastDeposit[msg.sender];
        if (lastDepositFrom > lastDeposit[to]) {
            lastDeposit[to] = lastDepositFrom;
        }

        return super.transfer(to, amount);
    }

    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        uint256 lastDepositFrom = lastDeposit[from];
        if (lastDepositFrom > lastDeposit[to]) {
            lastDeposit[to] = lastDepositFrom;
        }

        return super.transferFrom(from, to, amount);
    }
}

File 2 of 11 : Auth.sol
/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:[email protected]'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

contract Auth {
    error Unauthorized();
    error AlreadySet();
    error NoAdmin();

    event AdminAdded(address indexed newAdmin);
    event AdminDeleted(address indexed oldAdmin);
    event OperatorAdded(address indexed newOperator);
    event OperatorDeleted(address indexed oldOperator);

    // admin counter (assuming 255 admins to be max)
    uint8 adminsCounter;

    // Keeps track of all operators
    mapping(address => bool) public operators;

    // Keeps track of all admins
    mapping(address => bool) public admins;

    /**
     * @notice This constructor sets the initialAdmin address as an admin and operator.
     * @dev The adminsCounter is incremented unchecked.
     */
    constructor(address initialAdmin) {
        admins[initialAdmin] = true;
        unchecked {
            ++adminsCounter;
        }
        operators[initialAdmin] = true;
    }

    /*//////////////////////////////////////////////////////////////
                           Access Control Modifiers
    //////////////////////////////////////////////////////////////*/

    modifier onlyAdmin() {
        if (!admins[msg.sender]) {
            revert Unauthorized();
        }
        _;
    }

    modifier onlyOperator() {
        if (!operators[msg.sender]) {
            revert Unauthorized();
        }
        _;
    }

    /*//////////////////////////////////////////////////////////////
                           Maintenance Functions
    //////////////////////////////////////////////////////////////*/
    /**
     * @notice addAdmin() function allows an admin to add a new admin to the contract.
     * @dev This function is only accessible to the existing admins and requires the address of the new admin.
     * If the new admin is already set, the function will revert. Otherwise, the adminsCounter will be incremented and the new admin will be added to the admins
     * mapping. An AdminAdded event will be emitted.
     */
    function addAdmin(address newAdmin) external onlyAdmin {
        if (admins[newAdmin]) revert AlreadySet();
        ++adminsCounter;
        admins[newAdmin] = true;
        emit AdminAdded(newAdmin);
    }

    /**
     * @notice Deletes an admin from the list of admins.
     * @dev Only admins can delete other admins. If the adminsCounter is 0, the transaction will revert.
     */
    function deleteAdmin(address oldAdmin) external onlyAdmin {
        if (!admins[oldAdmin]) revert AlreadySet();
        --adminsCounter;
        if (adminsCounter == 0) revert NoAdmin();
        admins[oldAdmin] = false;
        emit AdminDeleted(oldAdmin);
    }

    /**
     * @notice Adds a new operator to the list of operators
     * @dev Only the admin can add a new operator
     * @param newOperator The address of the new operator
     */
    function addOperator(address newOperator) external onlyAdmin {
        if (operators[newOperator]) revert AlreadySet();
        operators[newOperator] = true;
        emit OperatorAdded(newOperator);
    }

    function deleteOperator(address oldOperator) external onlyAdmin {
        if (!operators[oldOperator]) revert AlreadySet();
        operators[oldOperator] = false;
        emit OperatorDeleted(oldOperator);
    }
}

File 3 of 11 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(4, from) // Append the "from" argument.
            mstore(36, to) // Append the "to" argument.
            mstore(68, amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because that's the total length of our calldata (4 + 32 * 3)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 100, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(4, to) // Append the "to" argument.
            mstore(36, amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 68, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(4, to) // Append the "to" argument.
            mstore(36, amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                // Counterintuitively, this call() must be positioned after the or() in the
                // surrounding and() because and() evaluates its arguments from right to left.
                call(gas(), token, 0, 0, 68, 0, 32)
            )

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }

        require(success, "APPROVE_FAILED");
    }
}

File 4 of 11 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
        return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
    }

    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is < 0.5 we return zero. This happens when
            // x <= floor(log(0.5e18) * 1e18) ~ -42e18
            if (x <= -42139678854452767551) return 0;

            // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
            // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
            if (x >= 135305999368893231589) revert("EXP_OVERFLOW");

            // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5**18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // k is in the range [-61, 195].

            // Evaluate using a (6, 7)-term rational approximation.
            // p is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r should be in the range (0.09, 0.25) * 2**96.

            // We now need to multiply r by:
            // * the scale factor s = ~6.031367120.
            // * the 2**k factor from the range reduction.
            // * the 1e18 / 2**96 factor for base conversion.
            // We do this all at once, with an intermediate result in 2**213
            // basis, so the final right shift is always by a positive amount.
            r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
        }
    }

    function lnWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            require(x > 0, "UNDEFINED");

            // We want to convert x from 10**18 fixed point to 2**96 fixed point.
            // We do this by multiplying by 2**96 / 10**18. But since
            // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
            // and add ln(2**96 / 10**18) at the end.

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            int256 k = int256(log2(uint256(x))) - 96;
            x <<= uint256(159 - k);
            x = int256(uint256(x) >> 159);

            // Evaluate using a (8, 8)-term rational approximation.
            // p is made monic, we will multiply by a scale factor later.
            int256 p = x + 3273285459638523848632254066296;
            p = ((p * x) >> 96) + 24828157081833163892658089445524;
            p = ((p * x) >> 96) + 43456485725739037958740375743393;
            p = ((p * x) >> 96) - 11111509109440967052023855526967;
            p = ((p * x) >> 96) - 45023709667254063763336534515857;
            p = ((p * x) >> 96) - 14706773417378608786704636184526;
            p = p * x - (795164235651350426258249787498 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            // q is monic by convention.
            int256 q = x + 5573035233440673466300451813936;
            q = ((q * x) >> 96) + 71694874799317883764090561454958;
            q = ((q * x) >> 96) + 283447036172924575727196451306956;
            q = ((q * x) >> 96) + 401686690394027663651624208769553;
            q = ((q * x) >> 96) + 204048457590392012362485061816622;
            q = ((q * x) >> 96) + 31853899698501571402653359427138;
            q = ((q * x) >> 96) + 909429971244387300277376558375;
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial is known not to have zeros in the domain.
                // No scaling required because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r is in the range (0, 0.125) * 2**96

            // Finalization, we need to:
            // * multiply by the scale factor s = 5.549…
            // * add ln(2**96 / 10**18)
            // * add k * ln(2)
            // * multiply by 10**18 / 2**96 = 5**18 >> 78

            // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
            r *= 1677202110996718588342820967067443963516166;
            // add ln(2) * k * 5e18 * 2**192
            r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
            // add ln(2**96 / 10**18) * 5e18 * 2**192
            r += 600920179829731861736702779321621459595472258049074101567377883020018308;
            // base conversion: mul 2**18 / 2**192
            r >>= 174;
        }
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function log2(uint256 x) internal pure returns (uint256 r) {
        require(x > 0, "UNDEFINED");

        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            r := or(r, shl(2, lt(0xf, shr(r, x))))
            r := or(r, shl(1, lt(0x3, shr(r, x))))
            r := or(r, lt(0x1, shr(r, x)))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // z will equal 0 if y is 0, unlike in Solidity where it will revert.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // z will equal 0 if y is 0, unlike in Solidity where it will revert.
            z := div(x, y)
        }
    }

    /// @dev Will return 0 instead of reverting if y is zero.
    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            // Add 1 to x * y if x % y > 0.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

File 5 of 11 : ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 6 of 11 : IERC4626.sol
/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:[email protected]'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

// Also a superset of ERC20 but due to some solmate <-> OZ IERC20 nastiness this interface doesn't include it
interface IERC4626 {
    /// @return assetTokenAddress The address of the asset token
    function asset() external view returns (address assetTokenAddress);

    /// @return totalManagedAssets The amount of eth controlled by the vault
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /// @param assets The amount of assets to convert to shares
    /// @return shares The value of the given assets in shares
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /// @param shares The amount of shares to convert to assets
    /// @return assets The value of the given shares in assets
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /// @param reciever The address in question of who would be depositing, doesn't matter in this case
    /// @return maxAssets The maximum amount of assets that can be deposited
    function maxDeposit(address reciever) external view returns (uint256 maxAssets);

    /// @param assets The amount of assets that would be deposited
    /// @return shares The amount of shares that would be minted, *under ideal conditions* only
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /// @param assets The amount of WETH which should be deposited
    /// @param receiver The address user whom should recieve the mevEth out
    /// @return shares The amount of shares minted
    function deposit(uint256 assets, address receiver) external payable returns (uint256 shares);

    /// @param reciever The address in question of who would be minting, doesn't matter in this case
    /// @return maxShares The maximum amount of shares that can be minted
    function maxMint(address reciever) external view returns (uint256 maxShares);

    /// @param shares The amount of shares that would be minted
    /// @return assets The amount of assets that would be required, *under ideal conditions* only
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /// @param shares The amount of shares that should be minted
    /// @param receiver The address user whom should recieve the mevEth out
    /// @return assets The amount of assets deposited
    function mint(uint256 shares, address receiver) external payable returns (uint256 assets);

    /// @param owner The address in question of who would be withdrawing
    /// @return maxAssets The maximum amount of assets that can be withdrawn
    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    /// @param assets The amount of assets that would be withdrawn
    /// @return shares The amount of shares that would be burned, *under ideal conditions* only
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    /// @param assets The amount of assets that should be withdrawn
    /// @param receiver The address user whom should recieve the mevEth out
    /// @param owner The address of the owner of the mevEth
    /// @return shares The amount of shares burned
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    /// @param owner The address in question of who would be redeeming their shares
    /// @return maxShares The maximum amount of shares they could redeem
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /// @param shares The amount of shares that would be burned
    /// @return assets The amount of assets that would be withdrawn, *under ideal conditions* only
    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    /// @param shares The amount of shares that should be burned
    /// @param receiver The address user whom should recieve the wETH out
    /// @param owner The address of the owner of the mevEth
    /// @return assets The amount of assets withdrawn
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);

    /**
     * @dev Emitted when a deposit is made, either through mint or deposit
     */
    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

    /**
     * @dev Emitted when a withdrawal is made, either through redeem or withdraw
     */
    event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
}

File 7 of 11 : WETH.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {ERC20} from "./ERC20.sol";

import {SafeTransferLib} from "../utils/SafeTransferLib.sol";

/// @notice Minimalist and modern Wrapped Ether implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/WETH.sol)
/// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol)
contract WETH is ERC20("Wrapped Ether", "WETH", 18) {
    using SafeTransferLib for address;

    event Deposit(address indexed from, uint256 amount);

    event Withdrawal(address indexed to, uint256 amount);

    function deposit() public payable virtual {
        _mint(msg.sender, msg.value);

        emit Deposit(msg.sender, msg.value);
    }

    function withdraw(uint256 amount) public virtual {
        _burn(msg.sender, amount);

        emit Withdrawal(msg.sender, amount);

        msg.sender.safeTransferETH(amount);
    }

    receive() external payable virtual {
        deposit();
    }
}

File 8 of 11 : Errors.sol
/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:[email protected]'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

interface MevEthErrors {
    /// Errors
    error StakingPaused();
    error NotEnoughEth();
    error ZeroValue();
    error InvalidOperator();
    error DepositTooSmall();
    error InvalidSender();
    error PrematureStakingModuleUpdateFinalization();
    error PrematureMevEthShareVaultUpdateFinalization();
    error InvalidPendingStakingModule();
    error InvalidPendingMevEthShareVault();
    error TransferExceedsAllowance();
    error TransferFailed();
    error ZeroAddress();
    error AlreadyInitialized();
    error SendError();
    error FeesTooHigh();
    error WrongDepositAmount();
    error WrongWithdrawAmount();
    error UnAuthorizedCaller();
    error WithdrawTooSmall();
    error NotFinalised();
    error AlreadyClaimed();
    error AlreadyFinalised();
    error IndexExceedsQueueLength();
    error DepositWasFrontrun();
    error SandwichProtection();
    error NonZeroVaultBalance();
    error AlreadyDeposited();
    error IncorrectWithdrawalCredentials();
}

File 9 of 11 : IStakingModule.sol
/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:[email protected]'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

interface IStakingModule {
    /**
     * @dev Structure for passing information about the validator deposit data.
     * @param operator - address of the operator.
     * @param pubkey - BLS public key of the validator, generated by the operator.
     * @param withdrawal_credentials - withdrawal credentials used for generating the deposit data.
     * @param signature - BLS signature of the validator, generated by the operator.
     * @param deposit_data_root - hash tree root of the deposit data, generated by the operator.
     */
    struct ValidatorData {
        address operator;
        bytes pubkey;
        bytes32 withdrawal_credentials;
        bytes signature;
        bytes32 deposit_data_root; // more efficient to be calculated off-chain
    }

    /**
     * @dev Allows users to deposit funds into the contract.
     * @param data ValidatorData calldata containing the validator's public key, withdrawal credentials, and amount of tokens to be deposited.
     * @param latestDepositRoot bytes32 containing the latest deposit root.
     */
    function deposit(ValidatorData calldata data, bytes32 latestDepositRoot) external payable;

    function validators() external view returns (uint256);

    function mevEth() external view returns (address);

    /**
     * @notice VALIDATOR_DEPOSIT_SIZE()
     *
     * This function returns the size of the validator deposit.
     *
     * @dev This function is used to determine the size of the validator deposit. It is used to ensure that validators have the correct amount of funds in order
     * to participate in the network.
     */
    function VALIDATOR_DEPOSIT_SIZE() external view returns (uint256);

    // onlyAdmin Functions
    /**
     * @notice This function is used to pay rewards to the users.
     * @dev This function is used to pay rewards to the users. It takes in a uint256 rewards parameter which is the amount of rewards to be paid.
     */
    function payRewards(uint256 rewards) external;
    /**
     * @notice This function allows a validator to withdraw their rewards from the contract.
     * @dev This function is called by a validator to withdraw their rewards from the contract. It will transfer the rewards to the validator's address.
     */
    function payValidatorWithdraw() external;
    function recoverToken(address token, address recipient, uint256 amount) external;
    /**
     * @notice record() function is used to record the data in the smart contract.
     * @dev record() function takes no parameters and returns four uint128 values.
     */
    function record() external returns (uint128, uint128, uint128, uint128);
    /**
     * @notice registerExit() allows users to exit the system.
     * @dev registerExit() is a function that allows users to exit the system. It is triggered by an external call.
     */
    function registerExit() external;

    function batchMigrate(IStakingModule.ValidatorData[] calldata batchData) external;
}

File 10 of 11 : IERC20Burnable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IERC20Burnable {
    function burnFrom(address account, uint256 amount) external;
}

File 11 of 11 : ITinyMevEth.sol
/// SPDX-License-Identifier: SSPL-1.-0

/**
 * @custom:org.protocol='mevETH LST Protocol'
 * @custom:org.security='mailto:[email protected]'
 * @custom:org.vcs-commit=$GIT_COMMIT_SHA
 * @custom:org.vendor='CommodityStream, Inc'
 * @custom:org.schema-version="1.0"
 * @custom.org.encryption="manifoldfinance.com/.well-known/pgp-key.asc"
 * @custom:org.preferred-languages="en"
 */

pragma solidity ^0.8.19;

/// @title TinyMevEth
/// @notice smol interface for interacting with MevEth
interface ITinyMevEth {
    /**
     * @dev Function to grant rewards to other users.
     * @notice This function is payable and should be called with the amount of rewards to be granted.
     */
    function grantRewards() external payable;
    /**
     * @dev Function to allow a validator to withdraw funds from the contract.
     * @notice This function must be called with a validator address and a payable amount.
     */
    function grantValidatorWithdraw() external payable;
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "safe-contracts/=lib/safe-tools/lib/safe-contracts/contracts/",
    "safe-tools/=lib/safe-tools/src/",
    "properties/=lib/properties/contracts/",
    "solady/utils/=lib/solady/src/utils/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 512,
    "details": {
      "constantOptimizer": true,
      "yul": true,
      "yulDetails": {
        "stackAllocation": true
      }
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"authority","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"AlreadyDeposited","type":"error"},{"inputs":[],"name":"AlreadyFinalised","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadySet","type":"error"},{"inputs":[],"name":"DepositTooSmall","type":"error"},{"inputs":[],"name":"IncorrectWithdrawalCredentials","type":"error"},{"inputs":[],"name":"IndexExceedsQueueLength","type":"error"},{"inputs":[],"name":"InvalidPendingMevEthShareVault","type":"error"},{"inputs":[],"name":"InvalidPendingStakingModule","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"NoAdmin","type":"error"},{"inputs":[],"name":"NotEnoughEth","type":"error"},{"inputs":[],"name":"NotFinalised","type":"error"},{"inputs":[],"name":"PrematureMevEthShareVaultUpdateFinalization","type":"error"},{"inputs":[],"name":"PrematureStakingModuleUpdateFinalization","type":"error"},{"inputs":[],"name":"SandwichProtection","type":"error"},{"inputs":[],"name":"StakingPaused","type":"error"},{"inputs":[],"name":"TransferExceedsAllowance","type":"error"},{"inputs":[],"name":"UnAuthorizedCaller","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"WithdrawTooSmall","type":"error"},{"inputs":[],"name":"WrongDepositAmount","type":"error"},{"inputs":[],"name":"WrongWithdrawAmount","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"}],"name":"AdminDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"creamAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mevEthAmount","type":"uint256"}],"name":"CreamRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"mevEthShareVault","type":"address"},{"indexed":true,"internalType":"address","name":"stakingModule","type":"address"}],"name":"MevEthInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"newVault","type":"address"}],"name":"MevEthShareVaultUpdateCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"pendingVault","type":"address"},{"indexed":true,"internalType":"uint64","name":"eligibleForFinalization","type":"uint64"}],"name":"MevEthShareVaultUpdateCommitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"newVault","type":"address"}],"name":"MevEthShareVaultUpdateFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOperator","type":"address"}],"name":"OperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOperator","type":"address"}],"name":"OperatorDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Rewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModule","type":"address"},{"indexed":true,"internalType":"address","name":"pendingModule","type":"address"}],"name":"StakingModuleUpdateCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModule","type":"address"},{"indexed":true,"internalType":"address","name":"pendingModule","type":"address"},{"indexed":true,"internalType":"uint64","name":"eligibleForFinalization","type":"uint64"}],"name":"StakingModuleUpdateCommitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldModule","type":"address"},{"indexed":true,"internalType":"address","name":"newModule","type":"address"}],"name":"StakingModuleUpdateFinalized","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakingModule","type":"address"},{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes32","name":"withdrawal_credentials","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"deposit_data_root","type":"bytes32"}],"indexed":false,"internalType":"struct IStakingModule.ValidatorData","name":"newValidator","type":"tuple"}],"name":"ValidatorCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ValidatorWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"WithdrawalQueueClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"withdrawalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"WithdrawalQueueOpened","type":"event"},{"inputs":[],"name":"CREAM_TO_MEV_ETH_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEPOSIT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_WITHDRAWAL","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"contract WETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"addOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"assetTokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateNeededEtherBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelUpdateMevEthShareVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelUpdateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawalId","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMevEthShareVault","type":"address"}],"name":"commitUpdateMevEthShareVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStakingModule","name":"newModule","type":"address"}],"name":"commitUpdateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creamToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes32","name":"withdrawal_credentials","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"deposit_data_root","type":"bytes32"}],"internalType":"struct IStakingModule.ValidatorData","name":"newData","type":"tuple"},{"internalType":"bytes32","name":"latestDepositRoot","type":"bytes32"}],"name":"createValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldAdmin","type":"address"}],"name":"deleteAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldOperator","type":"address"}],"name":"deleteOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"finalizeUpdateMevEthShareVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalizeUpdateStakingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fraction","outputs":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"grantRewards","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"grantValidatorWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"initialShareVault","type":"address"},{"internalType":"address","name":"initialStakingModule","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mevEthShareVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingMevEthShareVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingMevEthShareVaultCommittedTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingStakingModule","outputs":[{"internalType":"contract IStakingModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingStakingModuleCommittedTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRequestsFinalisedUntil","type":"uint256"}],"name":"processWithdrawalQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"creamAmount","type":"uint256"}],"name":"redeemCream","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestsFinalisedUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"newMinimum","type":"uint128"}],"name":"setMinWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingModule","outputs":[{"internalType":"contract IStakingModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalManagedAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdrawQueue","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalAmountQueued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ticketNumber","type":"uint256"}],"name":"withdrawalQueue","outputs":[{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"accumulatedAmount","type":"uint128"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

610100604081815234620004f157808262003af5803803809162000024828562000528565b833981010312620004f1576200003a826200054c565b906200004a60208094016200054c565b908051936200005985620004f6565b601a85527f4d6576204c6971756964205374616b696e672052656365697074000000000000818601528151916200009083620004f6565b60068352650dacaec8aa8960d31b828401526001600160a01b039485166000908152600283528181208054600160ff199182168117909255825460ff808216840116908216178355818552838320805482168317905588516001600160401b03999192918a8211620004dd57600391806200010c845462000561565b92601f938481116200048a575b508990848311600114620004275788926200041b575b505060001982851b1c191690841b1782555b8751908b8211620004075781906004996200015d8b5462000561565b828111620003b2575b50899183116001146200034f57879262000343575b505060001982841b1c191690831b1787555b60126080524660a052845180928590835493620001aa8562000561565b948585528a8086019884831692836000146200032357505050600114620002e3575b5050620001dc9250038262000528565b519020938251938401947f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8652838501527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608501524660808501523060a085015260a0845260c084019784891090891117620002d057505085905251902060c0521660e052600a80546001600160801b031916662386f26fc1000017905561355690816200059f823960805181610adc015260a05181612a46015260c05181612a6d015260e051818181610d1b01528181610dfe01528181611ec00152818161304e0152818161336d015261351e0152f35b634e487b7160e01b825260419052602490fd5b89925087528187209087915b8583106200030a575050620001dc93508201013880620001cc565b80548388018501528694508a93909201918101620002ef565b925092509350620001dc959250168652151560051b8201013880620001cc565b0151905038806200017b565b8a88528988208694509190601f198416895b8c8282106200039b575050841162000382575b505050811b0187556200018d565b015160001983861b60f8161c1916905538808062000374565b838501518655899790950194938401930162000361565b909192508a88528988208380860160051c8201928c8710620003fd575b91869589929594930160051c01915b828110620003ee57505062000166565b8a8155869550889101620003de565b92508192620003cf565b634e487b7160e01b86526041600452602486fd5b0151905038806200012f565b8589528a89208794509190601f1984168a5b8d8282106200047357505084116200045a575b505050811b01825562000141565b015160001983871b60f8161c191690553880806200044c565b8385015186558a9790950194938401930162000439565b9091508488528988208480850160051c8201928c8610620004d3575b918891869594930160051c01915b828110620004c457505062000119565b8a8155859450889101620004b4565b92508192620004a6565b634e487b7160e01b85526041600452602485fd5b600080fd5b604081019081106001600160401b038211176200051257604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b038211908210176200051257604052565b51906001600160a01b0382168203620004f157565b90600182811c9216801562000593575b60208310146200057d57565b634e487b7160e01b600052602260045260246000fd5b91607f16916200057156fe60806040526004361015610023575b361561001957600080fd5b610021613514565b005b60003560e01c806301e1d1141461046f57806306fdde031461046a57806307a2d13a146103ac578063095ea7b3146104655780630a28a4771461046057806313e7c9d81461045b578063158ef93e1461045657806318160ddd1461045157806323b872dd1461044c57806327e1f7df146104475780632e92056d14610442578063313ce5671461043d578063342c00b3146104385780633644e51514610433578063379607f51461042e57806338d52e0f1461041f5780633cb5c58814610429578063402d267d1461037f578063429b62e5146104245780634aa4a4fc1461041f5780634cdad5061461041a578063504b82bf14610415578063558cb7f7146104105780636a4c66181461040b5780636ca6f0fe146104065780636e553f651461040157806370480275146103fc57806370a08231146103f757806372cf7751146103f25780637ecebe00146103ed57806382b9ebaa146103e85780638865cf50146103e35780638a1c2426146103de57806393f4bcde146103d957806394bf804d146103d457806395849aa4146103cf57806395d89b41146103ca5780639870d7fe146103c55780639ed89c91146103c0578063a9059cbb146103bb578063aa1cb376146103b6578063ab91c7b0146103b1578063b3d7f6b9146103ac578063b40992a1146103a7578063b460af94146103a2578063ba0876521461039d578063bbb781cc14610398578063bbbad84914610393578063bc74efe81461038e578063beb8db5614610389578063c1a7a81314610384578063c63d75b61461037f578063c6e6f5921461033e578063c822adda1461037a578063ce96cb7714610375578063d02aaa6514610370578063d15ca1661461036b578063d505accf14610366578063d8894bb514610361578063d905777e1461035c578063dd62ed3e14610357578063ddc2f1ab14610352578063df2d43d81461034d578063e1e158a514610348578063eb09200a14610343578063ef8b30f71461033e578063f09a401614610339578063f999c50614610334578063f9cc45f21461032f5763fe1832110361000e576128a3565b61287c565b612821565b612747565b612237565b612729565b612707565b6126d8565b61262a565b6125e0565b612573565b612544565b61234a565b612323565b6122fc565b6122b4565b612255565b610e4d565b6120ec565b611d5b565b611c20565b611b66565b611b43565b611af2565b611abd565b611a03565b61065f565b6119e5565b6118ed565b61182f565b611708565b611678565b6115d1565b6114d3565b61149b565b611443565b61125e565b61120c565b6111f1565b6111b3565b61118c565b61114e565b61108f565b611056565b611039565b61100e565b610f0a565b610ee3565b610eb6565b610dde565b610e73565b610e22565b610c2f565b610c14565b610b00565b610ac2565b610aa4565b610983565b6107dd565b6107bf565b610799565b610756565b610724565b610696565b61057a565b610484565b600091031261047f57565b600080fd5b3461047f57600036600319011261047f5760206001600160801b0360105416604051908152f35b90600182811c921680156104db575b60208310146104c557565b634e487b7160e01b600052602260045260246000fd5b91607f16916104ba565b67ffffffffffffffff81116104f957604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176104f957604052565b6020808252825181830181905290939260005b82811061056657505060409293506000838284010152601f8019910116010190565b818101860151848201604001528501610544565b3461047f5760008060031936011261065c57604051908060035461059d816104ab565b8085529160019180831690811561063257506001146105d7575b6105d3856105c78187038261050f565b60405191829182610531565b0390f35b9250600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061061a5750505081016020016105c7826105d36105b7565b805460208587018101919091529093019281016105ff565b8695506105d3969350602092506105c794915060ff191682840152151560051b82010192936105b7565b80fd5b3461047f57602036600319011261047f57602061067d600435612f60565b604051908152f35b6001600160a01b0381160361047f57565b3461047f57604036600319011261047f576004356106b381610685565b6001600160a01b0360243591336000526007602052826106ea826040600020906001600160a01b0316600052602052604060002090565b5560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b3461047f57602036600319011261047f57600435612710810481018091116107515761067d602091612f1e565b612c7b565b3461047f57602036600319011261047f576001600160a01b0360043561077b81610685565b166000526001602052602060ff604060002054166040519015158152f35b3461047f57600036600319011261047f57602060ff60095460081c166040519015158152f35b3461047f57600036600319011261047f576020600554604051908152f35b3461047f57606036600319011261047f576004356107fa81610685565b6024359061080782610685565b604435916001600160a01b03928383169261086160406000868152601160205281812054978616978882528282208054821161097b575b5050868152600760205220336001600160a01b0316600052602052604060002090565b54600181016108fd575b50906108d87fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef936108b26108ee946001600160a01b03166000526006602052604060002090565b6108bd848254612e49565b90556001600160a01b03166000526006602052604060002090565b8054820190556040519081529081906020820190565b0390a360405160018152602090f35b9190818303928311610751577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef936108b26108d8926108ee9561096f33610957846001600160a01b03166000526007602052604060002090565b906001600160a01b0316600052602052604060002090565b5593945050935061086b565b55388061083e565b3461047f57602036600319011261047f576004356109a081610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0381169081835260026020526109e16109dd6040852060ff90541690565b1590565b610a8157610a0b6109fb6109f6855460ff1690565b613546565b60ff1660ff196000541617600055565b60ff610a18845460ff1690565b1615610a6f57610a3e610a48916001600160a01b03166000526002602052604060002090565b805460ff19169055565b7f989ddfce057dad219e0ae16f691b121bb0e348f0d8ae0ad400b4d5ac8d616c8b8280a280f35b604051631f8c1dbd60e11b8152600490fd5b60405163a741a04560e01b8152600490fd5b6040516282b42960e81b8152600490fd5b3461047f57600036600319011261047f576020601554604051908152f35b3461047f57600036600319011261047f57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461047f57602036600319011261047f576004803533600052600160205260409160ff83600020541615610c07576013548211610bf9576015544780821015610be95790610b4d91612e49565b92601454808410610bdb57610b9e610baa91610b986001610b7f610b8782610b7f8b6000526016602052604060002090565b015460801c90565b936000526016602052604060002090565b90612edb565b6001600160801b031690565b809410610bce57610021610bc985610bc186601455565b601554612ca1565b601555565b5163f14a42b760e01b8152fd5b505163135bf97f60e11b8152fd5b845163f14a42b760e01b81528390fd5b82516312d29a5560e21b8152fd5b82516282b42960e81b8152fd5b3461047f57600036600319011261047f57602061067d612a41565b3461047f57602036600319011261047f576004356014548111610dcc57610c60816000526016602052604060002090565b805460ff16610dba57610c8d610c80836000526016602052604060002090565b805460ff19166001179055565b60018101610cb3610bc9610cab610b9e84546001600160801b031690565b601554612e49565b815460081c6001600160a01b0316610cd5610b9e83546001600160801b031690565b936040517f54a5cca61d01babb886db109822515b9fdff5360b38a042acfb13e47fab8b6fe6001600160a01b038094169180610d1689829190602083019252565b0390a37f00000000000000000000000000000000000000000000000000000000000000001691823b1561047f57600060049460405195868092630d0e30db60e41b8252875af1938415610db557610d88610d9692610b9e9261002197610d9c575b505460081c6001600160a01b031690565b92546001600160801b031690565b91612e56565b80610da9610daf926104e5565b80610474565b38610d77565b6129e9565b604051630c8d9eab60e31b8152600490fd5b6040516306e85c8160e21b8152600490fd5b3461047f57600036600319011261047f5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461047f57600036600319011261047f57602067ffffffffffffffff60095460101c16604051908152f35b3461047f57602036600319011261047f57610e69600435610685565b602061067d612fa2565b3461047f57602036600319011261047f576001600160a01b03600435610e9881610685565b166000526002602052602060ff604060002054166040519015158152f35b3461047f57602036600319011261047f57600435612710810481039081116107515761067d602091612f60565b3461047f57600036600319011261047f5760206001600160a01b03600d5416604051908152f35b600036600319011261047f57610f3a610f2e610f2e600d546001600160a01b031690565b6001600160a01b031690565b33148015610ff1575b15610fdf573415610fcd57610f91610f756001600160801b033416610f706010546001600160801b031690565b612e1f565b6001600160801b03166001600160801b03196010541617601055565b610f9a43600f55565b604080513381523460208201527fc083a1647e3ee591bf42b82564ffb4d16fdbb26068f0080da911c8d8300fd84a9190a1005b604051637c946ed760e01b8152600490fd5b60405163e3272bbb60e01b8152600490fd5b50611007610f2e600b546001600160a01b031690565b3314610f43565b3461047f57600036600319011261047f57602067ffffffffffffffff60095460501c16604051908152f35b3461047f57600036600319011261047f57602060405161046a8152f35b604036600319011261047f57602060043561067d60243561107681610685565b61107e612e01565b61108783612f1e565b928391612fbc565b3461047f57602036600319011261047f576004356110ac81610685565b600090338252600260205260ff60408320541615610a93576001600160a01b03811690818352600260205260ff604084205416610a815760ff83541660ff8114610751576111279161110e6001610c80930160ff1660ff196000541617600055565b6001600160a01b03166000526002602052604060002090565b7f44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e3398280a280f35b3461047f57602036600319011261047f576001600160a01b0360043561117381610685565b1660005260066020526020604060002054604051908152f35b3461047f57600036600319011261047f5760206001600160a01b03600e5416604051908152f35b3461047f57602036600319011261047f576001600160a01b036004356111d881610685565b1660005260086020526020604060002054604051908152f35b3461047f57600036600319011261047f57602061067d612c0e565b3461047f57602036600319011261047f576004356001600160801b03811680910361047f5733600052600260205260ff6040600020541615610a93576001600160801b0319600a541617600a55600080f35b3461047f576003196040368201811361047f57600480359167ffffffffffffffff831161047f5760a083830194843603011261047f57600093338552600160205260ff828620541615611436576112b3612e01565b602484016112d46112cd6112c78385612cc9565b90612cfc565b5460ff1690565b61142757610c806112c76112e89284612cc9565b6112fd610f2e600d546001600160a01b031690565b926001600160a01b036044818616960135168503611419578251635552aa6560e01b8152936020858381845afa948515610db55787956113e9575b504761134b611345612c0e565b87612ca1565b116113da57908187923b156113d65761137c91855196878094819363b778a3a760e01b835288602435918401612dd4565b03925af1918215610db5577f8a8ef37c52979cf8197dd24ed66c48fbd26d1b35ee1879d8c0c6be67b64fe756936113bd936113c3575b505191829182612df0565b0390a280f35b80610da96113d0926104e5565b386113b2565b8280fd5b50825163f14a42b760e01b8152fd5b61140b91955060203d8111611412575b611403818361050f565b810190612bdf565b9338611338565b503d6113f9565b82516371b37a2760e11b8152fd5b50505163d5a8211560e01b8152fd5b50516282b42960e81b8152fd5b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a935760ff19600954166009557fa75958c26fdcd449db08b7c754dcddd7a15b023665ee9dbd2ef62d8e1befaa4a8180a180f35b604036600319011261047f57602060243561067d6004356114bb83610685565b6114c3612e01565b6114cc81612f60565b8093612fbc565b3461047f57602036600319011261047f576004356114f081610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0380911680156115bf57600e805473ffffffffffffffffffffffffffffffffffffffff1916821790556009805469ffffffffffffffff000019164260101b69ffffffffffffffff00001617905567ffffffffffffffff9161157b610f2e600d546001600160a01b031690565b9261159561158842612c91565b67ffffffffffffffff1690565b1692167f39610571f23fd1a159473075de5b697023e7a31da8488147ecce3c05489885fa8480a480f35b60405163817ae11560e01b8152600490fd5b3461047f5760008060031936011261065c5760405190806004546115f4816104ab565b80855291600191808316908115610632575060011461161d576105d3856105c78187038261050f565b9250600483527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8284106116605750505081016020016105c7826105d36105b7565b80546020858701810191909152909301928101611645565b3461047f57602036600319011261047f5760043561169581610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0316808252600160205260ff604083205416610a8157808252600160205260408220600160ff198254161790557fac6fa858e9350a46cec16539926e0fde25b7629f84b5a72bffaae4df888ae86d8280a280f35b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a935760095460101c67ffffffffffffffff16600e546001600160a01b03166001600160a01b0391828216908115801561181d575b6115bf5761158861177191612cae565b67ffffffffffffffff42161061180b576117db9261179a610f2e600d546001600160a01b031690565b167f2d2c1ec12191e7f1a0c23a865475c7abecc7f26edb6c409defa31748b28a50138580a36001600160a01b03166001600160a01b0319600d541617600d55565b6117f06001600160a01b0319600e5416600e55565b61180869ffffffffffffffff00001960095416600955565b80f35b6040516310733cc760e31b8152600490fd5b5067ffffffffffffffff811615611761565b3461047f5760408060031936011261047f5760043561184d81610685565b602435600033815260116020526001600160a01b0384822054931692838252848220805482116118e5575b50503381526006602052838120908154838103908111610751578592558381526006602052208181540190557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8351806118d83394829190602083019252565b0390a35160018152602090f35b553880611878565b3461047f57602036600319011261047f5760043561190a81610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0380911680156119d357600c805473ffffffffffffffffffffffffffffffffffffffff1916821790556009805471ffffffffffffffff0000000000000000000019164260501b71ffffffffffffffff000000000000000000001617905567ffffffffffffffff91600b546001600160a01b0316926119a961158842612c91565b1692167fa8aa7c0b023219361c11e0a52a6ae2e6b7404aa61f5df0fc03d6cb8acafd66bf8480a480f35b60405163d92e233d60e01b8152600490fd5b3461047f57600036600319011261047f576020601354604051908152f35b3461047f57602036600319011261047f57600435611a2081610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0316808252600160205260ff60408320541615610a8157808252600160205260408220805460ff191690557f69df2c5ec2ea4d1fbe1e503524f593b356162ca710671263827f2e1992b95ae18280a280f35b606090600319011261047f5760043590602435611aad81610685565b90604435611aba81610685565b90565b3461047f57611acb36611a91565b90612710830483019081841161075157602093611aea61067d93612f1e565b93849261326d565b3461047f57611b0036611a91565b909161271081046005548083810311610751578214611b3b575b81039080821161075157602093611b3361067d93612f60565b93849161326d565b506000611b1a565b3461047f57600036600319011261047f57602060ff600954166040519015158152f35b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a93576001600160a01b0380611bab610f2e600e546001600160a01b031690565b169081158015611c09575b6115bf57611bcf610f2e600d546001600160a01b031690565b167f372791c0ff91275afe8e3b839b282b0dbb7bb639dbe7cd5896eedfec4c8ed8c68380a36117f06001600160a01b0319600e5416600e55565b5060095460101c67ffffffffffffffff1615611bb6565b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a935760095460501c67ffffffffffffffff16600c546001600160a01b03166001600160a01b03918282169081158015611d49575b611d3757611588611c8991612cae565b67ffffffffffffffff421610611d2557611cf092611caf600b546001600160a01b031690565b167f4dfa26cce610e1567cfad6de12824202e3394a8e66665914b3aeec46b60eca118580a36001600160a01b03166001600160a01b0319600b541617600b55565b611d056001600160a01b0319600c5416600c55565b61180871ffffffffffffffff000000000000000000001960095416600955565b604051631a5340df60e31b8152600490fd5b604051634326d9bf60e11b8152600490fd5b5067ffffffffffffffff811615611c79565b3461047f57611d6936611a91565b919061271082046001600160801b0390816010541680858103116107515784146120e4575b830180841161075157611da090612f1e565b92611db6610b9e600a546001600160801b031690565b81106120d25733600090815260116020526040902094611dd96000965443612e49565b1580156120a4575b80612091575b61207f57611df58582613475565b611e15610f75848416611e106010546001600160801b031690565b612edb565b611e45611e2a848716611e1060105460801c90565b6001600160801b036010549181199060801b16911617601055565b611e4f8582613417565b611e5c4760155490612e49565b928293838110611f37575b505082611e7a575b602085604051908152f35b60408051928352602083018690526001600160a01b03928584169284169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9190a47f00000000000000000000000000000000000000000000000000000000000000001691823b15611f3357604051630d0e30db60e41b8152948560048185875af1928315610db557602095611f1794611f20575b50612e56565b38808080611e6f565b80610da9611f2d926104e5565b38611f11565b8480fd5b91935061203c611f478385612e49565b91611f5b611f5660135461323e565b601355565b8216611fca601354611f7b611f8b84610f706001610b7f611f7b87612e3a565b6000526016602052604060002090565b611fba611f9661324d565b600081526001600160a01b038d166020820152956001600160801b03166040870152565b6001600160801b03166060850152565b906001908051151560ff845491168060ff19831617855574ffffffffffffffffffffffffffffffffffffffff00602084015160081b16916affffffffffffffffffffff60a81b16171783556001600160801b036040820151169060606001600160801b031991015160801b1617910155565b601354604051918252906001600160a01b038616907f09dfd37369506d687db24de2b5f681eb0050ccd07eaafa95d0252899471dd74090602090a3913880611e67565b604051637ef2d89b60e01b8152600490fd5b5061209e600f5443612e49565b15611de7565b506120cc6120c5826001600160a01b03166000526011602052604060002090565b5443612e49565b15611de1565b6040516393c76c6f60e01b8152600490fd5b506000611d8e565b3461047f57602036600319011261047f57600435612108612e01565b8015610fcd5761212261211a82612ef4565b6103e8900490565b662386f26fc10000811061222557612171611e2a61213f83612f1e565b92612163610f756001600160801b03809316610f706010546001600160801b031690565b8316610f7060105460801c90565b7349d72e3973900a195a155a46441f0c08179fdb6490813b1561047f5760405163079cc67960e41b815233600482015260248101849052916000908390604490829084905af1908115610db5577f08a1751668afae790ff5a3e76783eb5dc7c53adc0b248d4af119bf0edb29f97c9261220d92612212575b506121f48133613159565b6040805194855260208501919091523393918291820190565b0390a2005b80610da961221f926104e5565b386121e9565b604051636ba4a1c760e01b8152600490fd5b3461047f57602036600319011261047f57602061067d600435612f1e565b3461047f57602036600319011261047f57600435600052601660205260806040600020600181549101546001600160a01b036040519260ff81161515845260081c1660208301526001600160801b0381166040830152821c6060820152f35b3461047f57602036600319011261047f57602061067d6004356122d681610685565b6001600160a01b03479116600052600683526122f6604060002054612f60565b90613507565b3461047f57600036600319011261047f5760206001600160a01b03600c5416604051908152f35b3461047f57600036600319011261047f5760206001600160801b03600a5416604051908152f35b3461047f5760e036600319011261047f5760043561236781610685565b6024359061237482610685565b604435606435926084359360ff8516850361047f576124ac60209161239b4282101561299d565b61247361247f6123a9612a41565b92886123c8816001600160a01b03166000526008602052604060002090565b8054906001820190556124366040519384928c8c8c8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c985526001600160a01b038092166020860152166040840152606083015260808201520152565b039161244a601f199384810183528261050f565b5190206040519384918883019687909160429261190160f01b8352600283015260228201520190565b0390810183528261050f565b5190206040805191825260ff909716602082015260a4359681019690965260c43560608701526080860190565b856000968792838052039060015afa15610db5577f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259084519083612525826109576001600160a01b039561250c8782168015159081612538575b506129f5565b6001600160a01b03166000526007602052604060002090565b556040519384528116931691602090a380f35b9050888c161438612506565b3461047f57600036600319011261047f5760406010548151906001600160801b038116825260801c6020820152f35b3461047f57602036600319011261047f57602061067d60043561259581610685565b6001600160a01b036125a647612f1e565b91166000526006835260406000205490613507565b604090600319011261047f576004356125d381610685565b90602435611aba81610685565b3461047f5760206126216001600160a01b036125fb366125bb565b9116600052600783526040600020906001600160a01b0316600052602052604060002090565b54604051908152f35b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a93576001600160a01b038061266c600c546001600160a01b031690565b1690811580156126c1575b611d3757600b546001600160a01b0316167f84251438ec5abdb3e7f88a1f74e49cc798585f96428d53f9b3b85232b7f4bde38380a3611d056001600160a01b0319600c5416600c55565b5060095460501c67ffffffffffffffff1615612677565b3461047f57600036600319011261047f5760206040517349d72e3973900a195a155a46441f0c08179fdb648152f35b3461047f57600036600319011261047f576020604051662386f26fc100008152f35b3461047f57600036600319011261047f576020601454604051908152f35b3461047f57612755366125bb565b90600091338352600260205260ff60408420541615610a93576001600160a01b038083169182156119d357169182156119d35760095460081c60ff16612810576127c9906127ad61010061ff00196009541617600955565b6001600160a01b03166001600160a01b0319600b541617600b55565b6127e9826001600160a01b03166001600160a01b0319600d541617600d55565b7f64ba02ab01156808d0b519bed16cc382b3fc7fbe9bae6951b30fb08742b824a88380a380f35b60405162dc149f60e41b8152600490fd5b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a9357600160ff1960095416176009557f26d1807b479eaba249c1214b82e4b65bbb0cc73ee8a17901324b1ef1b5904e498180a180f35b3461047f57600036600319011261047f5760206001600160a01b03600b5416604051908152f35b60008060031936011261065c576128c5610f2e600d546001600160a01b031690565b6001600160a01b03811633148015612980575b1561296e576801bc16d674ec800000340361295c57604080513381523460208201528392917f12b964a3993d1598dd8a3b627a3b90b4bc6b7a8f4f8bb6afde02a30d178e28ef91a1803b15612959578190600460405180948193634ad8d34b60e01b83525af18015610db55761294c575080f35b80610da9611808926104e5565b50fd5b6040516328b8c64b60e11b8152600490fd5b604051636edaef2f60e11b8152600490fd5b50612996610f2e600b546001600160a01b031690565b33146128d8565b156129a457565b60405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606490fd5b6040513d6000823e3d90fd5b156129fc57565b60405162461bcd60e51b815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606490fd5b6000467f000000000000000000000000000000000000000000000000000000000000000003612a8f57507f000000000000000000000000000000000000000000000000000000000000000090565b604051600354919081612aa1846104ab565b80835260209485840194600191878382169182600014612bba575050600114612b61575b5050509181612adc612b5b93612b4d95038261050f565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b03601f19810183528261050f565b51902090565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b828410612ba55750505082010181612adc612b5b612ac5565b80548685018601528794909301928101612b8c565b60ff1916885293151560051b86019093019350849250612adc9150612b5b9050612ac5565b9081602091031261047f575190565b8115612bf8570490565b634e487b7160e01b600052601260045260246000fd5b601554600460206001600160a01b03600d541660405192838092635552aa6560e01b82525afa908115610db557605a91606491600091612c5d575b50040280821115612c58575090565b905090565b612c75915060203d811161141257611403818361050f565b38612c49565b634e487b7160e01b600052601160045260246000fd5b9062093a80820180921161075157565b9190820180921161075157565b9062093a8067ffffffffffffffff8093160191821161075157565b903590601e198136030182121561047f570180359067ffffffffffffffff821161047f5760200191813603831361047f57565b6020908260405193849283378101601281520301902090565b9035601e198236030181121561047f57016020813591019167ffffffffffffffff821161047f57813603831361047f57565b908060209392818452848401376000828201840152601f01601f1916010190565b906001600160a01b038235612d7c81610685565b168152608080612dcb612da6612d956020870187612d15565b60a0602088015260a0870191612d47565b60408601356040860152612dbd6060870187612d15565b908683036060880152612d47565b93013591015290565b929190612deb602091604086526040860190612d68565b930152565b906020611aba928181520190612d68565b60ff60095416612e0d57565b6040516326d1807b60e01b8152600490fd5b9190916001600160801b038080941691160191821161075157565b60001981019190821161075157565b9190820391821161075157565b9091602090604460405194600080958194829363a9059cbb60e01b84526004526024525af13d15601f3d116001845114161716906060528160405215612e995750565b62461bcd60e51b815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606490fd5b6001600160801b03918216908216039190821161075157565b9061046a9182810292818404149015171561075157565b8181029291811591840414171561075157565b6010546001600160801b0381169081158015612f55575b15612f3f57505090565b611aba92612f509160801c90612f0b565b612bee565b508060801c15612f35565b6010546001600160801b03811680158015612f97575b15612f8057505090565b612f8d90611aba93612f0b565b9060801c90612bee565b508160801c15612f76565b60ff60095416612fb7576001600160801b0390565b600090565b662386f26fc10000821061222557613001611e2a6001600160801b03612ff3610f75828716610f706010546001600160801b031690565b8516610f7060105460801c90565b4361301f336001600160a01b03166000526011602052604060002090565b554361303e826001600160a01b03166000526011602052604060002090565b5534613111576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169061307b833033856131b4565b813b1561047f57604051632e1a7d4d60e01b815260048101849052916000908390602490829084905af1908115610db5577fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7926001600160a01b03926130fe575b505b6130e88582613159565b60408051948552602085019590955216923392a3565b80610da961310b926104e5565b386130dc565b813403613147576001600160a01b037fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7916130de565b604051636ff0acf960e11b8152600490fd5b6005548281018091116107515760206001600160a01b036000937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9360055516938484526006825260408420818154019055604051908152a3565b9192606460209294604051956000958694859384936323b872dd60e01b85526004526024526044525af13d15601f3d1160018451141617169060605281604052156131fc5750565b62461bcd60e51b815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606490fd5b60001981146107515760010190565b604051906080820182811067ffffffffffffffff8211176104f957604052565b9290613284610b9e600a546001600160801b031690565b83106120d2576132aa6120c5336001600160a01b03166000526011602052604060002090565b1580156133f0575b806133dd575b61207f576132c68282613475565b6132fd611e2a6001600160801b036132ef610f75828816611e106010546001600160801b031690565b8416611e1060105460801c90565b6133078282613417565b826133154760155490612e49565b106133cb5782613326575b50505050565b6040805184815260208101939093526001600160a01b03928584169284169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9190a47f00000000000000000000000000000000000000000000000000000000000000001691823b1561047f57604051630d0e30db60e41b81529260008460048186855af1938415610db5576133c294611f205750612e56565b38808080613320565b60405163f14a42b760e01b8152600490fd5b506133ea600f5443612e49565b156132b8565b506134116120c5826001600160a01b03166000526011602052604060002090565b156132b2565b6001600160a01b03168060005260066020526040600020805490838203918211610751576000937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092558060055403600555604051908152a3565b6001600160a01b03168060005260076020526134a76040600020336001600160a01b0316600052602052604060002090565b543382036134b457505050565b8281106134f557196134c4575050565b60005260076020526134ed336040600020906001600160a01b0316600052602052604060002090565b908154039055565b604051630e81252160e01b8152600490fd5b9080821015612c58575090565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016330361296e57565b60ff1680156107515760001901905600000000000000000000000018f3e9ab3dcd396c2d3e6e598a9f77621ea50fc3000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x60806040526004361015610023575b361561001957600080fd5b610021613514565b005b60003560e01c806301e1d1141461046f57806306fdde031461046a57806307a2d13a146103ac578063095ea7b3146104655780630a28a4771461046057806313e7c9d81461045b578063158ef93e1461045657806318160ddd1461045157806323b872dd1461044c57806327e1f7df146104475780632e92056d14610442578063313ce5671461043d578063342c00b3146104385780633644e51514610433578063379607f51461042e57806338d52e0f1461041f5780633cb5c58814610429578063402d267d1461037f578063429b62e5146104245780634aa4a4fc1461041f5780634cdad5061461041a578063504b82bf14610415578063558cb7f7146104105780636a4c66181461040b5780636ca6f0fe146104065780636e553f651461040157806370480275146103fc57806370a08231146103f757806372cf7751146103f25780637ecebe00146103ed57806382b9ebaa146103e85780638865cf50146103e35780638a1c2426146103de57806393f4bcde146103d957806394bf804d146103d457806395849aa4146103cf57806395d89b41146103ca5780639870d7fe146103c55780639ed89c91146103c0578063a9059cbb146103bb578063aa1cb376146103b6578063ab91c7b0146103b1578063b3d7f6b9146103ac578063b40992a1146103a7578063b460af94146103a2578063ba0876521461039d578063bbb781cc14610398578063bbbad84914610393578063bc74efe81461038e578063beb8db5614610389578063c1a7a81314610384578063c63d75b61461037f578063c6e6f5921461033e578063c822adda1461037a578063ce96cb7714610375578063d02aaa6514610370578063d15ca1661461036b578063d505accf14610366578063d8894bb514610361578063d905777e1461035c578063dd62ed3e14610357578063ddc2f1ab14610352578063df2d43d81461034d578063e1e158a514610348578063eb09200a14610343578063ef8b30f71461033e578063f09a401614610339578063f999c50614610334578063f9cc45f21461032f5763fe1832110361000e576128a3565b61287c565b612821565b612747565b612237565b612729565b612707565b6126d8565b61262a565b6125e0565b612573565b612544565b61234a565b612323565b6122fc565b6122b4565b612255565b610e4d565b6120ec565b611d5b565b611c20565b611b66565b611b43565b611af2565b611abd565b611a03565b61065f565b6119e5565b6118ed565b61182f565b611708565b611678565b6115d1565b6114d3565b61149b565b611443565b61125e565b61120c565b6111f1565b6111b3565b61118c565b61114e565b61108f565b611056565b611039565b61100e565b610f0a565b610ee3565b610eb6565b610dde565b610e73565b610e22565b610c2f565b610c14565b610b00565b610ac2565b610aa4565b610983565b6107dd565b6107bf565b610799565b610756565b610724565b610696565b61057a565b610484565b600091031261047f57565b600080fd5b3461047f57600036600319011261047f5760206001600160801b0360105416604051908152f35b90600182811c921680156104db575b60208310146104c557565b634e487b7160e01b600052602260045260246000fd5b91607f16916104ba565b67ffffffffffffffff81116104f957604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176104f957604052565b6020808252825181830181905290939260005b82811061056657505060409293506000838284010152601f8019910116010190565b818101860151848201604001528501610544565b3461047f5760008060031936011261065c57604051908060035461059d816104ab565b8085529160019180831690811561063257506001146105d7575b6105d3856105c78187038261050f565b60405191829182610531565b0390f35b9250600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061061a5750505081016020016105c7826105d36105b7565b805460208587018101919091529093019281016105ff565b8695506105d3969350602092506105c794915060ff191682840152151560051b82010192936105b7565b80fd5b3461047f57602036600319011261047f57602061067d600435612f60565b604051908152f35b6001600160a01b0381160361047f57565b3461047f57604036600319011261047f576004356106b381610685565b6001600160a01b0360243591336000526007602052826106ea826040600020906001600160a01b0316600052602052604060002090565b5560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b3461047f57602036600319011261047f57600435612710810481018091116107515761067d602091612f1e565b612c7b565b3461047f57602036600319011261047f576001600160a01b0360043561077b81610685565b166000526001602052602060ff604060002054166040519015158152f35b3461047f57600036600319011261047f57602060ff60095460081c166040519015158152f35b3461047f57600036600319011261047f576020600554604051908152f35b3461047f57606036600319011261047f576004356107fa81610685565b6024359061080782610685565b604435916001600160a01b03928383169261086160406000868152601160205281812054978616978882528282208054821161097b575b5050868152600760205220336001600160a01b0316600052602052604060002090565b54600181016108fd575b50906108d87fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef936108b26108ee946001600160a01b03166000526006602052604060002090565b6108bd848254612e49565b90556001600160a01b03166000526006602052604060002090565b8054820190556040519081529081906020820190565b0390a360405160018152602090f35b9190818303928311610751577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef936108b26108d8926108ee9561096f33610957846001600160a01b03166000526007602052604060002090565b906001600160a01b0316600052602052604060002090565b5593945050935061086b565b55388061083e565b3461047f57602036600319011261047f576004356109a081610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0381169081835260026020526109e16109dd6040852060ff90541690565b1590565b610a8157610a0b6109fb6109f6855460ff1690565b613546565b60ff1660ff196000541617600055565b60ff610a18845460ff1690565b1615610a6f57610a3e610a48916001600160a01b03166000526002602052604060002090565b805460ff19169055565b7f989ddfce057dad219e0ae16f691b121bb0e348f0d8ae0ad400b4d5ac8d616c8b8280a280f35b604051631f8c1dbd60e11b8152600490fd5b60405163a741a04560e01b8152600490fd5b6040516282b42960e81b8152600490fd5b3461047f57600036600319011261047f576020601554604051908152f35b3461047f57600036600319011261047f57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b3461047f57602036600319011261047f576004803533600052600160205260409160ff83600020541615610c07576013548211610bf9576015544780821015610be95790610b4d91612e49565b92601454808410610bdb57610b9e610baa91610b986001610b7f610b8782610b7f8b6000526016602052604060002090565b015460801c90565b936000526016602052604060002090565b90612edb565b6001600160801b031690565b809410610bce57610021610bc985610bc186601455565b601554612ca1565b601555565b5163f14a42b760e01b8152fd5b505163135bf97f60e11b8152fd5b845163f14a42b760e01b81528390fd5b82516312d29a5560e21b8152fd5b82516282b42960e81b8152fd5b3461047f57600036600319011261047f57602061067d612a41565b3461047f57602036600319011261047f576004356014548111610dcc57610c60816000526016602052604060002090565b805460ff16610dba57610c8d610c80836000526016602052604060002090565b805460ff19166001179055565b60018101610cb3610bc9610cab610b9e84546001600160801b031690565b601554612e49565b815460081c6001600160a01b0316610cd5610b9e83546001600160801b031690565b936040517f54a5cca61d01babb886db109822515b9fdff5360b38a042acfb13e47fab8b6fe6001600160a01b038094169180610d1689829190602083019252565b0390a37f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691823b1561047f57600060049460405195868092630d0e30db60e41b8252875af1938415610db557610d88610d9692610b9e9261002197610d9c575b505460081c6001600160a01b031690565b92546001600160801b031690565b91612e56565b80610da9610daf926104e5565b80610474565b38610d77565b6129e9565b604051630c8d9eab60e31b8152600490fd5b6040516306e85c8160e21b8152600490fd5b3461047f57600036600319011261047f5760206040516001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152f35b3461047f57600036600319011261047f57602067ffffffffffffffff60095460101c16604051908152f35b3461047f57602036600319011261047f57610e69600435610685565b602061067d612fa2565b3461047f57602036600319011261047f576001600160a01b03600435610e9881610685565b166000526002602052602060ff604060002054166040519015158152f35b3461047f57602036600319011261047f57600435612710810481039081116107515761067d602091612f60565b3461047f57600036600319011261047f5760206001600160a01b03600d5416604051908152f35b600036600319011261047f57610f3a610f2e610f2e600d546001600160a01b031690565b6001600160a01b031690565b33148015610ff1575b15610fdf573415610fcd57610f91610f756001600160801b033416610f706010546001600160801b031690565b612e1f565b6001600160801b03166001600160801b03196010541617601055565b610f9a43600f55565b604080513381523460208201527fc083a1647e3ee591bf42b82564ffb4d16fdbb26068f0080da911c8d8300fd84a9190a1005b604051637c946ed760e01b8152600490fd5b60405163e3272bbb60e01b8152600490fd5b50611007610f2e600b546001600160a01b031690565b3314610f43565b3461047f57600036600319011261047f57602067ffffffffffffffff60095460501c16604051908152f35b3461047f57600036600319011261047f57602060405161046a8152f35b604036600319011261047f57602060043561067d60243561107681610685565b61107e612e01565b61108783612f1e565b928391612fbc565b3461047f57602036600319011261047f576004356110ac81610685565b600090338252600260205260ff60408320541615610a93576001600160a01b03811690818352600260205260ff604084205416610a815760ff83541660ff8114610751576111279161110e6001610c80930160ff1660ff196000541617600055565b6001600160a01b03166000526002602052604060002090565b7f44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e3398280a280f35b3461047f57602036600319011261047f576001600160a01b0360043561117381610685565b1660005260066020526020604060002054604051908152f35b3461047f57600036600319011261047f5760206001600160a01b03600e5416604051908152f35b3461047f57602036600319011261047f576001600160a01b036004356111d881610685565b1660005260086020526020604060002054604051908152f35b3461047f57600036600319011261047f57602061067d612c0e565b3461047f57602036600319011261047f576004356001600160801b03811680910361047f5733600052600260205260ff6040600020541615610a93576001600160801b0319600a541617600a55600080f35b3461047f576003196040368201811361047f57600480359167ffffffffffffffff831161047f5760a083830194843603011261047f57600093338552600160205260ff828620541615611436576112b3612e01565b602484016112d46112cd6112c78385612cc9565b90612cfc565b5460ff1690565b61142757610c806112c76112e89284612cc9565b6112fd610f2e600d546001600160a01b031690565b926001600160a01b036044818616960135168503611419578251635552aa6560e01b8152936020858381845afa948515610db55787956113e9575b504761134b611345612c0e565b87612ca1565b116113da57908187923b156113d65761137c91855196878094819363b778a3a760e01b835288602435918401612dd4565b03925af1918215610db5577f8a8ef37c52979cf8197dd24ed66c48fbd26d1b35ee1879d8c0c6be67b64fe756936113bd936113c3575b505191829182612df0565b0390a280f35b80610da96113d0926104e5565b386113b2565b8280fd5b50825163f14a42b760e01b8152fd5b61140b91955060203d8111611412575b611403818361050f565b810190612bdf565b9338611338565b503d6113f9565b82516371b37a2760e11b8152fd5b50505163d5a8211560e01b8152fd5b50516282b42960e81b8152fd5b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a935760ff19600954166009557fa75958c26fdcd449db08b7c754dcddd7a15b023665ee9dbd2ef62d8e1befaa4a8180a180f35b604036600319011261047f57602060243561067d6004356114bb83610685565b6114c3612e01565b6114cc81612f60565b8093612fbc565b3461047f57602036600319011261047f576004356114f081610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0380911680156115bf57600e805473ffffffffffffffffffffffffffffffffffffffff1916821790556009805469ffffffffffffffff000019164260101b69ffffffffffffffff00001617905567ffffffffffffffff9161157b610f2e600d546001600160a01b031690565b9261159561158842612c91565b67ffffffffffffffff1690565b1692167f39610571f23fd1a159473075de5b697023e7a31da8488147ecce3c05489885fa8480a480f35b60405163817ae11560e01b8152600490fd5b3461047f5760008060031936011261065c5760405190806004546115f4816104ab565b80855291600191808316908115610632575060011461161d576105d3856105c78187038261050f565b9250600483527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b8284106116605750505081016020016105c7826105d36105b7565b80546020858701810191909152909301928101611645565b3461047f57602036600319011261047f5760043561169581610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0316808252600160205260ff604083205416610a8157808252600160205260408220600160ff198254161790557fac6fa858e9350a46cec16539926e0fde25b7629f84b5a72bffaae4df888ae86d8280a280f35b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a935760095460101c67ffffffffffffffff16600e546001600160a01b03166001600160a01b0391828216908115801561181d575b6115bf5761158861177191612cae565b67ffffffffffffffff42161061180b576117db9261179a610f2e600d546001600160a01b031690565b167f2d2c1ec12191e7f1a0c23a865475c7abecc7f26edb6c409defa31748b28a50138580a36001600160a01b03166001600160a01b0319600d541617600d55565b6117f06001600160a01b0319600e5416600e55565b61180869ffffffffffffffff00001960095416600955565b80f35b6040516310733cc760e31b8152600490fd5b5067ffffffffffffffff811615611761565b3461047f5760408060031936011261047f5760043561184d81610685565b602435600033815260116020526001600160a01b0384822054931692838252848220805482116118e5575b50503381526006602052838120908154838103908111610751578592558381526006602052208181540190557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8351806118d83394829190602083019252565b0390a35160018152602090f35b553880611878565b3461047f57602036600319011261047f5760043561190a81610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0380911680156119d357600c805473ffffffffffffffffffffffffffffffffffffffff1916821790556009805471ffffffffffffffff0000000000000000000019164260501b71ffffffffffffffff000000000000000000001617905567ffffffffffffffff91600b546001600160a01b0316926119a961158842612c91565b1692167fa8aa7c0b023219361c11e0a52a6ae2e6b7404aa61f5df0fc03d6cb8acafd66bf8480a480f35b60405163d92e233d60e01b8152600490fd5b3461047f57600036600319011261047f576020601354604051908152f35b3461047f57602036600319011261047f57600435611a2081610685565b600090338252600260205260ff60408320541615610a93576001600160a01b0316808252600160205260ff60408320541615610a8157808252600160205260408220805460ff191690557f69df2c5ec2ea4d1fbe1e503524f593b356162ca710671263827f2e1992b95ae18280a280f35b606090600319011261047f5760043590602435611aad81610685565b90604435611aba81610685565b90565b3461047f57611acb36611a91565b90612710830483019081841161075157602093611aea61067d93612f1e565b93849261326d565b3461047f57611b0036611a91565b909161271081046005548083810311610751578214611b3b575b81039080821161075157602093611b3361067d93612f60565b93849161326d565b506000611b1a565b3461047f57600036600319011261047f57602060ff600954166040519015158152f35b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a93576001600160a01b0380611bab610f2e600e546001600160a01b031690565b169081158015611c09575b6115bf57611bcf610f2e600d546001600160a01b031690565b167f372791c0ff91275afe8e3b839b282b0dbb7bb639dbe7cd5896eedfec4c8ed8c68380a36117f06001600160a01b0319600e5416600e55565b5060095460101c67ffffffffffffffff1615611bb6565b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a935760095460501c67ffffffffffffffff16600c546001600160a01b03166001600160a01b03918282169081158015611d49575b611d3757611588611c8991612cae565b67ffffffffffffffff421610611d2557611cf092611caf600b546001600160a01b031690565b167f4dfa26cce610e1567cfad6de12824202e3394a8e66665914b3aeec46b60eca118580a36001600160a01b03166001600160a01b0319600b541617600b55565b611d056001600160a01b0319600c5416600c55565b61180871ffffffffffffffff000000000000000000001960095416600955565b604051631a5340df60e31b8152600490fd5b604051634326d9bf60e11b8152600490fd5b5067ffffffffffffffff811615611c79565b3461047f57611d6936611a91565b919061271082046001600160801b0390816010541680858103116107515784146120e4575b830180841161075157611da090612f1e565b92611db6610b9e600a546001600160801b031690565b81106120d25733600090815260116020526040902094611dd96000965443612e49565b1580156120a4575b80612091575b61207f57611df58582613475565b611e15610f75848416611e106010546001600160801b031690565b612edb565b611e45611e2a848716611e1060105460801c90565b6001600160801b036010549181199060801b16911617601055565b611e4f8582613417565b611e5c4760155490612e49565b928293838110611f37575b505082611e7a575b602085604051908152f35b60408051928352602083018690526001600160a01b03928584169284169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9190a47f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691823b15611f3357604051630d0e30db60e41b8152948560048185875af1928315610db557602095611f1794611f20575b50612e56565b38808080611e6f565b80610da9611f2d926104e5565b38611f11565b8480fd5b91935061203c611f478385612e49565b91611f5b611f5660135461323e565b601355565b8216611fca601354611f7b611f8b84610f706001610b7f611f7b87612e3a565b6000526016602052604060002090565b611fba611f9661324d565b600081526001600160a01b038d166020820152956001600160801b03166040870152565b6001600160801b03166060850152565b906001908051151560ff845491168060ff19831617855574ffffffffffffffffffffffffffffffffffffffff00602084015160081b16916affffffffffffffffffffff60a81b16171783556001600160801b036040820151169060606001600160801b031991015160801b1617910155565b601354604051918252906001600160a01b038616907f09dfd37369506d687db24de2b5f681eb0050ccd07eaafa95d0252899471dd74090602090a3913880611e67565b604051637ef2d89b60e01b8152600490fd5b5061209e600f5443612e49565b15611de7565b506120cc6120c5826001600160a01b03166000526011602052604060002090565b5443612e49565b15611de1565b6040516393c76c6f60e01b8152600490fd5b506000611d8e565b3461047f57602036600319011261047f57600435612108612e01565b8015610fcd5761212261211a82612ef4565b6103e8900490565b662386f26fc10000811061222557612171611e2a61213f83612f1e565b92612163610f756001600160801b03809316610f706010546001600160801b031690565b8316610f7060105460801c90565b7349d72e3973900a195a155a46441f0c08179fdb6490813b1561047f5760405163079cc67960e41b815233600482015260248101849052916000908390604490829084905af1908115610db5577f08a1751668afae790ff5a3e76783eb5dc7c53adc0b248d4af119bf0edb29f97c9261220d92612212575b506121f48133613159565b6040805194855260208501919091523393918291820190565b0390a2005b80610da961221f926104e5565b386121e9565b604051636ba4a1c760e01b8152600490fd5b3461047f57602036600319011261047f57602061067d600435612f1e565b3461047f57602036600319011261047f57600435600052601660205260806040600020600181549101546001600160a01b036040519260ff81161515845260081c1660208301526001600160801b0381166040830152821c6060820152f35b3461047f57602036600319011261047f57602061067d6004356122d681610685565b6001600160a01b03479116600052600683526122f6604060002054612f60565b90613507565b3461047f57600036600319011261047f5760206001600160a01b03600c5416604051908152f35b3461047f57600036600319011261047f5760206001600160801b03600a5416604051908152f35b3461047f5760e036600319011261047f5760043561236781610685565b6024359061237482610685565b604435606435926084359360ff8516850361047f576124ac60209161239b4282101561299d565b61247361247f6123a9612a41565b92886123c8816001600160a01b03166000526008602052604060002090565b8054906001820190556124366040519384928c8c8c8601968791959493909260a09360c08401977f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c985526001600160a01b038092166020860152166040840152606083015260808201520152565b039161244a601f199384810183528261050f565b5190206040519384918883019687909160429261190160f01b8352600283015260228201520190565b0390810183528261050f565b5190206040805191825260ff909716602082015260a4359681019690965260c43560608701526080860190565b856000968792838052039060015afa15610db5577f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259084519083612525826109576001600160a01b039561250c8782168015159081612538575b506129f5565b6001600160a01b03166000526007602052604060002090565b556040519384528116931691602090a380f35b9050888c161438612506565b3461047f57600036600319011261047f5760406010548151906001600160801b038116825260801c6020820152f35b3461047f57602036600319011261047f57602061067d60043561259581610685565b6001600160a01b036125a647612f1e565b91166000526006835260406000205490613507565b604090600319011261047f576004356125d381610685565b90602435611aba81610685565b3461047f5760206126216001600160a01b036125fb366125bb565b9116600052600783526040600020906001600160a01b0316600052602052604060002090565b54604051908152f35b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a93576001600160a01b038061266c600c546001600160a01b031690565b1690811580156126c1575b611d3757600b546001600160a01b0316167f84251438ec5abdb3e7f88a1f74e49cc798585f96428d53f9b3b85232b7f4bde38380a3611d056001600160a01b0319600c5416600c55565b5060095460501c67ffffffffffffffff1615612677565b3461047f57600036600319011261047f5760206040517349d72e3973900a195a155a46441f0c08179fdb648152f35b3461047f57600036600319011261047f576020604051662386f26fc100008152f35b3461047f57600036600319011261047f576020601454604051908152f35b3461047f57612755366125bb565b90600091338352600260205260ff60408420541615610a93576001600160a01b038083169182156119d357169182156119d35760095460081c60ff16612810576127c9906127ad61010061ff00196009541617600955565b6001600160a01b03166001600160a01b0319600b541617600b55565b6127e9826001600160a01b03166001600160a01b0319600d541617600d55565b7f64ba02ab01156808d0b519bed16cc382b3fc7fbe9bae6951b30fb08742b824a88380a380f35b60405162dc149f60e41b8152600490fd5b3461047f5760008060031936011261065c57338152600260205260ff60408220541615610a9357600160ff1960095416176009557f26d1807b479eaba249c1214b82e4b65bbb0cc73ee8a17901324b1ef1b5904e498180a180f35b3461047f57600036600319011261047f5760206001600160a01b03600b5416604051908152f35b60008060031936011261065c576128c5610f2e600d546001600160a01b031690565b6001600160a01b03811633148015612980575b1561296e576801bc16d674ec800000340361295c57604080513381523460208201528392917f12b964a3993d1598dd8a3b627a3b90b4bc6b7a8f4f8bb6afde02a30d178e28ef91a1803b15612959578190600460405180948193634ad8d34b60e01b83525af18015610db55761294c575080f35b80610da9611808926104e5565b50fd5b6040516328b8c64b60e11b8152600490fd5b604051636edaef2f60e11b8152600490fd5b50612996610f2e600b546001600160a01b031690565b33146128d8565b156129a457565b60405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606490fd5b6040513d6000823e3d90fd5b156129fc57565b60405162461bcd60e51b815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606490fd5b6000467f000000000000000000000000000000000000000000000000000000000000000103612a8f57507fb0a8412dd8498ed14bdf74a71dbfd6a88b0e37f1a55ff39d82a1a2dd6194eb7690565b604051600354919081612aa1846104ab565b80835260209485840194600191878382169182600014612bba575050600114612b61575b5050509181612adc612b5b93612b4d95038261050f565b519020604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f95810195865260208601929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69085015246606085015230608085015291829060a0850190565b03601f19810183528261050f565b51902090565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b828410612ba55750505082010181612adc612b5b612ac5565b80548685018601528794909301928101612b8c565b60ff1916885293151560051b86019093019350849250612adc9150612b5b9050612ac5565b9081602091031261047f575190565b8115612bf8570490565b634e487b7160e01b600052601260045260246000fd5b601554600460206001600160a01b03600d541660405192838092635552aa6560e01b82525afa908115610db557605a91606491600091612c5d575b50040280821115612c58575090565b905090565b612c75915060203d811161141257611403818361050f565b38612c49565b634e487b7160e01b600052601160045260246000fd5b9062093a80820180921161075157565b9190820180921161075157565b9062093a8067ffffffffffffffff8093160191821161075157565b903590601e198136030182121561047f570180359067ffffffffffffffff821161047f5760200191813603831361047f57565b6020908260405193849283378101601281520301902090565b9035601e198236030181121561047f57016020813591019167ffffffffffffffff821161047f57813603831361047f57565b908060209392818452848401376000828201840152601f01601f1916010190565b906001600160a01b038235612d7c81610685565b168152608080612dcb612da6612d956020870187612d15565b60a0602088015260a0870191612d47565b60408601356040860152612dbd6060870187612d15565b908683036060880152612d47565b93013591015290565b929190612deb602091604086526040860190612d68565b930152565b906020611aba928181520190612d68565b60ff60095416612e0d57565b6040516326d1807b60e01b8152600490fd5b9190916001600160801b038080941691160191821161075157565b60001981019190821161075157565b9190820391821161075157565b9091602090604460405194600080958194829363a9059cbb60e01b84526004526024525af13d15601f3d116001845114161716906060528160405215612e995750565b62461bcd60e51b815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606490fd5b6001600160801b03918216908216039190821161075157565b9061046a9182810292818404149015171561075157565b8181029291811591840414171561075157565b6010546001600160801b0381169081158015612f55575b15612f3f57505090565b611aba92612f509160801c90612f0b565b612bee565b508060801c15612f35565b6010546001600160801b03811680158015612f97575b15612f8057505090565b612f8d90611aba93612f0b565b9060801c90612bee565b508160801c15612f76565b60ff60095416612fb7576001600160801b0390565b600090565b662386f26fc10000821061222557613001611e2a6001600160801b03612ff3610f75828716610f706010546001600160801b031690565b8516610f7060105460801c90565b4361301f336001600160a01b03166000526011602052604060002090565b554361303e826001600160a01b03166000526011602052604060002090565b5534613111576001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169061307b833033856131b4565b813b1561047f57604051632e1a7d4d60e01b815260048101849052916000908390602490829084905af1908115610db5577fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7926001600160a01b03926130fe575b505b6130e88582613159565b60408051948552602085019590955216923392a3565b80610da961310b926104e5565b386130dc565b813403613147576001600160a01b037fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7916130de565b604051636ff0acf960e11b8152600490fd5b6005548281018091116107515760206001600160a01b036000937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9360055516938484526006825260408420818154019055604051908152a3565b9192606460209294604051956000958694859384936323b872dd60e01b85526004526024526044525af13d15601f3d1160018451141617169060605281604052156131fc5750565b62461bcd60e51b815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606490fd5b60001981146107515760010190565b604051906080820182811067ffffffffffffffff8211176104f957604052565b9290613284610b9e600a546001600160801b031690565b83106120d2576132aa6120c5336001600160a01b03166000526011602052604060002090565b1580156133f0575b806133dd575b61207f576132c68282613475565b6132fd611e2a6001600160801b036132ef610f75828816611e106010546001600160801b031690565b8416611e1060105460801c90565b6133078282613417565b826133154760155490612e49565b106133cb5782613326575b50505050565b6040805184815260208101939093526001600160a01b03928584169284169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db9190a47f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691823b1561047f57604051630d0e30db60e41b81529260008460048186855af1938415610db5576133c294611f205750612e56565b38808080613320565b60405163f14a42b760e01b8152600490fd5b506133ea600f5443612e49565b156132b8565b506134116120c5826001600160a01b03166000526011602052604060002090565b156132b2565b6001600160a01b03168060005260066020526040600020805490838203918211610751576000937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092558060055403600555604051908152a3565b6001600160a01b03168060005260076020526134a76040600020336001600160a01b0316600052602052604060002090565b543382036134b457505050565b8281106134f557196134c4575050565b60005260076020526134ed336040600020906001600160a01b0316600052602052604060002090565b908154039055565b604051630e81252160e01b8152600490fd5b9080821015612c58575090565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216330361296e57565b60ff16801561075157600019019056

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000018f3e9ab3dcd396c2d3e6e598a9f77621ea50fc3000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : authority (address): 0x18F3e9Ab3dcd396C2d3e6e598a9F77621Ea50fC3
Arg [1] : weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000018f3e9ab3dcd396c2d3e6e598a9f77621ea50fc3
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

mevETH is the non-custodial liquid staking receipt that offers the highest potential rewards today. MEV Auction enables participating LST's to earn new sources of revenue for their validator set.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.