ETH Price: $2,392.35 (-3.45%)

Contract

0x679D4C1cC6855C57726BEA1784F578315d6431f6
 
Transaction Hash
Method
Block
From
To
0x60a06040198695962024-05-14 17:03:59141 days ago1715706239IN
 Create: LidoStEthStrategy
0 ETH0.0218834510.56833627

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
208826832024-10-03 4:45:1136 mins ago1727930711
0x679D4C1c...15d6431f6
13.5897087 ETH
208826832024-10-03 4:45:1136 mins ago1727930711
0x679D4C1c...15d6431f6
13.5897087 ETH
208766302024-10-02 8:30:4720 hrs ago1727857847
0x679D4C1c...15d6431f6
0.29636713 ETH
208766302024-10-02 8:30:4720 hrs ago1727857847
0x679D4C1c...15d6431f6
0.29636713 ETH
208754802024-10-02 4:40:1124 hrs ago1727844011
0x679D4C1c...15d6431f6
3.35407429 ETH
208754802024-10-02 4:40:1124 hrs ago1727844011
0x679D4C1c...15d6431f6
3.35407429 ETH
208682892024-10-01 4:35:112 days ago1727757311
0x679D4C1c...15d6431f6
0.67164597 ETH
208682892024-10-01 4:35:112 days ago1727757311
0x679D4C1c...15d6431f6
0.67164597 ETH
208651242024-09-30 18:00:112 days ago1727719211
0x679D4C1c...15d6431f6
0.59464597 ETH
208651242024-09-30 18:00:112 days ago1727719211
0x679D4C1c...15d6431f6
0.59464597 ETH
208610842024-09-30 4:30:113 days ago1727670611
0x679D4C1c...15d6431f6
4.20790838 ETH
208610842024-09-30 4:30:113 days ago1727670611
0x679D4C1c...15d6431f6
4.20790838 ETH
208562022024-09-29 12:09:233 days ago1727611763
0x679D4C1c...15d6431f6
12.13358213 ETH
208562022024-09-29 12:09:233 days ago1727611763
0x679D4C1c...15d6431f6
12.13358213 ETH
208506942024-09-28 17:41:474 days ago1727545307
0x679D4C1c...15d6431f6
0.00099937 ETH
208506942024-09-28 17:41:474 days ago1727545307
0x679D4C1c...15d6431f6
0.00099937 ETH
208505232024-09-28 17:07:114 days ago1727543231
0x679D4C1c...15d6431f6
0.00999414 ETH
208505232024-09-28 17:07:114 days ago1727543231
0x679D4C1c...15d6431f6
0.00999414 ETH
208461812024-09-28 2:35:115 days ago1727490911
0x679D4C1c...15d6431f6
9.86607414 ETH
208461812024-09-28 2:35:115 days ago1727490911
0x679D4C1c...15d6431f6
9.86607414 ETH
208395022024-09-27 4:15:116 days ago1727410511
0x679D4C1c...15d6431f6
1 ETH
208395022024-09-27 4:15:116 days ago1727410511
0x679D4C1c...15d6431f6
1 ETH
208323062024-09-26 4:10:237 days ago1727323823
0x679D4C1c...15d6431f6
0.00000125 ETH
208323062024-09-26 4:10:237 days ago1727323823
0x679D4C1c...15d6431f6
0.00000125 ETH
208251192024-09-25 4:05:118 days ago1727237111
0x679D4C1c...15d6431f6
0.002 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LidoStEthStrategy

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

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

import {EnumerableSet} from "oz/utils/structs/EnumerableSet.sol";
import {Strategy} from "./Strategy.sol";

import {IStETH} from "../interfaces/IStETH.sol";
import {IWStETH} from "../interfaces/IWStETH.sol";
import {ISwapManager} from "../interfaces/ISwapManager.sol";
import {IStrategyManager} from "../interfaces/IStrategyManager.sol";
import {TransferHelper} from "v3-periphery/libraries/TransferHelper.sol";
import {IWithdrawalQueueERC721} from "../interfaces/IWithdrawalQueueERC721.sol";

error Strategy__ZeroAmount();
error Strategy__LidoDeposit();
error Strategy__ZeroAddress();
error Strategy__ZeroPoolLiquidity();
error Strategy__InsufficientBalance();

/**
 * @title LidoStEthStrategy
 * @author Mavvverick
 * @dev A strategy contract for generating eth yield by managing Lido staked ETH (stETH)
 */
