ETH Price: $1,584.14 (-0.48%)
Gas: 0.37 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Instant Withdraw222909722025-04-17 20:01:596 hrs ago1744920119IN
0xFC1db086...E9980A5e1
0 ETH0.000687911.7
Instant Withdraw222908672025-04-17 19:40:597 hrs ago1744918859IN
0xFC1db086...E9980A5e1
0 ETH0.000768871.9
Instant Withdraw222906902025-04-17 19:05:117 hrs ago1744916711IN
0xFC1db086...E9980A5e1
0 ETH0.000440811.01337831
Instant Withdraw222906742025-04-17 19:01:597 hrs ago1744916519IN
0xFC1db086...E9980A5e1
0 ETH0.000426290.97999915
Instant Withdraw222844612025-04-16 22:12:2328 hrs ago1744841543IN
0xFC1db086...E9980A5e1
0 ETH0.000165420.44674591
Instant Withdraw222840222025-04-16 20:44:1129 hrs ago1744836251IN
0xFC1db086...E9980A5e1
0 ETH0.001045792.40823328
Instant Withdraw222771602025-04-15 21:46:352 days ago1744753595IN
0xFC1db086...E9980A5e1
0 ETH0.000653211.5
Instant Withdraw222703712025-04-14 23:00:233 days ago1744671623IN
0xFC1db086...E9980A5e1
0 ETH0.000118810.87447419
Request Withdraw222695952025-04-14 20:24:593 days ago1744662299IN
0xFC1db086...E9980A5e1
0 ETH0.000062920.65914419
Deposit222685772025-04-14 17:00:113 days ago1744650011IN
0xFC1db086...E9980A5e1
0.04481116 ETH0.00053693.78793123
Deposit222684832025-04-14 16:41:233 days ago1744648883IN
0xFC1db086...E9980A5e1
0.0159915 ETH0.000616564.34994211
Deposit222684642025-04-14 16:37:353 days ago1744648655IN
0xFC1db086...E9980A5e1
0.01765894 ETH0.000431854.43646811
Deposit222684342025-04-14 16:31:233 days ago1744648283IN
0xFC1db086...E9980A5e1
0.01973441 ETH0.000622784.39381571
Deposit222609402025-04-13 15:26:474 days ago1744558007IN
0xFC1db086...E9980A5e1
0.05064787 ETH0.000189421.51971381
Deposit222608012025-04-13 14:58:594 days ago1744556339IN
0xFC1db086...E9980A5e1
0.1 ETH0.000108820.76770574
Deposit222606952025-04-13 14:37:474 days ago1744555067IN
0xFC1db086...E9980A5e1
0.1 ETH0.000083940.86222672
Deposit222606922025-04-13 14:37:114 days ago1744555031IN
0xFC1db086...E9980A5e1
0.1 ETH0.000087610.9
Deposit222594432025-04-13 10:26:114 days ago1744539971IN
0xFC1db086...E9980A5e1
0.1 ETH0.000099220.7
Deposit222332842025-04-09 18:56:598 days ago1744225019IN
0xFC1db086...E9980A5e1
0.055 ETH0.0025088317.7
Request Withdraw222194022025-04-07 20:27:5910 days ago1744057679IN
0xFC1db086...E9980A5e1
0 ETH0.00014741.54401443
Request Withdraw222188262025-04-07 18:31:2310 days ago1744050683IN
0xFC1db086...E9980A5e1
0 ETH0.000250562.62452485
Deposit222179362025-04-07 15:32:4710 days ago1744039967IN
0xFC1db086...E9980A5e1
0.00199973 ETH0.000827685.83935157
Instant Withdraw222102332025-04-06 13:41:2311 days ago1743946883IN
0xFC1db086...E9980A5e1
0 ETH0.000321770.73963571
Instant Withdraw222094382025-04-06 11:01:2311 days ago1743937283IN
0xFC1db086...E9980A5e1
0 ETH0.000279450.64199528
Deposit222049062025-04-05 19:49:3512 days ago1743882575IN
0xFC1db086...E9980A5e1
0.0015 ETH0.000128910.9094704
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer*222685772025-04-14 17:00:113 days ago1744650011
0xFC1db086...E9980A5e1
0.04481116 ETH
Transfer*222684832025-04-14 16:41:233 days ago1744648883
0xFC1db086...E9980A5e1
0.0159915 ETH
Transfer*222684342025-04-14 16:31:233 days ago1744648283
0xFC1db086...E9980A5e1
0.01973441 ETH
Transfer*222609402025-04-13 15:26:474 days ago1744558007
0xFC1db086...E9980A5e1
0.05064787 ETH
Transfer*222608012025-04-13 14:58:594 days ago1744556339
0xFC1db086...E9980A5e1
0.1 ETH
Transfer*222594432025-04-13 10:26:114 days ago1744539971
0xFC1db086...E9980A5e1
0.1 ETH
Transfer*222332842025-04-09 18:56:598 days ago1744225019
0xFC1db086...E9980A5e1
0.055 ETH
Transfer*222179362025-04-07 15:32:4710 days ago1744039967
0xFC1db086...E9980A5e1
0.00199973 ETH
Transfer*222049062025-04-05 19:49:3512 days ago1743882575
0xFC1db086...E9980A5e1
0.0015 ETH
Transfer*222040962025-04-05 17:06:2312 days ago1743872783
0xFC1db086...E9980A5e1
0.005 ETH
Transfer*222028642025-04-05 12:58:4712 days ago1743857927
0xFC1db086...E9980A5e1
0.1335 ETH
Transfer*221904322025-04-03 19:20:1114 days ago1743708011
0xFC1db086...E9980A5e1
0.00193477 ETH
Transfer*221889012025-04-03 14:12:3514 days ago1743689555
0xFC1db086...E9980A5e1
0.01 ETH
Transfer*221842372025-04-02 22:32:5915 days ago1743633179
0xFC1db086...E9980A5e1
0.00307544 ETH
Transfer*221841982025-04-02 22:25:1115 days ago1743632711
0xFC1db086...E9980A5e1
0.002 ETH
Transfer*221841682025-04-02 22:19:1115 days ago1743632351
0xFC1db086...E9980A5e1
0.002 ETH
Transfer*221841682025-04-02 22:19:1115 days ago1743632351
0xFC1db086...E9980A5e1
0.00342196 ETH
Transfer*221818352025-04-02 14:30:3515 days ago1743604235
0xFC1db086...E9980A5e1
0.01 ETH
Transfer*221765162025-04-01 20:42:4716 days ago1743540167
0xFC1db086...E9980A5e1
0.029 ETH
Transfer*221761912025-04-01 19:37:1116 days ago1743536231
0xFC1db086...E9980A5e1
0.00365 ETH
Transfer*221572052025-03-30 4:01:2318 days ago1743307283
0xFC1db086...E9980A5e1
0.00000286 ETH
Deposit221572052025-03-30 4:01:2318 days ago1743307283
0xFC1db086...E9980A5e1
0.00000286 ETH
Transfer*221279952025-03-26 2:09:1123 days ago1742954951
0xFC1db086...E9980A5e1
0.024 ETH
Transfer*221207962025-03-25 2:00:1124 days ago1742868011
0xFC1db086...E9980A5e1
0.025 ETH
Transfer*220883092025-03-20 13:15:3528 days ago1742476535
0xFC1db086...E9980A5e1
0.015 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RealVault

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
shanghai EvmVersion
File 1 of 13 : RealVault.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC4626.sol

import {ReentrancyGuard} from "oz/utils/ReentrancyGuard.sol";
import {Ownable} from "oz/access/Ownable.sol";
import {Ownable2Step} from "oz/access/Ownable2Step.sol";
import {TransferHelper} from "v3-periphery/libraries/TransferHelper.sol";
import {IReal} from "./interfaces/IReal.sol";
import {IMinter} from "./interfaces/IMinter.sol";
import {IAssetsVault} from "./interfaces/IAssetsVault.sol";
import {IStrategyManager} from "./interfaces/IStrategyManager.sol";
import {ShareMath} from "./libraries/ShareMath.sol";

/**
 * @title Real Ether Vault (reETH)
 * @author Mavvverick
 * @notice The Real Vault (reETH) is responsible for managing deposit, withdrawal, and settlement processes
 * using ERC4626 standard. Users can deposit ETH into the Vault, where it is held securely until settlement,
 * thereby participating in the yield generation process and receiving rewards as reETH token holders.
 * Upon settlement, funds are deployed to the underlying strategy pool for yield generation.The Vault ensures
 * the security of deposited assets and facilitates seamless interactions within the Real Network ecosystem.
 * Users can interact with the Vault to deposit, withdraw, and settle RealETH tokens, contributing to the
 * stability and growth of the platform. Additionally, the Vault's architecture provides flexibility for
 * future yield staking /re-staking strategy and optimizations, ensuring its continued effectiveness in
 * managing assets and supporting the Real Network infrastructure.
 */
