ETH Price: $3,502.42 (+2.14%)
Gas: 3 Gwei

Contract

0x9Ba021B0a9b958B5E75cE9f6dff97C7eE52cb3E6
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Approve203445542024-07-20 1:47:231 hr ago1721440043IN
Dinero: apxETH Token
0 ETH0.000129632.80171738
Deposit203444162024-07-20 1:19:232 hrs ago1721438363IN
Dinero: apxETH Token
0 ETH0.00035542.88407085
Harvest203440332024-07-20 0:02:113 hrs ago1721433731IN
Dinero: apxETH Token
0 ETH0.000284063.86518829
Approve203426112024-07-19 19:16:598 hrs ago1721416619IN
Dinero: apxETH Token
0 ETH0.000276745.98422963
Deposit203426012024-07-19 19:14:598 hrs ago1721416499IN
Dinero: apxETH Token
0 ETH0.000689356.49764796
Transfer203417212024-07-19 16:17:5911 hrs ago1721405879IN
Dinero: apxETH Token
0 ETH0.0005485811.23880735
Redeem203409022024-07-19 13:33:1113 hrs ago1721395991IN
Dinero: apxETH Token
0 ETH0.000520064.77194245
Redeem203408752024-07-19 13:27:4713 hrs ago1721395667IN
Dinero: apxETH Token
0 ETH0.000460824.42320372
Approve203408732024-07-19 13:27:2313 hrs ago1721395643IN
Dinero: apxETH Token
0 ETH0.000208974.48854958
Harvest203386532024-07-19 6:02:1121 hrs ago1721368931IN
Dinero: apxETH Token
0 ETH0.000394115.36252973
Approve203379722024-07-19 3:45:3523 hrs ago1721360735IN
Dinero: apxETH Token
0 ETH0.000314956.81051487
Transfer203370352024-07-19 0:37:2326 hrs ago1721349443IN
Dinero: apxETH Token
0 ETH0.0002417.6026598
Redeem203356742024-07-18 20:03:5931 hrs ago1721333039IN
Dinero: apxETH Token
0 ETH0.0011996711.51239514
Approve203356702024-07-18 20:03:1131 hrs ago1721332991IN
Dinero: apxETH Token
0 ETH0.0005414711.70270179
Transfer203355432024-07-18 19:37:4731 hrs ago1721331467IN
Dinero: apxETH Token
0 ETH0.0005488111.24348201
Transfer203354912024-07-18 19:27:2331 hrs ago1721330843IN
Dinero: apxETH Token
0 ETH0.0006230912.76522816
Deposit203343072024-07-18 15:29:2335 hrs ago1721316563IN
Dinero: apxETH Token
0 ETH0.0018950518.70201562
Harvest203332762024-07-18 12:02:1139 hrs ago1721304131IN
Dinero: apxETH Token
0 ETH0.0008070210.9808534
Approve203322202024-07-18 8:29:4742 hrs ago1721291387IN
Dinero: apxETH Token
0 ETH0.000202958.36143527
Approve203299652024-07-18 0:55:232 days ago1721264123IN
Dinero: apxETH Token
0 ETH0.000249195.38440398
Deposit203299392024-07-18 0:50:112 days ago1721263811IN
Dinero: apxETH Token
0 ETH0.00059555.61238032
Deposit203297932024-07-18 0:20:592 days ago1721262059IN
Dinero: apxETH Token
0 ETH0.000589345.55438322
Redeem203287362024-07-17 20:48:112 days ago1721249291IN
Dinero: apxETH Token
0 ETH0.000969268.89273171
Approve203287152024-07-17 20:43:592 days ago1721249039IN
Dinero: apxETH Token
0 ETH0.0004707510.1113468
Harvest203279082024-07-17 18:02:112 days ago1721239331IN
Dinero: apxETH Token
0 ETH0.0008012410.90223701
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AutoPxEth

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 11 : AutoPxEth.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {Ownable2Step} from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import {ERC4626} from "solmate/mixins/ERC4626.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {Errors} from "./libraries/Errors.sol";
import {IPirexEth} from "./interfaces/IPirexEth.sol";

/**
 * @title AutoPxEth
 * @notice Autocompounding vault for (staked) pxETH, adapted from pxCVX vault system
 * @dev This contract enables autocompounding for pxETH assets and includes various fee mechanisms.
 * @author redactedcartel.finance
 */