contract LidoStEthStrategy is Strategy {
    using EnumerableSet for EnumerableSet.UintSet;

    /// @notice minimal amount of stETH that is possible to withdraw
    uint256 public constant MIN_STETH_WITHDRAWAL_AMOUNT = 1_00;

    /// @notice maximum amount of stETH that is possible to withdraw by a single request
    /// Prevents accumulating too much funds per single request fulfillment in the future.
    /// @dev To withdraw larger amounts, it's recommended to split it to several requests
    uint256 public constant MAX_STETH_WITHDRAWAL_AMOUNT = 1_000 * 10 ** 18;

    address public swapManager;
    IStETH public STETH; //strategy token
    address public WETH9; //swap token for uniV3
    address public WSTETH; //swap token for uniV3
    IWithdrawalQueueERC721 public stETHWithdrawalQueue;

    EnumerableSet.UintSet private withdrawQueue;

    /**
     * @param _stETHAdress The address of the stETH contract
     * @param _stETHWithdrawal The address of the stETH withdrawal contract
     * @param _wstETHAdress The address of the wrapped stETH (wstETH) contract
     * @param _weth9 The address of the WETH9 contract
     * @param _swapManager The address of the SwapManager contract
     * @param _manager The address of the strategy manager
     * @param _name The name of the strategy
     */
    constructor(
        address _stETHAdress,
        address _stETHWithdrawal,
        address _wstETHAdress,
        address _weth9,
        address _swapManager,
        address payable _manager,
        string memory _name
    ) Strategy(_manager, _name) {
        if (
            _stETHAdress == address(0) || _stETHWithdrawal == address(0) || _wstETHAdress == address(0)
                || _weth9 == address(0) || _swapManager == address(0)
        ) revert Strategy__ZeroAddress();

        STETH = IStETH(_stETHAdress);
        stETHWithdrawalQueue = IWithdrawalQueueERC721(_stETHWithdrawal);
        swapManager = _swapManager;
        WSTETH = _wstETHAdress;
        WETH9 = _weth9;
    }

    /**
     * @dev Internal function to perform an instant withdrawal of stETH using swap pools.
     * @param _amount The amount of stETH to withdraw
     * @return actualAmount The actual amount of ETH withdrawn
     */
    function _instantWithdraw(uint256 _amount) internal returns (uint256 actualAmount) {
        // swap stEth for eth
        actualAmount = _swapUsingFairQuote(_amount);
        TransferHelper.safeTransferETH(manager, address(this).balance);
    }

    /**
     * @dev Internal function to swap stETH for ETH using UniV3 or Curve.
     * @param _amountIn The amount of stETH to swap
     * @return actualAmount The actual amount of ETH received after swapping
     */
    function _swapUsingFairQuote(uint256 _amountIn) internal returns (uint256 actualAmount) {
        uint256 amountInForV3 = IWStETH(WSTETH).getWstETHByStETH(_amountIn);
        uint256 v3Out = ISwapManager(swapManager).estimateV3AmountOut(uint128(amountInForV3), WSTETH, WETH9);
        uint256 curveOut = ISwapManager(swapManager).estimateCurveAmountOut(_amountIn, address(STETH));

        if (v3Out == 0 && curveOut == 0) revert Strategy__ZeroPoolLiquidity();

        uint256 quoteAmount = v3Out > curveOut ? v3Out : curveOut;
        uint256 quoteAmountMin = ISwapManager(swapManager).getMinimumAmount(WETH9, quoteAmount);
        address tokenIn;

        if (v3Out > curveOut) {
            tokenIn = WSTETH;
            // wrap stETH for uniswap pool
            TransferHelper.safeApprove(address(STETH), WSTETH, _amountIn);
            _amountIn = IWStETH(WSTETH).wrap(_amountIn);
            TransferHelper.safeApprove(tokenIn, swapManager, _amountIn);
            actualAmount = ISwapManager(swapManager).swapUinv3(tokenIn, _amountIn, quoteAmountMin);
        } else {
            tokenIn = address(STETH);
            TransferHelper.safeApprove(tokenIn, swapManager, _amountIn);
            actualAmount = ISwapManager(swapManager).swapCurve(tokenIn, _amountIn, quoteAmountMin);
        }
    }

    function _checkPendingAssets(uint256[] memory requestIds)
        internal
        view
        returns (uint256[] memory ids, uint256 totalClaimable, uint256 totalPending)
    {
        uint256 requestLen = requestIds.length;
        if (requestLen == 0) return (ids, 0, 0);
        ids = new uint256[](requestLen);

        IWithdrawalQueueERC721.WithdrawalRequestStatus[] memory statuses =
            stETHWithdrawalQueue.getWithdrawalStatus(requestIds);

        uint256 index = 0;
        uint256 len = statuses.length;

        for (uint256 i = 0; i < len;) {
            IWithdrawalQueueERC721.WithdrawalRequestStatus memory status = statuses[i];
            if (status.isClaimed) {
                unchecked {
                    i++;
                }
                continue;
            }
            if (status.isFinalized) {
                unchecked {
                    ids[index++] = requestIds[i];
                }
                totalClaimable += status.amountOfStETH;
            } else {
                totalPending += status.amountOfStETH;
            }

            unchecked {
                i++;
            }
        }

        assembly {
            mstore(ids, index)
        }
    }

    /**
     * @notice Deposit ETH into the Lido stETH contract.
     * @dev Only the strategy manager can call this function.
     */
    function deposit() external payable override onlyManager {
        if (msg.value == 0) revert Strategy__ZeroAmount();
        uint256 shares = STETH.submit{value: msg.value}(address(0));
        if (shares == 0) revert Strategy__LidoDeposit();
    }

    /**
     * @notice Initiate a withdrawal of a specific amount of stETH.
     * @dev Only the strategy manager can call this function.
     * @param _ethAmount The amount of stETH to withdraw.
     * @return actualAmount The actual amount of stETH withdrawn.
     */
    function withdraw(uint256 _ethAmount) external override onlyManager returns (uint256 actualAmount) {
        if (_ethAmount == 0) revert Strategy__ZeroAmount();
        if (STETH.balanceOf(address(this)) < _ethAmount) revert Strategy__InsufficientBalance();

        // Withdrawing as little as 100 wei from the underlying strategy is not economically viable.
        if (_ethAmount < MIN_STETH_WITHDRAWAL_AMOUNT) return 0;

        //approve steth for WithdrawalQueueERC721
        TransferHelper.safeApprove(address(STETH), address(stETHWithdrawalQueue), _ethAmount);

        uint256 remainingBalance = _ethAmount;
        uint256 batchLen = ((_ethAmount - 1) / MAX_STETH_WITHDRAWAL_AMOUNT) + 1;
        uint256[] memory requestedAmounts = new uint256[](batchLen);
        uint256 index;

        while (remainingBalance != 0) {
            requestedAmounts[index] =
                remainingBalance > MAX_STETH_WITHDRAWAL_AMOUNT ? MAX_STETH_WITHDRAWAL_AMOUNT : remainingBalance;
            unchecked {
                remainingBalance -= requestedAmounts[index];
                index++;
            }
        }

        //raise a withdraw request to WithdrawalQueueERC721
        uint256[] memory ids = stETHWithdrawalQueue.requestWithdrawals(requestedAmounts, address(this));

        uint256 idsLen = ids.length;

        // push the withdraw request id
        for (uint256 i = 0; i < idsLen;) {
            withdrawQueue.add(ids[i]);
            unchecked {
                i++;
            }
        }

        actualAmount = _ethAmount;
        if (address(this).balance > 0) {
            TransferHelper.safeTransferETH(manager, address(this).balance);
        }
    }

    /**
     * @notice Claim all pending withdrawal assets from the stETH withdrawal queue.
     * @dev This function claims all pending withdrawal assets and transfers them to the assets vault.
     * Check claimable pending assets before calling this function.
     * The queue will always stay within bounds since withdrawal is requested once per rebase cycle,
     * which is 365 requests in a year for a 1-day epoch cycle or 52 requests in a year for a 7-day epoch cycle
     * If the queue expands to a level where withdrawQueue consumes excessive gas, use claimAllPendingAssetsByIds instead.
     */
    function claimAllPendingAssets() external override {
        uint256[] memory withdrawIds = withdrawQueue.values();
        (uint256[] memory ids,,) = checkPendingAssets(withdrawIds);

        uint256 len = ids.length;
        for (uint256 i = 0; i < len;) {
            stETHWithdrawalQueue.claimWithdrawal(ids[i]);
            // remove claimed request Ids
            withdrawQueue.remove(ids[i]);
            unchecked {
                i++;
            }
        }

        TransferHelper.safeTransferETH(IStrategyManager(manager).assetsVault(), address(this).balance);
    }

    /**
     * @notice Redeems eth amount and deposit redeemed amount in the bridge
     * NB! Array of request ids should be sorted
     * @param claimableRequestIds An array of withdrawal request IDs that are claimable
     * @param hints Array of hints used to find required checkpoint for the request
     *  Reverts if requestIds and hints arrays length differs
     *  Reverts if any requestId or hint in arguments are not valid
     *  Reverts if any request is not finalized or already claimed
     */
    function claimAllPendingAssetsByIds(uint256[] memory claimableRequestIds, uint256[] memory hints) external {
        // Claim withdrawal amount
        // Reverts if any request is not finalized or already claimed
        stETHWithdrawalQueue.claimWithdrawals(claimableRequestIds, hints);

        // remove claimed request Ids
        uint256 requestsLen = claimableRequestIds.length;
        for (uint256 i = 0; i < requestsLen;) {
            withdrawQueue.remove(claimableRequestIds[i]);
            unchecked {
                i++;
            }
        }

        // Transfer the claimed asset to the assets vault
        TransferHelper.safeTransferETH(IStrategyManager(manager).assetsVault(), address(this).balance);
    }

    /**
     * @notice Initiate an instant withdrawal of stETH using swap pools
     * @dev Only the strategy manager can call this function.
     * @param _amount The amount of stETH to withdraw.
     * @return actualAmount The actual amount of stETH withdrawn.
     */
    function instantWithdraw(uint256 _amount) external override onlyManager returns (uint256 actualAmount) {
        if (_amount == 0) return 0;
        actualAmount = _instantWithdraw(_amount);
    }

    /**
     * @notice Clear the strategy by withdrawing all stETH to the assets vault
     * @dev This function withdraws all stETH from the strategy and transfers them to the strategy manager's assets vault.
     * @return amount The amount of stETH withdrawn.
     */
    function clear() external override onlyManager returns (uint256 amount) {
        uint256 balance = STETH.balanceOf(address(this));
        // if stEth shares is zero return actualAmount = 0
        if (balance == 0) return 0;
        amount = _instantWithdraw(balance);

        // Transfer left over dust shares to the asset vault
        uint256 share = STETH.sharesOf(address(this));
        if (share > 0) {
            STETH.transferShares(IStrategyManager(manager).assetsVault(), share);
        }
    }

    /**
     * @notice Check the pending withdrawal assets from the stETH withdrawal queue.
     * @dev This function retrieves the pending withdrawal assets and returns their IDs, total claimable amount, and total pending amount.
     * @return ids An array of withdrawal request IDs.
     * @return totalClaimable The total amount of claimable stETH.
     * @return totalPending The total amount of pending stETH.
     */
    function checkPendingAssets()
        public
        view
        returns (uint256[] memory ids, uint256 totalClaimable, uint256 totalPending)
    {
        uint256[] memory requestIds = withdrawQueue.values();
        (ids, totalClaimable, totalPending) = _checkPendingAssets(requestIds);
    }

    /**
     * @notice Check the pending withdrawal assets from the stETH withdrawal queue.
     * @dev This function retrieves the pending withdrawal assets and returns their IDs, total claimable amount, and total pending amount.
     * @param requestIds An array of withdrawal request IDs
     * @return ids An array of withdrawal request IDs.
     * @return totalClaimable The total amount of claimable stETH.
     * @return totalPending The total amount of pending stETH.
     */
    function checkPendingAssets(uint256[] memory requestIds)
        public
        view
        returns (uint256[] memory ids, uint256 totalClaimable, uint256 totalPending)
    {
        (ids, totalClaimable, totalPending) = _checkPendingAssets(requestIds);
    }

    /**
     * @notice Get the pending and executable assets amount
     * @dev This function retrieves the pending and executable assets from the stETH withdrawal queue.
     * @return pending The total amount of pending stETH.
     * @return executable The total amount of claimable stETH.
     */
    function checkPendingStatus() external view override returns (uint256 pending, uint256 executable) {
        (, executable, pending) = checkPendingAssets();
    }

    /**
     * @notice Retrieves the withdrawal request ids
     * @return requestIds An array of withdrawal request IDs
     */
    function getRequestIds() public view returns (uint256[] memory requestIds) {
        return withdrawQueue.values();
    }

    /**
     * @notice Retrieves the withdrawal request ids
     * @return requestIdsLength An array size of withdrawal request IDs
     */
    function getRequestIdsLen() public view returns (uint256 requestIdsLength) {
        return withdrawQueue.length();
    }

    /**
     * @notice Retrieves the withdrawal status of stETH requests
     * @return requestIds An array of withdrawal request IDs
     * @return statuses An array of withdrawal request statuses
     */
    function getStETHWithdrawalStatus()
        public
        view
        returns (uint256[] memory requestIds, IWithdrawalQueueERC721.WithdrawalRequestStatus[] memory statuses)
    {
        requestIds = stETHWithdrawalQueue.getWithdrawalRequests(address(this));
        statuses = stETHWithdrawalQueue.getWithdrawalStatus(requestIds);
    }

    /**
     * @notice Retrieves the withdrawal status of stETH requests
     * NB! Array of request ids should be sorted
     * @param requestIds An array of stETH withdrawal request IDs for claim
     * @return statuses An array of withdrawal request statuses
     */
    function getStETHWithdrawalStatusForIds(uint256[] memory requestIds)
        public
        view
        returns (IWithdrawalQueueERC721.WithdrawalRequestStatus[] memory statuses)
    {
        statuses = stETHWithdrawalQueue.getWithdrawalStatus(requestIds);
    }

    /**
     * @notice Get the total value of assets managed by the strategy.
     * @dev This function retrieves the total value of assets managed by the strategy, including invested, claimable, and pending values.
     * @return value The total value of assets managed by the strategy.
     */
    function getTotalValue() public view override returns (uint256 value) {
        value = getInvestedValue() + getClaimableAndPendingValue();
    }

    /**
     * @notice Get the invested value of assets managed by the strategy.
     * @dev This function retrieves the invested value of assets managed by the strategy.
     * @return value The invested value of assets managed by the strategy.
     */
    function getInvestedValue() public view override returns (uint256 value) {
        value = STETH.balanceOf(address(this));
    }

    /**
     * @notice Get the pending value of assets managed by the strategy.
     * @dev This function retrieves the pending value of assets managed by the strategy.
     * @return value The pending value of assets managed by the strategy.
     */
    function getPendingValue() public view override returns (uint256 value) {
        (,, value) = checkPendingAssets();
    }
    /**
     * @notice Get the claimable value of assets managed by the strategy.
     * @dev This function retrieves the claimable value of assets managed by the strategy.
     * @return value The claimable value of assets managed by the strategy.
     */

    function getClaimableValue() public view returns (uint256 value) {
        (, value,) = checkPendingAssets();
    }

    /**
     * @notice Get the total claimable and pending value of assets managed by the strategy.
     * @dev This function retrieves the total claimable and pending value of assets managed by the strategy.
     * @return value The total claimable and pending value of assets managed by the strategy.
     */
    function getClaimableAndPendingValue() public view returns (uint256 value) {
        (, uint256 claimableValue, uint256 pendingValue) = checkPendingAssets();
        value = claimableValue + pendingValue;
    }

    receive() external payable {}
}