contract RealVault is ReentrancyGuard, Ownable2Step {
    uint256 internal constant ONE = 1;
    uint256 internal constant MULTIPLIER = 10 ** 18;
    uint256 internal constant ONE_HUNDRED_PERCENT = 100_0000;
    uint256 internal constant MAXMIUM_FEE_RATE = ONE_HUNDRED_PERCENT / 100; // 1%
    uint256 internal constant MINIMUM_REBASE_INTERVAL = 60 * 60; // 1hour
    uint256 internal constant NUMBER_OF_DEAD_SHARES = 10 ** 15;

    uint256 public minWithdrawableShares = 1_00;
    uint256 public rebaseTimeInterval = 24 * 60 * 60; // 1 day
    uint256 public rebaseTime;

    address public immutable minter;
    address public immutable real;
    address payable public immutable assetsVault;
    address payable public immutable strategyManager;

    address public proposal;
    address public feeRecipient;

    uint256 public latestRoundID;
    uint256 public withdrawFeeRate;

    uint256 public withdrawableAmountInPast;
    uint256 public withdrawingSharesInPast;
    uint256 public withdrawingSharesInRound;
    uint256 public withdrawAmountDust;

    /// @notice On every round's close, the pricePerShare value of an real token is stored
    /// This is used to determine the number of shares to be returned
    /// to a user at the time of minting
    mapping(uint256 => uint256) public roundPricePerShare;
    mapping(uint256 => uint256) public settlementTime;
    mapping(address => WithdrawReceipt) public userReceipts;

    struct WithdrawReceipt {
        uint256 withdrawRound;
        uint256 withdrawShares;
        uint256 withdrawableAmount;
    }

    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
    event InitiateWithdraw(address indexed account, uint256 shares, uint256 round);
    event CancelWithdraw(address indexed account, uint256 amount, uint256 round);
    event Withdrawn(address indexed account, uint256 amount, uint256 round);
    event WithdrawnFromStrategy(
        address indexed account, uint256 amount, uint256 actualAmount, uint256 totalAmount, uint256 round
    );
    event RollToNextRound(uint256 indexed round, uint256 vaultIn, uint256 vaultOut, uint256 sharePrice);
    event VaultMigrated(address indexed oldVault, address newVault);
    event StrategyAdded(address indexed strategy);
    event StrategyDestroyed(address indexed strategy);
    event StrategyCleared(address indexed strategy);
    event InvestmentPortfolioUpdated(address[] indexed strategies, uint256[] indexed ratios);
    event FeeCharged(address indexed account, uint256 amount);
    event SetWithdrawFeeRate(uint256 indexed oldRate, uint256 newRate);
    event SetFeeRecipient(address indexed oldAddr, address newAddr);
    event SetRebaseInterval(uint256 indexed interval);
    event SettleWithdrawDust(uint256 indexed dust);
    event MinWithdrawableSharesUpdated(uint256 indexed minShares);
    event ProposalUpdated(address indexed oldAddr, address newAddr);

    error RealVault__NotReady();
    error RealVault__Migrated();
    error RealVault__InsufficientShares();
    error RealVault__InvalidAmount();
    error RealVault__ZeroAddress();
    error RealVault__MininmumWithdraw();
    error RealVault__WithdrawInstantly();
    error RealVault__NoRequestFound();
    error RealVault__NotProposal();
    error RealVault__ExceedBalance();
    error RealVault__WaitInQueue();
    error RealVault__MinimumWithdrawableShares();
    error RealVault__ExceedRequestedAmount(uint256 requestedAmount, uint256 actualAmount);
    error RealVault__ExceedWithdrawAmount();
    error RealVault__ExceedMaxFeeRate(uint256 _feeRate);
    error RealVault__MinimumRebaseInterval(uint256 minInterval);

    /**
     * @param _intialOwner Address of the initial owner of the contract.
     * @param _minter Address of the minter contract.
     * @param _assetsVault Address of the assets vault contract.
     * @param _strategyManager Address of the strategy manager contract.
     * @param _proposal Address of the proposal contract.
     */
    constructor(
        address _intialOwner,
        address _minter,
        address payable _assetsVault,
        address payable _strategyManager,
        address _proposal
    ) payable Ownable(_intialOwner) {
        if (_proposal == address(0) || _assetsVault == address(0) || _strategyManager == address(0)) {
            revert RealVault__ZeroAddress();
        }

        minter = _minter;
        proposal = _proposal;
        assetsVault = _assetsVault;
        strategyManager = _strategyManager;

        real = IMinter(_minter).real();
        rebaseTime = block.timestamp;

        // mint dead shares
        if (IReal(real).totalSupply() == 0) {
            TransferHelper.safeTransferETH(assetsVault, NUMBER_OF_DEAD_SHARES);
            IMinter(minter).mint(address(0xdead), NUMBER_OF_DEAD_SHARES);
        }
    }

    /**
     * @dev Modifier to restrict access to only the proposal contract.
     */
    modifier onlyProposal() {
        if (proposal != msg.sender) revert RealVault__NotProposal();
        _;
    }

    /**
     * @dev Deposit assets into the RealVault.
     * @return mintAmount The amount of shares minted.
     */
    function deposit(uint256 mintAmountMin) external payable nonReentrant returns (uint256 mintAmount) {
        mintAmount = _depositFor(msg.sender, msg.sender, msg.value, mintAmountMin);
    }

    /**
     * @dev Deposit assets into the RealVault on behalf of another address.
     * @param receiver Address to receive the minted shares.
     * @return mintAmount The amount of shares minted.
     */
    function depositFor(address receiver, uint256 mintAmountMin)
        external
        payable
        nonReentrant
        returns (uint256 mintAmount)
    {
        mintAmount = _depositFor(msg.sender, receiver, msg.value, mintAmountMin);
    }

    /**
     * @dev Initiate a withdrawal request for a specified number of shares.
     * @param _shares Number of shares to withdraw.
     */
    function requestWithdraw(uint256 _shares) external nonReentrant {
        if (_shares == 0) revert RealVault__InvalidAmount();
        if (_shares < minWithdrawableShares) revert RealVault__MininmumWithdraw();

        uint256 _latestRoundID = latestRoundID;

        if (_latestRoundID == 0) revert RealVault__WithdrawInstantly();

        IReal realToken = IReal(real);
        IMinter realEthMinter = IMinter(minter);

        if (realToken.balanceOf(msg.sender) < _shares) revert RealVault__ExceedBalance();
        TransferHelper.safeTransferFrom(real, msg.sender, address(this), _shares);

        withdrawingSharesInRound = withdrawingSharesInRound + _shares;
        WithdrawReceipt memory mReceipt = userReceipts[msg.sender];

        if (mReceipt.withdrawRound == _latestRoundID) {
            mReceipt.withdrawShares = mReceipt.withdrawShares + _shares;
        } else if (mReceipt.withdrawRound == 0) {
            mReceipt.withdrawShares = _shares;
            mReceipt.withdrawRound = _latestRoundID;
        } else {
            // Withdraw previous round share first
            mReceipt = _updateUserReceipt(mReceipt, realEthMinter, _shares, _latestRoundID);
        }

        userReceipts[msg.sender] = mReceipt;
        emit InitiateWithdraw(msg.sender, _shares, _latestRoundID);
    }

    /**
     * @dev Cancel a pending withdrawal request.
     * @param _shares Number of shares to cancel the withdrawal for.
     */
    function cancelWithdraw(uint256 _shares) external nonReentrant {
        if (_shares == 0) revert RealVault__InvalidAmount();

        WithdrawReceipt memory mReceipt = userReceipts[msg.sender];
        uint256 _latestRoundID = latestRoundID;

        if (mReceipt.withdrawRound != _latestRoundID) revert RealVault__NoRequestFound();
        if (_shares > mReceipt.withdrawShares) {
            revert RealVault__ExceedRequestedAmount(_shares, mReceipt.withdrawShares);
        }

        unchecked {
            mReceipt.withdrawShares -= _shares;
        }

        // check minimum shares request
        if (mReceipt.withdrawShares != 0 && mReceipt.withdrawShares < minWithdrawableShares) {
            revert RealVault__MininmumWithdraw();
        }

        TransferHelper.safeTransfer(real, msg.sender, _shares);

        if (mReceipt.withdrawShares == 0) {
            mReceipt.withdrawRound = 0;
        }

        userReceipts[msg.sender] = mReceipt;
        withdrawingSharesInRound = withdrawingSharesInRound - _shares;

        emit CancelWithdraw(msg.sender, _shares, _latestRoundID);
    }

    /**
     * @dev Withdraw assets instantly or after a delay, depending on availability.
     * @param _amount Amount of assets to withdraw.
     * @param _shares Number of shares to withdraw.
     * @return actualWithdrawn The actual amount of assets withdrawn.
     */
    function instantWithdraw(uint256 _amount, uint256 _shares)
        external
        nonReentrant
        returns (uint256 actualWithdrawn)
    {
        if (_amount == 0 && _shares == 0) revert RealVault__InvalidAmount();

        IAssetsVault aVault = IAssetsVault(assetsVault);
        IMinter realEthMinter = IMinter(minter);

        uint256 _latestRoundID = latestRoundID;
        (uint256 idleAmount,) = getVaultAvailableAmount();

        if (_amount != 0) {
            WithdrawReceipt memory mReceipt = userReceipts[msg.sender];

            if (mReceipt.withdrawRound != _latestRoundID && mReceipt.withdrawRound != 0) {
                // Withdraw previous round share first
                mReceipt = _updateUserReceipt(mReceipt, realEthMinter, 0, 0);
            }

            if (mReceipt.withdrawableAmount < _amount) revert RealVault__ExceedWithdrawAmount();

            unchecked {
                mReceipt.withdrawableAmount -= _amount;
            }

            userReceipts[msg.sender] = mReceipt;

            withdrawableAmountInPast = withdrawableAmountInPast - _amount;
            actualWithdrawn = _amount;

            emit Withdrawn(msg.sender, _amount, _latestRoundID);
        }

        if (_shares != 0) {
            uint256 sharePrice;

            if (_latestRoundID == 0) {
                sharePrice = MULTIPLIER;
            } else {
                uint256 currSharePrice = currentSharePrice();
                uint256 latestSharePrice;

                unchecked {
                    latestSharePrice = roundPricePerShare[_latestRoundID - ONE];
                }
                sharePrice = latestSharePrice < currSharePrice ? latestSharePrice : currSharePrice;
            }

            uint256 ethAmount = ShareMath.sharesToAsset(_shares, sharePrice);

            realEthMinter.burn(msg.sender, _shares);

            if (ethAmount <= idleAmount) {
                actualWithdrawn = actualWithdrawn + ethAmount;

                emit Withdrawn(msg.sender, ethAmount, _latestRoundID);
            } else {
                actualWithdrawn = actualWithdrawn + idleAmount;

                unchecked {
                    ethAmount = ethAmount - idleAmount;
                }

                IStrategyManager manager = IStrategyManager(strategyManager);
                // if strategy sells the LSD token on the decentralized exchange (DEX),
                // deducting swap fees from the requested amount.
                uint256 actualAmount = manager.forceWithdraw(ethAmount);

                actualWithdrawn = actualWithdrawn + actualAmount;

                emit WithdrawnFromStrategy(msg.sender, ethAmount, actualAmount, actualWithdrawn, _latestRoundID);
            }
        }

        if (aVault.getBalance() < actualWithdrawn) revert RealVault__WaitInQueue();

        uint256 withFee;
        if (withdrawFeeRate != 0) {
            withFee = (actualWithdrawn * withdrawFeeRate) / ONE_HUNDRED_PERCENT;
            aVault.withdraw(feeRecipient, withFee);

            emit FeeCharged(msg.sender, withFee);
        }
        unchecked {
            aVault.withdraw(msg.sender, actualWithdrawn - withFee);
        }
    }

    /**
     * @dev Rebalances the strategies without incoming and outgoing amounts.
     */
    function onlyRebaseStrategies() external nonReentrant onlyProposal {
        IStrategyManager(strategyManager).onlyRebaseStrategies();
    }

    /**
     * @dev Transition to the next round, managing vault balances and share prices.
     */
    function rollToNextRound() external nonReentrant {
        if (block.timestamp < rebaseTime + rebaseTimeInterval) revert RealVault__NotReady();
        rebaseTime = block.timestamp;

        IStrategyManager manager = IStrategyManager(strategyManager);
        IAssetsVault aVault = IAssetsVault(assetsVault);
        uint256 previewSharePrice = currentSharePrice();

        uint256 vaultBalance = aVault.getBalance();
        uint256 amountToWithdraw = ShareMath.sharesToAsset(withdrawingSharesInRound, previewSharePrice);
        uint256 amountVaultNeed = withdrawableAmountInPast + amountToWithdraw;
        uint256 allPendingValue = manager.getAllStrategyPendingValue();

        uint256 vaultIn;
        uint256 vaultOut;

        if (vaultBalance > amountVaultNeed) {
            unchecked {
                vaultIn = vaultBalance - amountVaultNeed;
            }
        } else if (vaultBalance + allPendingValue < amountVaultNeed) {
            unchecked {
                vaultOut = amountVaultNeed - vaultBalance - allPendingValue;
            }
        }

        manager.rebaseStrategies(vaultIn, vaultOut);

        uint256 _latestRoundID = latestRoundID;
        uint256 newSharePrice = currentSharePrice();
        roundPricePerShare[_latestRoundID] = previewSharePrice < newSharePrice ? previewSharePrice : newSharePrice;

        settlementTime[_latestRoundID] = block.timestamp;
        unchecked {
            latestRoundID = _latestRoundID + ONE;
        }

        withdrawingSharesInPast = withdrawingSharesInPast + withdrawingSharesInRound;
        withdrawableAmountInPast =
            withdrawableAmountInPast + ShareMath.sharesToAsset(withdrawingSharesInRound, newSharePrice);
        withdrawingSharesInRound = 0;
        emit RollToNextRound(latestRoundID, vaultIn, vaultOut, newSharePrice);
    }

    /**
     * @dev Migrate the vault to a new contract.
     * @param _vault Address of the new vault.
     */
    function migrateVault(address _vault) external onlyProposal {
        IMinter(minter).setNewVault(_vault);
        IAssetsVault(assetsVault).setNewVault(_vault);
        IStrategyManager(strategyManager).setNewVault(_vault);

        // migrate pending withdrawals by transferring any real token balance held by the contract
        // to the new implementation which should manually migrate userReceipts entries.
        IReal realToken = IReal(real);
        uint256 balance = realToken.balanceOf(address(this));
        if (balance > 0) TransferHelper.safeTransfer(real, _vault, balance);

        emit VaultMigrated(address(this), _vault);
    }

    /**
     * @dev Add a new strategy to the strategy manager.
     * @param _strategy Address of the new strategy.
     */
    function addStrategy(address _strategy) external onlyProposal {
        IStrategyManager manager = IStrategyManager(strategyManager);

        manager.addStrategy(_strategy);
        emit StrategyAdded(_strategy);
    }

    /**
     * @dev Destroy a strategy from the strategy manager.
     * Funds must be returned to the asset valut from the strategy before destroyin the strategy.
     * @param _strategy Address of the strategy to destroy.
     */
    function destroyStrategy(address _strategy) external onlyOwner {
        IStrategyManager manager = IStrategyManager(strategyManager);

        manager.destroyStrategy(_strategy);
        emit StrategyDestroyed(_strategy);
    }

    /**
     * @dev Clear a strategy from the vault.
     * Invested funds will be returned to the asset valut from the strategy
     * @param _strategy Address of the strategy to clear.
     */
    function clearStrategy(address _strategy) external onlyOwner {
        IStrategyManager manager = IStrategyManager(strategyManager);

        manager.clearStrategy(_strategy);
        emit StrategyCleared(_strategy);
    }

    /**
     * @dev Update the investment portfolio of the vault.
     * Set the strategy and potfolio allocation ratio in the manager.
     * Previous strategy ratios will set to zero before applying the new allocation ratio.
     * @param _strategies Array of addresses representing the new strategies.
     * @param _ratios Array of ratios corresponding to the strategies.
     */
    function updateInvestmentPortfolio(address[] memory _strategies, uint256[] memory _ratios) external onlyProposal {
        IStrategyManager manager = IStrategyManager(strategyManager);

        manager.setStrategies(_strategies, _ratios);

        emit InvestmentPortfolioUpdated(_strategies, _ratios);
    }

    /**
     * @dev Update the address of the proposal contract or multisig.
     * @param _proposal Address of the new proposal contract or multisig.
     */
    function updateProposal(address _proposal) external onlyProposal {
        if (_proposal == address(0)) revert RealVault__ZeroAddress();
        emit ProposalUpdated(proposal, _proposal);
        proposal = _proposal;
    }

    function settleWithdrawDust(uint256 amount) external {
        uint256 _withdrawAmountDust = withdrawAmountDust;
        if (_withdrawAmountDust < MULTIPLIER) revert RealVault__InvalidAmount();
        if (amount > _withdrawAmountDust) revert RealVault__ExceedBalance();
        withdrawableAmountInPast -= amount;
        withdrawAmountDust -= amount;
        emit SettleWithdrawDust(amount);
    }

    // [INTERNAL FUNCTIONS]
    function _depositFor(address caller, address receiver, uint256 assets, uint256 mintAmountMin)
        internal
        returns (uint256 mintAmount)
    {
        if (assets == 0) revert RealVault__InvalidAmount();

        mintAmount = previewDeposit(address(this).balance); // shares amount to be minted
        if (mintAmount < mintAmountMin) revert RealVault__InsufficientShares();

        IAssetsVault(assetsVault).deposit{value: address(this).balance}();
        IMinter(minter).mint(receiver, mintAmount);
        emit Deposit(caller, receiver, assets, mintAmount);
    }

    function _updateUserReceipt(
        WithdrawReceipt memory mReceipt,
        IMinter realEthMinter,
        uint256 _shares,
        uint256 _latestRoundID
    ) private returns (WithdrawReceipt memory) {
        uint256 pps = roundPricePerShare[mReceipt.withdrawRound];
        uint256 withdrawAmount = ShareMath.sharesToAsset(mReceipt.withdrawShares, pps);
        uint256 convertedShares = ShareMath.assetToShares(withdrawAmount, pps);

        if (withdrawAmount > 0 && convertedShares < mReceipt.withdrawShares) {
            // Default is to round down (Solidity), track dust for withdrawAmount
            withdrawAmountDust++;
        }

        realEthMinter.burn(address(this), mReceipt.withdrawShares);
        withdrawingSharesInPast = withdrawingSharesInPast - mReceipt.withdrawShares;

        mReceipt.withdrawShares = _shares;
        mReceipt.withdrawableAmount = mReceipt.withdrawableAmount + withdrawAmount;

        mReceipt.withdrawRound = _latestRoundID;
        return mReceipt;
    }

    // [SETTER FUNCTIONS]

    /**
     * @dev Sets the withdrawal fee rate.
     * @param _withdrawFeeRate The new withdrawal fee rate.
     * Requirements:
     * - The new fee rate must not exceed the maximum fee rate.
     */
    function setWithdrawFeeRate(uint256 _withdrawFeeRate) external onlyOwner {
        if (_withdrawFeeRate > MAXMIUM_FEE_RATE) revert RealVault__ExceedMaxFeeRate(_withdrawFeeRate);

        emit SetWithdrawFeeRate(withdrawFeeRate, _withdrawFeeRate);

        withdrawFeeRate = _withdrawFeeRate;
    }

    /**
     * @dev Sets the fee recipient address.
     * @param _feeRecipient The new fee recipient address.
     * Requirements:
     * - The new fee recipient address must not be the zero address.
     */
    function setFeeRecipient(address _feeRecipient) external onlyOwner {
        if (_feeRecipient == address(0)) revert RealVault__ZeroAddress();

        emit SetFeeRecipient(feeRecipient, _feeRecipient);

        feeRecipient = _feeRecipient;
    }

    /**
     * @dev Sets the rebase interval.
     * @param _interval The new rebase interval.
     * Requirements:
     * - The new interval must not be less than the minimum rebase interval.
     */
    function setRebaseInterval(uint256 _interval) external onlyOwner {
        if (_interval < MINIMUM_REBASE_INTERVAL) revert RealVault__MinimumRebaseInterval(MINIMUM_REBASE_INTERVAL);
        rebaseTimeInterval = _interval;
        emit SetRebaseInterval(rebaseTimeInterval);
    }

    /**
     * @dev Sets the minimum withdrawable shares.
     * @param _minWithdrawableShares The new minimum withdrawable shares.
     * Requirements:
     * - The new minimum must not be less than the 100 wei.
     */
    function setMinWithdrawableShares(uint256 _minWithdrawableShares) external onlyOwner {
        if (_minWithdrawableShares < 1_00) revert RealVault__MinimumWithdrawableShares();
        minWithdrawableShares = _minWithdrawableShares;
        emit MinWithdrawableSharesUpdated(_minWithdrawableShares);
    }

    // [VIEW FUNCTIONS]

    /**
     * @dev Calculates the number of shares corresponding to a given asset amount.
     * @param assets The amount of assets to calculate shares for.
     * @return The number of shares.
     */
    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        uint256 sharePrice;
        if (latestRoundID == 0) {
            sharePrice = MULTIPLIER;
        } else {
            uint256 currSharePrice = currentSharePrice();
            uint256 latestSharePrice;
            unchecked {
                latestSharePrice = roundPricePerShare[latestRoundID - ONE];
            }
            sharePrice = latestSharePrice > currSharePrice ? latestSharePrice : currSharePrice;
        }

        return ShareMath.assetToShares(assets, sharePrice);
    }

    /**
     * @dev Retrieves the current share price.
     * Send a certain amount of shares to the blackhole address when the protocol accepts
     * deposits for the first time. https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706
     * @return price current share price.
     */
    function currentSharePrice() public view returns (uint256 price) {
        IReal realToken = IReal(real);
        uint256 totalReal = realToken.totalSupply();
        if (latestRoundID == 0) {
            return MULTIPLIER;
        }

        uint256 etherAmount = IAssetsVault(assetsVault).getBalance()
            + IStrategyManager(strategyManager).getAllStrategiesValue() - withdrawableAmountInPast;
        uint256 activeShare = totalReal - withdrawingSharesInPast;
        return (etherAmount * MULTIPLIER) / activeShare;
    }

    /**
     * @dev Retrieves the available amount in the vault.
     * @return idleAmount idle amount amount in the vault.
     * @return investedAmount invested amount in the vault.
     */
    function getVaultAvailableAmount() public view returns (uint256 idleAmount, uint256 investedAmount) {
        IAssetsVault vault = IAssetsVault(assetsVault);

        if (vault.getBalance() > withdrawableAmountInPast) {
            unchecked {
                idleAmount = vault.getBalance() - withdrawableAmountInPast;
            }
        }

        investedAmount = IStrategyManager(strategyManager).getTotalInvestedValue();
    }

    receive() external payable {}
}