contract AutoPxEth is Ownable2Step, ERC4626 {
    /**
     * @dev Library: SafeTransferLib - Provides safe transfer functions for ERC20 tokens.
     */
    using SafeTransferLib for ERC20;

    /**
     * @dev Library: FixedPointMathLib - Provides fixed-point arithmetic for uint256.
     */
    using FixedPointMathLib for uint256;

    // Constants

    /**
     * @dev Maximum withdrawal penalty percentage.
     */
    uint256 private constant MAX_WITHDRAWAL_PENALTY = 50_000;
    

    /**
     * @dev Maximum platform fee percentage.
     */
    uint256 private constant MAX_PLATFORM_FEE = 200_000;

    /**
     * @dev Fee denominator for precise fee calculations.
     */
    uint256 private constant FEE_DENOMINATOR = 1_000_000;

    /**
     * @dev Duration of the rewards period.
     */
    uint256 private constant REWARDS_DURATION = 7 days;

    // State variables for tracking rewards and actively staked assets

    /**
     * @notice Reference to the PirexEth contract.
     */
    IPirexEth public pirexEth;
    
    /**
     * @notice Timestamp when the current rewards period will end.
     */
    uint256 public periodFinish;
    
    /**
     * @notice Rate at which rewards are distributed per second.
     */
    uint256 public rewardRate;
    
    /**
     * @notice Timestamp of the last update to the reward variables.
     */
    uint256 public lastUpdateTime;
    
    /**
     * @notice Accumulated reward per token stored.
     */
    uint256 public rewardPerTokenStored;
    
    /**
     * @notice Last calculated reward per token paid to stakers.
     */
    uint256 public rewardPerTokenPaid;
    
    /**
     * @notice Total rewards available for distribution.
     */
    uint256 public rewards;
    
    /**
     * @notice Total assets actively staked in the vault.
     */
    uint256 public totalStaked;

    // State variables related to fees
    /**
     * @notice Withdrawal penalty percentage.
     */
    uint256 public withdrawalPenalty = 30_000;
    
    /**
     * @notice Platform fee percentage.
     */
    uint256 public platformFee = 100_000;
    
    /**
     * @notice Address of the platform that receives fees.
     */
    address public platform;

    // Events

    /**
     * @notice Emitted when rewards are harvested and staked.
     * @dev This event is emitted when a user triggers the harvest function.
     * @param caller address indexed Address that triggered the harvest.
     * @param value  uint256         Amount of rewards harvested.
     */
    event Harvest(address indexed caller, uint256 value);

    /**
     * @notice Emitted when the withdrawal penalty is updated.
     * @dev This event is emitted when the withdrawal penalty is modified.
     * @param penalty uint256 New withdrawal penalty percentage.
     */
    event WithdrawalPenaltyUpdated(uint256 penalty);

    /**
     * @notice Emitted when the platform fee is updated.
     * @dev This event is emitted when the platform fee is modified.
     * @param fee uint256 New platform fee percentage.
     */
    event PlatformFeeUpdated(uint256 fee);
    
    /**
     * @notice Emitted when the platform address is updated.
     * @dev This event is emitted when the platform address is modified.
     * @param _platform address New platform address.
     */
    event PlatformUpdated(address _platform);

    /**
     * @notice Emitted when new rewards are added to the vault.
     * @dev This event is emitted when new rewards are added to the vault.
     * @param reward uint256 Amount of rewards added.
     */
    event RewardAdded(uint256 reward);

    /**
     * @notice Emitted when the PirexEth contract address is set.
     * @dev This event is emitted when the PirexEth contract address is set.
     * @param _pirexEth address New PirexEth contract address.
     */
    event SetPirexEth(address _pirexEth);

    // Modifiers
    /**
     * @dev Update reward states modifier
     * @param updateEarned bool Whether to update earned amount so far
     */
    modifier updateReward(bool updateEarned) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdateTime = lastTimeRewardApplicable();

        if (updateEarned) {
            rewards = earned();
            rewardPerTokenPaid = rewardPerTokenStored;
        }
        _;
    }

    /**
     * @dev Contract constructor
     * @param _asset address Asset contract address
     * @param _platform address Platform address
     */
    constructor(
        address _asset,
        address _platform
    ) ERC4626(ERC20(_asset), "Autocompounding Pirex Ether", "apxETH") {
        if (_platform == address(0)) revert Errors.ZeroAddress();

        platform = _platform;
    }

    /*//////////////////////////////////////////////////////////////
                        RESTRICTED FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Set the PirexEth contract address
     * @dev Function access restricted to only owner
     * @param _pirexEth address PirexEth contract address
     */
    function setPirexEth(address _pirexEth) external onlyOwner {
        if (_pirexEth == address(0)) revert Errors.ZeroAddress();

        emit SetPirexEth(_pirexEth);

        pirexEth = IPirexEth(_pirexEth);
    }

    /**
     * @notice Set the withdrawal penalty
     * @dev Function access restricted to only owner
     * @param penalty uint256 Withdrawal penalty
     */
    function setWithdrawalPenalty(uint256 penalty) external onlyOwner {
        if (penalty > MAX_WITHDRAWAL_PENALTY) revert Errors.ExceedsMax();

        withdrawalPenalty = penalty;

        emit WithdrawalPenaltyUpdated(penalty);
    }

    /**
     * @notice Set the platform fee
     * @dev Function access restricted to only owner
     * @param fee uint256 Platform fee
     */
    function setPlatformFee(uint256 fee) external onlyOwner {
        if (fee > MAX_PLATFORM_FEE) revert Errors.ExceedsMax();

        platformFee = fee;

        emit PlatformFeeUpdated(fee);
    }

    /**
     * @notice Set the platform
     * @dev Function access restricted to only owner
     * @param _platform address Platform
     */
    function setPlatform(address _platform) external onlyOwner {
        if (_platform == address(0)) revert Errors.ZeroAddress();

        platform = _platform;

        emit PlatformUpdated(_platform);
    }

    /**
     * @notice Notify and sync the newly added rewards to be streamed over time
     * @dev Rewards are streamed following the duration set in REWARDS_DURATION
     */
    function notifyRewardAmount() external updateReward(false) {
        if (msg.sender != address(pirexEth)) revert Errors.NotPirexEth();

        // Rewards transferred directly to this contract are not added to totalStaked
        // To get the rewards w/o relying on a potentially incorrect passed in arg,
        // we can use the difference between the asset balance and totalStaked.
        // Additionally, to avoid re-distributing rewards, deduct the output of `earned`
        uint256 rewardBalance = asset.balanceOf(address(this)) -
            totalStaked -
            earned();

        rewardRate = rewardBalance / REWARDS_DURATION;

        if (rewardRate == 0) revert Errors.NoRewards();

        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp + REWARDS_DURATION;

        emit RewardAdded(rewardBalance);
    }

    /*//////////////////////////////////////////////////////////////
                                VIEWS
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc ERC4626
     * @notice Get the amount of available pxETH in the contract
     * @dev Rewards are streamed for the duration set in REWARDS_DURATION
     */
    function totalAssets() public view override returns (uint256) {
        // Based on the current totalStaked and available rewards
        uint256 _totalStaked = totalStaked;
        uint256 _rewards = ((_totalStaked *
            (rewardPerToken() - rewardPerTokenPaid)) / 1e18) + rewards;

        // Deduct the exact reward amount staked (after fees are deducted when calling `harvest`)
        return
            _totalStaked +
            (
                _rewards == 0
                    ? 0
                    : (_rewards - ((_rewards * platformFee) / FEE_DENOMINATOR))
            );
    }

    /**
     * @notice Returns the last effective timestamp of the current reward period
     * @return uint256 Timestamp
     */
    function lastTimeRewardApplicable() public view returns (uint256) {
        return block.timestamp < periodFinish ? block.timestamp : periodFinish;
    }

    /**
     * @notice Returns the amount of rewards per staked token/asset
     * @return uint256 Rewards amount
     */
    function rewardPerToken() public view returns (uint256) {
        if (totalStaked == 0) {
            return rewardPerTokenStored;
        }

        return
            rewardPerTokenStored +
            ((((lastTimeRewardApplicable() - lastUpdateTime) * rewardRate) *
                1e18) / totalStaked);
    }

    /**
     * @notice Returns the earned rewards amount so far
     * @return uint256 Rewards amount
     */
    function earned() public view returns (uint256) {
        return
            ((totalStaked * (rewardPerToken() - rewardPerTokenPaid)) / 1e18) +
            rewards;
    }

    /**
     * @notice Return the amount of assets per 1 (1e18) share
     * @return uint256 Assets
     */
    function assetsPerShare() external view returns (uint256) {
        return previewRedeem(1e18);
    }

    /*//////////////////////////////////////////////////////////////
                            INTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev Internal method to keep track of the total amount of staked token/asset on deposit/mint
     */
    function _stake(uint256 amount) internal updateReward(true) {
        totalStaked += amount;
    }

    /**
     * @dev Internal method to keep track of the total amount of staked token/asset on withdrawal/redeem
     */
    function _withdraw(uint256 amount) internal updateReward(true) {
        totalStaked -= amount;
    }

    /*//////////////////////////////////////////////////////////////
                            ERC4626 OVERRIDES
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc ERC4626
     * @dev Deduct the specified amount of assets from totalStaked to prepare for transfer to the user
     * @param assets uint256 Assets
     */
    function beforeWithdraw(uint256 assets, uint256) internal override {
        // Perform harvest to make sure that totalStaked is always equal or larger than assets to be withdrawn
        if (assets > totalStaked) harvest();

        _withdraw(assets);
    }

    /**
     * @inheritdoc ERC4626
     * @dev Include the new assets in totalStaked so that rewards can be properly distributed
     * @param assets uint256 Assets
     */
    function afterDeposit(uint256 assets, uint256) internal override {
        _stake(assets);
    }

    /**
     * @inheritdoc ERC4626
     * @dev Preview the amount of assets a user would receive from redeeming shares
     */
    function previewRedeem(
        uint256 shares
    ) public view override returns (uint256) {
        // Calculate assets based on a user's % ownership of vault shares
        uint256 assets = convertToAssets(shares);

        uint256 _totalSupply = totalSupply;

        // Calculate a penalty - zero if user is the last to withdraw.
        uint256 penalty = (_totalSupply == 0 || _totalSupply - shares == 0)
            ? 0
            : assets.mulDivUp(withdrawalPenalty, FEE_DENOMINATOR); // Round up the penalty in favour of the protocol.

        // Redeemable amount is the post-penalty amount
        return assets - penalty;
    }

    /**
     * @inheritdoc ERC4626
     * @notice Preview the amount of shares a user would need to redeem the specified asset amount
     * @dev This modified version takes into consideration the withdrawal fee
     */
    function previewWithdraw(
        uint256 assets
    ) public view override returns (uint256) {
        // Calculate shares based on the specified assets' proportion of the pool
        uint256 shares = convertToShares(assets);

        // Save 1 SLOAD
        uint256 _totalSupply = totalSupply;

        // Factor in additional shares to fulfill withdrawal if user is not the last to withdraw
        return
            (_totalSupply == 0 || _totalSupply - shares == 0)
                ? shares
                : (shares * FEE_DENOMINATOR) /
                    (FEE_DENOMINATOR - withdrawalPenalty);
    }

    /*//////////////////////////////////////////////////////////////
                            MUTATIVE FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Harvest and stake available rewards after distributing fees to the platform
     * @dev This function claims and stakes the available rewards, deducting a fee for the platform.
     */
    function harvest() public updateReward(true) {
        uint256 _rewards = rewards;

        if (_rewards != 0) {
            rewards = 0;

            // Fee for platform
            uint256 feeAmount = (_rewards * platformFee) / FEE_DENOMINATOR;

            // Deduct fee from reward balance
            _rewards -= feeAmount;

            // Claimed rewards should be in pxETH
            asset.safeTransfer(platform, feeAmount);

            // Stake rewards sans fee
            _stake(_rewards);

            emit Harvest(msg.sender, _rewards);
        }
    }

    /**
     * @notice Override transfer logic to trigger direct `initiateRedemption`.
     * @dev This function overrides the standard transfer logic to initiate redemption when transferring to the PirexEth contract.
     * @param to     address Transfer destination
     * @param amount uint256 Amount
     * @return       bool
     */
    function transfer(
        address to,
        uint256 amount
    ) public override returns (bool) {
        super.transfer(to, amount);

        if (to == address(pirexEth)) {
            pirexEth.initiateRedemption(amount, msg.sender, false);
        }

        return true;
    }

    /**
     * @notice Override transferFrom logic to trigger direct `initiateRedemption`.
     * @dev This function overrides the standard transferFrom logic to initiate redemption when transferring from the PirexEth contract.
     * @param from   Address of the transfer origin.
     * @param to     Address of the transfer destination.
     * @param amount Amount of tokens to transfer.
     * @return       A boolean indicating the success of the transfer.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public override returns (bool) {
        super.transferFrom(from, to, amount);

        if (to == address(pirexEth)) {
            pirexEth.initiateRedemption(amount, from, false);
        }

        return true;
    }
}

File 2 of 11 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;

import "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}

File 3 of 11 : ERC4626.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol";

/// @notice Minimal ERC4626 tokenized Vault implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    ERC20 public immutable asset;

    constructor(
        ERC20 _asset,
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol, _asset.decimals()) {
        asset = _asset;
    }

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual returns (uint256 shares) {
        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.

        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual returns (uint256 assets) {
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        // Check for rounding error since we round down in previewRedeem.
        require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }

    function previewMint(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    function previewRedeem(uint256 shares) public view virtual returns (uint256) {
        return convertToAssets(shares);
    }

    /*//////////////////////////////////////////////////////////////
                     DEPOSIT/WITHDRAWAL LIMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    function maxDeposit(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxMint(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxWithdraw(address owner) public view virtual returns (uint256) {
        return convertToAssets(balanceOf[owner]);
    }

    function maxRedeem(address owner) public view virtual returns (uint256) {
        return balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HOOKS LOGIC
    //////////////////////////////////////////////////////////////*/

    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}

    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}

File 4 of 11 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/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 5 of 11 : FixedPointMathLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    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.
    }

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

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        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) {
        /// @solidity memory-safe-assembly
        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 unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

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

File 6 of 11 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
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/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

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

        /// @solidity memory-safe-assembly
        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;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 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 the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

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

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 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 the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

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

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 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 the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

File 7 of 11 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

library Errors {
    /**
     * @dev Zero address specified
     */
    error ZeroAddress();

    /**
     * @dev Zero amount specified
     */
    error ZeroAmount();

    /**
     * @dev Invalid fee specified
     */
    error InvalidFee();

    /**
     * @dev Invalid max fee specified
     */
    error InvalidMaxFee();

    /**
     * @dev Zero multiplier used
     */
    error ZeroMultiplier();

    /**
     * @dev ETH deposit is paused
     */
    error DepositingEtherPaused();

    /**
     * @dev ETH deposit is not paused
     */
    error DepositingEtherNotPaused();

    /**
     * @dev Contract is paused
     */
    error Paused();

    /**
     * @dev Contract is not paused
     */
    error NotPaused();

    /**
     * @dev Validator not yet dissolved
     */
    error NotDissolved();

    /**
     * @dev Validator not yet withdrawable
     */
    error NotWithdrawable();

    /**
     * @dev Validator has been previously used before
     */
    error NoUsedValidator();

    /**
     * @dev Not oracle adapter
     */
    error NotOracleAdapter();

    /**
     * @dev Not reward recipient
     */
    error NotRewardRecipient();

    /**
     * @dev Exceeding max value
     */
    error ExceedsMax();

    /**
     * @dev No rewards available
     */
    error NoRewards();

    /**
     * @dev Not PirexEth
     */
    error NotPirexEth();

    /**
     * @dev Not minter
     */
    error NotMinter();

    /**
     * @dev Not burner
     */
    error NotBurner();

    /**
     * @dev Empty string
     */
    error EmptyString();

    /**
     * @dev Validator is Not Staking
     */
    error ValidatorNotStaking();

    /**
     * @dev not enough buffer
     */
    error NotEnoughBuffer();

    /**
     * @dev validator queue empty
     */
    error ValidatorQueueEmpty();

    /**
     * @dev out of bounds
     */
    error OutOfBounds();

    /**
     * @dev cannot trigger validator exit
     */
    error NoValidatorExit();

    /**
     * @dev cannot initiate redemption partially
     */
    error NoPartialInitiateRedemption();

    /**
     * @dev not enough validators
     */
    error NotEnoughValidators();

    /**
     * @dev not enough ETH
     */
    error NotEnoughETH();

    /**
     * @dev max processed count is invalid (< 1)
     */
    error InvalidMaxProcessedCount();

    /**
     * @dev fromIndex and toIndex are invalid
     */
    error InvalidIndexRanges();

    /**
     * @dev ETH is not allowed
     */
    error NoETHAllowed();

    /**
     * @dev ETH is not passed
     */
    error NoETH();

    /**
     * @dev validator status is neither dissolved nor slashed
     */
    error StatusNotDissolvedOrSlashed();

    /**
     * @dev validator status is neither withdrawable nor staking
     */
    error StatusNotWithdrawableOrStaking();

    /**
     * @dev account is not approved
     */
    error AccountNotApproved();

    /**
     * @dev invalid token specified
     */
    error InvalidToken();

    /**
     * @dev not same as deposit size
     */
    error InvalidAmount();

    /**
     * @dev contract not recognised
     */
    error UnrecorgnisedContract();

    /**
     * @dev empty array
     */
    error EmptyArray();

    /**
     * @dev arrays length mismatch
     */
    error MismatchedArrayLengths();
}

File 8 of 11 : IPirexEth.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import {DataTypes} from "../libraries/DataTypes.sol";

/**
 * @title IPirexEth
 * @notice Interface for the PirexEth contract
 * @dev This interface defines the methods for interacting with PirexEth.
 * @author redactedcartel.finance
 */
interface IPirexEth {
    /**
     * @notice Initiate redemption by burning pxETH in return for upxETH
     * @dev This function allows the initiation of redemption by burning pxETH in exchange for upxETH.
     * @param _assets                     uint256 The amount of assets to burn. If the caller is AutoPxEth, then apxETH; pxETH otherwise.
     * @param _receiver                   address The address to receive upxETH.
     * @param _shouldTriggerValidatorExit bool    Whether the initiation should trigger voluntary exit.
     * @return postFeeAmount              uint256 The amount of pxETH burnt for the receiver.
     * @return feeAmount                  uint256 The amount of pxETH distributed as fees.
     */
    function initiateRedemption(
        uint256 _assets,
        address _receiver,
        bool _shouldTriggerValidatorExit
    ) external returns (uint256 postFeeAmount, uint256 feeAmount);

    /**
     * @notice Dissolve validator
     * @dev This function dissolves a validator.
     * @param _pubKey bytes The public key of the validator.
     */
    function dissolveValidator(bytes calldata _pubKey) external payable;

    /**
     * @notice Update validator state to be slashed
     * @dev This function updates the validator state to be slashed.
     * @param _pubKey         bytes                     The public key of the validator.
     * @param _removeIndex    uint256                   The index of the validator to be slashed.
     * @param _amount         uint256                   The ETH amount released from the Beacon chain.
     * @param _unordered      bool                      Whether to remove from the staking validator queue in order or not.
     * @param _useBuffer      bool                      Whether to use a buffer to compensate for the loss.
     * @param _burnerAccounts DataTypes.BurnerAccount[] Burner accounts.
     */
    function slashValidator(
        bytes calldata _pubKey,
        uint256 _removeIndex,
        uint256 _amount,
        bool _unordered,
        bool _useBuffer,
        DataTypes.BurnerAccount[] calldata _burnerAccounts
    ) external payable;

    /**
     * @notice Harvest and mint staking rewards when available
     * @dev This function harvests and mints staking rewards when available.
     * @param _endBlock uint256 The block until which ETH rewards are computed.
     */
    function harvest(uint256 _endBlock) external payable;
}

File 9 of 11 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 10 of 11 : DataTypes.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

/**
 * @title DataTypes
 * @notice Library containing various data structures and enums for the PirexEth.
 * @dev This library provides data structures and enums crucial for the functionality of the Pirex protocol.
 * @author redactedcartel.finance
 */
library DataTypes {
    // Validator struct type
    struct Validator {
        // Publickey of the validator
        bytes pubKey;
        // Signature associated with the validator
        bytes signature;
        // Root hash of deposit data for the validator
        bytes32 depositDataRoot;
        // beneficiazry address to receive pxEth against preDeposit
        address receiver;
    }

    // ValidatorDeque struct type
    struct ValidatorDeque {
        // Beginning index of the validator deque
        int128 _begin;
        // End index of the validator deque
        int128 _end;
        // Mapping of validator index to Validator struct
        mapping(int128 => Validator) _validators;
    }

    // Burner Account Type
    struct BurnerAccount {
        // Address of the burner account
        address account;
        // Amount associated with the burner account
        uint256 amount;
    }

    // Configurable fees
    enum Fees {
        // Fee type for deposit
        Deposit,
        // Fee type for redemption
        Redemption,
        // Fee type for instant redemption
        InstantRedemption
    }

    // Configurable contracts
    enum Contract {
        // PxEth contract
        PxEth,
        // UpxEth contract
        UpxEth,
        // AutoPxEth contract
        AutoPxEth,
        // OracleAdapter contract
        OracleAdapter,
        // PirexEth contract
        PirexEth,
        // RewardRecipient contract
        RewardRecipient
    }

    // Validator statuses
    enum ValidatorStatus {
        // The validator is not staking and has no defined status.
        None,
        // The validator is actively participating in the staking process.
        // It could be in one of the following states: pending_initialized, pending_queued, or active_ongoing.
        Staking,
        // The validator has proceed with the withdrawal process.
        // It represents a meta state for active_exiting, exited_unslashed, and the withdrawal process being possible.
        Withdrawable,
        // The validator's status indicating that ETH is released to the pirexEthValidators
        // It represents the withdrawal_done status.
        Dissolved,
        // The validator's status indicating that it has been slashed due to misbehavior.
        // It serves as a meta state encompassing active_slashed, exited_slashed,
        // and the possibility of starting the withdrawal process (withdrawal_possible) or already completed (withdrawal_done)
        // with the release of ETH, subject to a penalty for the misbehavior.
        Slashed
    }
}

File 11 of 11 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {
    "src/libraries/ValidatorQueue.sol": {
      "ValidatorQueue": "0x9e0d7d79735e1c63333128149c7b616a0dc0bbdb"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_platform","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExceedsMax","type":"error"},{"inputs":[],"name":"NoRewards","type":"error"},{"inputs":[],"name":"NotPirexEth","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"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":"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":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PlatformFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_platform","type":"address"}],"name":"PlatformUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_pirexEth","type":"address"}],"name":"SetPirexEth","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":"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":false,"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"WithdrawalPenaltyUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","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":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetsPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","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":"nonpayable","type":"function"},{"inputs":[],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"nonpayable","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":[],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"pirexEth","outputs":[{"internalType":"contract IPirexEth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platform","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pirexEth","type":"address"}],"name":"setPirexEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_platform","type":"address"}],"name":"setPlatform","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"setWithdrawalPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","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":[],"name":"withdrawalPenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

610100604052617530601055620186a06011553480156200001f57600080fd5b506040516200269d3803806200269d8339810160408190526200004291620002c1565b816040518060400160405280601b81526020017f4175746f636f6d706f756e64696e672050697265782045746865720000000000815250604051806040016040528060068152602001650c2e0f08aa8960d31b8152508181846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000d9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ff9190620002f9565b6200010a336200019a565b6002620001188482620003ca565b506003620001278382620003ca565b5060ff81166080524660a0526200013d620001b8565b60c0525050506001600160a01b0392831660e05250508116620001735760405163d92e233d60e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b03929092169190911790555062000514565b600180546001600160a01b0319169055620001b58162000254565b50565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6002604051620001ec919062000496565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620002bc57600080fd5b919050565b60008060408385031215620002d557600080fd5b620002e083620002a4565b9150620002f060208401620002a4565b90509250929050565b6000602082840312156200030c57600080fd5b815160ff811681146200031e57600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200035057607f821691505b6020821081036200037157634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003c557600081815260208120601f850160051c81016020861015620003a05750805b601f850160051c820191505b81811015620003c157828155600101620003ac565b5050505b505050565b81516001600160401b03811115620003e657620003e662000325565b620003fe81620003f784546200033b565b8462000377565b602080601f8311600181146200043657600084156200041d5750858301515b600019600386901b1c1916600185901b178555620003c1565b600085815260208120601f198616915b82811015620004675788860151825594840194600190910190840162000446565b5085821015620004865787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000808354620004a6816200033b565b60018281168015620004c15760018114620004d75762000508565b60ff198416875282151583028701945062000508565b8760005260208060002060005b85811015620004ff5781548a820152908401908201620004e4565b50505082870194505b50929695505050505050565b60805160a05160c05160e0516121256200057860003960008181610450015281816109ad01528181610d4301528181610ee501528181611086015281816112c5015261141101526000610c1801526000610be80152600061040701526121256000f3fe608060405234801561001057600080fd5b50600436106103425760003560e01c806380faa57d116101b8578063c63d75b611610104578063d905777e116100a2578063e30c39781161007c578063e30c3978146106d8578063ebe2b12b146106e9578063ef8b30f7146106f2578063f2fde38b1461070557600080fd5b8063d905777e1461067b578063dd62ed3e146106a4578063df136d65146106cf57600080fd5b8063cd3daf9d116100de578063cd3daf9d14610645578063ce96cb771461064d578063d505accf14610660578063d6f192621461067357600080fd5b8063c63d75b61461048a578063c6e6f59214610629578063c8f33c911461063c57600080fd5b8063a2468c1911610171578063aa728d1c1161014b578063aa728d1c146105dd578063b3d7f6b9146105f0578063b460af9414610603578063ba0876521461061657600080fd5b8063a2468c19146105b8578063a8024b06146105c1578063a9059cbb146105ca57600080fd5b806380faa57d14610572578063817b1cd21461057a5780638da5cb5b1461058357806394bf804d1461059457806395d89b41146105a75780639ec5a894146105af57600080fd5b806338d52e0f116102925780636e553f651161023057806379ba50971161020a57806379ba50971461052e5780637b0a47ee146105365780637ecebe001461053f5780637faaa6c11461055f57600080fd5b80636e553f65146104f357806370a0823114610506578063715018a61461052657600080fd5b80634641257d1161026c5780634641257d146104b25780634bde38c8146104ba5780634cdad506146104cd5780636945c5ea146104e057600080fd5b806338d52e0f1461044b578063402d267d1461048a57806344c99e631461049f57600080fd5b806312e8e2c3116102ff57806326232a2e116102d957806326232a2e146103f9578063313ce5671461040257806335d16e171461043b5780633644e5151461044357600080fd5b806312e8e2c3146103ca57806318160ddd146103dd57806323b872dd146103e657600080fd5b806301e1d1141461034757806306fdde031461036257806307a2d13a14610377578063095ea7b31461038a5780630a28a477146103ad5780630c51dde4146103c0575b600080fd5b61034f610718565b6040519081526020015b60405180910390f35b61036a6107a8565b6040516103599190611d3b565b61034f610385366004611d89565b610836565b61039d610398366004611dbe565b610863565b6040519015158152602001610359565b61034f6103bb366004611d89565b6108d0565b6103c8610930565b005b6103c86103d8366004611d89565b610ab6565b61034f60045481565b61039d6103f4366004611de8565b610b1e565b61034f60115481565b6104297f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610359565b61034f610bcc565b61034f610be4565b6104727f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610359565b61034f610498366004611e24565b5060001990565b6103c86104ad366004611e24565b610c3a565b6103c8610cc7565b601254610472906001600160a01b031681565b61034f6104db366004611d89565b610db0565b6103c86104ee366004611e24565b610e0b565b61034f610501366004611e3f565b610e88565b61034f610514366004611e24565b60056020526000908152604090205481565b6103c8610f67565b6103c8610f7b565b61034f600a5481565b61034f61054d366004611e24565b60076020526000908152604090205481565b6103c861056d366004611d89565b610ff5565b61034f611055565b61034f600f5481565b6000546001600160a01b0316610472565b61034f6105a2366004611e3f565b61106c565b61036a611108565b61034f600e5481565b61034f60105481565b61034f600d5481565b61039d6105d8366004611dbe565b611115565b600854610472906001600160a01b031681565b61034f6105fe366004611d89565b6111bf565b61034f610611366004611e6b565b6111de565b61034f610624366004611e6b565b6112ec565b61034f610637366004611d89565b611438565b61034f600b5481565b61034f611458565b61034f61065b366004611e24565b6114b9565b6103c861066e366004611ea7565b6114db565b61034f61171f565b61034f610689366004611e24565b6001600160a01b031660009081526005602052604090205490565b61034f6106b2366004611f1a565b600660209081526000928352604080842090915290825290205481565b61034f600c5481565b6001546001600160a01b0316610472565b61034f60095481565b61034f610700366004611d89565b611763565b6103c8610713366004611e24565b61176e565b600080600f5490506000600e54670de0b6b3a7640000600d54610739611458565b6107439190611f5a565b61074d9085611f6d565b6107579190611f84565b6107619190611fa6565b9050801561079457620f42406011548261077b9190611f6d565b6107859190611f84565b61078f9082611f5a565b610797565b60005b6107a19083611fa6565b9250505090565b600280546107b590611fb9565b80601f01602080910402602001604051908101604052809291908181526020018280546107e190611fb9565b801561082e5780601f106108035761010080835404028352916020019161082e565b820191906000526020600020905b81548152906001019060200180831161081157829003601f168201915b505050505081565b600454600090801561085a5761085561084d610718565b8490836117df565b61085c565b825b9392505050565b3360008181526006602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906108be9086815260200190565b60405180910390a35060015b92915050565b6000806108dc83611438565b6004549091508015806108f657506108f48282611f5a565b155b6109265760105461090a90620f4240611f5a565b610917620f424084611f6d565b6109219190611f84565b610928565b815b949350505050565b600061093a611458565b600c55610945611055565b600b5580156109605761095661171f565b600e55600c54600d555b6008546001600160a01b0316331461098b576040516321f674f160e11b815260040160405180910390fd5b600061099561171f565b600f546040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156109fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a209190611ff3565b610a2a9190611f5a565b610a349190611f5a565b9050610a4362093a8082611f84565b600a819055600003610a6857604051630fec21fd60e21b815260040160405180910390fd5b42600b819055610a7c9062093a8090611fa6565b6009556040518181527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d9060200160405180910390a15050565b610abe6117fd565b62030d40811115610ae2576040516395e28b8560e01b815260040160405180910390fd5b60118190556040518181527f45610d581145924dd7090a5017e5f2b1d6f42213bb2e95707ff86846bbfcb1ca906020015b60405180910390a150565b6000610b2b848484611857565b506008546001600160a01b0390811690841603610bc257600854604051630feab8d160e21b8152600481018490526001600160a01b0386811660248301526000604483015290911690633faae3449060640160408051808303816000875af1158015610b9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbf919061200c565b50505b5060019392505050565b6000610bdf670de0b6b3a7640000610db0565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000004614610c1557610bdf611937565b507f000000000000000000000000000000000000000000000000000000000000000090565b610c426117fd565b6001600160a01b038116610c695760405163d92e233d60e01b815260040160405180910390fd5b6040516001600160a01b03821681527f613b19ff0295024b0e961d5dcb85080a6cadacf5b531919da0faa74ec05ddedc9060200160405180910390a1600880546001600160a01b0319166001600160a01b0392909216919091179055565b6001610cd1611458565b600c55610cdc611055565b600b558015610cf757610ced61171f565b600e55600c54600d555b600e548015610dac576000600e819055601154620f424090610d199084611f6d565b610d239190611f84565b9050610d2f8183611f5a565b601254909250610d6c906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836119d1565b610d7582611a4f565b60405182815233907fc9695243a805adb74c91f28311176c65b417e842d5699893cef56d18bfa48cba9060200160405180910390a2505b5050565b600080610dbc83610836565b6004549091506000811580610dd85750610dd68583611f5a565b155b610df357601054610dee908490620f4240611a9a565b610df6565b60005b9050610e028184611f5a565b95945050505050565b610e136117fd565b6001600160a01b038116610e3a5760405163d92e233d60e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b0383169081179091556040519081527f38703bc9e5fbfe6a4ab89353328531fd2a9b9b0a4953c587bd38e559da9c29cf90602001610b13565b6000610e9383611763565b905080600003610ed85760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f53484152455360a81b60448201526064015b60405180910390fd5b610f0d6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333086611ac0565b610f178282611b4a565b60408051848152602081018390526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a36108ca8382611ba4565b610f6f6117fd565b610f796000611bad565b565b60015433906001600160a01b03168114610fe95760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610ecf565b610ff281611bad565b50565b610ffd6117fd565b61c350811115611020576040516395e28b8560e01b815260040160405180910390fd5b60108190556040518181527f9d5ddc6fdb90a6647fe4981fdf08b45a5f9ef6d8ea960de27bef48fb4813259290602001610b13565b60006009544210611067575060095490565b504290565b6000611077836111bf565b90506110ae6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084611ac0565b6110b88284611b4a565b60408051828152602081018590526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a36108ca8184611ba4565b600380546107b590611fb9565b60006111218383611bc6565b506008546001600160a01b03908116908416036111b657600854604051630feab8d160e21b815260048101849052336024820152600060448201526001600160a01b0390911690633faae3449060640160408051808303816000875af115801561118f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b3919061200c565b50505b50600192915050565b600454600090801561085a576108556111d6610718565b849083611a9a565b60006111e9846108d0565b9050336001600160a01b03831614611259576001600160a01b03821660009081526006602090815260408083203384529091529020546000198114611257576112328282611f5a565b6001600160a01b03841660009081526006602090815260408083203384529091529020555b505b6112638482611c2c565b61126d8282611c47565b60408051858152602081018390526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a461085c6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001684866119d1565b6000336001600160a01b0383161461135c576001600160a01b0382166000908152600660209081526040808320338452909152902054600019811461135a576113358582611f5a565b6001600160a01b03841660009081526006602090815260408083203384529091529020555b505b61136584610db0565b9050806000036113a55760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f41535345545360a81b6044820152606401610ecf565b6113af8185611c2c565b6113b98285611c47565b60408051828152602081018690526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a461085c6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001684836119d1565b600454600090801561085a5761085581611450610718565b8591906117df565b6000600f5460000361146b5750600c5490565b600f54600a54600b5461147c611055565b6114869190611f5a565b6114909190611f6d565b6114a290670de0b6b3a7640000611f6d565b6114ac9190611f84565b600c54610bdf9190611fa6565b6001600160a01b0381166000908152600560205260408120546108ca90610836565b4284101561152b5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610ecf565b60006001611537610be4565b6001600160a01b038a811660008181526007602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611643573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906116795750876001600160a01b0316816001600160a01b0316145b6116b65760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610ecf565b6001600160a01b0390811660009081526006602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6000600e54670de0b6b3a7640000600d54611738611458565b6117429190611f5a565b600f5461174f9190611f6d565b6117599190611f84565b610bdf9190611fa6565b60006108ca82611438565b6117766117fd565b600180546001600160a01b0383166001600160a01b031990911681179091556117a76000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60008260001904841183021582026117f657600080fd5b5091020490565b6000546001600160a01b03163314610f795760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ecf565b6001600160a01b038316600090815260066020908152604080832033845290915281205460001981146118b35761188e8382611f5a565b6001600160a01b03861660009081526006602090815260408083203384529091529020555b6001600160a01b038516600090815260056020526040812080548592906118db908490611f5a565b90915550506001600160a01b03808516600081815260056020526040908190208054870190555190918716906000805160206120d0833981519152906119249087815260200190565b60405180910390a3506001949350505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60026040516119699190612030565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611a495760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610ecf565b50505050565b6001611a59611458565b600c55611a64611055565b600b558015611a7f57611a7561171f565b600e55600c54600d555b81600f6000828254611a919190611fa6565b90915550505050565b6000826000190484118302158202611ab157600080fd5b50910281810615159190040190565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611b435760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610ecf565b5050505050565b8060046000828254611b5c9190611fa6565b90915550506001600160a01b0382166000818152600560209081526040808320805486019055518481526000805160206120d083398151915291015b60405180910390a35050565b610dac82611a4f565b600180546001600160a01b0319169055610ff281611ca9565b33600090815260056020526040812080548391908390611be7908490611f5a565b90915550506001600160a01b038316600081815260056020526040908190208054850190555133906000805160206120d0833981519152906108be9086815260200190565b600f54821115611c3e57611c3e610cc7565b610dac82611cf9565b6001600160a01b03821660009081526005602052604081208054839290611c6f908490611f5a565b90915550506004805482900390556040518181526000906001600160a01b038416906000805160206120d083398151915290602001611b98565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001611d03611458565b600c55611d0e611055565b600b558015611d2957611d1f61171f565b600e55600c54600d555b81600f6000828254611a919190611f5a565b600060208083528351808285015260005b81811015611d6857858101830151858201604001528201611d4c565b506000604082860101526040601f19601f8301168501019250505092915050565b600060208284031215611d9b57600080fd5b5035919050565b80356001600160a01b0381168114611db957600080fd5b919050565b60008060408385031215611dd157600080fd5b611dda83611da2565b946020939093013593505050565b600080600060608486031215611dfd57600080fd5b611e0684611da2565b9250611e1460208501611da2565b9150604084013590509250925092565b600060208284031215611e3657600080fd5b61085c82611da2565b60008060408385031215611e5257600080fd5b82359150611e6260208401611da2565b90509250929050565b600080600060608486031215611e8057600080fd5b83359250611e9060208501611da2565b9150611e9e60408501611da2565b90509250925092565b600080600080600080600060e0888a031215611ec257600080fd5b611ecb88611da2565b9650611ed960208901611da2565b95506040880135945060608801359350608088013560ff81168114611efd57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611f2d57600080fd5b611f3683611da2565b9150611e6260208401611da2565b634e487b7160e01b600052601160045260246000fd5b818103818111156108ca576108ca611f44565b80820281158282048414176108ca576108ca611f44565b600082611fa157634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156108ca576108ca611f44565b600181811c90821680611fcd57607f821691505b602082108103611fed57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561200557600080fd5b5051919050565b6000806040838503121561201f57600080fd5b505080516020909101519092909150565b600080835481600182811c91508083168061204c57607f831692505b6020808410820361206b57634e487b7160e01b86526022600452602486fd5b81801561207f5760018114612094576120c1565b60ff19861689528415158502890196506120c1565b60008a81526020902060005b868110156120b95781548b8201529085019083016120a0565b505084890196505b50949897505050505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212205a186e64a59940a031ffe11bed5c60c1720f9b37cb66f3a46488390db0f38c8564736f6c6343000813003300000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc6000000000000000000000000a52fd396891e7a74b641a2cb1a6999fcf56b077e

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103425760003560e01c806380faa57d116101b8578063c63d75b611610104578063d905777e116100a2578063e30c39781161007c578063e30c3978146106d8578063ebe2b12b146106e9578063ef8b30f7146106f2578063f2fde38b1461070557600080fd5b8063d905777e1461067b578063dd62ed3e146106a4578063df136d65146106cf57600080fd5b8063cd3daf9d116100de578063cd3daf9d14610645578063ce96cb771461064d578063d505accf14610660578063d6f192621461067357600080fd5b8063c63d75b61461048a578063c6e6f59214610629578063c8f33c911461063c57600080fd5b8063a2468c1911610171578063aa728d1c1161014b578063aa728d1c146105dd578063b3d7f6b9146105f0578063b460af9414610603578063ba0876521461061657600080fd5b8063a2468c19146105b8578063a8024b06146105c1578063a9059cbb146105ca57600080fd5b806380faa57d14610572578063817b1cd21461057a5780638da5cb5b1461058357806394bf804d1461059457806395d89b41146105a75780639ec5a894146105af57600080fd5b806338d52e0f116102925780636e553f651161023057806379ba50971161020a57806379ba50971461052e5780637b0a47ee146105365780637ecebe001461053f5780637faaa6c11461055f57600080fd5b80636e553f65146104f357806370a0823114610506578063715018a61461052657600080fd5b80634641257d1161026c5780634641257d146104b25780634bde38c8146104ba5780634cdad506146104cd5780636945c5ea146104e057600080fd5b806338d52e0f1461044b578063402d267d1461048a57806344c99e631461049f57600080fd5b806312e8e2c3116102ff57806326232a2e116102d957806326232a2e146103f9578063313ce5671461040257806335d16e171461043b5780633644e5151461044357600080fd5b806312e8e2c3146103ca57806318160ddd146103dd57806323b872dd146103e657600080fd5b806301e1d1141461034757806306fdde031461036257806307a2d13a14610377578063095ea7b31461038a5780630a28a477146103ad5780630c51dde4146103c0575b600080fd5b61034f610718565b6040519081526020015b60405180910390f35b61036a6107a8565b6040516103599190611d3b565b61034f610385366004611d89565b610836565b61039d610398366004611dbe565b610863565b6040519015158152602001610359565b61034f6103bb366004611d89565b6108d0565b6103c8610930565b005b6103c86103d8366004611d89565b610ab6565b61034f60045481565b61039d6103f4366004611de8565b610b1e565b61034f60115481565b6104297f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610359565b61034f610bcc565b61034f610be4565b6104727f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc681565b6040516001600160a01b039091168152602001610359565b61034f610498366004611e24565b5060001990565b6103c86104ad366004611e24565b610c3a565b6103c8610cc7565b601254610472906001600160a01b031681565b61034f6104db366004611d89565b610db0565b6103c86104ee366004611e24565b610e0b565b61034f610501366004611e3f565b610e88565b61034f610514366004611e24565b60056020526000908152604090205481565b6103c8610f67565b6103c8610f7b565b61034f600a5481565b61034f61054d366004611e24565b60076020526000908152604090205481565b6103c861056d366004611d89565b610ff5565b61034f611055565b61034f600f5481565b6000546001600160a01b0316610472565b61034f6105a2366004611e3f565b61106c565b61036a611108565b61034f600e5481565b61034f60105481565b61034f600d5481565b61039d6105d8366004611dbe565b611115565b600854610472906001600160a01b031681565b61034f6105fe366004611d89565b6111bf565b61034f610611366004611e6b565b6111de565b61034f610624366004611e6b565b6112ec565b61034f610637366004611d89565b611438565b61034f600b5481565b61034f611458565b61034f61065b366004611e24565b6114b9565b6103c861066e366004611ea7565b6114db565b61034f61171f565b61034f610689366004611e24565b6001600160a01b031660009081526005602052604090205490565b61034f6106b2366004611f1a565b600660209081526000928352604080842090915290825290205481565b61034f600c5481565b6001546001600160a01b0316610472565b61034f60095481565b61034f610700366004611d89565b611763565b6103c8610713366004611e24565b61176e565b600080600f5490506000600e54670de0b6b3a7640000600d54610739611458565b6107439190611f5a565b61074d9085611f6d565b6107579190611f84565b6107619190611fa6565b9050801561079457620f42406011548261077b9190611f6d565b6107859190611f84565b61078f9082611f5a565b610797565b60005b6107a19083611fa6565b9250505090565b600280546107b590611fb9565b80601f01602080910402602001604051908101604052809291908181526020018280546107e190611fb9565b801561082e5780601f106108035761010080835404028352916020019161082e565b820191906000526020600020905b81548152906001019060200180831161081157829003601f168201915b505050505081565b600454600090801561085a5761085561084d610718565b8490836117df565b61085c565b825b9392505050565b3360008181526006602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906108be9086815260200190565b60405180910390a35060015b92915050565b6000806108dc83611438565b6004549091508015806108f657506108f48282611f5a565b155b6109265760105461090a90620f4240611f5a565b610917620f424084611f6d565b6109219190611f84565b610928565b815b949350505050565b600061093a611458565b600c55610945611055565b600b5580156109605761095661171f565b600e55600c54600d555b6008546001600160a01b0316331461098b576040516321f674f160e11b815260040160405180910390fd5b600061099561171f565b600f546040516370a0823160e01b81523060048201527f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc66001600160a01b0316906370a0823190602401602060405180830381865afa1580156109fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a209190611ff3565b610a2a9190611f5a565b610a349190611f5a565b9050610a4362093a8082611f84565b600a819055600003610a6857604051630fec21fd60e21b815260040160405180910390fd5b42600b819055610a7c9062093a8090611fa6565b6009556040518181527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d9060200160405180910390a15050565b610abe6117fd565b62030d40811115610ae2576040516395e28b8560e01b815260040160405180910390fd5b60118190556040518181527f45610d581145924dd7090a5017e5f2b1d6f42213bb2e95707ff86846bbfcb1ca906020015b60405180910390a150565b6000610b2b848484611857565b506008546001600160a01b0390811690841603610bc257600854604051630feab8d160e21b8152600481018490526001600160a01b0386811660248301526000604483015290911690633faae3449060640160408051808303816000875af1158015610b9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbf919061200c565b50505b5060019392505050565b6000610bdf670de0b6b3a7640000610db0565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000014614610c1557610bdf611937565b507f0f424b340b7316ff3b8fcbeddf5ba4f68d49c6743810405feab3c0fcb5260cd990565b610c426117fd565b6001600160a01b038116610c695760405163d92e233d60e01b815260040160405180910390fd5b6040516001600160a01b03821681527f613b19ff0295024b0e961d5dcb85080a6cadacf5b531919da0faa74ec05ddedc9060200160405180910390a1600880546001600160a01b0319166001600160a01b0392909216919091179055565b6001610cd1611458565b600c55610cdc611055565b600b558015610cf757610ced61171f565b600e55600c54600d555b600e548015610dac576000600e819055601154620f424090610d199084611f6d565b610d239190611f84565b9050610d2f8183611f5a565b601254909250610d6c906001600160a01b037f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc681169116836119d1565b610d7582611a4f565b60405182815233907fc9695243a805adb74c91f28311176c65b417e842d5699893cef56d18bfa48cba9060200160405180910390a2505b5050565b600080610dbc83610836565b6004549091506000811580610dd85750610dd68583611f5a565b155b610df357601054610dee908490620f4240611a9a565b610df6565b60005b9050610e028184611f5a565b95945050505050565b610e136117fd565b6001600160a01b038116610e3a5760405163d92e233d60e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b0383169081179091556040519081527f38703bc9e5fbfe6a4ab89353328531fd2a9b9b0a4953c587bd38e559da9c29cf90602001610b13565b6000610e9383611763565b905080600003610ed85760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f53484152455360a81b60448201526064015b60405180910390fd5b610f0d6001600160a01b037f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc616333086611ac0565b610f178282611b4a565b60408051848152602081018390526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a36108ca8382611ba4565b610f6f6117fd565b610f796000611bad565b565b60015433906001600160a01b03168114610fe95760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610ecf565b610ff281611bad565b50565b610ffd6117fd565b61c350811115611020576040516395e28b8560e01b815260040160405180910390fd5b60108190556040518181527f9d5ddc6fdb90a6647fe4981fdf08b45a5f9ef6d8ea960de27bef48fb4813259290602001610b13565b60006009544210611067575060095490565b504290565b6000611077836111bf565b90506110ae6001600160a01b037f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc616333084611ac0565b6110b88284611b4a565b60408051828152602081018590526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a36108ca8184611ba4565b600380546107b590611fb9565b60006111218383611bc6565b506008546001600160a01b03908116908416036111b657600854604051630feab8d160e21b815260048101849052336024820152600060448201526001600160a01b0390911690633faae3449060640160408051808303816000875af115801561118f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b3919061200c565b50505b50600192915050565b600454600090801561085a576108556111d6610718565b849083611a9a565b60006111e9846108d0565b9050336001600160a01b03831614611259576001600160a01b03821660009081526006602090815260408083203384529091529020546000198114611257576112328282611f5a565b6001600160a01b03841660009081526006602090815260408083203384529091529020555b505b6112638482611c2c565b61126d8282611c47565b60408051858152602081018390526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a461085c6001600160a01b037f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc61684866119d1565b6000336001600160a01b0383161461135c576001600160a01b0382166000908152600660209081526040808320338452909152902054600019811461135a576113358582611f5a565b6001600160a01b03841660009081526006602090815260408083203384529091529020555b505b61136584610db0565b9050806000036113a55760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f41535345545360a81b6044820152606401610ecf565b6113af8185611c2c565b6113b98285611c47565b60408051828152602081018690526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a461085c6001600160a01b037f00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc61684836119d1565b600454600090801561085a5761085581611450610718565b8591906117df565b6000600f5460000361146b5750600c5490565b600f54600a54600b5461147c611055565b6114869190611f5a565b6114909190611f6d565b6114a290670de0b6b3a7640000611f6d565b6114ac9190611f84565b600c54610bdf9190611fa6565b6001600160a01b0381166000908152600560205260408120546108ca90610836565b4284101561152b5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610ecf565b60006001611537610be4565b6001600160a01b038a811660008181526007602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611643573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906116795750876001600160a01b0316816001600160a01b0316145b6116b65760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610ecf565b6001600160a01b0390811660009081526006602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6000600e54670de0b6b3a7640000600d54611738611458565b6117429190611f5a565b600f5461174f9190611f6d565b6117599190611f84565b610bdf9190611fa6565b60006108ca82611438565b6117766117fd565b600180546001600160a01b0383166001600160a01b031990911681179091556117a76000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60008260001904841183021582026117f657600080fd5b5091020490565b6000546001600160a01b03163314610f795760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ecf565b6001600160a01b038316600090815260066020908152604080832033845290915281205460001981146118b35761188e8382611f5a565b6001600160a01b03861660009081526006602090815260408083203384529091529020555b6001600160a01b038516600090815260056020526040812080548592906118db908490611f5a565b90915550506001600160a01b03808516600081815260056020526040908190208054870190555190918716906000805160206120d0833981519152906119249087815260200190565b60405180910390a3506001949350505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60026040516119699190612030565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611a495760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610ecf565b50505050565b6001611a59611458565b600c55611a64611055565b600b558015611a7f57611a7561171f565b600e55600c54600d555b81600f6000828254611a919190611fa6565b90915550505050565b6000826000190484118302158202611ab157600080fd5b50910281810615159190040190565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611b435760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610ecf565b5050505050565b8060046000828254611b5c9190611fa6565b90915550506001600160a01b0382166000818152600560209081526040808320805486019055518481526000805160206120d083398151915291015b60405180910390a35050565b610dac82611a4f565b600180546001600160a01b0319169055610ff281611ca9565b33600090815260056020526040812080548391908390611be7908490611f5a565b90915550506001600160a01b038316600081815260056020526040908190208054850190555133906000805160206120d0833981519152906108be9086815260200190565b600f54821115611c3e57611c3e610cc7565b610dac82611cf9565b6001600160a01b03821660009081526005602052604081208054839290611c6f908490611f5a565b90915550506004805482900390556040518181526000906001600160a01b038416906000805160206120d083398151915290602001611b98565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001611d03611458565b600c55611d0e611055565b600b558015611d2957611d1f61171f565b600e55600c54600d555b81600f6000828254611a919190611f5a565b600060208083528351808285015260005b81811015611d6857858101830151858201604001528201611d4c565b506000604082860101526040601f19601f8301168501019250505092915050565b600060208284031215611d9b57600080fd5b5035919050565b80356001600160a01b0381168114611db957600080fd5b919050565b60008060408385031215611dd157600080fd5b611dda83611da2565b946020939093013593505050565b600080600060608486031215611dfd57600080fd5b611e0684611da2565b9250611e1460208501611da2565b9150604084013590509250925092565b600060208284031215611e3657600080fd5b61085c82611da2565b60008060408385031215611e5257600080fd5b82359150611e6260208401611da2565b90509250929050565b600080600060608486031215611e8057600080fd5b83359250611e9060208501611da2565b9150611e9e60408501611da2565b90509250925092565b600080600080600080600060e0888a031215611ec257600080fd5b611ecb88611da2565b9650611ed960208901611da2565b95506040880135945060608801359350608088013560ff81168114611efd57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611f2d57600080fd5b611f3683611da2565b9150611e6260208401611da2565b634e487b7160e01b600052601160045260246000fd5b818103818111156108ca576108ca611f44565b80820281158282048414176108ca576108ca611f44565b600082611fa157634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156108ca576108ca611f44565b600181811c90821680611fcd57607f821691505b602082108103611fed57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561200557600080fd5b5051919050565b6000806040838503121561201f57600080fd5b505080516020909101519092909150565b600080835481600182811c91508083168061204c57607f831692505b6020808410820361206b57634e487b7160e01b86526022600452602486fd5b81801561207f5760018114612094576120c1565b60ff19861689528415158502890196506120c1565b60008a81526020902060005b868110156120b95781548b8201529085019083016120a0565b505084890196505b50949897505050505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212205a186e64a59940a031ffe11bed5c60c1720f9b37cb66f3a46488390db0f38c8564736f6c63430008130033

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

00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc6000000000000000000000000a52fd396891e7a74b641a2cb1a6999fcf56b077e

-----Decoded View---------------
Arg [0] : _asset (address): 0x04C154b66CB340F3Ae24111CC767e0184Ed00Cc6
Arg [1] : _platform (address): 0xA52Fd396891E7A74b641a2Cb1A6999Fcf56B077e

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000004c154b66cb340f3ae24111cc767e0184ed00cc6
Arg [1] : 000000000000000000000000a52fd396891e7a74b641a2cb1a6999fcf56b077e


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

Pirex ETH, developed by Redacted, offers a user-friendly, liquid staking solution that serves as the foundation for the Dinero protocol. apxETH is an ERC-4626 vault that allows users to stake and unstake pxETH tokens, issuing/redeeming apxETH share tokens in return while autocompounding the yield.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.