File 2 of 13 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

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

import {IStrategyManager} from "../interfaces/IStrategyManager.sol";

error Strategy__ZeroAddress();
error Strategy__NotManager();
error Strategy__NotGovernance();

abstract contract Strategy {
    address payable public immutable manager;
    address public governance;
    string public name;

    modifier onlyGovernance() {
        if (governance != msg.sender) revert Strategy__NotGovernance();
        _;
    }

    event TransferGovernance(address indexed oldOwner, address newOwner);

    constructor(address payable _manager, string memory _name) {
        if (_manager == address(0)) revert Strategy__NotManager();

        governance = msg.sender;
        manager = _manager;
        name = _name;
    }

    /**
     * @dev Throws if the caller is not the manager address.
     */
    modifier onlyManager() {
        if (manager != msg.sender) revert Strategy__NotManager();
        _;
    }

    /**
     * @dev Deposit function to deposit funds into the strategy.
     */
    function deposit() external payable virtual onlyManager {}

    /**
     * @dev Withdraw function to withdraw funds from the strategy.
     * @param _amount The amount of funds to withdraw.
     * @return actualAmount The actual amount withdrawn.
     */
    function withdraw(uint256 _amount) external virtual onlyManager returns (uint256 actualAmount) {}

    /**
     * @dev Instant withdraw function to immediately withdraw funds from the strategy.
     * @param _amount The amount of funds to withdraw.
     * @return actualAmount The actual amount withdrawn.
     */
    function instantWithdraw(uint256 _amount) external virtual onlyManager returns (uint256 actualAmount) {}

    /**
     * @dev Clear function to clear any allocated funds or assets in the strategy.
     * @return amount The amount of funds cleared.
     */
    function clear() external virtual onlyManager returns (uint256 amount) {}

    /**
     * @dev Execute pending request function to execute any pending transactions in the strategy.
     */
    function claimAllPendingAssets() external virtual;

    /**
     * @dev Get all value function to get the total value of assets held in the strategy.
     * @return value The total value of assets held in the strategy.
     */
    function getTotalValue() public virtual returns (uint256 value);

    /**
     * @dev Get pending value function to get the pending value of assets in the strategy.
     * @return value The pending value of assets in the strategy.
     */
    function getPendingValue() public virtual returns (uint256 value);

    /**
     * @dev Get invested value function to get the currently invested value of assets in the strategy.
     * @return value The currently invested value of assets in the strategy.
     */
    function getInvestedValue() public virtual returns (uint256 value);

    /**
     * @dev Check pending status function to check the status of pending transactions in the strategy.
     * @return pending The amount of pending transactions.
     * @return executable The claimable amount of transactions ready to be executed.
     */
    function checkPendingStatus() external virtual returns (uint256 pending, uint256 executable);

    /**
     * @dev Sets the governance address.
     * @param _governance The address to set as the new governance.
     */
    function setGovernance(address _governance) external onlyGovernance {
        if (_governance == address(0)) revert Strategy__ZeroAddress();
        emit TransferGovernance(governance, _governance);
        governance = _governance;
    }
}

File 4 of 13 : IStETH.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.8.21;

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

/// @notice Interface defining a Lido liquid staking pool
/// @dev see also [Lido liquid staking pool core contract](https://docs.lido.fi/contracts/lido)
interface IStETH is IERC20, IERC20Permit {
    /**
     * @notice Send funds to the pool with optional _referral parameter
     * @dev This function is alternative way to submit funds. Supports optional referral address.
     * @return Amount of StETH shares generated
     */
    function submit(address _referral) external payable returns (uint256);

    /**
     * @return the amount of shares owned by `_account`.
     */
    function sharesOf(address _account) external view returns (uint256);

    /**
     * @notice Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account.
     *
     * @return amount of transferred tokens.
     * Emits a `TransferShares` event.
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `_recipient` cannot be the zero address.
     * - the caller must have at least `_sharesAmount` shares.
     * - the contract must not be paused.
     *
     * @dev The `_sharesAmount` argument is the amount of shares, not tokens.
     */
    function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);

    /**
     * @return the amount of shares that corresponds to `_ethAmount` protocol-controlled Ether.
     */
    function getSharesByPooledEth(uint256 _pooledEthAmount) external view returns (uint256);

    /**
     * @return the amount of Ether that corresponds to `_sharesAmount` token shares.
     */
    function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);
}

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

/**
 * @title Wrapped stETH Interface
 * @dev Interface for a contract representing wrapped staked Ether (wstETH).
 */
abstract contract IWStETH {
    /**
     * @dev Unwraps a specified amount of wstETH tokens into stETH tokens.
     * @param _wstETHAmount The amount of wstETH tokens to unwrap.
     * @return The amount of stETH tokens received.
     */
    function unwrap(uint256 _wstETHAmount) external virtual returns (uint256);

    /**
     * @notice Exchanges stETH to wstETH
     * @param _stETHAmount amount of stETH to wrap in exchange for wstETH
     * @dev Requirements:
     *  - `_stETHAmount` must be non-zero
     *  - msg.sender must approve at least `_stETHAmount` stETH to this
     *    contract.
     *  - msg.sender must have at least `_stETHAmount` of stETH.
     * User should first approve _stETHAmount to the WstETH contract
     * @return Amount of wstETH user receives after wrap
     */
    function wrap(uint256 _stETHAmount) external virtual returns (uint256);

    /**
     * @dev Converts a specified amount of stETH tokens into wstETH tokens.
     * @param _stETHAmount The amount of stETH tokens to convert.
     * @return The amount of wstETH tokens received.
     */
    function getWstETHByStETH(uint256 _stETHAmount) external view virtual returns (uint256);

    /**
     * @dev Converts a specified amount of wstETH tokens into stETH tokens.
     * @param _wstETHAmount The amount of wstETH tokens to convert.
     * @return The amount of stETH tokens received.
     */
    function getStETHByWstETH(uint256 _wstETHAmount) external view virtual returns (uint256);

    /**
     * @dev Retrieves the current exchange rate of stETH to wstETH.
     * @return The current exchange rate of stETH to wstETH.
     */
    function stEthPerToken() external view virtual returns (uint256);
}

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

/**
 * @title SwapManager Interface
 * @dev Interface for a contract managing token swaps.
 */