File 2 of 13 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 3 of 13 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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 4 of 13 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {Ownable} from "./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.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. 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();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

File 5 of 13 : TransferHelper.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

library TransferHelper {
    /// @notice Transfers tokens from the targeted address to the given destination
    /// @notice Errors with 'STF' if transfer fails
    /// @param token The contract address of the token to be transferred
    /// @param from The originating address from which the tokens will be transferred
    /// @param to The destination address of the transfer
    /// @param value The amount to be transferred
    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
    }

    /// @notice Transfers tokens from msg.sender to a recipient
    /// @dev Errors with ST if transfer fails
    /// @param token The contract address of the token which will be transferred
    /// @param to The recipient of the transfer
    /// @param value The value of the transfer
    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors with 'SA' if transfer fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
    }

    /// @notice Transfers ETH to the recipient address
    /// @dev Fails with `STE`
    /// @param to The destination of the transfer
    /// @param value The value to be transferred
    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'STE');
    }
}

File 6 of 13 : IReal.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

import {IERC20} from "oz/token/ERC20/IERC20.sol";

/**
 * @title Real Interface
 * @dev Interface for a token contract representing real-world assets.
 */
interface IReal is IERC20 {
    /**
     * @dev Mints tokens and assigns them to the specified address.
     * @param _to The address to which the minted tokens will be assigned.
     * @param _amount The amount of tokens to mint.
     */
    function mint(address _to, uint256 _amount) external;

    /**
     * @dev Burns tokens from the specified address.
     * @param _from The address from which tokens will be burned.
     * @param _amount The amount of tokens to burn.
     */
    function burn(address _from, uint256 _amount) external;
}

File 7 of 13 : IMinter.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

/**
 * @title Minter Interface
 * @dev Interface for a contract responsible for minting and burning tokens.
 */
interface IMinter {
    /**
     * @dev Sets a new vault address.
     * @param _vault The address of the new vault.
     */
    function setNewVault(address _vault) external;

    /**
     * @dev Mints tokens and assigns them to the specified address.
     * @param _to The address to which the minted tokens will be assigned.
     * @param _amount The amount of tokens to mint.
     */
    function mint(address _to, uint256 _amount) external;

    /**
     * @dev Burns tokens from the specified address.
     * @param _from The address from which tokens will be burned.
     * @param _amount The amount of tokens to burn.
     */
    function burn(address _from, uint256 _amount) external;

    /**
     * @dev Gets the address of the real token.
     * @return The address of the real token.
     */
    function real() external view returns (address);

    /**
     * @dev Gets the address of the real token vault.
     * @return The address of the real token vault.
     */
    function vault() external view returns (address);

    /**
     * @dev Gets the price of the token.
     * @return price The price of the token.
     */
    function getTokenPrice() external view returns (uint256 price);
}

File 8 of 13 : IAssetsVault.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

/**
 * @title AssetsVault Interface
 * @dev Interface for managing assets within a vault contract.
 */
interface IAssetsVault {
    /**
     * @dev Deposits funds into the vault.
     */
    function deposit() external payable;

    /**
     * @dev Withdraws funds from the vault.
     * @param to The address to which the withdrawn funds will be transferred.
     * @param amount The amount of funds to withdraw.
     */
    function withdraw(address to, uint256 amount) external;

    /**
     * @dev Sets a new vault address.
     * @param _vault The address of the new vault.
     */
    function setNewVault(address _vault) external;

    /**
     * @dev Gets the balance of the vault.
     * @return balanceAmount The balance of the vault.
     */
    function getBalance() external view returns (uint256 balanceAmount);
}

File 9 of 13 : IStrategyManager.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

/**
 * @title StrategyManager Interface
 * @dev Interface for a contract managing multiple eth investment strategies.
 */
interface IStrategyManager {
    /**
     * @dev Sets a new vault address.
     * @param _vault The address of the new vault.
     */
    function setNewVault(address _vault) external;

    /**
     * @dev Adds a new strategy to be managed.
     * @param _strategy The address of the strategy to add.
     */
    function addStrategy(address _strategy) external;

    /**
     * @dev Destroys a strategy, removing it from management.
     * @param _strategy The address of the strategy to destroy.
     */
    function destroyStrategy(address _strategy) external;

    /**
     * @dev Clears a strategy, potentially withdrawing its funds and resetting parameters.
     * @param _strategy The address of the strategy to clear.
     */
    function clearStrategy(address _strategy) external;

    /**
     * @dev Rebalances the strategies based on incoming and outgoing amounts.
     * @param amountIn The amount of funds to be rebalanced into the strategies.
     * @param amountOut The amount of funds to be rebalanced out of the strategies.
     */
    function rebaseStrategies(uint256 amountIn, uint256 amountOut) external;

    /**
     * @dev Rebalances the strategies without incoming and outgoing amounts.
     */
    function onlyRebaseStrategies() external;

    /**
     * @dev Forces a withdrawal of a specified amount of ETH from the strategies.
     * @param ethAmount The amount of ETH to withdraw.
     * @return actualAmount The actual amount of ETH withdrawn.
     */
    function forceWithdraw(uint256 ethAmount) external returns (uint256 actualAmount);

    /**
     * @dev Sets the strategies and their corresponding ratios.
     * @param _strategies The addresses of the strategies to set.
     * @param _ratios The corresponding ratios for each strategy.
     */
    function setStrategies(address[] memory _strategies, uint256[] memory _ratios) external;

    /**
     * @dev Retrieves the address of the assets vault managed by the strategy manager.
     * @return vault The address of the assets vault.
     */
    function assetsVault() external view returns (address vault);

    /**
     * @dev Retrieves the total value managed by all strategies.
     * @return amount The total value managed by all strategies.
     */
    function getAllStrategiesValue() external view returns (uint256 amount);

    /**
     * @dev Retrieves the total valid value managed by all strategies.
     * @return amount The total valid value managed by all strategies.
     */
    function getTotalInvestedValue() external view returns (uint256 amount);

    /**
     * @dev Retrieves the total pending value managed by all strategies.
     * @return amount The total pending value managed by all strategies.
     */
    function getAllStrategyPendingValue() external view returns (uint256 amount);
}

File 10 of 13 : ShareMath.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.21;

import {FullMath} from "v3-core-0.8/libraries/FullMath.sol";

library ShareMath {
    uint256 internal constant DECIMAL = 18;
    uint256 internal constant DECIMAL_OFFSET = 10 ** DECIMAL;
    uint256 internal constant PLACEHOLDER_UINT = 1;

    /**
     * @notice Converts an amount of tokens to shares.
     * @param assetAmount The amount of tokens to convert.
     * @param assetPerShare The price per share.
     * @return The equivalent amount of shares.
     *
     * Note: All rounding errors should be rounded down in the interest of the protocol's safety.
     * Token transfers, including deposit and withdraw operations, may require a rounding, leading to potential
     * transferring at most one GWEI less than expected aggregated over a long period of time.
     */
    function assetToShares(uint256 assetAmount, uint256 assetPerShare) internal pure returns (uint256) {
        require(assetPerShare > PLACEHOLDER_UINT, "ShareMath Lib: Invalid assetPerShare");
        return FullMath.mulDiv(assetAmount, DECIMAL_OFFSET, assetPerShare);
    }

    /**
     * @notice Converts an amount of shares to tokens.
     * @param shares The amount of shares to convert.
     * @param assetPerShare The price per share.
     * @return The equivalent amount of tokens.
     */
    function sharesToAsset(uint256 shares, uint256 assetPerShare) internal pure returns (uint256) {
        require(assetPerShare > PLACEHOLDER_UINT, "ShareMath Lib: Invalid assetPerShare");
        return FullMath.mulDiv(shares, assetPerShare, DECIMAL_OFFSET);
    }
}

File 11 of 13 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 12 of 13 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

File 13 of 13 : FullMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (0 - denominator) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the precoditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            result = mulDiv(a, b, denominator);
            if (mulmod(a, b, denominator) > 0) {
                require(result < type(uint256).max);
                result++;
            }
        }
    }
}