interface ISwapManager {
    /**
     * @dev Swaps a specified amount of input tokens for output tokens.
     * @param tokenIn The address of the input token.
     * @param amountIn The amount of input tokens to swap.
     * @return amountOut  The amount of output tokens received.
     */
    function swap(address tokenIn, uint256 amountIn) external returns (uint256 amountOut);

    /**
     * @dev Sets a Uniswap V3 pool address on the whitelist for a specific token.
     * @param token The address of the token.
     * @param pool The address of the V3 pool.
     */
    function setWhitelistV3Pool(address token, address pool) external;

    /**
     * @dev Sets a Curve pool address on the whitelist for a specific token.
     * @param token The address of the token.
     * @param pool The address of the Curve pool.
     */
    function setWhitelistCurvePool(address token, address pool) external;

    /**
     * @dev Sets the fee for a specific pool.
     * @param token The address of the token.
     * @param fees The fee to be set.
     */
    function setPoolFee(address token, uint24 fees) external;
    function transferETH() external;

    /**
     * @dev Estimates the output amount of a token swap using the fair quote method.
     * @param tokenIn The address of the input token.
     * @param amountIn The amount of input tokens.
     * @return amountOut The estimated amount of output tokens.
     */
    function getFairQuote(address tokenIn, uint256 amountIn) external returns (uint256 amountOut);

    function swapUinv3(address tokenIn, uint256 amountIn, uint256 amountOutMinimum)
        external
        returns (uint256 amountOut);

    function swapCurve(address tokenIn, uint256 amountIn, uint256 amountOutMinimum)
        external
        returns (uint256 amountOut);

    function getMinimumAmount(address token, uint256 amount) external view returns (uint256);

    /**
     * @dev Estimates the output amount of a token swap in a Curve pool.
     * @param amountIn The amount of input tokens.
     * @param tokenIn The address of the input token.
     * @return amountOut The estimated amount of output tokens.
     */
    function estimateCurveAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256 amountOut);

    /**
     * @dev Estimates the output amount of a token swap in a V3 pool.
     * @param amountIn The amount of input tokens.
     * @param tokenIn The address of the input token.
     * @param tokenOut The address of the output token.
     * @return amountOut The estimated amount of output tokens.
     */
    function estimateV3AmountOut(uint128 amountIn, address tokenIn, address tokenOut)
        external
        view
        returns (uint256 amountOut);
}

File 7 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 8 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 9 of 13 : IWithdrawalQueueERC721.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.21;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IWithdrawalQueueERC721 is IERC721 {
    /// @notice output format struct for `_getWithdrawalStatus()` method
    struct WithdrawalRequestStatus {
        /// @notice stETH token amount that was locked on withdrawal queue for this request
        uint256 amountOfStETH;
        /// @notice amount of stETH shares locked on withdrawal queue for this request
        uint256 amountOfShares;
        /// @notice address that can claim or transfer this request
        address owner;
        /// @notice timestamp of when the request was created, in seconds
        uint256 timestamp;
        /// @notice true, if request is finalized
        bool isFinalized;
        /// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)
        bool isClaimed;
    }

    /// @dev See {IERC721-balanceOf}.
    function balanceOf(address _owner) external view returns (uint256);

    /// @notice Returns all withdrawal requests that belongs to the `_owner` address
    ///
    /// WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
    /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
    /// this function has an unbounded cost, and using it as part of a state-changing function may render the function
    /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.

    function getWithdrawalRequests(address _owner) external view returns (uint256[] memory requestsIds);
    /// @notice Returns status for requests with provided ids
    /// @param _requestIds array of withdrawal request ids
    function getWithdrawalStatus(uint256[] calldata _requestIds)
        external
        view
        returns (WithdrawalRequestStatus[] memory statuses);

    /// @notice length of the checkpoint array. Last possible value for the hint.
    ///  NB! checkpoints are indexed from 1, so it returns 0 if there is no checkpoints
    function getLastCheckpointIndex() external view returns (uint256);

    /// @notice Request the batch of stETH for withdrawal. Approvals for the passed amounts should be done before.
    /// @param _amounts an array of stETH amount values.
    ///  The standalone withdrawal request will be created for each item in the passed list.
    /// @param _owner address that will be able to manage the created requests.
    ///  If `address(0)` is passed, `msg.sender` will be used as owner.
    /// @return requestIds an array of the created withdrawal request ids
    function requestWithdrawals(uint256[] calldata _amounts, address _owner)
        external
        returns (uint256[] memory requestIds);

    /// @notice Finds the list of hints for the given `_requestIds` searching among the checkpoints with indices
    ///  in the range  `[_firstIndex, _lastIndex]`.
    ///  NB! Array of request ids should be sorted
    ///  NB! `_firstIndex` should be greater than 0, because checkpoint list is 1-based array
    ///  Usage: findCheckpointHints(_requestIds, 1, getLastCheckpointIndex())
    /// @param _requestIds ids of the requests sorted in the ascending order to get hints for
    /// @param _firstIndex left boundary of the search range. Should be greater than 0
    /// @param _lastIndex right boundary of the search range. Should be less than or equal to getLastCheckpointIndex()
    /// @return hintIds array of hints used to find required checkpoint for the request
    function findCheckpointHints(uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex)
        external
        view
        returns (uint256[] memory hintIds);

    /// @notice Claim a batch of withdrawal requests if they are finalized sending locked ether to the owner
    /// @param _requestIds array of request ids to claim
    /// @param _hints checkpoint hint for each id. Can be obtained with `findCheckpointHints()`
    /// @dev
    ///  Reverts if requestIds and hints arrays length differs
    ///  Reverts if any requestId or hint in arguments are not valid
    ///  Reverts if any request is not finalized or already claimed
    ///  Reverts if msg sender is not an owner of the requests
    function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external;

    /// @notice Claim one`_requestId` request once finalized sending locked ether to the owner
    /// @param _requestId request id to claim
    /// @dev use unbounded loop to find a hint, which can lead to OOG
    /// @dev
    ///  Reverts if requestId or hint are not valid
    ///  Reverts if request is not finalized or already claimed
    ///  Reverts if msg sender is not an owner of request
    function claimWithdrawal(uint256 _requestId) external;

    /// @notice Claim a batch of withdrawal requests if they are finalized sending ether to `_recipient`
    /// @param _requestIds array of request ids to claim
    /// @param _hints checkpoint hint for each id. Can be obtained with `findCheckpointHints()`
    /// @param _recipient address where claimed ether will be sent to
    /// @dev
    ///  Reverts if recipient is equal to zero
    ///  Reverts if requestIds and hints arrays length differs
    ///  Reverts if any requestId or hint in arguments are not valid
    ///  Reverts if any request is not finalized or already claimed
    ///  Reverts if msg sender is not an owner of the requests
    function claimWithdrawalsTo(uint256[] calldata _requestIds, uint256[] calldata _hints, address _recipient)
        external;

    function finaliseRequest(uint256 _requestId) external;

    function finalize(uint256 _lastRequestIdToBeFinalized, uint256 _maxShareRate) external payable;

    function getLastRequestId() external view returns (uint256);

    function prefinalize(uint256[] calldata _batches, uint256 _maxShareRate)
        external
        view
        returns (uint256 ethToLock, uint256 sharesToBurn);
}

File 10 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 11 of 13 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

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

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

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

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

[{"inputs":[{"internalType":"address","name":"_stETHAdress","type":"address"},{"internalType":"address","name":"_stETHWithdrawal","type":"address"},{"internalType":"address","name":"_wstETHAdress","type":"address"},{"internalType":"address","name":"_weth9","type":"address"},{"internalType":"address","name":"_swapManager","type":"address"},{"internalType":"address payable","name":"_manager","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Strategy__InsufficientBalance","type":"error"},{"inputs":[],"name":"Strategy__LidoDeposit","type":"error"},{"inputs":[],"name":"Strategy__NotGovernance","type":"error"},{"inputs":[],"name":"Strategy__NotManager","type":"error"},{"inputs":[],"name":"Strategy__ZeroAddress","type":"error"},{"inputs":[],"name":"Strategy__ZeroAddress","type":"error"},{"inputs":[],"name":"Strategy__ZeroAmount","type":"error"},{"inputs":[],"name":"Strategy__ZeroPoolLiquidity","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"TransferGovernance","type":"event"},{"inputs":[],"name":"MAX_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STETH_WITHDRAWAL_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkPendingAssets","outputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256","name":"totalClaimable","type":"uint256"},{"internalType":"uint256","name":"totalPending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"name":"checkPendingAssets","outputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256","name":"totalClaimable","type":"uint256"},{"internalType":"uint256","name":"totalPending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkPendingStatus","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"},{"internalType":"uint256","name":"executable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimAllPendingAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"claimableRequestIds","type":"uint256[]"},{"internalType":"uint256[]","name":"hints","type":"uint256[]"}],"name":"claimAllPendingAssetsByIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clear","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getClaimableAndPendingValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimableValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInvestedValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRequestIds","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRequestIdsLen","outputs":[{"internalType":"uint256","name":"requestIdsLength","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStETHWithdrawalStatus","outputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct IWithdrawalQueueERC721.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"requestIds","type":"uint256[]"}],"name":"getStETHWithdrawalStatusForIds","outputs":[{"components":[{"internalType":"uint256","name":"amountOfStETH","type":"uint256"},{"internalType":"uint256","name":"amountOfShares","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bool","name":"isFinalized","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"}],"internalType":"struct IWithdrawalQueueERC721.WithdrawalRequestStatus[]","name":"statuses","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"instantWithdraw","outputs":[{"internalType":"uint256","name":"actualAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_governance","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stETHWithdrawalQueue","outputs":[{"internalType":"contract IWithdrawalQueueERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"actualAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a060405234801562000010575f80fd5b50604051620025d2380380620025d2833981016040819052620000339162000193565b81816001600160a01b0382166200005d57604051631db8f31760e31b815260040160405180910390fd5b5f80546001600160a01b031916331790556001600160a01b03821660805260016200008982826200036c565b5050506001600160a01b0387161580620000aa57506001600160a01b038616155b80620000bd57506001600160a01b038516155b80620000d057506001600160a01b038416155b80620000e357506001600160a01b038316155b1562000102576040516372f5fcdf60e11b815260040160405180910390fd5b5050600380546001600160a01b03199081166001600160a01b0397881617909155600680548216958716959095179094556002805485169186169190911790556005805484169285169290921790915560048054909216921691909117905562000434565b6001600160a01b03811681146200017c575f80fd5b50565b634e487b7160e01b5f52604160045260245ffd5b5f805f805f805f60e0888a031215620001aa575f80fd5b8751620001b78162000167565b80975050602080890151620001cc8162000167565b60408a0151909750620001df8162000167565b60608a0151909650620001f28162000167565b60808a0151909550620002058162000167565b60a08a0151909450620002188162000167565b60c08a01519093506001600160401b038082111562000235575f80fd5b818b0191508b601f83011262000249575f80fd5b8151818111156200025e576200025e6200017f565b604051601f8201601f19908116603f011681019083821181831017156200028957620002896200017f565b816040528281528e86848701011115620002a1575f80fd5b5f93505b82841015620002c45784840186015181850187015292850192620002a5565b5f86848301015280965050505050505092959891949750929550565b600181811c90821680620002f557607f821691505b6020821081036200031457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000367575f81815260208120601f850160051c81016020861015620003425750805b601f850160051c820191505b8181101562000363578281556001016200034e565b5050505b505050565b81516001600160401b038111156200038857620003886200017f565b620003a081620003998454620002e0565b846200031a565b602080601f831160018114620003d6575f8415620003be5750858301515b5f19600386901b1c1916600185901b17855562000363565b5f85815260208120601f198616915b828110156200040657888601518255948401946001909101908401620003e5565b50858210156200042457878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60805161214d620004855f395f81816102ca015281816106a0015281816109690152818161099d01528181610b0301528181610e0501528181610f8901528181611149015261150d015261214d5ff3fe6080604052600436106101bc575f3560e01c806375421af3116100f2578063c00f60c411610092578063db2296cd11610062578063db2296cd146104c1578063e00bfe50146104dd578063eea94dab146104fc578063fd92bff214610510575f80fd5b8063c00f60c414610472578063caa648b414610486578063d0e30db01461049a578063d9fb643a146104a2575f80fd5b80639e354677116100cd5780639e354677146103f4578063ab033ea914610413578063ac33a27314610432578063b9a5e71914610453575f80fd5b806375421af3146103885780637ca9c0f9146103b157806383b39e23146103d3575f80fd5b80632e1a7d4d1161015d57806352efea6e1161013857806352efea6e146103235780635aa6e675146103375780636c23ab4c14610355578063709d039d14610369575f80fd5b80632e1a7d4d1461029a578063481c6a75146102b95780634aa4a4fc14610304575f80fd5b80630d25a957116101985780630d25a95714610223578063162275f4146102375780631b63a9ec1461024b5780631c2ca2fd14610277575f80fd5b80621a5597146101c757806303f112e5146101ee57806306fdde0314610202575f80fd5b366101c357005b5f80fd5b3480156101d2575f80fd5b506101db61052f565b6040519081526020015b60405180910390f35b3480156101f9575f80fd5b506101db61053f565b34801561020d575f80fd5b5061021661054f565b6040516101e59190611afb565b34801561022e575f80fd5b506101db606481565b348015610242575f80fd5b506101db6105db565b348015610256575f80fd5b5061026a610265366004611c26565b6105fe565b6040516101e59190611cda565b348015610282575f80fd5b5061028b610676565b6040516101e593929190611d1a565b3480156102a5575f80fd5b506101db6102b4366004611d3e565b61069d565b3480156102c4575f80fd5b506102ec7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101e5565b34801561030f575f80fd5b506004546102ec906001600160a01b031681565b34801561032e575f80fd5b506101db61099a565b348015610342575f80fd5b505f546102ec906001600160a01b031681565b348015610360575f80fd5b506101db610bf6565b348015610374575f80fd5b506002546102ec906001600160a01b031681565b348015610393575f80fd5b5061039c610c60565b604080519283526020830191909152016101e5565b3480156103bc575f80fd5b506103c5610c73565b6040516101e5929190611d55565b3480156103de575f80fd5b506103f26103ed366004611d82565b610d5c565b005b3480156103ff575f80fd5b5061028b61040e366004611c26565b610e8e565b34801561041e575f80fd5b506103f261042d366004611df6565b610e9b565b34801561043d575f80fd5b50610446610f50565b6040516101e59190611e11565b34801561045e575f80fd5b506006546102ec906001600160a01b031681565b34801561047d575f80fd5b506101db610f5c565b348015610491575f80fd5b506101db610f6c565b6103f2610f87565b3480156104ad575f80fd5b506005546102ec906001600160a01b031681565b3480156104cc575f80fd5b506101db683635c9adc5dea0000081565b3480156104e8575f80fd5b506003546102ec906001600160a01b031681565b348015610507575f80fd5b506103f2611084565b34801561051b575f80fd5b506101db61052a366004611d3e565b611146565b5f610538610676565b9392505050565b5f61054a60076111a7565b905090565b6001805461055c90611e23565b80601f016020809104026020016040519081016040528092919081815260200182805461058890611e23565b80156105d35780601f106105aa576101008083540402835291602001916105d3565b820191905f5260205f20905b8154815290600101906020018083116105b657829003601f168201915b505050505081565b5f805f6105e6610676565b925092505080826105f79190611e6f565b9250505090565b600654604051635c625c2d60e11b81526060916001600160a01b03169063b8c4b85a9061062f908590600401611e11565b5f60405180830381865afa158015610649573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106709190810190611e91565b92915050565b60605f805f61068560076111b0565b9050610690816111bc565b9196909550909350915050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146106e757604051631db8f31760e31b815260040160405180910390fd5b815f03610707576040516348d0b82d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815230600482015283916001600160a01b0316906370a0823190602401602060405180830381865afa15801561074d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107719190611f7e565b10156107905760405163171a6e5960e11b815260040160405180910390fd5b60648210156107a057505f919050565b6003546006546107bd916001600160a01b03908116911684611352565b815f683635c9adc5dea000006107d4600184611f95565b6107de9190611fa8565b6107e9906001611e6f565b90505f8167ffffffffffffffff81111561080557610805611b2d565b60405190808252806020026020018201604052801561082e578160200160208202803683370190505b5090505f5b83156108a157683635c9adc5dea00000841161084f578361085a565b683635c9adc5dea000005b82828151811061086c5761086c611fc7565b60200260200101818152505081818151811061088a5761088a611fc7565b602090810291909101015190930392600101610833565b600654604051636b34082160e11b81525f916001600160a01b03169063d6681042906108d39086903090600401611fdb565b5f604051808303815f875af11580156108ee573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109159190810190612004565b80519091505f5b8181101561095a5761095183828151811061093957610939611fc7565b6020026020010151600761145290919063ffffffff16565b5060010161091c565b50879650471561098e5761098e7f00000000000000000000000000000000000000000000000000000000000000004761145d565b5050505050505b919050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146109e457604051631db8f31760e31b815260040160405180910390fd5b6003546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610a2a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a4e9190611f7e565b9050805f03610a5e575f91505090565b610a67816114fc565b600354604051633d7ad0b760e21b81523060048201529193505f916001600160a01b039091169063f5eb42dc90602401602060405180830381865afa158015610ab2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ad69190611f7e565b90508015610bf15760035f9054906101000a90046001600160a01b03166001600160a01b0316638fcb4e5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b0c1f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b819190612090565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303815f875af1158015610bcb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bef9190611f7e565b505b505090565b6003546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610c3c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061054a9190611f7e565b5f80610c6a610676565b94909350915050565b600654604051637d031b6560e01b815230600482015260609182916001600160a01b0390911690637d031b65906024015f60405180830381865afa158015610cbd573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ce49190810190612004565b600654604051635c625c2d60e11b81529193506001600160a01b03169063b8c4b85a90610d15908590600401611e11565b5f60405180830381865afa158015610d2f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d569190810190611e91565b90509091565b60065460405163e3afe0a360e01b81526001600160a01b039091169063e3afe0a390610d8e90859085906004016120ab565b5f604051808303815f87803b158015610da5575f80fd5b505af1158015610db7573d5f803e3d5ffd5b5050835191505f90505b81811015610dff57610df6848281518110610dde57610dde611fc7565b6020026020010151600761153290919063ffffffff16565b50600101610dc1565b50610e897f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637b0c1f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e839190612090565b4761145d565b505050565b60605f80610690846111bc565b5f546001600160a01b03163314610ec557604051630be1411f60e31b815260040160405180910390fd5b6001600160a01b038116610eec576040516372f5fcdf60e11b815260040160405180910390fd5b5f546040516001600160a01b038381168252909116907f2276211a3f2c7bc1943fe83cc63f8f970204ff6a4b83c690df2bc54d8f2792ad9060200160405180910390a25f80546001600160a01b0319166001600160a01b0392909216919091179055565b606061054a60076111b0565b5f610f65610676565b5092915050565b5f610f756105db565b610f7d610bf6565b61054a9190611e6f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610fd057604051631db8f31760e31b815260040160405180910390fd5b345f03610ff0576040516348d0b82d60e01b815260040160405180910390fd5b60035460405163a1903eab60e01b81525f60048201819052916001600160a01b03169063a1903eab90349060240160206040518083038185885af115801561103a573d5f803e3d5ffd5b50505050506040513d601f19601f8201168201806040525081019061105f9190611f7e565b9050805f036110815760405163b6acf41560e01b815260040160405180910390fd5b50565b5f61108f60076111b0565b90505f61109b82610e8e565b505080519091505f5b81811015610dff5760065483516001600160a01b039091169063f8444436908590849081106110d5576110d5611fc7565b60200260200101516040518263ffffffff1660e01b81526004016110fb91815260200190565b5f604051808303815f87803b158015611112575f80fd5b505af1158015611124573d5f803e3d5ffd5b5050505061113d838281518110610dde57610dde611fc7565b506001016110a4565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331461119057604051631db8f31760e31b815260040160405180910390fd5b815f0361119e57505f919050565b610670826114fc565b5f610670825490565b60605f6105388361153d565b60605f805f84519050805f036111d857505f915081905061134b565b8067ffffffffffffffff8111156111f1576111f1611b2d565b60405190808252806020026020018201604052801561121a578160200160208202803683370190505b50600654604051635c625c2d60e11b81529195505f916001600160a01b039091169063b8c4b85a90611250908990600401611e11565b5f60405180830381865afa15801561126a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112919190810190611e91565b80519091505f90815b81811015611344575f8482815181106112b5576112b5611fc7565b602002602001015190508060a00151156112d2575060010161129a565b80608001511561132c578982815181106112ee576112ee611fc7565b602002602001015189858060010196508151811061130e5761130e611fc7565b602090810291909101015280516113259089611e6f565b975061133b565b80516113389088611e6f565b96505b5060010161129a565b5050855250505b9193909250565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291515f928392908716916113ad91906120cf565b5f604051808303815f865af19150503d805f81146113e6576040519150601f19603f3d011682016040523d82523d5f602084013e6113eb565b606091505b509150915081801561141557508051158061141557508080602001905181019061141591906120ea565b61144b5760405162461bcd60e51b8152602060048201526002602482015261534160f01b60448201526064015b60405180910390fd5b5050505050565b5f6105388383611596565b604080515f808252602082019092526001600160a01b03841690839060405161148691906120cf565b5f6040518083038185875af1925050503d805f81146114c0576040519150601f19603f3d011682016040523d82523d5f602084013e6114c5565b606091505b5050905080610e895760405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606401611442565b5f611506826115e2565b90506109957f00000000000000000000000000000000000000000000000000000000000000004761145d565b5f61053883836119f6565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561158a57602002820191905f5260205f20905b815481526020019060010190808311611576575b50505050509050919050565b5f8181526001830160205260408120546115db57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610670565b505f610670565b60055460405162b0e38960e81b8152600481018390525f9182916001600160a01b039091169063b0e3890090602401602060405180830381865afa15801561162c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116509190611f7e565b6002546005546004805460405163650fc20d60e11b81526fffffffffffffffffffffffffffffffff8616928101929092526001600160a01b039283166024830152821660448201529293505f9291169063ca1f841a90606401602060405180830381865afa1580156116c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116e89190611f7e565b60025460035460405163373033eb60e21b8152600481018890526001600160a01b0391821660248201529293505f9291169063dcc0cfac90604401602060405180830381865afa15801561173e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117629190611f7e565b905081158015611770575080155b1561178e576040516356d6a99560e01b815260040160405180910390fd5b5f81831161179c578161179e565b825b6002546004805460405163a74984c760e01b81526001600160a01b0391821692810192909252602482018490529293505f929091169063a74984c790604401602060405180830381865afa1580156117f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061181c9190611f7e565b90505f8385111561194f57506005546003546001600160a01b03918216916118469116828a611352565b600554604051630ea598cb60e41b8152600481018a90526001600160a01b039091169063ea598cb0906024016020604051808303815f875af115801561188e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118b29190611f7e565b6002549098506118cd9082906001600160a01b03168a611352565b6002546040516386b3abbb60e01b81526001600160a01b038381166004830152602482018b905260448201859052909116906386b3abbb906064016020604051808303815f875af1158015611924573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119489190611f7e565b965061098e565b506003546002546001600160a01b039182169161196f918391168a611352565b600254604051631818888b60e21b81526001600160a01b038381166004830152602482018b90526044820185905290911690636062222c906064016020604051808303815f875af11580156119c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ea9190611f7e565b98975050505050505050565b5f8181526001830160205260408120548015611ad0575f611a18600183611f95565b85549091505f90611a2b90600190611f95565b9050808214611a8a575f865f018281548110611a4957611a49611fc7565b905f5260205f200154905080875f018481548110611a6957611a69611fc7565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611a9b57611a9b612103565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610670565b5f915050610670565b5f5b83811015611af3578181015183820152602001611adb565b50505f910152565b602081525f8251806020840152611b19816040850160208701611ad9565b601f01601f19169190910160400192915050565b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715611b6457611b64611b2d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611b9357611b93611b2d565b604052919050565b5f67ffffffffffffffff821115611bb457611bb4611b2d565b5060051b60200190565b5f82601f830112611bcd575f80fd5b81356020611be2611bdd83611b9b565b611b6a565b82815260059290921b84018101918181019086841115611c00575f80fd5b8286015b84811015611c1b5780358352918301918301611c04565b509695505050505050565b5f60208284031215611c36575f80fd5b813567ffffffffffffffff811115611c4c575f80fd5b611c5884828501611bbe565b949350505050565b5f8151808452602080850194508084015f5b83811015611ccf5781518051885283810151848901526040808201516001600160a01b0316908901526060808201519089015260808082015115159089015260a09081015115159088015260c09096019590820190600101611c72565b509495945050505050565b602081525f6105386020830184611c60565b5f8151808452602080850194508084015f5b83811015611ccf57815187529582019590820190600101611cfe565b606081525f611d2c6060830186611cec565b60208301949094525060400152919050565b5f60208284031215611d4e575f80fd5b5035919050565b604081525f611d676040830185611cec565b8281036020840152611d798185611c60565b95945050505050565b5f8060408385031215611d93575f80fd5b823567ffffffffffffffff80821115611daa575f80fd5b611db686838701611bbe565b93506020850135915080821115611dcb575f80fd5b50611dd885828601611bbe565b9150509250929050565b6001600160a01b0381168114611081575f80fd5b5f60208284031215611e06575f80fd5b813561053881611de2565b602081525f6105386020830184611cec565b600181811c90821680611e3757607f821691505b602082108103611e5557634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561067057610670611e5b565b80518015158114610995575f80fd5b5f6020808385031215611ea2575f80fd5b825167ffffffffffffffff811115611eb8575f80fd5b8301601f81018513611ec8575f80fd5b8051611ed6611bdd82611b9b565b81815260c09182028301840191848201919088841115611ef4575f80fd5b938501935b83851015611f725780858a031215611f10575f8081fd5b611f18611b41565b855181528686015187820152604080870151611f3381611de2565b90820152606086810151908201526080611f4e818801611e82565b9082015260a0611f5f878201611e82565b9082015283529384019391850191611ef9565b50979650505050505050565b5f60208284031215611f8e575f80fd5b5051919050565b8181038181111561067057610670611e5b565b5f82611fc257634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b604081525f611fed6040830185611cec565b905060018060a01b03831660208301529392505050565b5f6020808385031215612015575f80fd5b825167ffffffffffffffff81111561202b575f80fd5b8301601f8101851361203b575f80fd5b8051612049611bdd82611b9b565b81815260059190911b82018301908381019087831115612067575f80fd5b928401925b828410156120855783518252928401929084019061206c565b979650505050505050565b5f602082840312156120a0575f80fd5b815161053881611de2565b604081525f6120bd6040830185611cec565b8281036020840152611d798185611cec565b5f82516120e0818460208701611ad9565b9190910192915050565b5f602082840312156120fa575f80fd5b61053882611e82565b634e487b7160e01b5f52603160045260245ffdfea2646970667358221220612627996a8c74d967f9f193429e8739aeef0243444108089ebee8508244ed6b64736f6c63430008150033000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000889edc2edab5f40e902b864ad4d7ade8e412f9b10000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004ac36e1fa7dabefec885f30b163c571080b2c3350000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd800000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000184c69646f20496e766573746d656e742053747261746567790000000000000000

Deployed Bytecode

0x6080604052600436106101bc575f3560e01c806375421af3116100f2578063c00f60c411610092578063db2296cd11610062578063db2296cd146104c1578063e00bfe50146104dd578063eea94dab146104fc578063fd92bff214610510575f80fd5b8063c00f60c414610472578063caa648b414610486578063d0e30db01461049a578063d9fb643a146104a2575f80fd5b80639e354677116100cd5780639e354677146103f4578063ab033ea914610413578063ac33a27314610432578063b9a5e71914610453575f80fd5b806375421af3146103885780637ca9c0f9146103b157806383b39e23146103d3575f80fd5b80632e1a7d4d1161015d57806352efea6e1161013857806352efea6e146103235780635aa6e675146103375780636c23ab4c14610355578063709d039d14610369575f80fd5b80632e1a7d4d1461029a578063481c6a75146102b95780634aa4a4fc14610304575f80fd5b80630d25a957116101985780630d25a95714610223578063162275f4146102375780631b63a9ec1461024b5780631c2ca2fd14610277575f80fd5b80621a5597146101c757806303f112e5146101ee57806306fdde0314610202575f80fd5b366101c357005b5f80fd5b3480156101d2575f80fd5b506101db61052f565b6040519081526020015b60405180910390f35b3480156101f9575f80fd5b506101db61053f565b34801561020d575f80fd5b5061021661054f565b6040516101e59190611afb565b34801561022e575f80fd5b506101db606481565b348015610242575f80fd5b506101db6105db565b348015610256575f80fd5b5061026a610265366004611c26565b6105fe565b6040516101e59190611cda565b348015610282575f80fd5b5061028b610676565b6040516101e593929190611d1a565b3480156102a5575f80fd5b506101db6102b4366004611d3e565b61069d565b3480156102c4575f80fd5b506102ec7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd881565b6040516001600160a01b0390911681526020016101e5565b34801561030f575f80fd5b506004546102ec906001600160a01b031681565b34801561032e575f80fd5b506101db61099a565b348015610342575f80fd5b505f546102ec906001600160a01b031681565b348015610360575f80fd5b506101db610bf6565b348015610374575f80fd5b506002546102ec906001600160a01b031681565b348015610393575f80fd5b5061039c610c60565b604080519283526020830191909152016101e5565b3480156103bc575f80fd5b506103c5610c73565b6040516101e5929190611d55565b3480156103de575f80fd5b506103f26103ed366004611d82565b610d5c565b005b3480156103ff575f80fd5b5061028b61040e366004611c26565b610e8e565b34801561041e575f80fd5b506103f261042d366004611df6565b610e9b565b34801561043d575f80fd5b50610446610f50565b6040516101e59190611e11565b34801561045e575f80fd5b506006546102ec906001600160a01b031681565b34801561047d575f80fd5b506101db610f5c565b348015610491575f80fd5b506101db610f6c565b6103f2610f87565b3480156104ad575f80fd5b506005546102ec906001600160a01b031681565b3480156104cc575f80fd5b506101db683635c9adc5dea0000081565b3480156104e8575f80fd5b506003546102ec906001600160a01b031681565b348015610507575f80fd5b506103f2611084565b34801561051b575f80fd5b506101db61052a366004611d3e565b611146565b5f610538610676565b9392505050565b5f61054a60076111a7565b905090565b6001805461055c90611e23565b80601f016020809104026020016040519081016040528092919081815260200182805461058890611e23565b80156105d35780601f106105aa576101008083540402835291602001916105d3565b820191905f5260205f20905b8154815290600101906020018083116105b657829003601f168201915b505050505081565b5f805f6105e6610676565b925092505080826105f79190611e6f565b9250505090565b600654604051635c625c2d60e11b81526060916001600160a01b03169063b8c4b85a9061062f908590600401611e11565b5f60405180830381865afa158015610649573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106709190810190611e91565b92915050565b60605f805f61068560076111b0565b9050610690816111bc565b9196909550909350915050565b5f7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b031633146106e757604051631db8f31760e31b815260040160405180910390fd5b815f03610707576040516348d0b82d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815230600482015283916001600160a01b0316906370a0823190602401602060405180830381865afa15801561074d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107719190611f7e565b10156107905760405163171a6e5960e11b815260040160405180910390fd5b60648210156107a057505f919050565b6003546006546107bd916001600160a01b03908116911684611352565b815f683635c9adc5dea000006107d4600184611f95565b6107de9190611fa8565b6107e9906001611e6f565b90505f8167ffffffffffffffff81111561080557610805611b2d565b60405190808252806020026020018201604052801561082e578160200160208202803683370190505b5090505f5b83156108a157683635c9adc5dea00000841161084f578361085a565b683635c9adc5dea000005b82828151811061086c5761086c611fc7565b60200260200101818152505081818151811061088a5761088a611fc7565b602090810291909101015190930392600101610833565b600654604051636b34082160e11b81525f916001600160a01b03169063d6681042906108d39086903090600401611fdb565b5f604051808303815f875af11580156108ee573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109159190810190612004565b80519091505f5b8181101561095a5761095183828151811061093957610939611fc7565b6020026020010151600761145290919063ffffffff16565b5060010161091c565b50879650471561098e5761098e7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd84761145d565b5050505050505b919050565b5f7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b031633146109e457604051631db8f31760e31b815260040160405180910390fd5b6003546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610a2a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a4e9190611f7e565b9050805f03610a5e575f91505090565b610a67816114fc565b600354604051633d7ad0b760e21b81523060048201529193505f916001600160a01b039091169063f5eb42dc90602401602060405180830381865afa158015610ab2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ad69190611f7e565b90508015610bf15760035f9054906101000a90046001600160a01b03166001600160a01b0316638fcb4e5b7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316637b0c1f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b819190612090565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303815f875af1158015610bcb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bef9190611f7e565b505b505090565b6003546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610c3c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061054a9190611f7e565b5f80610c6a610676565b94909350915050565b600654604051637d031b6560e01b815230600482015260609182916001600160a01b0390911690637d031b65906024015f60405180830381865afa158015610cbd573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ce49190810190612004565b600654604051635c625c2d60e11b81529193506001600160a01b03169063b8c4b85a90610d15908590600401611e11565b5f60405180830381865afa158015610d2f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d569190810190611e91565b90509091565b60065460405163e3afe0a360e01b81526001600160a01b039091169063e3afe0a390610d8e90859085906004016120ab565b5f604051808303815f87803b158015610da5575f80fd5b505af1158015610db7573d5f803e3d5ffd5b5050835191505f90505b81811015610dff57610df6848281518110610dde57610dde611fc7565b6020026020010151600761153290919063ffffffff16565b50600101610dc1565b50610e897f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316637b0c1f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e839190612090565b4761145d565b505050565b60605f80610690846111bc565b5f546001600160a01b03163314610ec557604051630be1411f60e31b815260040160405180910390fd5b6001600160a01b038116610eec576040516372f5fcdf60e11b815260040160405180910390fd5b5f546040516001600160a01b038381168252909116907f2276211a3f2c7bc1943fe83cc63f8f970204ff6a4b83c690df2bc54d8f2792ad9060200160405180910390a25f80546001600160a01b0319166001600160a01b0392909216919091179055565b606061054a60076111b0565b5f610f65610676565b5092915050565b5f610f756105db565b610f7d610bf6565b61054a9190611e6f565b7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b03163314610fd057604051631db8f31760e31b815260040160405180910390fd5b345f03610ff0576040516348d0b82d60e01b815260040160405180910390fd5b60035460405163a1903eab60e01b81525f60048201819052916001600160a01b03169063a1903eab90349060240160206040518083038185885af115801561103a573d5f803e3d5ffd5b50505050506040513d601f19601f8201168201806040525081019061105f9190611f7e565b9050805f036110815760405163b6acf41560e01b815260040160405180910390fd5b50565b5f61108f60076111b0565b90505f61109b82610e8e565b505080519091505f5b81811015610dff5760065483516001600160a01b039091169063f8444436908590849081106110d5576110d5611fc7565b60200260200101516040518263ffffffff1660e01b81526004016110fb91815260200190565b5f604051808303815f87803b158015611112575f80fd5b505af1158015611124573d5f803e3d5ffd5b5050505061113d838281518110610dde57610dde611fc7565b506001016110a4565b5f7f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd86001600160a01b0316331461119057604051631db8f31760e31b815260040160405180910390fd5b815f0361119e57505f919050565b610670826114fc565b5f610670825490565b60605f6105388361153d565b60605f805f84519050805f036111d857505f915081905061134b565b8067ffffffffffffffff8111156111f1576111f1611b2d565b60405190808252806020026020018201604052801561121a578160200160208202803683370190505b50600654604051635c625c2d60e11b81529195505f916001600160a01b039091169063b8c4b85a90611250908990600401611e11565b5f60405180830381865afa15801561126a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112919190810190611e91565b80519091505f90815b81811015611344575f8482815181106112b5576112b5611fc7565b602002602001015190508060a00151156112d2575060010161129a565b80608001511561132c578982815181106112ee576112ee611fc7565b602002602001015189858060010196508151811061130e5761130e611fc7565b602090810291909101015280516113259089611e6f565b975061133b565b80516113389088611e6f565b96505b5060010161129a565b5050855250505b9193909250565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291515f928392908716916113ad91906120cf565b5f604051808303815f865af19150503d805f81146113e6576040519150601f19603f3d011682016040523d82523d5f602084013e6113eb565b606091505b509150915081801561141557508051158061141557508080602001905181019061141591906120ea565b61144b5760405162461bcd60e51b8152602060048201526002602482015261534160f01b60448201526064015b60405180910390fd5b5050505050565b5f6105388383611596565b604080515f808252602082019092526001600160a01b03841690839060405161148691906120cf565b5f6040518083038185875af1925050503d805f81146114c0576040519150601f19603f3d011682016040523d82523d5f602084013e6114c5565b606091505b5050905080610e895760405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606401611442565b5f611506826115e2565b90506109957f0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd84761145d565b5f61053883836119f6565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561158a57602002820191905f5260205f20905b815481526020019060010190808311611576575b50505050509050919050565b5f8181526001830160205260408120546115db57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610670565b505f610670565b60055460405162b0e38960e81b8152600481018390525f9182916001600160a01b039091169063b0e3890090602401602060405180830381865afa15801561162c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116509190611f7e565b6002546005546004805460405163650fc20d60e11b81526fffffffffffffffffffffffffffffffff8616928101929092526001600160a01b039283166024830152821660448201529293505f9291169063ca1f841a90606401602060405180830381865afa1580156116c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116e89190611f7e565b60025460035460405163373033eb60e21b8152600481018890526001600160a01b0391821660248201529293505f9291169063dcc0cfac90604401602060405180830381865afa15801561173e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117629190611f7e565b905081158015611770575080155b1561178e576040516356d6a99560e01b815260040160405180910390fd5b5f81831161179c578161179e565b825b6002546004805460405163a74984c760e01b81526001600160a01b0391821692810192909252602482018490529293505f929091169063a74984c790604401602060405180830381865afa1580156117f8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061181c9190611f7e565b90505f8385111561194f57506005546003546001600160a01b03918216916118469116828a611352565b600554604051630ea598cb60e41b8152600481018a90526001600160a01b039091169063ea598cb0906024016020604051808303815f875af115801561188e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118b29190611f7e565b6002549098506118cd9082906001600160a01b03168a611352565b6002546040516386b3abbb60e01b81526001600160a01b038381166004830152602482018b905260448201859052909116906386b3abbb906064016020604051808303815f875af1158015611924573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119489190611f7e565b965061098e565b506003546002546001600160a01b039182169161196f918391168a611352565b600254604051631818888b60e21b81526001600160a01b038381166004830152602482018b90526044820185905290911690636062222c906064016020604051808303815f875af11580156119c6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ea9190611f7e565b98975050505050505050565b5f8181526001830160205260408120548015611ad0575f611a18600183611f95565b85549091505f90611a2b90600190611f95565b9050808214611a8a575f865f018281548110611a4957611a49611fc7565b905f5260205f200154905080875f018481548110611a6957611a69611fc7565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611a9b57611a9b612103565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610670565b5f915050610670565b5f5b83811015611af3578181015183820152602001611adb565b50505f910152565b602081525f8251806020840152611b19816040850160208701611ad9565b601f01601f19169190910160400192915050565b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715611b6457611b64611b2d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611b9357611b93611b2d565b604052919050565b5f67ffffffffffffffff821115611bb457611bb4611b2d565b5060051b60200190565b5f82601f830112611bcd575f80fd5b81356020611be2611bdd83611b9b565b611b6a565b82815260059290921b84018101918181019086841115611c00575f80fd5b8286015b84811015611c1b5780358352918301918301611c04565b509695505050505050565b5f60208284031215611c36575f80fd5b813567ffffffffffffffff811115611c4c575f80fd5b611c5884828501611bbe565b949350505050565b5f8151808452602080850194508084015f5b83811015611ccf5781518051885283810151848901526040808201516001600160a01b0316908901526060808201519089015260808082015115159089015260a09081015115159088015260c09096019590820190600101611c72565b509495945050505050565b602081525f6105386020830184611c60565b5f8151808452602080850194508084015f5b83811015611ccf57815187529582019590820190600101611cfe565b606081525f611d2c6060830186611cec565b60208301949094525060400152919050565b5f60208284031215611d4e575f80fd5b5035919050565b604081525f611d676040830185611cec565b8281036020840152611d798185611c60565b95945050505050565b5f8060408385031215611d93575f80fd5b823567ffffffffffffffff80821115611daa575f80fd5b611db686838701611bbe565b93506020850135915080821115611dcb575f80fd5b50611dd885828601611bbe565b9150509250929050565b6001600160a01b0381168114611081575f80fd5b5f60208284031215611e06575f80fd5b813561053881611de2565b602081525f6105386020830184611cec565b600181811c90821680611e3757607f821691505b602082108103611e5557634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561067057610670611e5b565b80518015158114610995575f80fd5b5f6020808385031215611ea2575f80fd5b825167ffffffffffffffff811115611eb8575f80fd5b8301601f81018513611ec8575f80fd5b8051611ed6611bdd82611b9b565b81815260c09182028301840191848201919088841115611ef4575f80fd5b938501935b83851015611f725780858a031215611f10575f8081fd5b611f18611b41565b855181528686015187820152604080870151611f3381611de2565b90820152606086810151908201526080611f4e818801611e82565b9082015260a0611f5f878201611e82565b9082015283529384019391850191611ef9565b50979650505050505050565b5f60208284031215611f8e575f80fd5b5051919050565b8181038181111561067057610670611e5b565b5f82611fc257634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b604081525f611fed6040830185611cec565b905060018060a01b03831660208301529392505050565b5f6020808385031215612015575f80fd5b825167ffffffffffffffff81111561202b575f80fd5b8301601f8101851361203b575f80fd5b8051612049611bdd82611b9b565b81815260059190911b82018301908381019087831115612067575f80fd5b928401925b828410156120855783518252928401929084019061206c565b979650505050505050565b5f602082840312156120a0575f80fd5b815161053881611de2565b604081525f6120bd6040830185611cec565b8281036020840152611d798185611cec565b5f82516120e0818460208701611ad9565b9190910192915050565b5f602082840312156120fa575f80fd5b61053882611e82565b634e487b7160e01b5f52603160045260245ffdfea2646970667358221220612627996a8c74d967f9f193429e8739aeef0243444108089ebee8508244ed6b64736f6c63430008150033

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

000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000889edc2edab5f40e902b864ad4d7ade8e412f9b10000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004ac36e1fa7dabefec885f30b163c571080b2c3350000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd800000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000184c69646f20496e766573746d656e742053747261746567790000000000000000

-----Decoded View---------------
Arg [0] : _stETHAdress (address): 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84
Arg [1] : _stETHWithdrawal (address): 0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1
Arg [2] : _wstETHAdress (address): 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
Arg [3] : _weth9 (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [4] : _swapManager (address): 0x4AC36E1Fa7daBeFEc885f30B163c571080b2c335
Arg [5] : _manager (address): 0x5Cba18d504D4158dC1A18C5Dc6BB2a30B230DdD8
Arg [6] : _name (string): Lido Investment Strategy

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84
Arg [1] : 000000000000000000000000889edc2edab5f40e902b864ad4d7ade8e412f9b1
Arg [2] : 0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [4] : 0000000000000000000000004ac36e1fa7dabefec885f30b163c571080b2c335
Arg [5] : 0000000000000000000000005cba18d504d4158dc1a18c5dc6bb2a30b230ddd8
Arg [6] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [8] : 4c69646f20496e766573746d656e742053747261746567790000000000000000


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.