Settings
{
  "remappings": [
    "src/=src/",
    "forge-std/=lib/forge-std/src/",
    "oz/=lib/openzeppelin-contracts/contracts/",
    "v3-periphery/=lib/v3-periphery/contracts/",
    "@uniswap/v3-core/=lib/v3-core/",
    "v3-core-0.8/=lib/v3-core-0.8/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "v3-core/=lib/v3-core/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_intialOwner","type":"address"},{"internalType":"address","name":"_minter","type":"address"},{"internalType":"address payable","name":"_assetsVault","type":"address"},{"internalType":"address payable","name":"_strategyManager","type":"address"},{"internalType":"address","name":"_proposal","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"RealVault__ExceedBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"RealVault__ExceedMaxFeeRate","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestedAmount","type":"uint256"},{"internalType":"uint256","name":"actualAmount","type":"uint256"}],"name":"RealVault__ExceedRequestedAmount","type":"error"},{"inputs":[],"name":"RealVault__ExceedWithdrawAmount","type":"error"},{"inputs":[],"name":"RealVault__InsufficientShares","type":"error"},{"inputs":[],"name":"RealVault__InvalidAmount","type":"error"},{"inputs":[],"name":"RealVault__Migrated","type":"error"},{"inputs":[{"internalType":"uint256","name":"minInterval","type":"uint256"}],"name":"RealVault__MinimumRebaseInterval","type":"error"},{"inputs":[],"name":"RealVault__MinimumWithdrawableShares","type":"error"},{"inputs":[],"name":"RealVault__MininmumWithdraw","type":"error"},{"inputs":[],"name":"RealVault__NoRequestFound","type":"error"},{"inputs":[],"name":"RealVault__NotProposal","type":"error"},{"inputs":[],"name":"RealVault__NotReady","type":"error"},{"inputs":[],"name":"RealVault__WaitInQueue","type":"error"},{"inputs":[],"name":"RealVault__WithdrawInstantly","type":"error"},{"inputs":[],"name":"RealVault__ZeroAddress","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"CancelWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","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":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"InitiateWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"strategies","type":"address[]"},{"indexed":true,"internalType":"uint256[]","name":"ratios","type":"uint256[]"}],"name":"InvestmentPortfolioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"MinWithdrawableSharesUpdated","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":true,"internalType":"address","name":"oldAddr","type":"address"},{"indexed":false,"internalType":"address","name":"newAddr","type":"address"}],"name":"ProposalUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharePrice","type":"uint256"}],"name":"RollToNextRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAddr","type":"address"},{"indexed":false,"internalType":"address","name":"newAddr","type":"address"}],"name":"SetFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"interval","type":"uint256"}],"name":"SetRebaseInterval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"SetWithdrawFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"dust","type":"uint256"}],"name":"SettleWithdrawDust","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyDestroyed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":false,"internalType":"address","name":"newVault","type":"address"}],"name":"VaultMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"WithdrawnFromStrategy","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"assetsVault","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"cancelWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"clearStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentSharePrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmountMin","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"mintAmountMin","type":"uint256"}],"name":"depositFor","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"destroyStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultAvailableAmount","outputs":[{"internalType":"uint256","name":"idleAmount","type":"uint256"},{"internalType":"uint256","name":"investedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"instantWithdraw","outputs":[{"internalType":"uint256","name":"actualWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestRoundID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"migrateVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minWithdrawableShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onlyRebaseStrategies","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":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposal","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"real","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebaseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebaseTimeInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"requestWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollToNextRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minWithdrawableShares","type":"uint256"}],"name":"setMinWithdrawableShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interval","type":"uint256"}],"name":"setRebaseInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawFeeRate","type":"uint256"}],"name":"setWithdrawFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"settleWithdrawDust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"settlementTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_strategies","type":"address[]"},{"internalType":"uint256[]","name":"_ratios","type":"uint256[]"}],"name":"updateInvestmentPortfolio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proposal","type":"address"}],"name":"updateProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userReceipts","outputs":[{"internalType":"uint256","name":"withdrawRound","type":"uint256"},{"internalType":"uint256","name":"withdrawShares","type":"uint256"},{"internalType":"uint256","name":"withdrawableAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawAmountDust","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawableAmountInPast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawingSharesInPast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawingSharesInRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

610100604052606460035562015180600455604051620033b0380380620033b0833981016040819052620000339162000385565b60015f55846001600160a01b0381166200006757604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b620000728162000257565b506001600160a01b03811615806200009157506001600160a01b038316155b80620000a457506001600160a01b038216155b15620000c3576040516334b8f1b160e21b815260040160405180910390fd5b6001600160a01b038481166080819052600680546001600160a01b03191684841617905584821660c05290831660e052604080516364aa783b60e11b8152905163c954f076916004808201926020929091908290030181865afa1580156200012d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000153919062000401565b6001600160a01b031660a081905242600555604080516318160ddd60e01b815290516318160ddd916004808201926020929091908290030181865afa1580156200019f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001c5919062000426565b5f036200024c5760c051620001e29066038d7ea4c6800062000275565b6080516040516340c10f1960e01b815261dead600482015266038d7ea4c6800060248201526001600160a01b03909116906340c10f19906044015f604051808303815f87803b15801562000234575f80fd5b505af115801562000247573d5f803e3d5ffd5b505050505b50505050506200046c565b600280546001600160a01b031916905562000272816200031f565b50565b604080515f808252602082019092526001600160a01b038416908390604051620002a091906200043e565b5f6040518083038185875af1925050503d805f8114620002dc576040519150601f19603f3d011682016040523d82523d5f602084013e620002e1565b606091505b50509050806200031a5760405162461bcd60e51b815260206004820152600360248201526253544560e81b60448201526064016200005e565b505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b038116811462000272575f80fd5b5f805f805f60a086880312156200039a575f80fd5b8551620003a78162000370565b6020870151909550620003ba8162000370565b6040870151909450620003cd8162000370565b6060870151909350620003e08162000370565b6080870151909250620003f38162000370565b809150509295509295909350565b5f6020828403121562000412575f80fd5b81516200041f8162000370565b9392505050565b5f6020828403121562000437575f80fd5b5051919050565b5f82515f5b818110156200045f576020818601810151858301520162000443565b505f920191825250919050565b60805160a05160c05160e051612e5a620005565f395f81816103ab0152818161095501528181610b1a01528181610d1a01528181610ec501528181611025015281816112e701528181611604015281816117ce015281816118880152611d6d01525f818161057201528181610aa401528181610d9a01528181611046015281816116db01528181611ae5015261242d01525f81816106d001528181610b8601528181610c0a01528181610c77015281816113fc015281816114b701526119f801525f818161027e01528181610a300152818161141e01528181611b0701526124be0152612e5a5ff3fe608060405260043610610262575f3560e01c8063753ec1031161013f578063b6b55f25116100b3578063ea99e68911610078578063ea99e6891461074d578063ef037fb914610762578063ef8b30f714610781578063f2fde38b146107a0578063f76339dc146107bf578063fe735117146107d4575f80fd5b8063b6b55f25146106ac578063c954f076146106bf578063e30c3978146106f2578063e74b981b1461070f578063e8ac623a1461072e575f80fd5b806387153eb11161010457806387153eb1146105bd5780638da5cb5b146105e857806397663b74146106055780639f01f7ba14610619578063a4786f3d14610638578063b18f2e911461068d575f80fd5b8063753ec1031461050f578063768aac5d1461052e57806379ba50971461054d5780637b0c1f291461056157806382f1631f14610594575f80fd5b806346904840116101d657806360e760d51161019b57806360e760d51461047e57806364737b0b14610493578063715018a6146104a857806371551336146104bc578063717dd445146104d1578063745400c9146104f0575f80fd5b806346904840146103f85780634f070a27146104175780634fded071146104365780635069fb571461045557806351b77fb314610469575f80fd5b806325849b4e1161022757806325849b4e1461033f5780632712b5391461035457806328a79576146103735780632f4f21e21461038757806339b70e381461039a5780633c49fc0f146103cd575f80fd5b8063075461721461026d578063096015b0146102bd5780631465d289146102de578063223e5479146102fd57806324f3082a1461031c575f80fd5b3661026957005b5f80fd5b348015610278575f80fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102c8575f80fd5b506102dc6102d736600461290a565b6107e9565b005b3480156102e9575f80fd5b506102dc6102f836600461290a565b610862565b348015610308575f80fd5b506102dc610317366004612937565b61090b565b348015610327575f80fd5b5061033160055481565b6040519081526020016102b4565b34801561034a575f80fd5b50610331600d5481565b34801561035f575f80fd5b506102dc61036e366004612937565b6109e6565b34801561037e575f80fd5b50610331610c73565b610331610395366004612950565b610e65565b3480156103a5575f80fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d8575f80fd5b506103316103e736600461290a565b600f6020525f908152604090205481565b348015610403575f80fd5b506007546102a0906001600160a01b031681565b348015610422575f80fd5b506102dc610431366004612a48565b610e8b565b348015610441575f80fd5b506102dc61045036600461290a565b610f8b565b348015610460575f80fd5b506102dc610fe7565b348015610474575f80fd5b50610331600b5481565b348015610489575f80fd5b50610331600c5481565b34801561049e575f80fd5b5061033160035481565b3480156104b3575f80fd5b506102dc6112af565b3480156104c7575f80fd5b5061033160045481565b3480156104dc575f80fd5b506102dc6104eb366004612937565b6112c0565b3480156104fb575f80fd5b506102dc61050a36600461290a565b611378565b34801561051a575f80fd5b506006546102a0906001600160a01b031681565b348015610539575f80fd5b506102dc610548366004612937565b6115dd565b348015610558575f80fd5b506102dc611695565b34801561056c575f80fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b34801561059f575f80fd5b506105a86116d6565b604080519283526020830191909152016102b4565b3480156105c8575f80fd5b506103316105d736600461290a565b600e6020525f908152604090205481565b3480156105f3575f80fd5b506001546001600160a01b03166102a0565b348015610610575f80fd5b506102dc611853565b348015610624575f80fd5b506102dc61063336600461290a565b6118fd565b348015610643575f80fd5b50610672610652366004612937565b60106020525f908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016102b4565b348015610698575f80fd5b506103316106a7366004612b02565b611aad565b6103316106ba36600461290a565b611feb565b3480156106ca575f80fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b3480156106fd575f80fd5b506002546001600160a01b03166102a0565b34801561071a575f80fd5b506102dc610729366004612937565b612010565b348015610739575f80fd5b506102dc610748366004612937565b6120a5565b348015610758575f80fd5b5061033160095481565b34801561076d575f80fd5b506102dc61077c36600461290a565b61215d565b34801561078c575f80fd5b5061033161079b36600461290a565b6121be565b3480156107ab575f80fd5b506102dc6107ba366004612937565b61221d565b3480156107ca575f80fd5b5061033160085481565b3480156107df575f80fd5b50610331600a5481565b6107f161228e565b6107ff6064620f4240612b36565b81111561082757604051630ee5417f60e01b8152600481018290526024015b60405180910390fd5b6009546040518281527f4b3c5e4d7a59d85563d40eacdce201f42b27dd0f184fc2aef47c140a9775617d9060200160405180910390a2600955565b600d54670de0b6b3a764000081101561088e5760405163e362981960e01b815260040160405180910390fd5b808211156108af576040516375e5007560e01b815260040160405180910390fd5b81600a5f8282546108c09190612b55565b9250508190555081600d5f8282546108d89190612b55565b909155505060405182907fd3f775f0b61e2937725111756dce1955a33a47dd04fdd791766d1022541ec6f9905f90a25050565b6006546001600160a01b0316331461093657604051633a89a8db60e11b815260040160405180910390fd5b60405163223e547960e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000919082169063223e5479906024015f604051808303815f87803b158015610999575f80fd5b505af11580156109ab573d5f803e3d5ffd5b50506040516001600160a01b03851692507f3f008fd510eae7a9e7bee13513d7b83bef8003d488b5a3d0b0da4de71d6846f191505f90a25050565b6006546001600160a01b03163314610a1157604051633a89a8db60e11b815260040160405180910390fd5b604051630e7b77f760e41b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e7b77f70906024015f604051808303815f87803b158015610a71575f80fd5b505af1158015610a83573d5f803e3d5ffd5b5050604051630e7b77f760e41b81526001600160a01b0384811660048301527f000000000000000000000000000000000000000000000000000000000000000016925063e7b77f7091506024015f604051808303815f87803b158015610ae7575f80fd5b505af1158015610af9573d5f803e3d5ffd5b5050604051630e7b77f760e41b81526001600160a01b0384811660048301527f000000000000000000000000000000000000000000000000000000000000000016925063e7b77f7091506024015f604051808303815f87803b158015610b5d575f80fd5b505af1158015610b6f573d5f803e3d5ffd5b50506040516370a0823160e01b81523060048201527f000000000000000000000000000000000000000000000000000000000000000092505f91506001600160a01b038316906370a0823190602401602060405180830381865afa158015610bd9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bfd9190612b68565b90508015610c3057610c307f000000000000000000000000000000000000000000000000000000000000000084836122bb565b6040516001600160a01b038416815230907faa10add0ff0f23b874d2d1fa353ab28a639aa51906dec303238cdb1f1e54ea429060200160405180910390a2505050565b5f807f000000000000000000000000000000000000000000000000000000000000000090505f816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf99190612b68565b90506008545f03610d1457670de0b6b3a76400009250505090565b5f600a547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639d241e7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d989190612b68565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e189190612b68565b610e229190612b7f565b610e2c9190612b55565b90505f600b5483610e3d9190612b55565b905080610e52670de0b6b3a764000084612b92565b610e5c9190612b36565b94505050505090565b5f610e6e6123b6565b610e7a338434856123de565b9050610e8560015f55565b92915050565b6006546001600160a01b03163314610eb657604051633a89a8db60e11b815260040160405180910390fd5b604051633fea70a760e01b81527f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b03821690633fea70a790610f069086908690600401612ba9565b5f604051808303815f87803b158015610f1d575f80fd5b505af1158015610f2f573d5f803e3d5ffd5b5050505081604051610f419190612c2b565b604051809103902083604051610f579190612c60565b604051908190038120907f886538ec00824aebc44dcefaf3572b74d610c4ba35469bb923eb542e7b4e9554905f90a3505050565b610f9361228e565b6064811015610fb5576040516354b2322360e11b815260040160405180910390fd5b600381905560405181907ff84f3bcac008f2f0998cd522e5e7dabb95e2d6c66aab378d3ac88ec507f3657f905f90a250565b610fef6123b6565b600454600554610fff9190612b7f565b42101561101f576040516341e2a36f60e01b815260040160405180910390fd5b426005557f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000005f61106e610c73565b90505f826001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110d19190612b68565b90505f6110e0600c5484612569565b90505f81600a546110f19190612b7f565b90505f866001600160a01b031663f41d7a186040518163ffffffff1660e01b8152600401602060405180830381865afa158015611130573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111549190612b68565b90505f808386111561116a578386039150611183565b836111758488612b7f565b101561118357828685030390505b604051630ecc3e7160e21b815260048101839052602481018290526001600160a01b038a1690633b30f9c4906044015f604051808303815f87803b1580156111c9575f80fd5b505af11580156111db573d5f803e3d5ffd5b505060085491505f90506111ed610c73565b90508089106111fc57806111fe565b885b5f838152600e6020908152604080832093909355600f90522042905560018201600855600c54600b546112319190612b7f565b600b55600c546112419082612569565b600a5461124e9190612b7f565b600a555f600c5560085460408051868152602081018690529081018390527fd2792f2bd70f462289b37051570ea123ec2faa689d0966f04ea499497c47aea49060600160405180910390a250505050505050505050506112ad60015f55565b565b6112b761228e565b6112ad5f6125a0565b6112c861228e565b60405163717dd44560e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000919082169063717dd445906024015f604051808303815f87803b15801561132b575f80fd5b505af115801561133d573d5f803e3d5ffd5b50506040516001600160a01b03851692507f13a19f2899b0ae7e8561c01327e3d76320f1fa1f10134f6181b536fab6198c0391505f90a25050565b6113806123b6565b805f036113a05760405163e362981960e01b815260040160405180910390fd5b6003548110156113c3576040516315bf079960e31b815260040160405180910390fd5b6008545f8190036113e757604051631dcf2e0560e01b815260040160405180910390fd5b6040516370a0823160e01b81523360048201527f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009084906001600160a01b038416906370a0823190602401602060405180830381865afa15801561146f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114939190612b68565b10156114b2576040516375e5007560e01b815260040160405180910390fd5b6114de7f00000000000000000000000000000000000000000000000000000000000000003330876125b9565b83600c546114ec9190612b7f565b600c55335f9081526010602090815260409182902082516060810184528154808252600183015493820193909352600290910154928101929092528490036115485784816020015161153e9190612b7f565b602082015261156e565b80515f0361155f576020810185905283815261156e565b61156b818387876126be565b90505b335f81815260106020908152604091829020845181558482015160018201558483015160029091015581518881529081018790527f0c53c82ad07e2d592d88ece3b066777dd60f1118e2a081b380efc4358f0d9e2a910160405180910390a2505050506115da60015f55565b50565b6115e561228e565b60405163768aac5d60e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000919082169063768aac5d906024015f604051808303815f87803b158015611648575f80fd5b505af115801561165a573d5f803e3d5ffd5b50506040516001600160a01b03851692507f888bbdad435cac9001badf15d0c64faa59238552c77e930843899893b00569f691505f90a25050565b60025433906001600160a01b031681146116cd5760405163118cdaa760e01b81526001600160a01b038216600482015260240161081e565b6115da816125a0565b5f805f7f00000000000000000000000000000000000000000000000000000000000000009050600a54816001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561173b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061175f9190612b68565b11156117cc57600a54816001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117a4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c89190612b68565b0392505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e82f133b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611828573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061184c9190612b68565b9150509091565b61185b6123b6565b6006546001600160a01b0316331461188657604051633a89a8db60e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166397663b746040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156118de575f80fd5b505af11580156118f0573d5f803e3d5ffd5b505050506112ad60015f55565b6119056123b6565b805f036119255760405163e362981960e01b815260040160405180910390fd5b335f90815260106020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925260085490811461198057604051630c06d9f960e21b815260040160405180910390fd5b81602001518311156119b5576020820151604051631135472760e21b815261081e918591600401918252602082015260400190565b60208201805184810390915283148015906119d557506003548260200151105b156119f3576040516315bf079960e31b815260040160405180910390fd5b611a1e7f000000000000000000000000000000000000000000000000000000000000000033856122bb565b81602001515f03611a2d575f82525b335f908152601060209081526040918290208451815590840151600182015590830151600290910155600c54611a64908490612b55565b600c55604080518481526020810183905233917f39e2e01794006bc1f63835af5c05db790beca4bfb40de3f02cc3ddf22dccc0fb910160405180910390a250506115da60015f55565b5f611ab66123b6565b82158015611ac2575081155b15611ae05760405163e362981960e01b815260040160405180910390fd5b6008547f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000905f611b306116d6565b5090508615611c3957335f9081526010602090815260409182902082516060810184528154808252600183015493820193909352600290910154928101929092528314801590611b805750805115155b15611b9457611b9181855f806126be565b90505b8781604001511015611bb957604051630a1b0a5f60e21b815260040160405180910390fd5b604080820180518a90038152335f908152601060209081529290208351815591830151600183015551600290910155600a54611bf6908990612b55565b600a55604080518981526020810185905289975033917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a2505b8515611e42575f825f03611c565750670de0b6b3a7640000611c88565b5f611c5f610c73565b5f1985015f908152600e6020526040902054909150818110611c815781611c83565b805b925050505b5f611c938883612569565b604051632770a7eb60e21b8152336004820152602481018a90529091506001600160a01b03861690639dc29fac906044015f604051808303815f87803b158015611cdb575f80fd5b505af1158015611ced573d5f803e3d5ffd5b50505050828111611d4557611d028188612b7f565b604080518381526020810187905291985033917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a2611e3f565b611d4f8388612b7f565b604051630fcc56f760e01b81529184900360048301819052909750907f0000000000000000000000000000000000000000000000000000000000000000905f906001600160a01b03831690630fcc56f7906024016020604051808303815f875af1158015611dbf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611de39190612b68565b9050611def818a612b7f565b60408051858152602081018490529081018290526060810188905290995033907f5737794397f1d4268fc3eb86a7624b2d9919508137c4c4c857bd9a84b44ad3359060800160405180910390a250505b50505b84846001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e7f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ea39190612b68565b1015611ec257604051637ea54e3360e11b815260040160405180910390fd5b5f6009545f14611f8157620f424060095487611ede9190612b92565b611ee89190612b36565b60075460405163f3fef3a360e01b81526001600160a01b0391821660048201526024810183905291925086169063f3fef3a3906044015f604051808303815f87803b158015611f35575f80fd5b505af1158015611f47573d5f803e3d5ffd5b50506040518381523392507f55bb3cade9d43b798a4fe5ffdd05024b2d7870df53920673bfc7e68047cd0ab1915060200160405180910390a25b60405163f3fef3a360e01b815233600482015281870360248201526001600160a01b0386169063f3fef3a3906044015f604051808303815f87803b158015611fc7575f80fd5b505af1158015611fd9573d5f803e3d5ffd5b505050505050505050610e8560015f55565b5f611ff46123b6565b612000333334856123de565b905061200b60015f55565b919050565b61201861228e565b6001600160a01b03811661203f576040516334b8f1b160e21b815260040160405180910390fd5b6007546040516001600160a01b038381168252909116907fd9d6b85b6d670cd443496fc6d03390f739bbff47f96a8e33fb0cdd52ad26f5c29060200160405180910390a2600780546001600160a01b0319166001600160a01b0392909216919091179055565b6006546001600160a01b031633146120d057604051633a89a8db60e11b815260040160405180910390fd5b6001600160a01b0381166120f7576040516334b8f1b160e21b815260040160405180910390fd5b6006546040516001600160a01b038381168252909116907f0fad96636e11ba67c870dd54ead446e136995874f8367a6bbe67410b89d2199b9060200160405180910390a2600680546001600160a01b0319166001600160a01b0392909216919091179055565b61216561228e565b610e1081101561218c576040516385e1176760e01b8152610e10600482015260240161081e565b600481905560405181907f73b75c75399b0450cd07a0e5188f0e06ce9e484fea18044b25e0326feb8e0e2a905f90a250565b5f806008545f036121d85750670de0b6b3a764000061220c565b5f6121e1610c73565b6008545f19015f908152600e60205260409020549091508181116122055781612207565b805b925050505b61221683826127dc565b9392505050565b61222561228e565b600280546001600160a01b0383166001600160a01b031990911681179091556122566001546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6001546001600160a01b031633146112ad5760405163118cdaa760e01b815233600482015260240161081e565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916123169190612c92565b5f604051808303815f865af19150503d805f811461234f576040519150601f19603f3d011682016040523d82523d5f602084013e612354565b606091505b509150915081801561237e57508051158061237e57508080602001905181019061237e9190612cbe565b6123af5760405162461bcd60e51b815260206004820152600260248201526114d560f21b604482015260640161081e565b5050505050565b60025f54036123d857604051633ee5aeb560e01b815260040160405180910390fd5b60025f55565b5f825f036123ff5760405163e362981960e01b815260040160405180910390fd5b612408476121be565b90508181101561242b5760405163349fb22560e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004015f604051808303818588803b158015612484575f80fd5b505af1158015612496573d5f803e3d5ffd5b50506040516340c10f1960e01b81526001600160a01b038881166004830152602482018690527f00000000000000000000000000000000000000000000000000000000000000001693506340c10f19925060440190505f604051808303815f87803b158015612503575f80fd5b505af1158015612515573d5f803e3d5ffd5b505060408051868152602081018590526001600160a01b038089169450891692507fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3949350505050565b5f6001821161258a5760405162461bcd60e51b815260040161081e90612cdd565b612216838361259b6012600a612e01565b61280f565b600280546001600160a01b03191690556115da816128b9565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f9283929088169161261c9190612c92565b5f604051808303815f865af19150503d805f8114612655576040519150601f19603f3d011682016040523d82523d5f602084013e61265a565b606091505b50915091508180156126845750805115806126845750808060200190518101906126849190612cbe565b6126b65760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015260640161081e565b505050505050565b6126df60405180606001604052805f81526020015f81526020015f81525090565b84515f908152600e60209081526040822054908701519091906127029083612569565b90505f61270f82846127dc565b90505f821180156127235750876020015181105b1561273d57600d8054905f61273783612e0c565b91905055505b6020880151604051632770a7eb60e21b815230600482015260248101919091526001600160a01b03881690639dc29fac906044015f604051808303815f87803b158015612788575f80fd5b505af115801561279a573d5f803e3d5ffd5b5050506020890151600b546127af9250612b55565b600b556020880186905260408801516127c9908390612b7f565b6040890152505050908452509192915050565b5f600182116127fd5760405162461bcd60e51b815260040161081e90612cdd565b6122168361280d6012600a612e01565b845b5f80805f19858709858702925082811083820303915050805f03612843575f8411612838575f80fd5b508290049050612216565b80841161284e575f80fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f6020828403121561291a575f80fd5b5035919050565b80356001600160a01b038116811461200b575f80fd5b5f60208284031215612947575f80fd5b61221682612921565b5f8060408385031215612961575f80fd5b61296a83612921565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156129b5576129b5612978565b604052919050565b5f67ffffffffffffffff8211156129d6576129d6612978565b5060051b60200190565b5f82601f8301126129ef575f80fd5b81356020612a046129ff836129bd565b61298c565b82815260059290921b84018101918181019086841115612a22575f80fd5b8286015b84811015612a3d5780358352918301918301612a26565b509695505050505050565b5f8060408385031215612a59575f80fd5b823567ffffffffffffffff80821115612a70575f80fd5b818501915085601f830112612a83575f80fd5b81356020612a936129ff836129bd565b82815260059290921b84018101918181019089841115612ab1575f80fd5b948201945b83861015612ad657612ac786612921565b82529482019490820190612ab6565b96505086013592505080821115612aeb575f80fd5b50612af8858286016129e0565b9150509250929050565b5f8060408385031215612b13575f80fd5b50508035926020909101359150565b634e487b7160e01b5f52601160045260245ffd5b5f82612b5057634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610e8557610e85612b22565b5f60208284031215612b78575f80fd5b5051919050565b80820180821115610e8557610e85612b22565b8082028115828204841417610e8557610e85612b22565b604080825283519082018190525f906020906060840190828701845b82811015612bea5781516001600160a01b031684529284019290840190600101612bc5565b505050838103828501528451808252858301918301905f5b81811015612c1e57835183529284019291840191600101612c02565b5090979650505050505050565b81515f9082906020808601845b83811015612c5457815185529382019390820190600101612c38565b50929695505050505050565b81515f9082906020808601845b83811015612c545781516001600160a01b031685529382019390820190600101612c6d565b5f82515f5b81811015612cb15760208186018101518583015201612c97565b505f920191825250919050565b5f60208284031215612cce575f80fd5b81518015158114612216575f80fd5b60208082526024908201527f53686172654d617468204c69623a20496e76616c6964206173736574506572536040820152636861726560e01b606082015260800190565b600181815b80851115612d5b57815f1904821115612d4157612d41612b22565b80851615612d4e57918102915b93841c9390800290612d26565b509250929050565b5f82612d7157506001610e85565b81612d7d57505f610e85565b8160018114612d935760028114612d9d57612db9565b6001915050610e85565b60ff841115612dae57612dae612b22565b50506001821b610e85565b5060208310610133831016604e8410600b8410161715612ddc575081810a610e85565b612de68383612d21565b805f1904821115612df957612df9612b22565b029392505050565b5f6122168383612d63565b5f60018201612e1d57612e1d612b22565b506001019056fea264697066735822122069611275abcc7e8f6af121b60f73cd1634c30807f66f933c4cc3066ee4fc5e7d64736f6c63430008150033000000000000000000000000eb658c4ea908ac4daf9c309d8f883d6ad758b3a3000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb622940000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8000000000000000000000000eb658c4ea908ac4daf9c309d8f883d6ad758b3a3

Deployed Bytecode

0x608060405260043610610262575f3560e01c8063753ec1031161013f578063b6b55f25116100b3578063ea99e68911610078578063ea99e6891461074d578063ef037fb914610762578063ef8b30f714610781578063f2fde38b146107a0578063f76339dc146107bf578063fe735117146107d4575f80fd5b8063b6b55f25146106ac578063c954f076146106bf578063e30c3978146106f2578063e74b981b1461070f578063e8ac623a1461072e575f80fd5b806387153eb11161010457806387153eb1146105bd5780638da5cb5b146105e857806397663b74146106055780639f01f7ba14610619578063a4786f3d14610638578063b18f2e911461068d575f80fd5b8063753ec1031461050f578063768aac5d1461052e57806379ba50971461054d5780637b0c1f291461056157806382f1631f14610594575f80fd5b806346904840116101d657806360e760d51161019b57806360e760d51461047e57806364737b0b14610493578063715018a6146104a857806371551336146104bc578063717dd445146104d1578063745400c9146104f0575f80fd5b806346904840146103f85780634f070a27146104175780634fded071146104365780635069fb571461045557806351b77fb314610469575f80fd5b806325849b4e1161022757806325849b4e1461033f5780632712b5391461035457806328a79576146103735780632f4f21e21461038757806339b70e381461039a5780633c49fc0f146103cd575f80fd5b8063075461721461026d578063096015b0146102bd5780631465d289146102de578063223e5479146102fd57806324f3082a1461031c575f80fd5b3661026957005b5f80fd5b348015610278575f80fd5b506102a07f000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da81565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102c8575f80fd5b506102dc6102d736600461290a565b6107e9565b005b3480156102e9575f80fd5b506102dc6102f836600461290a565b610862565b348015610308575f80fd5b506102dc610317366004612937565b61090b565b348015610327575f80fd5b5061033160055481565b6040519081526020016102b4565b34801561034a575f80fd5b50610331600d5481565b34801561035f575f80fd5b506102dc61036e366004612937565b6109e6565b34801561037e575f80fd5b50610331610c73565b610331610395366004612950565b610e65565b3480156103a5575f80fd5b506102a07f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd881565b3480156103d8575f80fd5b506103316103e736600461290a565b600f6020525f908152604090205481565b348015610403575f80fd5b506007546102a0906001600160a01b031681565b348015610422575f80fd5b506102dc610431366004612a48565b610e8b565b348015610441575f80fd5b506102dc61045036600461290a565b610f8b565b348015610460575f80fd5b506102dc610fe7565b348015610474575f80fd5b50610331600b5481565b348015610489575f80fd5b50610331600c5481565b34801561049e575f80fd5b5061033160035481565b3480156104b3575f80fd5b506102dc6112af565b3480156104c7575f80fd5b5061033160045481565b3480156104dc575f80fd5b506102dc6104eb366004612937565b6112c0565b3480156104fb575f80fd5b506102dc61050a36600461290a565b611378565b34801561051a575f80fd5b506006546102a0906001600160a01b031681565b348015610539575f80fd5b506102dc610548366004612937565b6115dd565b348015610558575f80fd5b506102dc611695565b34801561056c575f80fd5b506102a07f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb6229481565b34801561059f575f80fd5b506105a86116d6565b604080519283526020830191909152016102b4565b3480156105c8575f80fd5b506103316105d736600461290a565b600e6020525f908152604090205481565b3480156105f3575f80fd5b506001546001600160a01b03166102a0565b348015610610575f80fd5b506102dc611853565b348015610624575f80fd5b506102dc61063336600461290a565b6118fd565b348015610643575f80fd5b50610672610652366004612937565b60106020525f908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016102b4565b348015610698575f80fd5b506103316106a7366004612b02565b611aad565b6103316106ba36600461290a565b611feb565b3480156106ca575f80fd5b506102a07f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f1542181565b3480156106fd575f80fd5b506002546001600160a01b03166102a0565b34801561071a575f80fd5b506102dc610729366004612937565b612010565b348015610739575f80fd5b506102dc610748366004612937565b6120a5565b348015610758575f80fd5b5061033160095481565b34801561076d575f80fd5b506102dc61077c36600461290a565b61215d565b34801561078c575f80fd5b5061033161079b36600461290a565b6121be565b3480156107ab575f80fd5b506102dc6107ba366004612937565b61221d565b3480156107ca575f80fd5b5061033160085481565b3480156107df575f80fd5b50610331600a5481565b6107f161228e565b6107ff6064620f4240612b36565b81111561082757604051630ee5417f60e01b8152600481018290526024015b60405180910390fd5b6009546040518281527f4b3c5e4d7a59d85563d40eacdce201f42b27dd0f184fc2aef47c140a9775617d9060200160405180910390a2600955565b600d54670de0b6b3a764000081101561088e5760405163e362981960e01b815260040160405180910390fd5b808211156108af576040516375e5007560e01b815260040160405180910390fd5b81600a5f8282546108c09190612b55565b9250508190555081600d5f8282546108d89190612b55565b909155505060405182907fd3f775f0b61e2937725111756dce1955a33a47dd04fdd791766d1022541ec6f9905f90a25050565b6006546001600160a01b0316331461093657604051633a89a8db60e11b815260040160405180910390fd5b60405163223e547960e01b81526001600160a01b0382811660048301527f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8919082169063223e5479906024015f604051808303815f87803b158015610999575f80fd5b505af11580156109ab573d5f803e3d5ffd5b50506040516001600160a01b03851692507f3f008fd510eae7a9e7bee13513d7b83bef8003d488b5a3d0b0da4de71d6846f191505f90a25050565b6006546001600160a01b03163314610a1157604051633a89a8db60e11b815260040160405180910390fd5b604051630e7b77f760e41b81526001600160a01b0382811660048301527f000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da169063e7b77f70906024015f604051808303815f87803b158015610a71575f80fd5b505af1158015610a83573d5f803e3d5ffd5b5050604051630e7b77f760e41b81526001600160a01b0384811660048301527f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb6229416925063e7b77f7091506024015f604051808303815f87803b158015610ae7575f80fd5b505af1158015610af9573d5f803e3d5ffd5b5050604051630e7b77f760e41b81526001600160a01b0384811660048301527f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd816925063e7b77f7091506024015f604051808303815f87803b158015610b5d575f80fd5b505af1158015610b6f573d5f803e3d5ffd5b50506040516370a0823160e01b81523060048201527f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f1542192505f91506001600160a01b038316906370a0823190602401602060405180830381865afa158015610bd9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bfd9190612b68565b90508015610c3057610c307f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f1542184836122bb565b6040516001600160a01b038416815230907faa10add0ff0f23b874d2d1fa353ab28a639aa51906dec303238cdb1f1e54ea429060200160405180910390a2505050565b5f807f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f1542190505f816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf99190612b68565b90506008545f03610d1457670de0b6b3a76400009250505090565b5f600a547f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316639d241e7a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d989190612b68565b7f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb622946001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e189190612b68565b610e229190612b7f565b610e2c9190612b55565b90505f600b5483610e3d9190612b55565b905080610e52670de0b6b3a764000084612b92565b610e5c9190612b36565b94505050505090565b5f610e6e6123b6565b610e7a338434856123de565b9050610e8560015f55565b92915050565b6006546001600160a01b03163314610eb657604051633a89a8db60e11b815260040160405180910390fd5b604051633fea70a760e01b81527f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8906001600160a01b03821690633fea70a790610f069086908690600401612ba9565b5f604051808303815f87803b158015610f1d575f80fd5b505af1158015610f2f573d5f803e3d5ffd5b5050505081604051610f419190612c2b565b604051809103902083604051610f579190612c60565b604051908190038120907f886538ec00824aebc44dcefaf3572b74d610c4ba35469bb923eb542e7b4e9554905f90a3505050565b610f9361228e565b6064811015610fb5576040516354b2322360e11b815260040160405180910390fd5b600381905560405181907ff84f3bcac008f2f0998cd522e5e7dabb95e2d6c66aab378d3ac88ec507f3657f905f90a250565b610fef6123b6565b600454600554610fff9190612b7f565b42101561101f576040516341e2a36f60e01b815260040160405180910390fd5b426005557f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd87f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb622945f61106e610c73565b90505f826001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110d19190612b68565b90505f6110e0600c5484612569565b90505f81600a546110f19190612b7f565b90505f866001600160a01b031663f41d7a186040518163ffffffff1660e01b8152600401602060405180830381865afa158015611130573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111549190612b68565b90505f808386111561116a578386039150611183565b836111758488612b7f565b101561118357828685030390505b604051630ecc3e7160e21b815260048101839052602481018290526001600160a01b038a1690633b30f9c4906044015f604051808303815f87803b1580156111c9575f80fd5b505af11580156111db573d5f803e3d5ffd5b505060085491505f90506111ed610c73565b90508089106111fc57806111fe565b885b5f838152600e6020908152604080832093909355600f90522042905560018201600855600c54600b546112319190612b7f565b600b55600c546112419082612569565b600a5461124e9190612b7f565b600a555f600c5560085460408051868152602081018690529081018390527fd2792f2bd70f462289b37051570ea123ec2faa689d0966f04ea499497c47aea49060600160405180910390a250505050505050505050506112ad60015f55565b565b6112b761228e565b6112ad5f6125a0565b6112c861228e565b60405163717dd44560e01b81526001600160a01b0382811660048301527f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8919082169063717dd445906024015f604051808303815f87803b15801561132b575f80fd5b505af115801561133d573d5f803e3d5ffd5b50506040516001600160a01b03851692507f13a19f2899b0ae7e8561c01327e3d76320f1fa1f10134f6181b536fab6198c0391505f90a25050565b6113806123b6565b805f036113a05760405163e362981960e01b815260040160405180910390fd5b6003548110156113c3576040516315bf079960e31b815260040160405180910390fd5b6008545f8190036113e757604051631dcf2e0560e01b815260040160405180910390fd5b6040516370a0823160e01b81523360048201527f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f15421907f000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da9084906001600160a01b038416906370a0823190602401602060405180830381865afa15801561146f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114939190612b68565b10156114b2576040516375e5007560e01b815260040160405180910390fd5b6114de7f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f154213330876125b9565b83600c546114ec9190612b7f565b600c55335f9081526010602090815260409182902082516060810184528154808252600183015493820193909352600290910154928101929092528490036115485784816020015161153e9190612b7f565b602082015261156e565b80515f0361155f576020810185905283815261156e565b61156b818387876126be565b90505b335f81815260106020908152604091829020845181558482015160018201558483015160029091015581518881529081018790527f0c53c82ad07e2d592d88ece3b066777dd60f1118e2a081b380efc4358f0d9e2a910160405180910390a2505050506115da60015f55565b50565b6115e561228e565b60405163768aac5d60e01b81526001600160a01b0382811660048301527f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8919082169063768aac5d906024015f604051808303815f87803b158015611648575f80fd5b505af115801561165a573d5f803e3d5ffd5b50506040516001600160a01b03851692507f888bbdad435cac9001badf15d0c64faa59238552c77e930843899893b00569f691505f90a25050565b60025433906001600160a01b031681146116cd5760405163118cdaa760e01b81526001600160a01b038216600482015260240161081e565b6115da816125a0565b5f805f7f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb622949050600a54816001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561173b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061175f9190612b68565b11156117cc57600a54816001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117a4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c89190612b68565b0392505b7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b031663e82f133b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611828573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061184c9190612b68565b9150509091565b61185b6123b6565b6006546001600160a01b0316331461188657604051633a89a8db60e11b815260040160405180910390fd5b7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b03166397663b746040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156118de575f80fd5b505af11580156118f0573d5f803e3d5ffd5b505050506112ad60015f55565b6119056123b6565b805f036119255760405163e362981960e01b815260040160405180910390fd5b335f90815260106020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925260085490811461198057604051630c06d9f960e21b815260040160405180910390fd5b81602001518311156119b5576020820151604051631135472760e21b815261081e918591600401918252602082015260400190565b60208201805184810390915283148015906119d557506003548260200151105b156119f3576040516315bf079960e31b815260040160405180910390fd5b611a1e7f000000000000000000000000c0cc5ea00cae0894b441e3b5a3bb57aa92f1542133856122bb565b81602001515f03611a2d575f82525b335f908152601060209081526040918290208451815590840151600182015590830151600290910155600c54611a64908490612b55565b600c55604080518481526020810183905233917f39e2e01794006bc1f63835af5c05db790beca4bfb40de3f02cc3ddf22dccc0fb910160405180910390a250506115da60015f55565b5f611ab66123b6565b82158015611ac2575081155b15611ae05760405163e362981960e01b815260040160405180910390fd5b6008547f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb62294907f000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da905f611b306116d6565b5090508615611c3957335f9081526010602090815260409182902082516060810184528154808252600183015493820193909352600290910154928101929092528314801590611b805750805115155b15611b9457611b9181855f806126be565b90505b8781604001511015611bb957604051630a1b0a5f60e21b815260040160405180910390fd5b604080820180518a90038152335f908152601060209081529290208351815591830151600183015551600290910155600a54611bf6908990612b55565b600a55604080518981526020810185905289975033917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a2505b8515611e42575f825f03611c565750670de0b6b3a7640000611c88565b5f611c5f610c73565b5f1985015f908152600e6020526040902054909150818110611c815781611c83565b805b925050505b5f611c938883612569565b604051632770a7eb60e21b8152336004820152602481018a90529091506001600160a01b03861690639dc29fac906044015f604051808303815f87803b158015611cdb575f80fd5b505af1158015611ced573d5f803e3d5ffd5b50505050828111611d4557611d028188612b7f565b604080518381526020810187905291985033917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a2611e3f565b611d4f8388612b7f565b604051630fcc56f760e01b81529184900360048301819052909750907f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8905f906001600160a01b03831690630fcc56f7906024016020604051808303815f875af1158015611dbf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611de39190612b68565b9050611def818a612b7f565b60408051858152602081018490529081018290526060810188905290995033907f5737794397f1d4268fc3eb86a7624b2d9919508137c4c4c857bd9a84b44ad3359060800160405180910390a250505b50505b84846001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e7f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ea39190612b68565b1015611ec257604051637ea54e3360e11b815260040160405180910390fd5b5f6009545f14611f8157620f424060095487611ede9190612b92565b611ee89190612b36565b60075460405163f3fef3a360e01b81526001600160a01b0391821660048201526024810183905291925086169063f3fef3a3906044015f604051808303815f87803b158015611f35575f80fd5b505af1158015611f47573d5f803e3d5ffd5b50506040518381523392507f55bb3cade9d43b798a4fe5ffdd05024b2d7870df53920673bfc7e68047cd0ab1915060200160405180910390a25b60405163f3fef3a360e01b815233600482015281870360248201526001600160a01b0386169063f3fef3a3906044015f604051808303815f87803b158015611fc7575f80fd5b505af1158015611fd9573d5f803e3d5ffd5b505050505050505050610e8560015f55565b5f611ff46123b6565b612000333334856123de565b905061200b60015f55565b919050565b61201861228e565b6001600160a01b03811661203f576040516334b8f1b160e21b815260040160405180910390fd5b6007546040516001600160a01b038381168252909116907fd9d6b85b6d670cd443496fc6d03390f739bbff47f96a8e33fb0cdd52ad26f5c29060200160405180910390a2600780546001600160a01b0319166001600160a01b0392909216919091179055565b6006546001600160a01b031633146120d057604051633a89a8db60e11b815260040160405180910390fd5b6001600160a01b0381166120f7576040516334b8f1b160e21b815260040160405180910390fd5b6006546040516001600160a01b038381168252909116907f0fad96636e11ba67c870dd54ead446e136995874f8367a6bbe67410b89d2199b9060200160405180910390a2600680546001600160a01b0319166001600160a01b0392909216919091179055565b61216561228e565b610e1081101561218c576040516385e1176760e01b8152610e10600482015260240161081e565b600481905560405181907f73b75c75399b0450cd07a0e5188f0e06ce9e484fea18044b25e0326feb8e0e2a905f90a250565b5f806008545f036121d85750670de0b6b3a764000061220c565b5f6121e1610c73565b6008545f19015f908152600e60205260409020549091508181116122055781612207565b805b925050505b61221683826127dc565b9392505050565b61222561228e565b600280546001600160a01b0383166001600160a01b031990911681179091556122566001546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6001546001600160a01b031633146112ad5760405163118cdaa760e01b815233600482015260240161081e565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291515f928392908716916123169190612c92565b5f604051808303815f865af19150503d805f811461234f576040519150601f19603f3d011682016040523d82523d5f602084013e612354565b606091505b509150915081801561237e57508051158061237e57508080602001905181019061237e9190612cbe565b6123af5760405162461bcd60e51b815260206004820152600260248201526114d560f21b604482015260640161081e565b5050505050565b60025f54036123d857604051633ee5aeb560e01b815260040160405180910390fd5b60025f55565b5f825f036123ff5760405163e362981960e01b815260040160405180910390fd5b612408476121be565b90508181101561242b5760405163349fb22560e11b815260040160405180910390fd5b7f000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb622946001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004015f604051808303818588803b158015612484575f80fd5b505af1158015612496573d5f803e3d5ffd5b50506040516340c10f1960e01b81526001600160a01b038881166004830152602482018690527f000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da1693506340c10f19925060440190505f604051808303815f87803b158015612503575f80fd5b505af1158015612515573d5f803e3d5ffd5b505060408051868152602081018590526001600160a01b038089169450891692507fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3949350505050565b5f6001821161258a5760405162461bcd60e51b815260040161081e90612cdd565b612216838361259b6012600a612e01565b61280f565b600280546001600160a01b03191690556115da816128b9565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291515f9283929088169161261c9190612c92565b5f604051808303815f865af19150503d805f8114612655576040519150601f19603f3d011682016040523d82523d5f602084013e61265a565b606091505b50915091508180156126845750805115806126845750808060200190518101906126849190612cbe565b6126b65760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015260640161081e565b505050505050565b6126df60405180606001604052805f81526020015f81526020015f81525090565b84515f908152600e60209081526040822054908701519091906127029083612569565b90505f61270f82846127dc565b90505f821180156127235750876020015181105b1561273d57600d8054905f61273783612e0c565b91905055505b6020880151604051632770a7eb60e21b815230600482015260248101919091526001600160a01b03881690639dc29fac906044015f604051808303815f87803b158015612788575f80fd5b505af115801561279a573d5f803e3d5ffd5b5050506020890151600b546127af9250612b55565b600b556020880186905260408801516127c9908390612b7f565b6040890152505050908452509192915050565b5f600182116127fd5760405162461bcd60e51b815260040161081e90612cdd565b6122168361280d6012600a612e01565b845b5f80805f19858709858702925082811083820303915050805f03612843575f8411612838575f80fd5b508290049050612216565b80841161284e575f80fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f6020828403121561291a575f80fd5b5035919050565b80356001600160a01b038116811461200b575f80fd5b5f60208284031215612947575f80fd5b61221682612921565b5f8060408385031215612961575f80fd5b61296a83612921565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff811182821017156129b5576129b5612978565b604052919050565b5f67ffffffffffffffff8211156129d6576129d6612978565b5060051b60200190565b5f82601f8301126129ef575f80fd5b81356020612a046129ff836129bd565b61298c565b82815260059290921b84018101918181019086841115612a22575f80fd5b8286015b84811015612a3d5780358352918301918301612a26565b509695505050505050565b5f8060408385031215612a59575f80fd5b823567ffffffffffffffff80821115612a70575f80fd5b818501915085601f830112612a83575f80fd5b81356020612a936129ff836129bd565b82815260059290921b84018101918181019089841115612ab1575f80fd5b948201945b83861015612ad657612ac786612921565b82529482019490820190612ab6565b96505086013592505080821115612aeb575f80fd5b50612af8858286016129e0565b9150509250929050565b5f8060408385031215612b13575f80fd5b50508035926020909101359150565b634e487b7160e01b5f52601160045260245ffd5b5f82612b5057634e487b7160e01b5f52601260045260245ffd5b500490565b81810381811115610e8557610e85612b22565b5f60208284031215612b78575f80fd5b5051919050565b80820180821115610e8557610e85612b22565b8082028115828204841417610e8557610e85612b22565b604080825283519082018190525f906020906060840190828701845b82811015612bea5781516001600160a01b031684529284019290840190600101612bc5565b505050838103828501528451808252858301918301905f5b81811015612c1e57835183529284019291840191600101612c02565b5090979650505050505050565b81515f9082906020808601845b83811015612c5457815185529382019390820190600101612c38565b50929695505050505050565b81515f9082906020808601845b83811015612c545781516001600160a01b031685529382019390820190600101612c6d565b5f82515f5b81811015612cb15760208186018101518583015201612c97565b505f920191825250919050565b5f60208284031215612cce575f80fd5b81518015158114612216575f80fd5b60208082526024908201527f53686172654d617468204c69623a20496e76616c6964206173736574506572536040820152636861726560e01b606082015260800190565b600181815b80851115612d5b57815f1904821115612d4157612d41612b22565b80851615612d4e57918102915b93841c9390800290612d26565b509250929050565b5f82612d7157506001610e85565b81612d7d57505f610e85565b8160018114612d935760028114612d9d57612db9565b6001915050610e85565b60ff841115612dae57612dae612b22565b50506001821b610e85565b5060208310610133831016604e8410600b8410161715612ddc575081810a610e85565b612de68383612d21565b805f1904821115612df957612df9612b22565b029392505050565b5f6122168383612d63565b5f60018201612e1d57612e1d612b22565b506001019056fea264697066735822122069611275abcc7e8f6af121b60f73cd1634c30807f66f933c4cc3066ee4fc5e7d64736f6c63430008150033

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

000000000000000000000000eb658c4ea908ac4daf9c309d8f883d6ad758b3a3000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb622940000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8000000000000000000000000eb658c4ea908ac4daf9c309d8f883d6ad758b3a3

-----Decoded View---------------
Arg [0] : _intialOwner (address): 0xeB658c4Ea908aC4dAF9c309D8f883d6aD758b3A3
Arg [1] : _minter (address): 0x655756824385F8903AC8cFDa17B656cc26f7C7da
Arg [2] : _assetsVault (address): 0xf985E2c73d74BefF3C8c16EFC4fa5ab4cfb62294
Arg [3] : _strategyManager (address): 0x5Cba18d504D4158dC1A18C5Dc6BB2a30B230DdD8
Arg [4] : _proposal (address): 0xeB658c4Ea908aC4dAF9c309D8f883d6aD758b3A3

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000eb658c4ea908ac4daf9c309d8f883d6ad758b3a3
Arg [1] : 000000000000000000000000655756824385f8903ac8cfda17b656cc26f7c7da
Arg [2] : 000000000000000000000000f985e2c73d74beff3c8c16efc4fa5ab4cfb62294
Arg [3] : 0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8
Arg [4] : 000000000000000000000000eb658c4ea908ac4daf9c309d8f883d6ad758b3a3


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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