ETH Price: $2,277.71 (-6.28%)

Contract

0xd29c222614Bbd050e196B6CdcCB54011FD41a144

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Set Approval For...2961106982025-01-16 18:33:36381 days ago1737052416IN
0xd29c2226...1FD41a144
0 ETH0.000003870.01
Withdraw2468092792024-08-26 5:51:52525 days ago1724651512IN
0xd29c2226...1FD41a144
0 ETH0.000001070.01
Deposit ETH2466293152024-08-25 17:17:53525 days ago1724606273IN
0xd29c2226...1FD41a144
0.025 ETH0.000001380.01
Withdraw2448994282024-08-20 16:47:26530 days ago1724172446IN
0xd29c2226...1FD41a144
0 ETH0.000001060.01
Withdraw2444252572024-08-19 7:43:51532 days ago1724053431IN
0xd29c2226...1FD41a144
0 ETH0.000001140.01
Withdraw2443478122024-08-19 2:19:50532 days ago1724033990IN
0xd29c2226...1FD41a144
0 ETH0.000001130.01
Withdraw2443228992024-08-19 0:35:41532 days ago1724027741IN
0xd29c2226...1FD41a144
0 ETH0.000001120.01
Deposit ETH2425941882024-08-13 23:42:53537 days ago1723592573IN
0xd29c2226...1FD41a144
1.4 ETH0.000000990.01
Deposit ETH2425930842024-08-13 23:38:15537 days ago1723592295IN
0xd29c2226...1FD41a144
1 ETH0.0000010.01
Deposit2424686072024-08-13 14:56:14537 days ago1723560974IN
0xd29c2226...1FD41a144
0 ETH0.000001620.012583
Withdraw2421566152024-08-12 17:01:26538 days ago1723482086IN
0xd29c2226...1FD41a144
0 ETH0.000001730.01
Withdraw2421350052024-08-12 15:30:46538 days ago1723476646IN
0xd29c2226...1FD41a144
0 ETH0.000016360.145603
Withdraw2419919912024-08-12 5:31:59539 days ago1723440719IN
0xd29c2226...1FD41a144
0 ETH0.000001140.01
Withdraw2419430912024-08-12 2:07:27539 days ago1723428447IN
0xd29c2226...1FD41a144
0 ETH0.000001130.01
Withdraw2419373872024-08-12 1:43:37539 days ago1723427017IN
0xd29c2226...1FD41a144
0 ETH0.000001150.01
Deposit ETH2401950922024-08-06 23:59:24544 days ago1722988764IN
0xd29c2226...1FD41a144
1 ETH0.000000910.01
Deposit ETH2401928102024-08-06 23:49:43544 days ago1722988183IN
0xd29c2226...1FD41a144
0.5 ETH0.000000950.01
Deposit ETH2401875842024-08-06 23:27:50544 days ago1722986870IN
0xd29c2226...1FD41a144
1 ETH0.000001040.01
Deposit ETH2401872422024-08-06 23:26:24544 days ago1722986784IN
0xd29c2226...1FD41a144
1 ETH0.000001040.01
Deposit2401342362024-08-06 19:43:35544 days ago1722973415IN
0xd29c2226...1FD41a144
0 ETH0.000001070.01
Deposit2401228142024-08-06 18:55:46544 days ago1722970546IN
0xd29c2226...1FD41a144
0 ETH0.000001360.01
Withdraw2398143422024-08-05 21:22:05545 days ago1722892925IN
0xd29c2226...1FD41a144
0 ETH0.000001620.012562
Withdraw2397423932024-08-05 16:18:53545 days ago1722874733IN
0xd29c2226...1FD41a144
0 ETH0.000014580.11455
Withdraw2396622272024-08-05 10:42:13545 days ago1722854533IN
0xd29c2226...1FD41a144
0 ETH0.000032760.258104
Withdraw2395901832024-08-05 5:40:13546 days ago1722836413IN
0xd29c2226...1FD41a144
0 ETH0.000033960.27773
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
2466293152024-08-25 17:17:53525 days ago1724606273
0xd29c2226...1FD41a144
0.025 ETH
2425941882024-08-13 23:42:53537 days ago1723592573
0xd29c2226...1FD41a144
1.4 ETH
2425930842024-08-13 23:38:15537 days ago1723592295
0xd29c2226...1FD41a144
1 ETH
2401950922024-08-06 23:59:24544 days ago1722988764
0xd29c2226...1FD41a144
1 ETH
2401928102024-08-06 23:49:43544 days ago1722988183
0xd29c2226...1FD41a144
0.5 ETH
2401875842024-08-06 23:27:50544 days ago1722986870
0xd29c2226...1FD41a144
1 ETH
2401872422024-08-06 23:26:24544 days ago1722986784
0xd29c2226...1FD41a144
1 ETH
2377847342024-07-30 23:45:51551 days ago1722383151
0xd29c2226...1FD41a144
1 ETH
2377811572024-07-30 23:30:53551 days ago1722382253
0xd29c2226...1FD41a144
1 ETH
2377163362024-07-30 18:59:58551 days ago1722365998
0xd29c2226...1FD41a144
0.4 ETH
2353710702024-07-23 23:31:46558 days ago1721777506
0xd29c2226...1FD41a144
1 ETH
2353633282024-07-23 22:59:10558 days ago1721775550
0xd29c2226...1FD41a144
1 ETH
2353576592024-07-23 22:35:23558 days ago1721774123
0xd29c2226...1FD41a144
0.05 ETH
2324818402024-07-15 13:54:19566 days ago1721051659
0xd29c2226...1FD41a144
0.2603 ETH
2305493862024-07-09 23:23:39572 days ago1720567419
0xd29c2226...1FD41a144
0.1 ETH
2257097892024-06-25 22:30:24586 days ago1719354624
0xd29c2226...1FD41a144
0.01 ETH
2232955612024-06-18 22:52:26593 days ago1718751146
0xd29c2226...1FD41a144
0.1 ETH
2208945452024-06-11 23:59:48600 days ago1718150388
0xd29c2226...1FD41a144
0.5 ETH
2208856102024-06-11 23:22:48600 days ago1718148168
0xd29c2226...1FD41a144
0.13 ETH
2184801762024-06-04 23:53:49607 days ago1717545229
0xd29c2226...1FD41a144
0.6 ETH
2160580592024-05-28 23:15:54614 days ago1716938154
0xd29c2226...1FD41a144
1 ETH
2160032402024-05-28 19:27:11614 days ago1716924431
0xd29c2226...1FD41a144
0.2 ETH
2136877892024-05-21 23:44:25621 days ago1716335065
0xd29c2226...1FD41a144
1.03 ETH
2136396142024-05-21 20:20:33621 days ago1716322833
0xd29c2226...1FD41a144
0.5 ETH
2113316602024-05-14 23:38:58628 days ago1715729938
0xd29c2226...1FD41a144
0.1 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x96B460AC...6cE6E25D2
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Carousel

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "../VaultV2.sol";

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {
    SafeERC20
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";

/// @author Y2K Finance Team

contract Carousel is VaultV2 {
    using SafeERC20 for IERC20;
    using FixedPointMathLib for uint256;
    /*///////////////////////////////////////////////////////////////
                               IMMUTABLES AND STORAGE
    //////////////////////////////////////////////////////////////*/
    // Earthquake parameters
    uint256 public relayerFee;
    uint256 public depositFee;
    uint256 public minQueueDeposit;
    IERC20 public immutable emissionsToken;

    mapping(address => uint256) public ownerToRollOverQueueIndex;
    QueueItem[] public rolloverQueue;
    QueueItem[] public depositQueue;
    mapping(uint256 => uint256) public rolloverAccounting;
    mapping(uint256 => uint256) public emissions;

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

    /** @notice constructor
        @param _data  Carousel.ConstructorArgs struct containing the data to be used in the constructor;
     */
    constructor(ConstructorArgs memory _data)
        VaultV2(
            _data.isWETH,
            _data.assetAddress,
            _data.name,
            _data.symbol,
            _data.tokenURI,
            _data.token,
            _data.strike,
            _data.controller
        )
    {
        if (_data.relayerFee < 10000) revert RelayerFeeToLow();
        if (_data.depositFee > 250) revert BPSToHigh();
        if (_data.emissionsToken == address(0)) revert AddressZero();
        emissionsToken = IERC20(_data.emissionsToken);
        relayerFee = _data.relayerFee;
        depositFee = _data.depositFee;
        minQueueDeposit = _data.minQueueDeposit;

        // set epoch 0 to be allways available to deposit into Queue
        epochExists[0] = true;
        epochConfig[0] = EpochConfig({
            epochBegin: 10**10 * 40 - 7 days,
            epochEnd: 10**10 * 40,
            epochCreation: uint40(block.timestamp)
        });
        epochs.push(0);
    }

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

    /** @notice Deposit function
        @dev if receiver intends to deposit into queue and is contract, it must implement 1155 receiver interface otherwise funds will be stuck
        @param  _id epoch id, if 0 deposit will be queued;
        @param _assets   uint256 of how many assets you want to deposit;
        @param _receiver  address of the receiver of the shares provided by this function, that represent the ownership of the deposited asset;
     */
    function deposit(
        uint256 _id,
        uint256 _assets,
        address _receiver
    )
        public
        override(VaultV2)
        epochIdExists(_id)
        epochHasNotStarted(_id)
        minRequiredDeposit(_assets, _id)
        nonReentrant
    {
        // make sure that epoch exists
        // epoch has not started (valid deposit period)
        // amount is enough to pay for relayer fees in case of queue deposit
        // function is not reentrant
        if (_receiver == address(0)) revert AddressZero();

        _asset().safeTransferFrom(msg.sender, address(this), _assets);
        // handles deposit logic for all cases (direct deposit, late deposit (if activated), queue deposit)
        _deposit(_id, _assets, _receiver);
    }

    function depositETH(uint256 _id, address _receiver)
        external
        payable
        override(VaultV2)
        minRequiredDeposit(msg.value, _id)
        epochIdExists(_id)
        epochHasNotStarted(_id)
        nonReentrant
    {
        if (!isWETH) revert CanNotDepositETH();
        if (_receiver == address(0)) revert AddressZero();

        IWETH(address(asset)).deposit{value: msg.value}();

        uint256 assets = msg.value;

        _deposit(_id, assets, _receiver);
    }

    /**
    @notice Withdraw entitled assets and burn shares of epoch
    @param  _id uint256 identifier of the epoch;
    @param _shares uint256 amount of shares to withdraw, this value will be used to calculate how many assets you are entitle to according the vaults claimTVL;
    @param _receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset;
    @param _owner Address of the _shares owner;
    @return assets How many assets the owner is entitled to, according to the epoch outcome;
     */
    function withdraw(
        uint256 _id,
        uint256 _shares,
        address _receiver,
        address _owner
    )
        external
        virtual
        override(VaultV2)
        epochIdExists(_id)
        epochHasEnded(_id)
        notRollingOver(_owner, _id, _shares)
        nonReentrant
        returns (uint256 assets)
    {
        // make sure that epoch exists
        // epoch is resolved
        // owners funds are not locked in rollover
        // function is not reentrant
        if (_receiver == address(0)) revert AddressZero();

        if (
            msg.sender != _owner &&
            isApprovedForAll(_owner, msg.sender) == false
        ) revert OwnerDidNotAuthorize(msg.sender, _owner);

        _burn(_owner, _id, _shares);
        uint256 entitledEmissions = previewEmissionsWithdraw(_id, _shares);
        if (epochNull[_id] == false) {
            assets = previewWithdraw(_id, _shares);
        } else {
            assets = _shares;
        }
        if (assets > 0) {
            SemiFungibleVault.asset.safeTransfer(_receiver, assets);
        }
        if (entitledEmissions > 0) {
            emissionsToken.safeTransfer(_receiver, entitledEmissions);
        }

        emit WithdrawWithEmissions(
            msg.sender,
            _receiver,
            _owner,
            _id,
            _shares,
            assets,
            entitledEmissions
        );

        return assets;
    }

    /*///////////////////////////////////////////////////////////////
                        TRANSFER LOGIC
        add notRollingOver modifier to all transfer functions      
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public override notRollingOver(from, id, amount) {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address, /*from*/
        address, /*to*/
        uint256[] memory, /*ids*/
        uint256[] memory, /*amounts*/
        bytes memory /*data*/
    ) public pure override {
        revert();
    }

    /*///////////////////////////////////////////////////////////////
                        Carousel Rollover Logic
    //////////////////////////////////////////////////////////////*/

    /** @notice enlists in rollover queue
        @dev user needs to have >= _assets in epoch (_epochId)
        @param  _epochId epoch id
        @param _shares   uint256 amount of shares to rollover;
        @param _receiver  address of the receiver of the emissions;
     */
    function enlistInRollover(
        uint256 _epochId,
        uint256 _shares,
        address _receiver
    ) public epochIdExists(_epochId) {
        // check if sender is approved by owner
        if (
            msg.sender != _receiver &&
            isApprovedForAll(_receiver, msg.sender) == false
        ) revert OwnerDidNotAuthorize(msg.sender, _receiver);
        // check if user has enough balance
        if (balanceOf(_receiver, _epochId) < _shares)
            revert InsufficientBalance();
        // to prevent spamming rollover queue and to ensure relayerFee can be payed,
        // shares rolled over must be worth at least minQueueDeposit
        if (!epochResolved[_epochId] && (_shares < minQueueDeposit))
            revert MinDeposit();
        else if (
            epochResolved[_epochId] &&
            (previewWithdraw(_epochId, _shares) < minQueueDeposit)
        ) revert MinDeposit();

        // check if user has already queued up a rollover
        if (ownerToRollOverQueueIndex[_receiver] != 0) {
            uint256 index = getRolloverIndex(_receiver);
            // if so, update the queue
            rolloverQueue[index].shares = _shares;
            rolloverQueue[index].epochId = _epochId;
        } else {
            // if not, add to queue
            rolloverQueue.push(
                QueueItem({
                    shares: _shares,
                    receiver: _receiver,
                    epochId: _epochId
                })
            );
            // index will allways be higher than 0
            ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length;
        }

        emit RolloverQueued(_receiver, _shares, _epochId);
    }

    /** @notice delists from rollover queue
        @param _owner address that is delisting from rollover queue
     */
    function delistInRollover(address _owner) public {
        // @note
        // its not possible for users to delete the QueueItem from the array because
        // during rollover, earlier users in rollover queue, can grief attack later users by deleting their queue item
        // instead we just set the assets to 0 and the epochId to 0 as a flag to indicate that the user is no longer in the queue

        // check if user is enlisted in rollover queue
        if (!isEnlistedInRolloverQueue(_owner)) revert NoRolloverQueued();
        // check if sender is approved by owner
        if (
            msg.sender != _owner &&
            isApprovedForAll(_owner, msg.sender) == false
        ) revert OwnerDidNotAuthorize(msg.sender, _owner);

        // set assets to 0 but keep the queue item
        uint256 index = getRolloverIndex(_owner);
        rolloverQueue[index].shares = 0;
        rolloverQueue[index].epochId = 0;
    }

    /** @notice mints deposit in rollover queue
        @param _epochId epoch id
        @param _operations  uint256 of how many operations to execute;
     */
    function mintDepositInQueue(uint256 _epochId, uint256 _operations)
        external
        epochIdExists(_epochId)
        epochHasNotStarted(_epochId)
        nonReentrant
    {
        // make sure there is already a new epoch set
        // epoch has not started
        QueueItem[] memory queue = depositQueue;
        uint256 length = depositQueue.length;

        // dont allow minting if epochId is 0
        if (_epochId == 0) revert InvalidEpochId();

        if (length == 0) revert OverflowQueue();
        // relayers can always input a very big number to mint all deposit queues, without the need to read depostQueue length first
        if (_operations > length) _operations = length;

        // queue is executed from the tail to the head
        // get last index of queue
        uint256 i = length - 1;
        uint256 relayerFeeShortfall;
        while ((length - _operations) <= i) {
            // this loop impelements FILO (first in last out) stack to reduce gas cost and improve code readability
            // changing it to FIFO (first in first out) would require more code changes and would be more expensive
            // @note non neglectable min-deposit creates barriers for attackers to DDOS the queue

            uint256 assetsToDeposit = queue[i].shares;

            if (depositFee > 0) {
                (
                    uint256 feeAmount,
                    uint256 assetsAfterFee
                ) = getEpochDepositFee(_epochId, assetsToDeposit);
                assetsToDeposit = assetsAfterFee;
                _asset().safeTransfer(treasury(), feeAmount);
            }

            // if minDeposit has chagned during QueueItem is in the queue and relayerFee is now higher than deposit amount
            // mint 0 and pay relayerFeeShortfall to relayer
            if (assetsToDeposit > relayerFee) {
                assetsToDeposit -= relayerFee;
            } else {
                relayerFeeShortfall += (relayerFee - assetsToDeposit);
                assetsToDeposit = 0;
            }

            _mintShares(queue[i].receiver, _epochId, assetsToDeposit);
            emit Deposit(
                msg.sender,
                queue[i].receiver,
                _epochId,
                assetsToDeposit
            );
            depositQueue.pop();
            if (i == 0) break;
            unchecked {
                i--;
            }
        }

        emit RelayerMinted(_epochId, _operations);

        asset.safeTransfer(
            msg.sender,
            (_operations * relayerFee) - relayerFeeShortfall
        );
    }

    /** @notice mints for rollovers
        @param _epochId epoch id
        @param _operations  uint256 of how many operations to execute;
     */
    function mintRollovers(uint256 _epochId, uint256 _operations)
        external
        epochIdExists(_epochId)
        epochHasNotStarted(_epochId)
        nonReentrant
    {
        // epoch has not started
        // dont allow rollover if epochId is 0
        if (_epochId == 0) revert InvalidEpochId();

        uint256 length = rolloverQueue.length;
        uint256 index = rolloverAccounting[_epochId];

        // revert if queue is empty or operations are more than queue length
        if (length == 0) revert OverflowQueue();

        if (_operations > length || (index + _operations) > length)
            _operations = length - index;

        // prev epoch is resolved
        if (!epochResolved[epochs[epochs.length - 2]])
            revert EpochNotResolved();

        // make sure epoch is next epoch
        if (epochs[epochs.length - 1] != _epochId) revert InvalidEpochId();

        QueueItem[] memory queue = rolloverQueue;

        // account for how many operations have been done
        uint256 prevIndex = index;
        uint256 executions = 0;

        while ((index - prevIndex) < (_operations)) {
            // only roll over if last epoch is resolved and user rollover position is valid
            if (
                epochResolved[queue[index].epochId] && queue[index].shares > 0
            ) {
                uint256 entitledAmount = previewWithdraw(
                    queue[index].epochId,
                    queue[index].shares
                );

                // mint only if user won epoch he is rolling over
                if (entitledAmount > queue[index].shares) {
                    // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert.
                    if (entitledAmount <= relayerFee) {
                        index++;
                        continue;
                    }

                    // to calculate originalDepositValue get the diff between shares and value of shares
                    // convert this value amount value back to shares
                    // subtract from assets
                    uint256 originalDepositValue = queue[index].shares -
                        previewAmountInShares(
                            queue[index].epochId,
                            (entitledAmount - queue[index].shares) // subtract profit from share value
                        );
                    // @note we know shares were locked up to this point
                    _burn(
                        queue[index].receiver,
                        queue[index].epochId,
                        originalDepositValue
                    );
                    // @note emission token is a known token which has no before transfer hooks which makes transfer safer
                    emissionsToken.safeTransfer(
                        queue[index].receiver,
                        previewEmissionsWithdraw(
                            queue[index].epochId,
                            originalDepositValue
                        )
                    );

                    emit WithdrawWithEmissions(
                        msg.sender,
                        queue[index].receiver,
                        queue[index].receiver,
                        _epochId,
                        originalDepositValue,
                        entitledAmount,
                        previewEmissionsWithdraw(
                            queue[index].epochId,
                            originalDepositValue
                        )
                    );
                    uint256 amountToMint = queue[index].shares - relayerFee;
                    _mintShares(queue[index].receiver, _epochId, amountToMint);
                    emit Deposit(
                        msg.sender,
                        queue[index].receiver,
                        _epochId,
                        amountToMint
                    );
                    rolloverQueue[index].shares = amountToMint;
                    rolloverQueue[index].epochId = _epochId;
                    // only pay relayer for successful mints
                    executions++;
                }
            }
            index++;
        }

        if (executions > 0) rolloverAccounting[_epochId] = index;

        if (executions * relayerFee > 0)
            asset.safeTransfer(msg.sender, executions * relayerFee);

        emit RelayerMinted(_epochId, executions);
    }

    /*///////////////////////////////////////////////////////////////
                        INTERNAL MUTATIVE LOGIC
    //////////////////////////////////////////////////////////////*/

    /** @notice deposits assets into epoch
        @param _id epoch id
        @param _assets amount of assets to deposit
        @param _receiver address of receiver
     */
    function _deposit(
        uint256 _id,
        uint256 _assets,
        address _receiver
    ) internal {
        // mint logic, either in queue or direct deposit
        if (_id != 0) {
            uint256 assetsToDeposit = _assets;

            if (depositFee > 0) {
                (
                    uint256 feeAmount,
                    uint256 assetsAfterFee
                ) = getEpochDepositFee(_id, _assets);
                assetsToDeposit = assetsAfterFee;
                _asset().safeTransfer(treasury(), feeAmount);
            }

            _mintShares(_receiver, _id, assetsToDeposit);

            emit Deposit(msg.sender, _receiver, _id, _assets);
        } else {
            depositQueue.push(
                QueueItem({shares: _assets, receiver: _receiver, epochId: _id})
            );

            emit DepositInQueue(msg.sender, _receiver, _id, _assets);
        }
    }

    /** @notice mints shares of vault for user
        @param to address of receiver
        @param id epoch id
        @param amount amount of shares to mint
     */
    function _mintShares(
        address to,
        uint256 id,
        uint256 amount
    ) internal {
        _mint(to, id, amount, EMPTY);
    }

    /*///////////////////////////////////////////////////////////////
                        ADMIN FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /**
    @notice This function is called by the controller if the epoch has started, but the counterparty vault has no value. In this case the users can withdraw their deposit. Additionally, emissions are transferred to the treasury. 
    @param  _id uint256 identifier of the epoch
     */
    function setEpochNull(uint256 _id)
        public
        override
        onlyController
        epochIdExists(_id)
        epochHasEnded(_id)
    {
        epochNull[_id] = true;
        if (emissions[_id] > 0) {
            emissionsToken.safeTransfer(treasury(), emissions[_id]);
            emissions[_id] = 0;
        }
    }

    /** @notice sets emissions
     * @param _epochId epoch id
     * @param _emissionAmount emissions rate
     */
    function setEmissions(uint256 _epochId, uint256 _emissionAmount)
        external
        onlyFactory
        epochIdExists(_epochId)
    {
        emissions[_epochId] = _emissionAmount;
    }

    /** @notice changes relayer fee
     * @param _relayerFee relayer fee
     */
    function changeRelayerFee(uint256 _relayerFee) external onlyFactory {
        relayerFee = _relayerFee;
    }

    /** @notice changes deposit fee
     * @param _depositFee deposit fee
     */
    function changeDepositFee(uint256 _depositFee) external onlyFactory {
        depositFee = _depositFee;
    }

    /** @notice cleans up rollover queue
     * @dev this function can only be called if there is no active deposit window
     * @param _addressesToDelist addresses to delist
     */
    function cleanUpRolloverQueue(address[] memory _addressesToDelist)
        external
        onlyFactory
        epochHasStarted(epochs[epochs.length - 1])
    {
        // check that there is no active deposit window;
        for (uint256 i = 0; i < _addressesToDelist.length; i++) {
            address owner = _addressesToDelist[i];
            uint256 index = ownerToRollOverQueueIndex[owner];
            if (index == 0) continue;
            uint256 queueIndex = index - 1;
            if (rolloverQueue[queueIndex].shares == 0) {
                // overwrite the item to be removed with the last item in the queue
                rolloverQueue[queueIndex] = rolloverQueue[
                    rolloverQueue.length - 1
                ];
                // remove the last item in the queue
                rolloverQueue.pop();
                // update the index of prev last user ( mapping index is allways array index + 1)
                ownerToRollOverQueueIndex[rolloverQueue[queueIndex].receiver] =
                    queueIndex +
                    1;
                // remove receiver from index mapping
                delete ownerToRollOverQueueIndex[owner];
            }
        }
    }

    /*///////////////////////////////////////////////////////////////
                        Getter Functions
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice calculates fee percent based on time
     * @param minX min x value
     * @param maxX max x value
     */
    function calculateFeePercent(int256 minX, int256 maxX)
        public
        view
        returns (uint256 _y)
    {
        /**
         * Two Point Form
         * https://www.cuemath.com/geometry/two-point-form/
         * https://ethereum.stackexchange.com/a/143172
         */
        // minY will always be 0 thats why is (maxY - minY) shorten to maxY
        int256 maxY = int256(depositFee) * int256(FixedPointMathLib.WAD);
        _y = uint256( // cast to uint256
            ((((maxY) / (maxX - minX)) * (int256(block.timestamp) - maxX)) +
                maxY) / (int256(FixedPointMathLib.WAD)) // two point math // scale down
        );
    }

    /** @notice returns the rollover index
     * @dev will revert if user is not in rollover queue
     * @param _owner address of the owner
     * @return rollover index
     */
    function getRolloverIndex(address _owner) public view returns (uint256) {
        return ownerToRollOverQueueIndex[_owner] - 1;
    }

    /** @notice retruns deposit fee at this time
     * @param _id epoch id
     * @param _assets amount of assets
     * @return feeAmount fee amount
     * @return assetsAfterFee assets after fee
     */
    function getEpochDepositFee(uint256 _id, uint256 _assets)
        public
        view
        returns (uint256 feeAmount, uint256 assetsAfterFee)
    {
        (uint256 maxX, , uint256 minX) = getEpochConfig(_id);
        // deposit fee is calcualted linearly between time of epoch creation and epoch starting (deposit window)
        // this is because late depositors have an informational advantage
        uint256 fee = calculateFeePercent(int256(minX), int256(maxX));
        // min minRequiredDeposit modifier ensures that _assets has high enough value to not devide by 0
        // 0.5% = multiply by 10000 then divide by 50
        feeAmount = _assets.mulDivDown(fee, 10000);
        assetsAfterFee = _assets - feeAmount;
    }

    /** @notice returns the emissions to withdraw
     * @param _id epoch id
     * @param _assets amount of assets to withdraw
     * @return entitledAmount amount of emissions to withdraw
     */
    function previewEmissionsWithdraw(uint256 _id, uint256 _assets)
        public
        view
        returns (uint256 entitledAmount)
    {
        entitledAmount = _assets.mulDivDown(emissions[_id], finalTVL[_id]);
    }

    /** @notice returns the amount of assets to withdraw
     * @param _id epoch id
     * @param _assets amount of shares
     * @return entitledShareAmount amount of emissions to withdraw
     */
    function previewAmountInShares(uint256 _id, uint256 _assets)
        public
        view
        returns (uint256 entitledShareAmount)
    {
        if (claimTVL[_id] != 0) {
            entitledShareAmount = _assets.mulDivDown(
                finalTVL[_id],
                claimTVL[_id]
            );
        } else {
            entitledShareAmount = 0;
        }
    }

    /** @notice returns the deposit queue length
     * @return queue length for the deposit
     */
    function getDepositQueueLength() public view returns (uint256) {
        return depositQueue.length;
    }

    /** @notice returns the queue length for the rollover
     * @return queue length for the rollover
     */
    function getRolloverQueueLength() public view returns (uint256) {
        return rolloverQueue.length;
    }

    /** @notice returns the total value locked in the rollover queue
     * @return tvl total value locked in the rollover queue
     */
    function getRolloverTVLByEpochId(uint256 _epochId)
        public
        view
        returns (uint256 tvl)
    {
        for (uint256 i = 0; i < rolloverQueue.length; i++) {
            uint256 assets = epochResolved[rolloverQueue[i].epochId]
                ? previewWithdraw(
                    rolloverQueue[i].epochId,
                    rolloverQueue[i].shares
                )
                : rolloverQueue[i].shares;

            if (
                rolloverQueue[i].epochId == _epochId &&
                (assets >= rolloverQueue[i].shares) // check if position is in profit and getting rollover
            ) {
                tvl += rolloverQueue[i].shares;
            }
        }
    }

    function getRolloverTVL() public view returns (uint256 tvl) {
        for (uint256 i = 0; i < rolloverQueue.length; i++) {
            uint256 assets = epochResolved[rolloverQueue[i].epochId]
                ? previewWithdraw(
                    rolloverQueue[i].epochId,
                    rolloverQueue[i].shares
                )
                : rolloverQueue[i].shares;

            if (
                assets >= rolloverQueue[i].shares // check if position is in profit and getting rollover
            ) {
                tvl += rolloverQueue[i].shares;
            }
        }
    }

    function getRolloverQueueItem(uint256 _index)
        public
        view
        returns (
            address receiver,
            uint256 shares,
            uint256 epochId
        )
    {
        receiver = rolloverQueue[_index].receiver;
        shares = rolloverQueue[_index].shares;
        epochId = rolloverQueue[_index].epochId;
    }

    /** @notice returns users rollover balance and epoch which is rolling over
     * @param _owner address of the user
     * @return shares balance of the user in rollover position
     * @return epochId epoch id
     */
    function getRolloverPosition(address _owner)
        public
        view
        returns (uint256 shares, uint256 epochId)
    {
        if (!isEnlistedInRolloverQueue(_owner)) {
            return (0, 0);
        }
        uint256 index = getRolloverIndex(_owner);
        shares = rolloverQueue[index].shares;
        epochId = rolloverQueue[index].epochId;
    }

    /** @notice returns is user is enlisted in the rollover queue
     * @param _owner address of the user
     * @return bool is user enlisted in the rollover queue
     */
    function isEnlistedInRolloverQueue(address _owner)
        public
        view
        returns (bool)
    {
        if (ownerToRollOverQueueIndex[_owner] == 0) {
            return false;
        }
        return rolloverQueue[getRolloverIndex(_owner)].shares != 0;
    }

    /** @notice returns the total value locked in the deposit queue
     * @return tvl total value locked in the deposit queue
     */
    function getDepositQueueTVL() public view returns (uint256 tvl) {
        for (uint256 i = 0; i < depositQueue.length; i++) {
            tvl += depositQueue[i].shares;
        }
    }

    /*//////////////////////////////////////////////////////////////
                                STRUCTS
    //////////////////////////////////////////////////////////////*/

    struct QueueItem {
        uint256 shares;
        address receiver;
        uint256 epochId;
    }

    struct ConstructorArgs {
        bool isWETH;
        address assetAddress;
        string name;
        string symbol;
        string tokenURI;
        address token;
        uint256 strike;
        address controller;
        address emissionsToken;
        uint256 relayerFee;
        uint256 depositFee;
        uint256 minQueueDeposit;
    }

    /*//////////////////////////////////////////////////////////////
                                MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /** @notice checks if deposit is at least min required
     * @param _assets amount of assets to deposit
     * @param _epochId epoch id
     */
    modifier minRequiredDeposit(uint256 _assets, uint256 _epochId) {
        if (_epochId == 0 && _assets < minQueueDeposit) revert MinDeposit();
        _;
    }

    /** @notice checks if not rolling over
     * @param _receiver address of the receiver
     * @param _epochId epoch id
     * @param _shares amount of assets to deposit
     */
    modifier notRollingOver(
        address _receiver,
        uint256 _epochId,
        uint256 _shares
    ) {
        if (isEnlistedInRolloverQueue(_receiver)) {
            QueueItem memory item = rolloverQueue[getRolloverIndex(_receiver)];
            if (
                item.epochId == _epochId &&
                (balanceOf(_receiver, _epochId) - item.shares) < _shares
            ) revert AlreadyRollingOver();
        }
        _;
    }

    /*//////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/

    error MinDeposit();
    error OverflowQueue();
    error AlreadyRollingOver();
    error InvalidEpochId();
    error InsufficientBalance();
    error NoRolloverQueued();
    error RelayerFeeToLow();
    error BPSToHigh();
    /*//////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event WithdrawWithEmissions(
        address caller,
        address receiver,
        address indexed owner,
        uint256 indexed id,
        uint256 assets,
        uint256 shares,
        uint256 emissions
    );

    /** @notice emitted when a deposit is queued
     * @param sender the address of the sender
     * @param receiver the address of the receiver
     * @param epochId the epoch id
     * @param shares the amount of assets
     */
    event DepositInQueue(
        address indexed sender,
        address indexed receiver,
        uint256 epochId,
        uint256 shares
    );

    /** @notice emitted when shares are minted by relayer
     * @param epochId the epoch id
     * @param operations how many positions were minted
     */
    event RelayerMinted(uint256 epochId, uint256 operations);

    /** @notice emitted when a rollover is queued
     * @param sender the address of the sender
     * @param shares the amount of assets
     * @param epochId the epoch id
     */
    event RolloverQueued(
        address indexed sender,
        uint256 shares,
        uint256 epochId
    );
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {
    ReentrancyGuard
} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./SemiFungibleVault.sol";
import {IVaultV2} from "./interfaces/IVaultV2.sol";
import {IVaultFactoryV2} from "./interfaces/IVaultFactoryV2.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {
    SafeERC20
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";

/// @author Y2K Finance Team

contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard {
    using SafeERC20 for IERC20;
    using FixedPointMathLib for uint256;

    /*///////////////////////////////////////////////////////////////
                               IMMUTABLES AND STORAGE
    //////////////////////////////////////////////////////////////*/

    // Earthquake parameters
    address public immutable token;
    uint256 public immutable strike;
    // Earthquake bussiness logic
    bool public immutable isWETH;
    address public counterPartyVault;
    address public factory;
    address public controller;
    uint256[] public epochs;

    mapping(uint256 => uint256) public finalTVL;
    mapping(uint256 => uint256) public claimTVL;
    mapping(uint256 => uint256) public epochAccounting;
    mapping(uint256 => EpochConfig) public epochConfig;
    mapping(uint256 => bool) public epochResolved;
    mapping(uint256 => bool) public epochExists;
    mapping(uint256 => bool) public epochNull;
    mapping(address => bool) public whitelistedAddresses;

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

    /** @notice constructor
        @param _assetAddress  address of the asset that will be used as collateral;
        @param _name  string representing the name of the vault;
        @param _symbol  string representing the symbol of the vault;
        @param _tokenURI  string representing the tokenURI of the vault;
        @param _token  address of the token that will be used as collateral;
        @param _strike  uint256 representing the strike price of the vault;
        @param _controller  address of the controller of the vault;
     */
    constructor(
        bool _isWETH,
        address _assetAddress,
        string memory _name,
        string memory _symbol,
        string memory _tokenURI,
        address _token,
        uint256 _strike,
        address _controller
    ) SemiFungibleVault(IERC20(_assetAddress), _name, _symbol, _tokenURI) {
        if (_controller == address(0)) revert AddressZero();
        if (_token == address(0)) revert AddressZero();
        if (_assetAddress == address(0)) revert AddressZero();
        token = _token;
        strike = _strike;
        factory = msg.sender;
        controller = _controller;
        isWETH = _isWETH;
    }

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

    /**
        @param  _id uint256 epoch identifier;
        @param  _assets uint256 amount of assets the user wants to deposit denominated in underlying asset decimals;
        @param _receiver address of the receiver of the shares minted;
     */
    function deposit(
        uint256 _id,
        uint256 _assets,
        address _receiver
    )
        public
        virtual
        override(SemiFungibleVault)
        epochIdExists(_id)
        epochHasNotStarted(_id)
        nonReentrant
    {
        if (_receiver == address(0)) revert AddressZero();
        SemiFungibleVault.asset.safeTransferFrom(
            msg.sender,
            address(this),
            _assets
        );

        _mint(_receiver, _id, _assets, EMPTY);

        emit Deposit(msg.sender, _receiver, _id, _assets);
    }

    /**
        @notice Deposit ETH function
        @param  _id  uint256 representing the id of the epoch;
       @param _receiver address of the receiver of the shares minted;
     */
    function depositETH(
        uint256 _id,
        address _receiver
    )
        external
        payable
        virtual
        epochIdExists(_id)
        epochHasNotStarted(_id)
        nonReentrant
    {
        if (!isWETH) revert CanNotDepositETH();
        require(msg.value > 0, "ZeroValue");
        if (_receiver == address(0)) revert AddressZero();

        IWETH(address(asset)).deposit{value: msg.value}();
        _mint(_receiver, _id, msg.value, EMPTY);

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

    /**
    @notice Withdraw entitled assets and burn shares of epoch
    @param  _id uint256 identifier of the epoch;
    @param _shares uint256 amount of shares to withdraw, this value will be used to calculate how many assets you are entitle to according the vaults claimTVL;
    @param _receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset;
    @param _owner Address of the _shares owner;
    @return assets How many assets the owner is entitled to, according to the epoch outcome;
     */
    function withdraw(
        uint256 _id,
        uint256 _shares,
        address _receiver,
        address _owner
    )
        external
        virtual
        override(SemiFungibleVault)
        epochIdExists(_id)
        epochHasEnded(_id)
        nonReentrant
        returns (uint256 assets)
    {
        if (_receiver == address(0)) revert AddressZero();

        if (
            msg.sender != _owner &&
            isApprovedForAll(_owner, msg.sender) == false
        ) revert OwnerDidNotAuthorize(msg.sender, _owner);

        _burn(_owner, _id, _shares);

        if (epochNull[_id] == false) {
            assets = previewWithdraw(_id, _shares);
        } else {
            assets = _shares;
        }
        if (assets > 0) {
            SemiFungibleVault.asset.safeTransfer(_receiver, assets);
        }

        emit Withdraw(msg.sender, _receiver, _owner, _id, _shares, assets);

        return assets;
    }

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

    /**
        @notice returns total assets for the id of given epoch
        @param  _id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000;
     */
    function totalAssets(
        uint256 _id
    ) public view override(SemiFungibleVault, IVaultV2) returns (uint256) {
        // epochIdExists(_id)
        return totalSupply(_id);
    }

    /*///////////////////////////////////////////////////////////////
                           FACTORY FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /**
    @notice Function to set the epoch, only the factory can call this function
    @param  _epochBegin uint40 in UNIX timestamp, representing the begin date of the epoch
    @param  _epochEnd uint40 in UNIX timestamp, representing the end date of the epoch
    @param  _epochId uint256 id representing the epoch
     */
    function setEpoch(
        uint40 _epochBegin,
        uint40 _epochEnd,
        uint256 _epochId
    ) external onlyFactory {
        if (_epochId == 0 || _epochBegin == 0 || _epochEnd == 0)
            revert InvalidEpoch();
        if (epochExists[_epochId] == true) revert EpochAlreadyExists();

        if (_epochBegin >= _epochEnd) revert EpochEndMustBeAfterBegin();

        epochExists[_epochId] = true;

        epochConfig[_epochId] = EpochConfig({
            epochBegin: _epochBegin,
            epochEnd: _epochEnd,
            epochCreation: uint40(block.timestamp)
        });
        epochs.push(_epochId);
    }

    /**
    @notice Factory function, changes controller address
    @param _controller New controller address
     */
    function changeController(address _controller) public onlyFactory {
        if (_controller == address(0)) revert AddressZero();
        controller = _controller;
    }

    /**
    @notice Factory function, whitelist address
    @param _wAddress whitelist destination address 
    */
    function whiteListAddress(address _wAddress) public onlyFactory {
        if (_wAddress == address(0)) revert AddressZero();
        whitelistedAddresses[_wAddress] = !whitelistedAddresses[_wAddress];
    }

    /**
    @notice Factory function, changes _counterPartyVault address
    @param _counterPartyVault New _counterPartyVault address
     */
    function setCounterPartyVault(
        address _counterPartyVault
    ) external onlyFactory {
        if (_counterPartyVault == address(0)) revert AddressZero();
        counterPartyVault = _counterPartyVault;
    }

    /*///////////////////////////////////////////////////////////////
                         CONTROLLER LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
    @notice Controller can call this function to resolve the epoch, this function will set the epoch as ended and store the deposited TVL of the epoch
    @param  _id identifier of the epoch
     */
    function resolveEpoch(
        uint256 _id
    ) external onlyController epochIdExists(_id) epochHasStarted(_id) {
        if (epochResolved[_id]) revert EpochAlreadyEnded();
        epochResolved[_id] = true;
        finalTVL[_id] = totalAssets(_id);
    }

    /**
    solhint-disable-next-line max-line-length
    @notice Controller can call after the epoch has ended, this function allows the transfer of tokens to the counterparty vault or treasury. Controller is trusted to do correct accounting. 
    @param  _id uint256 identifier of the epoch
    @param _amount amount that is send to destination
    @param _receiver address of counterparty vault or treasury
    */
    function sendTokens(
        uint256 _id,
        uint256 _amount,
        address _receiver
    ) external onlyController epochIdExists(_id) epochHasEnded(_id) {
        if (_amount > finalTVL[_id]) revert AmountExceedsTVL();
        if (epochAccounting[_id] + _amount > finalTVL[_id])
            revert AmountExceedsTVL();
        if (
            !whitelistedAddresses[_receiver] &&
            _receiver != counterPartyVault &&
            _receiver != treasury()
        ) revert DestinationNotAuthorized(_receiver);
        epochAccounting[_id] += _amount;
        SemiFungibleVault.asset.safeTransfer(_receiver, _amount);
    }

    /**
    @notice Controller can call after the epoch has ended, this function stores the value that the holders of the epoch are entiteld to. The value is determined on the controller side
    @param  _id uint256 identifier of the epoch
    @param _claimTVL uint256 representing the TVL the vault has, storing this value in a mapping
     */
    function setClaimTVL(
        uint256 _id,
        uint256 _claimTVL
    ) external onlyController epochIdExists(_id) epochHasEnded(_id) {
        claimTVL[_id] = _claimTVL;
    }

    /**
    @notice This function is called by the controller if the epoch has started, but the counterparty vault has no value. In this case the users can withdraw their deposit.
    @param  _id uint256 identifier of the epoch
     */
    function setEpochNull(
        uint256 _id
    ) public virtual onlyController epochIdExists(_id) epochHasEnded(_id) {
        epochNull[_id] = true;
    }

    /*///////////////////////////////////////////////////////////////
                         LOOKUP FUNCTIONS
    //////////////////////////////////////////////////////////////*/
    /**
        @notice Shows assets conversion output from withdrawing assets
        @param  _id uint256 epoch identifier
        @param _shares amount of user shares to withdraw
     */
    function previewWithdraw(
        uint256 _id,
        uint256 _shares
    ) public view override(SemiFungibleVault) returns (uint256 entitledAssets) {
        // entitledAmount amount is derived from the claimTVL and the finalTVL
        // if user deposited 1000 assets and the claimTVL is 50% lower than finalTVL, the user is entitled to 500 assets
        // if user deposited 1000 assets and the claimTVL is 50% higher than finalTVL, the user is entitled to 1500 assets
        entitledAssets = _shares.mulDivDown(claimTVL[_id], finalTVL[_id]);
    }

    /** @notice Lookup total epochs length
     */
    function getEpochsLength() public view returns (uint256) {
        return epochs.length;
    }

    /** @notice Lookup all set epochs
     */
    function getAllEpochs() public view returns (uint256[] memory) {
        return epochs;
    }

    /** @notice Lookup epoch begin and end
        @param _id id hashed from marketIndex, epoch begin and end and casted to uint256;
     */
    function getEpochConfig(
        uint256 _id
    )
        public
        view
        returns (uint40 epochBegin, uint40 epochEnd, uint40 epochCreation)
    {
        epochBegin = epochConfig[_id].epochBegin;
        epochEnd = epochConfig[_id].epochEnd;
        epochCreation = epochConfig[_id].epochCreation;
    }

    function treasury() public view returns (address) {
        return IVaultFactoryV2(factory).treasury();
    }

    function _asset() internal view returns (IERC20) {
        return asset;
    }

    /*//////////////////////////////////////////////////////////////
                                STRUCTS
    //////////////////////////////////////////////////////////////*/

    struct EpochConfig {
        uint40 epochBegin;
        uint40 epochEnd;
        uint40 epochCreation;
    }

    /*//////////////////////////////////////////////////////////////
                                MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /** @notice Only factory addresses can call functions that use this modifier
     */
    modifier onlyFactory() {
        if (msg.sender != factory) revert AddressNotFactory(msg.sender);
        _;
    }

    /** @notice Only controller addresses can call functions that use this modifier
     */
    modifier onlyController() {
        if (msg.sender != controller) revert AddressNotController(msg.sender);
        _;
    }

    /** @notice You can only call functions that use this modifier before the epoch has started
     */
    modifier epochHasNotStarted(uint256 _id) {
        if (block.timestamp > epochConfig[_id].epochBegin)
            revert EpochAlreadyStarted();
        _;
    }

    /** @notice You can only call functions that use this modifier after the epoch has started
     */
    modifier epochHasStarted(uint256 _id) {
        if (block.timestamp < epochConfig[_id].epochBegin)
            revert EpochNotStarted();
        _;
    }

    /** @notice Check if epoch exists
     */
    modifier epochIdExists(uint256 id) {
        if (!epochExists[id]) revert EpochDoesNotExist();
        _;
    }

    /** @notice You can only call functions that use this modifier after the epoch has ended
     */
    modifier epochHasEnded(uint256 id) {
        if (!epochResolved[id]) revert EpochNotResolved();
        _;
    }

    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/
    error AddressZero();
    error AddressNotFactory(address _contract);
    error AddressNotController(address _contract);
    error EpochDoesNotExist();
    error EpochAlreadyStarted();
    error EpochNotResolved();
    error EpochAlreadyEnded();
    error EpochNotStarted();
    error ZeroValue();
    error OwnerDidNotAuthorize(address _sender, address _owner);
    error EpochEndMustBeAfterBegin();
    error EpochAlreadyExists();
    error DestinationNotAuthorized(address _counterparty);
    error AmountExceedsTVL();
    error AlreadyInitialized();
    error InvalidEpoch();
    error CanNotDepositETH();
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            // Start off with z at 1.
            z := 1

            // Used below to help find a nearby power of 2.
            let y := x

            // Find the lowest power of 2 that is at least sqrt(x).
            if iszero(lt(y, 0x100000000000000000000000000000000)) {
                y := shr(128, y) // Like dividing by 2 ** 128.
                z := shl(64, z) // Like multiplying by 2 ** 64.
            }
            if iszero(lt(y, 0x10000000000000000)) {
                y := shr(64, y) // Like dividing by 2 ** 64.
                z := shl(32, z) // Like multiplying by 2 ** 32.
            }
            if iszero(lt(y, 0x100000000)) {
                y := shr(32, y) // Like dividing by 2 ** 32.
                z := shl(16, z) // Like multiplying by 2 ** 16.
            }
            if iszero(lt(y, 0x10000)) {
                y := shr(16, y) // Like dividing by 2 ** 16.
                z := shl(8, z) // Like multiplying by 2 ** 8.
            }
            if iszero(lt(y, 0x100)) {
                y := shr(8, y) // Like dividing by 2 ** 8.
                z := shl(4, z) // Like multiplying by 2 ** 4.
            }
            if iszero(lt(y, 0x10)) {
                y := shr(4, y) // Like dividing by 2 ** 4.
                z := shl(2, z) // Like multiplying by 2 ** 2.
            }
            if iszero(lt(y, 0x8)) {
                // Equivalent to 2 ** z.
                z := shl(1, z)
            }

            // Shifting right by 1 is like dividing by 2.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // Compute a rounded down version of z.
            let zRoundDown := div(x, z)

            // If zRoundDown is smaller, use it.
            if lt(zRoundDown, z) {
                z := zRoundDown
            }
        }
    }
}

File 6 of 20 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {
    SafeERC20
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ERC1155Supply} from "./CustomERC1155/ERC1155Supply.sol";
import {ERC1155} from "./CustomERC1155/ERC1155.sol";
import {ISemiFungibleVault} from "./interfaces/ISemiFungibleVault.sol";

/// @author MiguelBits
/// @author SlumDog

abstract contract SemiFungibleVault is ISemiFungibleVault, ERC1155Supply {
    using SafeERC20 for IERC20;

    /*///////////////////////////////////////////////////////////////
                               IMMUTABLES AND STORAGE
    //////////////////////////////////////////////////////////////*/
    IERC20 public immutable asset;
    string public name;
    string public symbol;
    bytes internal constant EMPTY = "";

    /** @notice Contract constructor
     * @param _asset ERC20 token
     * @param _name Token name
     * @param _symbol Token symbol
     */
    constructor(
        IERC20 _asset,
        string memory _name,
        string memory _symbol,
        string memory _uri
    ) ERC1155(_uri) {
        asset = _asset;
        name = _name;
        symbol = _symbol;
    }

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

    /** @notice Triggers deposit into vault and mints shares for receiver
     * @param id Vault id
     * @param assets Amount of tokens to deposit
     * @param receiver Receiver of shares
     */
    function deposit(
        uint256 id,
        uint256 assets,
        address receiver
    ) public virtual {
        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, id, assets, EMPTY);

        emit Deposit(msg.sender, receiver, id, assets);
    }

    /** @notice Triggers withdraw from vault and burns receivers' shares
     * @param id Vault id
     * @param assets Amount of tokens to withdraw
     * @param receiver Receiver of assets
     * @param owner Owner of shares
     * @return shares Amount of shares burned
     */
    function withdraw(
        uint256 id,
        uint256 assets,
        address receiver,
        address owner
    ) external virtual returns (uint256 shares) {
        require(
            msg.sender == owner || isApprovedForAll(owner, msg.sender),
            "Only owner can withdraw, or owner has approved receiver for all"
        );

        shares = previewWithdraw(id, assets);

        _burn(owner, id, shares);

        emit Withdraw(msg.sender, receiver, owner, id, assets, shares);
        asset.safeTransfer(receiver, assets);
    }

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

    /**@notice Returns total assets for token
     * @param  _id uint256 token id of token
     */
    function totalAssets(uint256 _id) public view virtual returns (uint256) {
        return totalSupply(_id);
    }

    /**
        @notice Shows assets conversion output from withdrawing assets
        @param  id uint256 token id of token
        @param assets Total number of assets
     */
    function previewWithdraw(uint256 id, uint256 assets)
        public
        view
        virtual
        returns (uint256)
    {}
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IVaultV2 {
    // function name() external view  returns (string memory);
    // function symbol() external view  returns (string memory);
    // function asset() external view  returns (address);

    function token() external view returns (address);

    function strike() external view returns (uint256);

    function controller() external view returns (address);

    function counterPartyVault() external view returns (address);

    function getEpochConfig(uint256)
        external
        view
        returns (
            uint40,
            uint40,
            uint40
        );

    function totalAssets(uint256) external view returns (uint256);

    function epochExists(uint256 _id) external view returns (bool);

    function epochResolved(uint256 _id) external view returns (bool);

    function finalTVL(uint256 _id) external view returns (uint256);

    function claimTVL(uint256 _id) external view returns (uint256);

    function setEpoch(
        uint40 _epochBegin,
        uint40 _epochEnd,
        uint256 _epochId
    ) external;

    function resolveEpoch(uint256 _id) external;

    function setClaimTVL(uint256 _id, uint256 _amount) external;

    function changeController(address _controller) external;

    function sendTokens(
        uint256 _id,
        uint256 _amount,
        address _receiver
    ) external;

    function whiteListAddress(address _treasury) external;

    function setCounterPartyVault(address _counterPartyVault) external;

    function setEpochNull(uint256 _id) external;

    function whitelistedAddresses(address _address)
        external
        view
        returns (bool);
}

pragma solidity 0.8.17;

interface IVaultFactoryV2 {
    function createNewMarket(
        uint256 fee,
        address token,
        address depeg,
        uint256 beginEpoch,
        uint256 endEpoch,
        address oracle,
        string memory name
    ) external returns (address);

    function treasury() external view returns (address);

    function getVaults(uint256) external view returns (address[2] memory);

    function getEpochFee(uint256) external view returns (uint16);

    function marketToOracle(uint256 _marketId) external view returns (address);

    function transferOwnership(address newOwner) external;

    function changeTimelocker(address newTimelocker) external;

    function marketIdToVaults(uint256 _marketId)
        external
        view
        returns (address[2] memory);
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.17;

interface IWETH {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol)

pragma solidity ^0.8.0;

import "./ERC1155.sol";

/**
 * @dev Extension of ERC1155 that adds tracking of total supply per id.
 *
 * Useful for scenarios where Fungible and Non-fungible tokens have to be
 * clearly identified. Note: While a totalSupply of 1 might mean the
 * corresponding is an NFT, there is no guarantees that no other token with the
 * same id are not going to be minted.
 */
abstract contract ERC1155Supply is ERC1155 {
    mapping(uint256 => uint256) private _totalSupply;

    /**
     * @dev Total amount of tokens in with a given id.
     */
    function totalSupply(uint256 id) public view virtual returns (uint256) {
        return _totalSupply[id];
    }

    /**
     * @dev Indicates whether any token exist with a given id, or not.
     */
    function exists(uint256 id) public view virtual returns (bool) {
        return ERC1155Supply.totalSupply(id) > 0;
    }

    /**
     * @dev See {ERC1155-_beforeTokenTransfer}.
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual override {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);

        if (from == address(0)) {
            for (uint256 i = 0; i < ids.length; ++i) {
                _totalSupply[ids[i]] += amounts[i];
            }
        }

        if (to == address(0)) {
            for (uint256 i = 0; i < ids.length; ++i) {
                uint256 id = ids[i];
                uint256 amount = amounts[i];
                uint256 supply = _totalSupply[id];
                require(
                    supply >= amount,
                    "ERC1155: burn amount exceeds totalSupply"
                );
                unchecked {
                    _totalSupply[id] = supply - amount;
                }
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 *
 * _Available since v3.1._
 */
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
    using Address for address;

    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

    // Mapping from account to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory uri_) {
        _setURI(uri_);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC165, IERC165)
        returns (bool)
    {
        return
            interfaceId == type(IERC1155).interfaceId ||
            interfaceId == type(IERC1155MetadataURI).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256) public view virtual override returns (string memory) {
        return _uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(
            account != address(0),
            "ERC1155: address zero is not a valid owner"
        );
        return _balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
        public
        view
        virtual
        override
        returns (uint256[] memory)
    {
        require(
            accounts.length == ids.length,
            "ERC1155: accounts and ids length mismatch"
        );

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved)
        public
        virtual
        override
    {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator)
        public
        view
        virtual
        override
        returns (bool)
    {
        return _operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: transfer caller is not owner nor approved"
        );
        _safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        uint256 fromBalance = _balances[id][from];
        require(
            fromBalance >= amount,
            "ERC1155: insufficient balance for transfer"
        );
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

        emit TransferSingle(operator, from, to, id, amount);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(
            ids.length == amounts.length,
            "ERC1155: ids and amounts length mismatch"
        );
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(
                fromBalance >= amount,
                "ERC1155: insufficient balance for transfer"
            );
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
            _balances[id][to] += amount;
        }

        emit TransferBatch(operator, from, to, ids, amounts);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(
            operator,
            from,
            to,
            ids,
            amounts,
            data
        );
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the amounts in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

    /**
     * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        _balances[id][to] += amount;
        emit TransferSingle(operator, address(0), to, id, amount);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        // remove _doSafeTransferAcceptanceCheck to prevent reverting in queue
        // if receiver is a contract and does not implement the ERC1155Holder interface funds will be stuck
        // _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");
        require(
            ids.length == amounts.length,
            "ERC1155: ids and amounts length mismatch"
        );

        address operator = _msgSender();

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; i++) {
            _balances[ids[i]][to] += amounts[i];
        }

        emit TransferBatch(operator, address(0), to, ids, amounts);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(
            operator,
            address(0),
            to,
            ids,
            amounts,
            data
        );
    }

    /**
     * @dev Destroys `amount` tokens of token type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `amount` tokens of token type `id`.
     */
    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }

        emit TransferSingle(operator, from, address(0), id, amount);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     */
    function _burnBatch(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");
        require(
            ids.length == amounts.length,
            "ERC1155: ids and amounts length mismatch"
        );

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        for (uint256 i = 0; i < ids.length; i++) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(
                fromBalance >= amount,
                "ERC1155: burn amount exceeds balance"
            );
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
        }

        emit TransferBatch(operator, from, address(0), ids, amounts);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC1155: setting approval status for self");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `ids` and `amounts` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `id` and `amount` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try
                IERC1155Receiver(to).onERC1155Received(
                    operator,
                    from,
                    id,
                    amount,
                    data
                )
            returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try
                IERC1155Receiver(to).onERC1155BatchReceived(
                    operator,
                    from,
                    ids,
                    amounts,
                    data
                )
            returns (bytes4 response) {
                if (
                    response != IERC1155Receiver.onERC1155BatchReceived.selector
                ) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }

    function _asSingletonArray(uint256 element)
        private
        pure
        returns (uint256[] memory)
    {
        uint256[] memory array = new uint256[](1);
        array[0] = element;

        return array;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface ISemiFungibleVault {
    function asset() external view returns (IERC20);

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function deposit(
        uint256,
        uint256,
        address
    ) external;

    function withdraw(
        uint256,
        uint256,
        address,
        address
    ) external returns (uint256);

    function totalAssets(uint256) external returns (uint256);

    function previewWithdraw(uint256, uint256) external returns (uint256);

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

    /** @notice Deposit into vault when event is emitted
     * @param caller Address of deposit caller
     * @param owner receiver who will own of the tokens representing this deposit
     * @param id Vault id
     * @param assets Amount of owner assets to deposit into vault
     */
    event Deposit(
        address caller,
        address indexed owner,
        uint256 indexed id,
        uint256 assets
    );

    /** @notice Withdraw from vault when event is emitted
     * @param caller Address of withdraw caller
     * @param receiver Address of receiver of assets
     * @param owner Owner of shares
     * @param id Vault id
     * @param assets Amount of owner assets to withdraw from vault
     * @param shares Amount of owner shares to burn
     */
    event Withdraw(
        address caller,
        address receiver,
        address indexed owner,
        uint256 indexed id,
        uint256 assets,
        uint256 shares
    );
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.0;

import "../IERC1155.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

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

pragma solidity ^0.8.0;

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @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": [
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@chainlink/=lib/chainlink/contracts/src/v0.8/",
    "@solmate/=lib/solmate/src/",
    "@pythnetwork/pyth-sdk-solidity/=lib/pyth-sdk-solidity/",
    "@redstone-finance/evm-connector/contracts/=lib/redstone-oracles-monorepo/packages/evm-connector/contracts/",
    "@ensdomains/=lib/redstone-oracles-monorepo/node_modules/@ensdomains/",
    "@eth-optimism/=lib/redstone-oracles-monorepo/node_modules/@eth-optimism/contracts/",
    "@ethereum-waffle/=lib/redstone-oracles-monorepo/node_modules/@ethereum-waffle/mock-contract/src/",
    "chainlink/=lib/chainlink/",
    "ds-test/=lib/ds-test/src/",
    "eth-gas-reporter/=lib/redstone-oracles-monorepo/node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat-deploy/=lib/redstone-oracles-monorepo/node_modules/hardhat-deploy/",
    "hardhat/=lib/redstone-oracles-monorepo/node_modules/hardhat/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "pyth-sdk-solidity/=lib/pyth-sdk-solidity/",
    "redstone-oracles-monorepo/=lib/redstone-oracles-monorepo/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"components":[{"internalType":"bool","name":"isWETH","type":"bool"},{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"strike","type":"uint256"},{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"emissionsToken","type":"address"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"uint256","name":"depositFee","type":"uint256"},{"internalType":"uint256","name":"minQueueDeposit","type":"uint256"}],"internalType":"struct Carousel.ConstructorArgs","name":"_data","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"AddressNotController","type":"error"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"AddressNotFactory","type":"error"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadyRollingOver","type":"error"},{"inputs":[],"name":"AmountExceedsTVL","type":"error"},{"inputs":[],"name":"BPSToHigh","type":"error"},{"inputs":[],"name":"CanNotDepositETH","type":"error"},{"inputs":[{"internalType":"address","name":"_counterparty","type":"address"}],"name":"DestinationNotAuthorized","type":"error"},{"inputs":[],"name":"EpochAlreadyEnded","type":"error"},{"inputs":[],"name":"EpochAlreadyExists","type":"error"},{"inputs":[],"name":"EpochAlreadyStarted","type":"error"},{"inputs":[],"name":"EpochDoesNotExist","type":"error"},{"inputs":[],"name":"EpochEndMustBeAfterBegin","type":"error"},{"inputs":[],"name":"EpochNotResolved","type":"error"},{"inputs":[],"name":"EpochNotStarted","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidEpoch","type":"error"},{"inputs":[],"name":"InvalidEpochId","type":"error"},{"inputs":[],"name":"MinDeposit","type":"error"},{"inputs":[],"name":"NoRolloverQueued","type":"error"},{"inputs":[],"name":"OverflowQueue","type":"error"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"OwnerDidNotAuthorize","type":"error"},{"inputs":[],"name":"RelayerFeeToLow","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"epochId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"DepositInQueue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epochId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"operations","type":"uint256"}],"name":"RelayerMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"epochId","type":"uint256"}],"name":"RolloverQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"emissions","type":"uint256"}],"name":"WithdrawWithEmissions","type":"event"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"minX","type":"int256"},{"internalType":"int256","name":"maxX","type":"int256"}],"name":"calculateFeePercent","outputs":[{"internalType":"uint256","name":"_y","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"changeController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositFee","type":"uint256"}],"name":"changeDepositFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_relayerFee","type":"uint256"}],"name":"changeRelayerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimTVL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addressesToDelist","type":"address[]"}],"name":"cleanUpRolloverQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"counterPartyVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"delistInRollover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"depositQueue","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"epochId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"emissions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emissionsToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochId","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"enlistInRollover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochAccounting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochConfig","outputs":[{"internalType":"uint40","name":"epochBegin","type":"uint40"},{"internalType":"uint40","name":"epochEnd","type":"uint40"},{"internalType":"uint40","name":"epochCreation","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochNull","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochResolved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"finalTVL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllEpochs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDepositQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDepositQueueTVL","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getEpochConfig","outputs":[{"internalType":"uint40","name":"epochBegin","type":"uint40"},{"internalType":"uint40","name":"epochEnd","type":"uint40"},{"internalType":"uint40","name":"epochCreation","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"getEpochDepositFee","outputs":[{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"assetsAfterFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEpochsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getRolloverIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getRolloverPosition","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"epochId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getRolloverQueueItem","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"epochId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRolloverQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRolloverTVL","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochId","type":"uint256"}],"name":"getRolloverTVLByEpochId","outputs":[{"internalType":"uint256","name":"tvl","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"isEnlistedInRolloverQueue","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isWETH","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minQueueDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochId","type":"uint256"},{"internalType":"uint256","name":"_operations","type":"uint256"}],"name":"mintDepositInQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochId","type":"uint256"},{"internalType":"uint256","name":"_operations","type":"uint256"}],"name":"mintRollovers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ownerToRollOverQueueIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"previewAmountInShares","outputs":[{"internalType":"uint256","name":"entitledShareAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"previewEmissionsWithdraw","outputs":[{"internalType":"uint256","name":"entitledAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"entitledAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relayerFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"resolveEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rolloverAccounting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rolloverQueue","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"epochId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"sendTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_claimTVL","type":"uint256"}],"name":"setClaimTVL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_counterPartyVault","type":"address"}],"name":"setCounterPartyVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochId","type":"uint256"},{"internalType":"uint256","name":"_emissionAmount","type":"uint256"}],"name":"setEmissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"_epochBegin","type":"uint40"},{"internalType":"uint40","name":"_epochEnd","type":"uint40"},{"internalType":"uint256","name":"_epochId","type":"uint256"}],"name":"setEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"setEpochNull","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strike","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wAddress","type":"address"}],"name":"whiteListAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedAddresses","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

0x6101206040523480156200001257600080fd5b506040516200587738038062005877833981016040819052620000359162000450565b8051602082015160408301516060840151608085015160a086015160c087015160e088015186868686806200006a816200030e565b506001600160a01b038416608052600462000086848262000633565b50600562000095838262000633565b505060016006555050506001600160a01b038116620000c757604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b038316620000ef57604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0387166200011757604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0392831660a05260c091909152600880546001600160a01b031990811633179091556009805492909316911617905550505050151560e05261012081015161271011156200017f576040516318df8e6160e21b815260040160405180910390fd5b60fa8161014001511115620001a757604051633102829f60e11b815260040160405180910390fd5b6101008101516001600160a01b0316620001d457604051639fabe1c160e01b815260040160405180910390fd5b610100808201516001600160a01b0316905261012081015160135561014081015160145561016001516015557f6e0956cda88cad152e89927e53611735b61a5c762d1428573c6931b0a5efcb01805460ff1916600190811790915560408051606081018252645d21d265808152645d21dba00060208281019182524264ffffffffff9081169484019485526000808052600e90925292517fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c80549351955185166a01000000000000000000000264ffffffffff60501b1996861665010000000000026001600160501b031990951692909516919091179290921793909316919091179055600a8054928301815581527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155620006ff565b60026200031c828262000633565b5050565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b03811182821017156200035c576200035c62000320565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200038d576200038d62000320565b604052919050565b80518015158114620003a657600080fd5b919050565b80516001600160a01b0381168114620003a657600080fd5b600082601f830112620003d557600080fd5b81516001600160401b03811115620003f157620003f162000320565b602062000407601f8301601f1916820162000362565b82815285828487010111156200041c57600080fd5b60005b838110156200043c5785810183015182820184015282016200041f565b506000928101909101919091529392505050565b6000602082840312156200046357600080fd5b81516001600160401b03808211156200047b57600080fd5b9083019061018082860312156200049157600080fd5b6200049b62000336565b620004a68362000395565b8152620004b660208401620003ab565b6020820152604083015182811115620004ce57600080fd5b620004dc87828601620003c3565b604083015250606083015182811115620004f557600080fd5b6200050387828601620003c3565b6060830152506080830151828111156200051c57600080fd5b6200052a87828601620003c3565b6080830152506200053e60a08401620003ab565b60a082015260c083015160c08201526200055b60e08401620003ab565b60e0820152610100915062000572828401620003ab565b918101919091526101208281015190820152610140808301519082015261016091820151918101919091529392505050565b600181811c90821680620005b957607f821691505b602082108103620005da57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200062e57600081815260208120601f850160051c81016020861015620006095750805b601f850160051c820191505b818110156200062a5782815560010162000615565b5050505b505050565b81516001600160401b038111156200064f576200064f62000320565b6200066781620006608454620005a4565b84620005e0565b602080601f8311600181146200069f5760008415620006865750858301515b600019600386901b1c1916600185901b1785556200062a565b600085815260208120601f198616915b82811015620006d057888601518255948401946001909101908401620006af565b5085821015620006ef5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e051610100516150ed6200078a600039600081816105cb01528181611c580152818161214501526130b10152600081816108b3015261184901526000610ba101526000610f0e015260008181610703015281816113c2015281816118ae01528181611c1e015281816123be015281816128aa0152612b6301526150ed6000f3fe60806040526004361061043b5760003560e01c806383290a3c11610234578063c94eb7b91161012e578063ef884adb116100b6578063f7f2f8241161007a578063f7f2f82414610ea7578063f8afcdc614610ebc578063faf5cb0d14610edc578063fc0c546a14610efc578063fcb8029714610f3057600080fd5b8063ef884adb14610e05578063f242432a14610e25578063f3e9a03114610e45578063f567244c14610e72578063f77c479114610e8757600080fd5b8063cf1f9f9a116100fd578063cf1f9f9a14610d60578063cf52a7b214610d90578063e16bbe7f14610db0578063e88d956714610dc5578063e985e9c514610de557600080fd5b8063c94eb7b914610ce9578063cb6da67014610d09578063ce5feeca14610d36578063cf09dff914610d4b57600080fd5b8063a50b66a9116101bc578063bd85b03911610180578063bd85b03914610c10578063bef12cce14610c3d578063bfac9cd414610c89578063c45a015514610ca9578063c6b61e4c14610cc957600080fd5b8063a50b66a914610b42578063ad5be0c414610b6f578063ad8f500814610b8f578063b082246014610bc3578063b7630ccf14610be357600080fd5b8063907061fe11610203578063907061fe14610a885780639460585714610acd57806395d89b4114610aed5780639c407b6e14610b02578063a22cb46514610b2257600080fd5b806383290a3c146109e55780638ac654b014610a285780638dbdbe6d14610a485780638e507fba14610a6857600080fd5b8063488bd7b0116103455780635a806ac0116102cd57806377d5063f1161029157806377d5063f146109405780637ba21ff4146109605780637e8679561461097557806380d8d2d5146109955780638175f7f5146109b557600080fd5b80635a806ac0146108a157806361d027b3146108d557806367a52793146108ea5780636e7542e31461090057806371b3177a1461092057600080fd5b80634e72fc02116103145780634e72fc02146107ff5780634f558e791461081f578063517a0a5d1461084e57806353a7efd01461086e57806356150edf1461088e57600080fd5b8063488bd7b0146107655780634d01614b146107855780634d1cba89146107a55780634e1273f4146107d257600080fd5b8063210ca05d116103c85780632fdeb111116103975780632fdeb111146106c55780633634a9a3146106db57806338d52e0f146106f15780633cebb823146107255780633e0483651461074557600080fd5b8063210ca05d146105b9578063243219d114610605578063298f5c1c146106355780632eb2c2d6146106aa57600080fd5b806306fdde031161040f57806306fdde03146105085780630e89341c1461052a5780630e9c7c0d1461054a57806317d026e614610577578063195474041461059957600080fd5b8062fdd58e1461044057806301ffc9a71461047357806306b07b62146104a357806306c933d8146104d8575b600080fd5b34801561044c57600080fd5b5061046061045b36600461476a565b610f50565b6040519081526020015b60405180910390f35b34801561047f57600080fd5b5061049361048e3660046147ac565b610fe9565b604051901515815260200161046a565b3480156104af57600080fd5b506104c36104be3660046147c9565b611039565b6040805192835260208301919091520161046a565b3480156104e457600080fd5b506104936104f33660046147c9565b60126020526000908152604090205460ff1681565b34801561051457600080fd5b5061051d6110b5565b60405161046a9190614836565b34801561053657600080fd5b5061051d610545366004614849565b611143565b34801561055657600080fd5b50610460610565366004614849565b600d6020526000908152604090205481565b34801561058357600080fd5b50610597610592366004614849565b6111d7565b005b3480156105a557600080fd5b506105976105b4366004614862565b611209565b3480156105c557600080fd5b506105ed7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161046a565b34801561061157600080fd5b50610493610620366004614849565b60116020526000908152604090205460ff1681565b34801561064157600080fd5b50610682610650366004614849565b6000908152600e602052604090205464ffffffffff80821692650100000000008304821692600160501b900490911690565b6040805164ffffffffff9485168152928416602084015292169181019190915260600161046a565b3480156106b657600080fd5b5061059761043b3660046149e7565b3480156106d157600080fd5b5061046060135481565b3480156106e757600080fd5b5061046060155481565b3480156106fd57600080fd5b506105ed7f000000000000000000000000000000000000000000000000000000000000000081565b34801561073157600080fd5b506105976107403660046147c9565b6113f0565b34801561075157600080fd5b50610597610760366004614a95565b611466565b34801561077157600080fd5b50610460610780366004614a95565b611509565b34801561079157600080fd5b506104606107a0366004614a95565b611535565b3480156107b157600080fd5b506104606107c03660046147c9565b60166020526000908152604090205481565b3480156107de57600080fd5b506107f26107ed366004614b26565b61159e565b60405161046a9190614b8a565b34801561080b57600080fd5b5061046061081a366004614a95565b6116c8565b34801561082b57600080fd5b5061049361083a366004614849565b600090815260036020526040902054151590565b34801561085a57600080fd5b506104606108693660046147c9565b6116ed565b34801561087a57600080fd5b506105976108893660046147c9565b611712565b61059761089c366004614bce565b611788565b3480156108ad57600080fd5b506104937f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506105ed61193e565b3480156108f657600080fd5b5061046060145481565b34801561090c57600080fd5b5061049361091b3660046147c9565b6119b1565b34801561092c57600080fd5b5061046061093b366004614bfe565b611a0c565b34801561094c57600080fd5b5061059761095b366004614a95565b611cf0565b34801561096c57600080fd5b5061046061242e565b34801561098157600080fd5b50610597610990366004614c62565b612484565b3480156109a157600080fd5b506105976109b0366004614a95565b61261d565b3480156109c157600080fd5b506104936109d0366004614849565b600f6020526000908152604090205460ff1681565b3480156109f157600080fd5b50610a05610a00366004614849565b61268e565b604080519384526001600160a01b0390921660208401529082015260600161046a565b348015610a3457600080fd5b50610597610a43366004614a95565b6126cd565b348015610a5457600080fd5b50610597610a63366004614862565b612a70565b348015610a7457600080fd5b50610597610a83366004614c9e565b612b96565b348015610a9457600080fd5b50610aa8610aa3366004614849565b612e12565b604080516001600160a01b03909416845260208401929092529082015260600161046a565b348015610ad957600080fd5b50610460610ae8366004614849565b612ea6565b348015610af957600080fd5b5061051d612eba565b348015610b0e57600080fd5b50610597610b1d366004614849565b612ec7565b348015610b2e57600080fd5b50610597610b3d366004614ce1565b612fc6565b348015610b4e57600080fd5b50610460610b5d366004614849565b600c6020526000908152604090205481565b348015610b7b57600080fd5b50610597610b8a366004614849565b612fd5565b348015610b9b57600080fd5b506104607f000000000000000000000000000000000000000000000000000000000000000081565b348015610bcf57600080fd5b506007546105ed906001600160a01b031681565b348015610bef57600080fd5b50610460610bfe366004614849565b600b6020526000908152604090205481565b348015610c1c57600080fd5b50610460610c2b366004614849565b60009081526003602052604090205490565b348015610c4957600080fd5b50610682610c58366004614849565b600e6020526000908152604090205464ffffffffff80821691650100000000008104821691600160501b9091041683565b348015610c9557600080fd5b506104c3610ca4366004614a95565b6130eb565b348015610cb557600080fd5b506008546105ed906001600160a01b031681565b348015610cd557600080fd5b50610460610ce4366004614849565b613140565b348015610cf557600080fd5b50610460610d04366004614849565b613161565b348015610d1557600080fd5b50610460610d24366004614849565b601a6020526000908152604090205481565b348015610d4257600080fd5b50600a54610460565b348015610d5757600080fd5b50601754610460565b348015610d6c57600080fd5b50610493610d7b366004614849565b60106020526000908152604090205460ff1681565b348015610d9c57600080fd5b50610597610dab3660046147c9565b6132e0565b348015610dbc57600080fd5b5061046061335d565b348015610dd157600080fd5b50610597610de0366004614849565b613469565b348015610df157600080fd5b50610493610e00366004614d0f565b61349b565b348015610e1157600080fd5b50610597610e20366004614862565b6134c9565b348015610e3157600080fd5b50610597610e40366004614d3d565b613793565b348015610e5157600080fd5b50610460610e60366004614849565b60196020526000908152604090205481565b348015610e7e57600080fd5b506107f26138d9565b348015610e9357600080fd5b506009546105ed906001600160a01b031681565b348015610eb357600080fd5b50601854610460565b348015610ec857600080fd5b50610597610ed73660046147c9565b613931565b348015610ee857600080fd5b50610a05610ef7366004614849565b613a0b565b348015610f0857600080fd5b506105ed7f000000000000000000000000000000000000000000000000000000000000000081565b348015610f3c57600080fd5b50610460610f4b366004614a95565b613a1b565b60006001600160a01b038316610fc05760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b148061101a57506001600160e01b031982166303a24d0760e21b145b80610fe357506301ffc9a760e01b6001600160e01b0319831614610fe3565b600080611045836119b1565b61105457506000928392509050565b600061105f846116ed565b90506017818154811061107457611074614da6565b90600052602060002090600302016000015492506017818154811061109b5761109b614da6565b906000526020600020906003020160020154915050915091565b600480546110c290614dbc565b80601f01602080910402602001604051908101604052809291908181526020018280546110ee90614dbc565b801561113b5780601f106111105761010080835404028352916020019161113b565b820191906000526020600020905b81548152906001019060200180831161111e57829003601f168201915b505050505081565b60606002805461115290614dbc565b80601f016020809104026020016040519081016040528092919081815260200182805461117e90614dbc565b80156111cb5780601f106111a0576101008083540402835291602001916111cb565b820191906000526020600020905b8154815290600101906020018083116111ae57829003601f168201915b50505050509050919050565b6008546001600160a01b031633146112045760405163017bb92160e41b8152336004820152602401610fb7565b601355565b6009546001600160a01b0316331461123657604051632e91ff8760e21b8152336004820152602401610fb7565b600083815260106020526040902054839060ff16611267576040516364638b8160e01b815260040160405180910390fd5b6000848152600f6020526040902054849060ff166112985760405163974264a560e01b815260040160405180910390fd5b6000858152600b60205260409020548411156112c75760405163ec5af4fd60e01b815260040160405180910390fd5b6000858152600b6020908152604080832054600d909252909120546112ed908690614e06565b111561130c5760405163ec5af4fd60e01b815260040160405180910390fd5b6001600160a01b03831660009081526012602052604090205460ff1615801561134357506007546001600160a01b03848116911614155b8015611368575061135261193e565b6001600160a01b0316836001600160a01b031614155b15611391576040516362e0097160e01b81526001600160a01b0384166004820152602401610fb7565b6000858152600d6020526040812080548692906113af908490614e06565b909155506113e990506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168486613a65565b5050505050565b6008546001600160a01b0316331461141d5760405163017bb92160e41b8152336004820152602401610fb7565b6001600160a01b03811661144457604051639fabe1c160e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6009546001600160a01b0316331461149357604051632e91ff8760e21b8152336004820152602401610fb7565b600082815260106020526040902054829060ff166114c4576040516364638b8160e01b815260040160405180910390fd5b6000838152600f6020526040902054839060ff166114f55760405163974264a560e01b815260040160405180910390fd5b50506000918252600c602052604090912055565b6000828152600c6020908152604080832054600b90925282205461152e918491613ac8565b9392505050565b600080670de0b6b3a764000060145461154e9190614e19565b9050670de0b6b3a7640000816115648542614e49565b61156e8787614e49565b6115789085614e70565b6115829190614e19565b61158c9190614eac565b6115969190614e70565b949350505050565b606081518351146116035760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610fb7565b6000835167ffffffffffffffff81111561161f5761161f61489b565b604051908082528060200260200182016040528015611648578160200160208202803683370190505b50905060005b84518110156116c05761169385828151811061166c5761166c614da6565b602002602001015185838151811061168657611686614da6565b6020026020010151610f50565b8282815181106116a5576116a5614da6565b60209081029190910101526116b981614ed4565b905061164e565b509392505050565b6000828152601a6020908152604080832054600b90925282205461152e918491613ac8565b6001600160a01b038116600090815260166020526040812054610fe390600190614eed565b6008546001600160a01b0316331461173f5760405163017bb92160e41b8152336004820152602401610fb7565b6001600160a01b03811661176657604051639fabe1c160e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b348280158015611799575060155482105b156117b75760405163011bcd8360e41b815260040160405180910390fd5b600084815260106020526040902054849060ff166117e8576040516364638b8160e01b815260040160405180910390fd5b6000858152600e6020526040902054859064ffffffffff16421115611820576040516326ddce9160e01b815260040160405180910390fd5b6002600654036118425760405162461bcd60e51b8152600401610fb790614f00565b60026006557f000000000000000000000000000000000000000000000000000000000000000061188557604051630b5b714560e11b815260040160405180910390fd5b6001600160a01b0385166118ac57604051639fabe1c160e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561190757600080fd5b505af115801561191b573d6000803e3d6000fd5b50505050506000349050611930878288613ae7565b505060016006555050505050565b600854604080516361d027b360e01b815290516000926001600160a01b0316916361d027b39160048083019260209291908290030181865afa158015611988573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ac9190614f37565b905090565b6001600160a01b03811660009081526016602052604081205481036119d857506000919050565b60176119e3836116ed565b815481106119f3576119f3614da6565b6000918252602090912060039091020154151592915050565b600084815260106020526040812054859060ff16611a3d576040516364638b8160e01b815260040160405180910390fd5b6000868152600f6020526040902054869060ff16611a6e5760405163974264a560e01b815260040160405180910390fd5b838787611a7a836119b1565b15611b235760006017611a8c856116ed565b81548110611a9c57611a9c614da6565b60009182526020918290206040805160608101825260039093029091018054835260018101546001600160a01b031693830193909352600290920154918101829052915083148015611b03575080518290611af78686610f50565b611b019190614eed565b105b15611b2157604051632b03aec760e01b815260040160405180910390fd5b505b600260065403611b455760405162461bcd60e51b8152600401610fb790614f00565b60026006556001600160a01b038816611b7157604051639fabe1c160e01b815260040160405180910390fd5b336001600160a01b03881614801590611b915750611b8f873361349b565b155b15611bc05760405163425da22160e11b81523360048201526001600160a01b0388166024820152604401610fb7565b611bcb878b8b613c75565b6000611bd78b8b6116c8565b60008c81526011602052604081205491925060ff90911615159003611c0757611c008b8b611509565b9650611c0b565b8996505b8615611c4557611c456001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168a89613a65565b8015611c7f57611c7f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168a83613a65565b604080513381526001600160a01b038b811660208301529181018c905260608101899052608081018390528c918a16907f3e77193b57691ea1ff89912476e90e2ff7221958af62459a9898e76b32fe77359060a00160405180910390a3505050600160065550919695505050505050565b600082815260106020526040902054829060ff16611d21576040516364638b8160e01b815260040160405180910390fd5b6000838152600e6020526040902054839064ffffffffff16421115611d59576040516326ddce9160e01b815260040160405180910390fd5b600260065403611d7b5760405162461bcd60e51b8152600401610fb790614f00565b60026006556000849003611da257604051630395a9c360e41b815260040160405180910390fd5b60175460008581526019602052604081205490829003611dd557604051635d95121160e11b815260040160405180910390fd5b81851180611deb575081611de98683614e06565b115b15611dfd57611dfa8183614eed565b94505b600a8054600f91600091611e1390600290614eed565b81548110611e2357611e23614da6565b6000918252602080832090910154835282019290925260400190205460ff16611e5f5760405163974264a560e01b815260040160405180910390fd5b600a8054879190611e7290600190614eed565b81548110611e8257611e82614da6565b906000526020600020015414611eab57604051630395a9c360e41b815260040160405180910390fd5b60006017805480602002602001604051908101604052809291908181526020016000905b82821015611f245760008481526020908190206040805160608101825260038602909201805483526001808201546001600160a01b031684860152600290910154918301919091529083529092019101611ecf565b505050509050600082905060005b87611f3d8386614eed565b101561237457600f6000848681518110611f5957611f59614da6565b602002602001015160400151815260200190815260200160002060009054906101000a900460ff168015611faa57506000838581518110611f9c57611f9c614da6565b602002602001015160000151115b15612362576000611ff5848681518110611fc657611fc6614da6565b602002602001015160400151858781518110611fe457611fe4614da6565b602002602001015160000151611509565b905083858151811061200957612009614da6565b602002602001015160000151811115612360576013548111612038578461202f81614ed4565b95505050611f32565b600061208485878151811061204f5761204f614da6565b60200260200101516040015186888151811061206d5761206d614da6565b60200260200101516000015184610f4b9190614eed565b85878151811061209657612096614da6565b6020026020010151600001516120ac9190614eed565b90506120f38587815181106120c3576120c3614da6565b6020026020010151602001518688815181106120e1576120e1614da6565b60200260200101516040015183613c75565b61216c85878151811061210857612108614da6565b60200260200101516020015161213b87898151811061212957612129614da6565b602002602001015160400151846116c8565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190613a65565b8a85878151811061217f5761217f614da6565b6020026020010151602001516001600160a01b03167f3e77193b57691ea1ff89912476e90e2ff7221958af62459a9898e76b32fe773533888a815181106121c8576121c8614da6565b60200260200101516020015185876121fd8c8e815181106121eb576121eb614da6565b602002602001015160400151896116c8565b604080516001600160a01b039687168152959094166020860152928401919091526060830152608082015260a00160405180910390a3600060135486888151811061224a5761224a614da6565b6020026020010151600001516122609190614eed565b905061228a86888151811061227757612277614da6565b6020026020010151602001518d83613e0a565b8b86888151811061229d5761229d614da6565b6020026020010151602001516001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d733846040516122f79291906001600160a01b03929092168252602082015260400190565b60405180910390a3806017888154811061231357612313614da6565b9060005260206000209060030201600001819055508b6017888154811061233c5761233c614da6565b60009182526020909120600260039092020101558361235a81614ed4565b94505050505b505b8361236c81614ed4565b945050611f32565b801561238c5760008981526019602052604090208490555b60006013548261239c9190614f54565b11156123e5576123e533601354836123b49190614f54565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190613a65565b604080518a8152602081018390527f8d4b7c83e8e9b0d8f4a5cc8dbe9ad5c61c9d347e581ced21717cce3f997141c4910160405180910390a15050600160065550505050505050565b6000805b601854811015612480576018818154811061244f5761244f614da6565b9060005260206000209060030201600001548261246c9190614e06565b91508061247881614ed4565b915050612432565b5090565b6008546001600160a01b031633146124b15760405163017bb92160e41b8152336004820152602401610fb7565b8015806124c3575064ffffffffff8316155b806124d3575064ffffffffff8216155b156124f15760405163d5b25b6360e01b815260040160405180910390fd5b60008181526010602052604090205460ff16151560010361252557604051631c1b415b60e11b815260040160405180910390fd5b8164ffffffffff168364ffffffffff161061255357604051631d02ec5360e11b815260040160405180910390fd5b6000818152601060209081526040808320805460ff19166001908117909155815160608101835264ffffffffff9788168152958716868401908152428816878401908152868652600e90945291842095518654925193518816600160501b0264ffffffffff60501b19948916650100000000000269ffffffffffffffffffff199094169190981617919091179190911694909417909255600a805493840181559091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155565b6008546001600160a01b0316331461264a5760405163017bb92160e41b8152336004820152602401610fb7565b600082815260106020526040902054829060ff1661267b576040516364638b8160e01b815260040160405180910390fd5b506000918252601a602052604090912055565b6018818154811061269e57600080fd5b60009182526020909120600390910201805460018201546002909201549092506001600160a01b039091169083565b600082815260106020526040902054829060ff166126fe576040516364638b8160e01b815260040160405180910390fd5b6000838152600e6020526040902054839064ffffffffff16421115612736576040516326ddce9160e01b815260040160405180910390fd5b6002600654036127585760405162461bcd60e51b8152600401610fb790614f00565b600260068190555060006018805480602002602001604051908101604052809291908181526020016000905b828210156127d95760008481526020908190206040805160608101825260038602909201805483526001808201546001600160a01b031684860152600290910154918301919091529083529092019101612784565b50506018549293505050600086900361280557604051630395a9c360e41b815260040160405180910390fd5b8060000361282657604051635d95121160e11b815260040160405180910390fd5b80851115612832578094505b600061283f600183614eed565b905060005b8161284f8885614eed565b11612a0b57600084838151811061286857612868614da6565b6020026020010151600001519050600060145411156128d45760008061288e8b846130eb565b915091508092506128d16128a061193e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169084613a65565b50505b6013548111156128f2576013546128eb9082614eed565b9050612911565b806013546129009190614eed565b61290a9083614e06565b9150600090505b61293985848151811061292657612926614da6565b6020026020010151602001518a83613e0a565b8885848151811061294c5761294c614da6565b6020026020010151602001516001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d733846040516129a69291906001600160a01b03929092168252602082015260400190565b60405180910390a360188054806129bf576129bf614f6b565b6000828152602081206003600019909301928302018181556001810180546001600160a01b031916905560020181905591558390036129fe5750612a0b565b5060001990910190612844565b60408051898152602081018990527f8d4b7c83e8e9b0d8f4a5cc8dbe9ad5c61c9d347e581ced21717cce3f997141c4910160405180910390a1612a6133826013548a612a579190614f54565b6123b49190614eed565b50506001600655505050505050565b600083815260106020526040902054839060ff16612aa1576040516364638b8160e01b815260040160405180910390fd5b6000848152600e6020526040902054849064ffffffffff16421115612ad9576040516326ddce9160e01b815260040160405180910390fd5b838580158015612aea575060155482105b15612b085760405163011bcd8360e41b815260040160405180910390fd5b600260065403612b2a5760405162461bcd60e51b8152600401610fb790614f00565b60026006556001600160a01b038516612b5657604051639fabe1c160e01b815260040160405180910390fd5b612b8b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333089613e25565b611930878787613ae7565b6008546001600160a01b03163314612bc35760405163017bb92160e41b8152336004820152602401610fb7565b600a8054612bd390600190614eed565b81548110612be357612be3614da6565b6000918252602080832090910154808352600e90915260409091205464ffffffffff16421015612c26576040516333e7d47160e11b815260040160405180910390fd5b60005b8251811015612e0d576000838281518110612c4657612c46614da6565b60200260200101519050600060166000836001600160a01b03166001600160a01b0316815260200190815260200160002054905080600003612c89575050612dfb565b6000612c96600183614eed565b905060178181548110612cab57612cab614da6565b906000526020600020906003020160000154600003612df75760178054612cd490600190614eed565b81548110612ce457612ce4614da6565b906000526020600020906003020160178281548110612d0557612d05614da6565b60009182526020909120825460039092020190815560018083015490820180546001600160a01b0319166001600160a01b039092169190911790556002918201549101556017805480612d5a57612d5a614f6b565b600082815260208120600360001990930192830201818155600181810180546001600160a01b03191690556002909101919091559155612d9b908290614e06565b6016600060178481548110612db257612db2614da6565b60009182526020808320600160039093020191909101546001600160a01b03908116845283820194909452604092830182209490945591861682526016909252908120555b5050505b80612e0581614ed4565b915050612c29565b505050565b600080600060178481548110612e2a57612e2a614da6565b906000526020600020906003020160010160009054906101000a90046001600160a01b0316925060178481548110612e6457612e64614da6565b906000526020600020906003020160000154915060178481548110612e8b57612e8b614da6565b90600052602060002090600302016002015490509193909250565b600081815260036020526040812054610fe3565b600580546110c290614dbc565b6009546001600160a01b03163314612ef457604051632e91ff8760e21b8152336004820152602401610fb7565b600081815260106020526040902054819060ff16612f25576040516364638b8160e01b815260040160405180910390fd5b6000828152600e6020526040902054829064ffffffffff16421015612f5d576040516333e7d47160e11b815260040160405180910390fd5b6000838152600f602052604090205460ff1615612f8d57604051639a246e6f60e01b815260040160405180910390fd5b6000838152600f60205260409020805460ff19166001179055612faf83612ea6565b6000938452600b6020526040909320929092555050565b612fd1338383613e63565b5050565b6009546001600160a01b0316331461300257604051632e91ff8760e21b8152336004820152602401610fb7565b600081815260106020526040902054819060ff16613033576040516364638b8160e01b815260040160405180910390fd5b6000828152600f6020526040902054829060ff166130645760405163974264a560e01b815260040160405180910390fd5b6000838152601160209081526040808320805460ff19166001179055601a90915290205415612e0d576130d861309861193e565b6000858152601a60205260409020546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190613a65565b50506000908152601a6020526040812055565b6000828152600e6020526040812054819064ffffffffff80821691600160501b900416826131198284611535565b90506131288682612710613ac8565b94506131348587614eed565b93505050509250929050565b600a818154811061315057600080fd5b600091825260209091200154905081565b6000805b6017548110156132da576000600f60006017848154811061318857613188614da6565b906000526020600020906003020160020154815260200190815260200160002060009054906101000a900460ff166131e457601782815481106131cd576131cd614da6565b906000526020600020906003020160000154613236565b613236601783815481106131fa576131fa614da6565b9060005260206000209060030201600201546017848154811061321f5761321f614da6565b906000526020600020906003020160000154611509565b9050836017838154811061324c5761324c614da6565b90600052602060002090600302016002015414801561328f57506017828154811061327957613279614da6565b9060005260206000209060030201600001548110155b156132c757601782815481106132a7576132a7614da6565b906000526020600020906003020160000154836132c49190614e06565b92505b50806132d281614ed4565b915050613165565b50919050565b6008546001600160a01b0316331461330d5760405163017bb92160e41b8152336004820152602401610fb7565b6001600160a01b03811661333457604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b03166000908152601260205260409020805460ff19811660ff90911615179055565b6000805b601754811015612480576000600f60006017848154811061338457613384614da6565b906000526020600020906003020160020154815260200190815260200160002060009054906101000a900460ff166133e057601782815481106133c9576133c9614da6565b9060005260206000209060030201600001546133f6565b6133f6601783815481106131fa576131fa614da6565b90506017828154811061340b5761340b614da6565b9060005260206000209060030201600001548110613456576017828154811061343657613436614da6565b906000526020600020906003020160000154836134539190614e06565b92505b508061346181614ed4565b915050613361565b6008546001600160a01b031633146134965760405163017bb92160e41b8152336004820152602401610fb7565b601455565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b600083815260106020526040902054839060ff166134fa576040516364638b8160e01b815260040160405180910390fd5b336001600160a01b0383161480159061351a5750613518823361349b565b155b156135495760405163425da22160e11b81523360048201526001600160a01b0383166024820152604401610fb7565b826135548386610f50565b101561357357604051631e9acf1760e31b815260040160405180910390fd5b6000848152600f602052604090205460ff16158015613593575060155483105b156135b15760405163011bcd8360e41b815260040160405180910390fd5b6000848152600f602052604090205460ff1680156135d957506015546135d78585611509565b105b156135f75760405163011bcd8360e41b815260040160405180910390fd5b6001600160a01b0382166000908152601660205260409020541561367a576000613620836116ed565b9050836017828154811061363657613636614da6565b906000526020600020906003020160000181905550846017828154811061365f5761365f614da6565b90600052602060002090600302016002018190555050613749565b604080516060810182528481526001600160a01b0384811660208084018281528486018a815260178054600181018255600082815297517fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1560039092029182015592517fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c16840180546001600160a01b0319169190971617909555517fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c179091015591549083526016909152919020555b60408051848152602081018690526001600160a01b038416917f5723e0c0d8d7df62467bd503cb8cbb2aa63075a8e4ea63cf1a62441cb3ce3bd9910160405180910390a250505050565b84838361379f836119b1565b1561384857600060176137b1856116ed565b815481106137c1576137c1614da6565b60009182526020918290206040805160608101825260039093029091018054835260018101546001600160a01b03169383019390935260029092015491810182905291508314801561382857508051829061381c8686610f50565b6138269190614eed565b105b1561384657604051632b03aec760e01b815260040160405180910390fd5b505b6001600160a01b0388163314806138645750613864883361349b565b6138c25760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2063616c6c6572206973206e6f74206f776e6572206e6f7260448201526808185c1c1c9bdd995960ba1b6064820152608401610fb7565b6138cf8888888888613f3b565b5050505050505050565b6060600a80548060200260200160405190810160405280929190818152602001828054801561392757602002820191906000526020600020905b815481526020019060010190808311613913575b5050505050905090565b61393a816119b1565b6139575760405163531d450560e01b815260040160405180910390fd5b336001600160a01b038216148015906139775750613975813361349b565b155b156139a65760405163425da22160e11b81523360048201526001600160a01b0382166024820152604401610fb7565b60006139b1826116ed565b90506000601782815481106139c8576139c8614da6565b9060005260206000209060030201600001819055506000601782815481106139f2576139f2614da6565b9060005260206000209060030201600201819055505050565b6017818154811061269e57600080fd5b6000828152600c602052604081205415613a5c576000838152600b6020908152604080832054600c90925290912054613a55918491613ac8565b9050610fe3565b50600092915050565b6040516001600160a01b038316602482015260448101829052612e0d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526140f4565b828202811515841585830485141716613ae057600080fd5b0492915050565b8215613b7057601454829015613b1957600080613b0486866130eb565b91509150809250613b166128a061193e565b50505b613b24828583613e0a565b604080513381526020810185905285916001600160a01b038516917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a350505050565b604080516060810182528381526001600160a01b0383811660208084018281528486018981526018805460018101825560009190915295517fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e60039097029687015590517fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2f860180546001600160a01b031916919095161790935591517fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d30909301929092558251868152908101859052909133917f4987482318beb9b0fe3a677f40a54caa3fe453449015e849c3e255444982dd8391015b60405180910390a3505050565b6001600160a01b038316613cd75760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610fb7565b336000613ce3846141c6565b90506000613cf0846141c6565b9050613d1083876000858560405180602001604052806000815250614211565b6000858152602081815260408083206001600160a01b038a16845290915290205484811015613d8d5760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610fb7565b6000868152602081815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46040805160208101909152600090525b50505050505050565b612e0d83838360405180602001604052806000815250614392565b6040516001600160a01b0380851660248301528316604482015260648101829052613e5d9085906323b872dd60e01b90608401613a91565b50505050565b816001600160a01b0316836001600160a01b031603613ed65760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610fb7565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101613c68565b6001600160a01b038416613f9f5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608401610fb7565b336000613fab856141c6565b90506000613fb8856141c6565b9050613fc8838989858589614211565b6000868152602081815260408083206001600160a01b038c1684529091529020548581101561404c5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610fb7565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290614089908490614e06565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46140e9848a8a8a8a8a6144a2565b505050505050505050565b6000614149826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661463e9092919063ffffffff16565b805190915015612e0d57808060200190518101906141679190614f81565b612e0d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610fb7565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061420057614200614da6565b602090810291909101015292915050565b6001600160a01b0385166142985760005b83518110156142965782818151811061423d5761423d614da6565b60200260200101516003600086848151811061425b5761425b614da6565b6020026020010151815260200190815260200160002060008282546142809190614e06565b9091555061428f905081614ed4565b9050614222565b505b6001600160a01b03841661438a5760005b8351811015613e015760008482815181106142c6576142c6614da6565b6020026020010151905060008483815181106142e4576142e4614da6565b60200260200101519050600060036000848152602001908152602001600020549050818110156143675760405162461bcd60e51b815260206004820152602860248201527f455243313135353a206275726e20616d6f756e74206578636565647320746f74604482015267616c537570706c7960c01b6064820152608401610fb7565b6000928352600360205260409092209103905561438381614ed4565b90506142a9565b505050505050565b6001600160a01b0384166143f25760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610fb7565b3360006143fe856141c6565b9050600061440b856141c6565b905061441c83600089858589614211565b6000868152602081815260408083206001600160a01b038b1684529091528120805487929061444c908490614e06565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4613e01565b6001600160a01b0384163b1561438a5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906144e69089908990889088908890600401614f9e565b6020604051808303816000875af1925050508015614521575060408051601f3d908101601f1916820190925261451e91810190614fd8565b60015b6145cd5761452d614ff5565b806308c379a0036145665750614541615011565b8061454c5750614568565b8060405162461bcd60e51b8152600401610fb79190614836565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e20455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610fb7565b6001600160e01b0319811663f23a6e6160e01b14613e015760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608401610fb7565b60606115968484600085856001600160a01b0385163b6146a05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610fb7565b600080866001600160a01b031685876040516146bc919061509b565b60006040518083038185875af1925050503d80600081146146f9576040519150601f19603f3d011682016040523d82523d6000602084013e6146fe565b606091505b509150915061470e828286614719565b979650505050505050565b6060831561472857508161152e565b8251156147385782518084602001fd5b8160405162461bcd60e51b8152600401610fb79190614836565b6001600160a01b038116811461476757600080fd5b50565b6000806040838503121561477d57600080fd5b823561478881614752565b946020939093013593505050565b6001600160e01b03198116811461476757600080fd5b6000602082840312156147be57600080fd5b813561152e81614796565b6000602082840312156147db57600080fd5b813561152e81614752565b60005b838110156148015781810151838201526020016147e9565b50506000910152565b600081518084526148228160208601602086016147e6565b601f01601f19169290920160200192915050565b60208152600061152e602083018461480a565b60006020828403121561485b57600080fd5b5035919050565b60008060006060848603121561487757600080fd5b8335925060208401359150604084013561489081614752565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff811182821017156148d7576148d761489b565b6040525050565b600067ffffffffffffffff8211156148f8576148f861489b565b5060051b60200190565b600082601f83011261491357600080fd5b81356020614920826148de565b60405161492d82826148b1565b83815260059390931b850182019282810191508684111561494d57600080fd5b8286015b848110156149685780358352918301918301614951565b509695505050505050565b600082601f83011261498457600080fd5b813567ffffffffffffffff81111561499e5761499e61489b565b6040516149b5601f8301601f1916602001826148b1565b8181528460208386010111156149ca57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156149ff57600080fd5b8535614a0a81614752565b94506020860135614a1a81614752565b9350604086013567ffffffffffffffff80821115614a3757600080fd5b614a4389838a01614902565b94506060880135915080821115614a5957600080fd5b614a6589838a01614902565b93506080880135915080821115614a7b57600080fd5b50614a8888828901614973565b9150509295509295909350565b60008060408385031215614aa857600080fd5b50508035926020909101359150565b600082601f830112614ac857600080fd5b81356020614ad5826148de565b604051614ae282826148b1565b83815260059390931b8501820192828101915086841115614b0257600080fd5b8286015b84811015614968578035614b1981614752565b8352918301918301614b06565b60008060408385031215614b3957600080fd5b823567ffffffffffffffff80821115614b5157600080fd5b614b5d86838701614ab7565b93506020850135915080821115614b7357600080fd5b50614b8085828601614902565b9150509250929050565b6020808252825182820181905260009190848201906040850190845b81811015614bc257835183529284019291840191600101614ba6565b50909695505050505050565b60008060408385031215614be157600080fd5b823591506020830135614bf381614752565b809150509250929050565b60008060008060808587031215614c1457600080fd5b84359350602085013592506040850135614c2d81614752565b91506060850135614c3d81614752565b939692955090935050565b803564ffffffffff81168114614c5d57600080fd5b919050565b600080600060608486031215614c7757600080fd5b614c8084614c48565b9250614c8e60208501614c48565b9150604084013590509250925092565b600060208284031215614cb057600080fd5b813567ffffffffffffffff811115614cc757600080fd5b61159684828501614ab7565b801515811461476757600080fd5b60008060408385031215614cf457600080fd5b8235614cff81614752565b91506020830135614bf381614cd3565b60008060408385031215614d2257600080fd5b8235614d2d81614752565b91506020830135614bf381614752565b600080600080600060a08688031215614d5557600080fd5b8535614d6081614752565b94506020860135614d7081614752565b93506040860135925060608601359150608086013567ffffffffffffffff811115614d9a57600080fd5b614a8888828901614973565b634e487b7160e01b600052603260045260246000fd5b600181811c90821680614dd057607f821691505b6020821081036132da57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610fe357610fe3614df0565b80820260008212600160ff1b84141615614e3557614e35614df0565b8181058314821517610fe357610fe3614df0565b8181036000831280158383131683831282161715614e6957614e69614df0565b5092915050565b600082614e8d57634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615614ea757614ea7614df0565b500590565b8082018281126000831280158216821582161715614ecc57614ecc614df0565b505092915050565b600060018201614ee657614ee6614df0565b5060010190565b81810381811115610fe357610fe3614df0565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208284031215614f4957600080fd5b815161152e81614752565b8082028115828204841417610fe357610fe3614df0565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f9357600080fd5b815161152e81614cd3565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061470e9083018461480a565b600060208284031215614fea57600080fd5b815161152e81614796565b600060033d111561500e5760046000803e5060005160e01c5b90565b600060443d101561501f5790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561504f57505050505090565b82850191508151818111156150675750505050505090565b843d87010160208285010111156150815750505050505090565b615090602082860101876148b1565b509095945050505050565b600082516150ad8184602087016147e6565b919091019291505056fea26469706673582212209105bf00d7efc7a28960e6255ed306446df04d9723342ad5c0e25621a2ae755664736f6c634300081100330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb90000000000000000000000000000000000000000000000000dab6c47ffc28000000000000000000000000000e386e6a5238c32e3fc6f2202f42158cdd15eb51400000000000000000000000065c936f008bc34fe819bce9fa5afd9dc2d49977f0000000000000000000000000000000000000000000000000000b5e620f4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058d15e17628000000000000000000000000000000000000000000000000000000000000000001b79326b555344545f3938355f574554482a434f4c4c41544552414c000000000000000000000000000000000000000000000000000000000000000000000000046359324b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001368747470733a2f2f79326b2e66696e616e636500000000000000000000000000

Deployed Bytecode

0x60806040526004361061043b5760003560e01c806383290a3c11610234578063c94eb7b91161012e578063ef884adb116100b6578063f7f2f8241161007a578063f7f2f82414610ea7578063f8afcdc614610ebc578063faf5cb0d14610edc578063fc0c546a14610efc578063fcb8029714610f3057600080fd5b8063ef884adb14610e05578063f242432a14610e25578063f3e9a03114610e45578063f567244c14610e72578063f77c479114610e8757600080fd5b8063cf1f9f9a116100fd578063cf1f9f9a14610d60578063cf52a7b214610d90578063e16bbe7f14610db0578063e88d956714610dc5578063e985e9c514610de557600080fd5b8063c94eb7b914610ce9578063cb6da67014610d09578063ce5feeca14610d36578063cf09dff914610d4b57600080fd5b8063a50b66a9116101bc578063bd85b03911610180578063bd85b03914610c10578063bef12cce14610c3d578063bfac9cd414610c89578063c45a015514610ca9578063c6b61e4c14610cc957600080fd5b8063a50b66a914610b42578063ad5be0c414610b6f578063ad8f500814610b8f578063b082246014610bc3578063b7630ccf14610be357600080fd5b8063907061fe11610203578063907061fe14610a885780639460585714610acd57806395d89b4114610aed5780639c407b6e14610b02578063a22cb46514610b2257600080fd5b806383290a3c146109e55780638ac654b014610a285780638dbdbe6d14610a485780638e507fba14610a6857600080fd5b8063488bd7b0116103455780635a806ac0116102cd57806377d5063f1161029157806377d5063f146109405780637ba21ff4146109605780637e8679561461097557806380d8d2d5146109955780638175f7f5146109b557600080fd5b80635a806ac0146108a157806361d027b3146108d557806367a52793146108ea5780636e7542e31461090057806371b3177a1461092057600080fd5b80634e72fc02116103145780634e72fc02146107ff5780634f558e791461081f578063517a0a5d1461084e57806353a7efd01461086e57806356150edf1461088e57600080fd5b8063488bd7b0146107655780634d01614b146107855780634d1cba89146107a55780634e1273f4146107d257600080fd5b8063210ca05d116103c85780632fdeb111116103975780632fdeb111146106c55780633634a9a3146106db57806338d52e0f146106f15780633cebb823146107255780633e0483651461074557600080fd5b8063210ca05d146105b9578063243219d114610605578063298f5c1c146106355780632eb2c2d6146106aa57600080fd5b806306fdde031161040f57806306fdde03146105085780630e89341c1461052a5780630e9c7c0d1461054a57806317d026e614610577578063195474041461059957600080fd5b8062fdd58e1461044057806301ffc9a71461047357806306b07b62146104a357806306c933d8146104d8575b600080fd5b34801561044c57600080fd5b5061046061045b36600461476a565b610f50565b6040519081526020015b60405180910390f35b34801561047f57600080fd5b5061049361048e3660046147ac565b610fe9565b604051901515815260200161046a565b3480156104af57600080fd5b506104c36104be3660046147c9565b611039565b6040805192835260208301919091520161046a565b3480156104e457600080fd5b506104936104f33660046147c9565b60126020526000908152604090205460ff1681565b34801561051457600080fd5b5061051d6110b5565b60405161046a9190614836565b34801561053657600080fd5b5061051d610545366004614849565b611143565b34801561055657600080fd5b50610460610565366004614849565b600d6020526000908152604090205481565b34801561058357600080fd5b50610597610592366004614849565b6111d7565b005b3480156105a557600080fd5b506105976105b4366004614862565b611209565b3480156105c557600080fd5b506105ed7f00000000000000000000000065c936f008bc34fe819bce9fa5afd9dc2d49977f81565b6040516001600160a01b03909116815260200161046a565b34801561061157600080fd5b50610493610620366004614849565b60116020526000908152604090205460ff1681565b34801561064157600080fd5b50610682610650366004614849565b6000908152600e602052604090205464ffffffffff80821692650100000000008304821692600160501b900490911690565b6040805164ffffffffff9485168152928416602084015292169181019190915260600161046a565b3480156106b657600080fd5b5061059761043b3660046149e7565b3480156106d157600080fd5b5061046060135481565b3480156106e757600080fd5b5061046060155481565b3480156106fd57600080fd5b506105ed7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b34801561073157600080fd5b506105976107403660046147c9565b6113f0565b34801561075157600080fd5b50610597610760366004614a95565b611466565b34801561077157600080fd5b50610460610780366004614a95565b611509565b34801561079157600080fd5b506104606107a0366004614a95565b611535565b3480156107b157600080fd5b506104606107c03660046147c9565b60166020526000908152604090205481565b3480156107de57600080fd5b506107f26107ed366004614b26565b61159e565b60405161046a9190614b8a565b34801561080b57600080fd5b5061046061081a366004614a95565b6116c8565b34801561082b57600080fd5b5061049361083a366004614849565b600090815260036020526040902054151590565b34801561085a57600080fd5b506104606108693660046147c9565b6116ed565b34801561087a57600080fd5b506105976108893660046147c9565b611712565b61059761089c366004614bce565b611788565b3480156108ad57600080fd5b506104937f000000000000000000000000000000000000000000000000000000000000000181565b3480156108e157600080fd5b506105ed61193e565b3480156108f657600080fd5b5061046060145481565b34801561090c57600080fd5b5061049361091b3660046147c9565b6119b1565b34801561092c57600080fd5b5061046061093b366004614bfe565b611a0c565b34801561094c57600080fd5b5061059761095b366004614a95565b611cf0565b34801561096c57600080fd5b5061046061242e565b34801561098157600080fd5b50610597610990366004614c62565b612484565b3480156109a157600080fd5b506105976109b0366004614a95565b61261d565b3480156109c157600080fd5b506104936109d0366004614849565b600f6020526000908152604090205460ff1681565b3480156109f157600080fd5b50610a05610a00366004614849565b61268e565b604080519384526001600160a01b0390921660208401529082015260600161046a565b348015610a3457600080fd5b50610597610a43366004614a95565b6126cd565b348015610a5457600080fd5b50610597610a63366004614862565b612a70565b348015610a7457600080fd5b50610597610a83366004614c9e565b612b96565b348015610a9457600080fd5b50610aa8610aa3366004614849565b612e12565b604080516001600160a01b03909416845260208401929092529082015260600161046a565b348015610ad957600080fd5b50610460610ae8366004614849565b612ea6565b348015610af957600080fd5b5061051d612eba565b348015610b0e57600080fd5b50610597610b1d366004614849565b612ec7565b348015610b2e57600080fd5b50610597610b3d366004614ce1565b612fc6565b348015610b4e57600080fd5b50610460610b5d366004614849565b600c6020526000908152604090205481565b348015610b7b57600080fd5b50610597610b8a366004614849565b612fd5565b348015610b9b57600080fd5b506104607f0000000000000000000000000000000000000000000000000dab6c47ffc2800081565b348015610bcf57600080fd5b506007546105ed906001600160a01b031681565b348015610bef57600080fd5b50610460610bfe366004614849565b600b6020526000908152604090205481565b348015610c1c57600080fd5b50610460610c2b366004614849565b60009081526003602052604090205490565b348015610c4957600080fd5b50610682610c58366004614849565b600e6020526000908152604090205464ffffffffff80821691650100000000008104821691600160501b9091041683565b348015610c9557600080fd5b506104c3610ca4366004614a95565b6130eb565b348015610cb557600080fd5b506008546105ed906001600160a01b031681565b348015610cd557600080fd5b50610460610ce4366004614849565b613140565b348015610cf557600080fd5b50610460610d04366004614849565b613161565b348015610d1557600080fd5b50610460610d24366004614849565b601a6020526000908152604090205481565b348015610d4257600080fd5b50600a54610460565b348015610d5757600080fd5b50601754610460565b348015610d6c57600080fd5b50610493610d7b366004614849565b60106020526000908152604090205460ff1681565b348015610d9c57600080fd5b50610597610dab3660046147c9565b6132e0565b348015610dbc57600080fd5b5061046061335d565b348015610dd157600080fd5b50610597610de0366004614849565b613469565b348015610df157600080fd5b50610493610e00366004614d0f565b61349b565b348015610e1157600080fd5b50610597610e20366004614862565b6134c9565b348015610e3157600080fd5b50610597610e40366004614d3d565b613793565b348015610e5157600080fd5b50610460610e60366004614849565b60196020526000908152604090205481565b348015610e7e57600080fd5b506107f26138d9565b348015610e9357600080fd5b506009546105ed906001600160a01b031681565b348015610eb357600080fd5b50601854610460565b348015610ec857600080fd5b50610597610ed73660046147c9565b613931565b348015610ee857600080fd5b50610a05610ef7366004614849565b613a0b565b348015610f0857600080fd5b506105ed7f000000000000000000000000fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb981565b348015610f3c57600080fd5b50610460610f4b366004614a95565b613a1b565b60006001600160a01b038316610fc05760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b148061101a57506001600160e01b031982166303a24d0760e21b145b80610fe357506301ffc9a760e01b6001600160e01b0319831614610fe3565b600080611045836119b1565b61105457506000928392509050565b600061105f846116ed565b90506017818154811061107457611074614da6565b90600052602060002090600302016000015492506017818154811061109b5761109b614da6565b906000526020600020906003020160020154915050915091565b600480546110c290614dbc565b80601f01602080910402602001604051908101604052809291908181526020018280546110ee90614dbc565b801561113b5780601f106111105761010080835404028352916020019161113b565b820191906000526020600020905b81548152906001019060200180831161111e57829003601f168201915b505050505081565b60606002805461115290614dbc565b80601f016020809104026020016040519081016040528092919081815260200182805461117e90614dbc565b80156111cb5780601f106111a0576101008083540402835291602001916111cb565b820191906000526020600020905b8154815290600101906020018083116111ae57829003601f168201915b50505050509050919050565b6008546001600160a01b031633146112045760405163017bb92160e41b8152336004820152602401610fb7565b601355565b6009546001600160a01b0316331461123657604051632e91ff8760e21b8152336004820152602401610fb7565b600083815260106020526040902054839060ff16611267576040516364638b8160e01b815260040160405180910390fd5b6000848152600f6020526040902054849060ff166112985760405163974264a560e01b815260040160405180910390fd5b6000858152600b60205260409020548411156112c75760405163ec5af4fd60e01b815260040160405180910390fd5b6000858152600b6020908152604080832054600d909252909120546112ed908690614e06565b111561130c5760405163ec5af4fd60e01b815260040160405180910390fd5b6001600160a01b03831660009081526012602052604090205460ff1615801561134357506007546001600160a01b03848116911614155b8015611368575061135261193e565b6001600160a01b0316836001600160a01b031614155b15611391576040516362e0097160e01b81526001600160a01b0384166004820152602401610fb7565b6000858152600d6020526040812080548692906113af908490614e06565b909155506113e990506001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1168486613a65565b5050505050565b6008546001600160a01b0316331461141d5760405163017bb92160e41b8152336004820152602401610fb7565b6001600160a01b03811661144457604051639fabe1c160e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6009546001600160a01b0316331461149357604051632e91ff8760e21b8152336004820152602401610fb7565b600082815260106020526040902054829060ff166114c4576040516364638b8160e01b815260040160405180910390fd5b6000838152600f6020526040902054839060ff166114f55760405163974264a560e01b815260040160405180910390fd5b50506000918252600c602052604090912055565b6000828152600c6020908152604080832054600b90925282205461152e918491613ac8565b9392505050565b600080670de0b6b3a764000060145461154e9190614e19565b9050670de0b6b3a7640000816115648542614e49565b61156e8787614e49565b6115789085614e70565b6115829190614e19565b61158c9190614eac565b6115969190614e70565b949350505050565b606081518351146116035760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610fb7565b6000835167ffffffffffffffff81111561161f5761161f61489b565b604051908082528060200260200182016040528015611648578160200160208202803683370190505b50905060005b84518110156116c05761169385828151811061166c5761166c614da6565b602002602001015185838151811061168657611686614da6565b6020026020010151610f50565b8282815181106116a5576116a5614da6565b60209081029190910101526116b981614ed4565b905061164e565b509392505050565b6000828152601a6020908152604080832054600b90925282205461152e918491613ac8565b6001600160a01b038116600090815260166020526040812054610fe390600190614eed565b6008546001600160a01b0316331461173f5760405163017bb92160e41b8152336004820152602401610fb7565b6001600160a01b03811661176657604051639fabe1c160e01b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b348280158015611799575060155482105b156117b75760405163011bcd8360e41b815260040160405180910390fd5b600084815260106020526040902054849060ff166117e8576040516364638b8160e01b815260040160405180910390fd5b6000858152600e6020526040902054859064ffffffffff16421115611820576040516326ddce9160e01b815260040160405180910390fd5b6002600654036118425760405162461bcd60e51b8152600401610fb790614f00565b60026006557f000000000000000000000000000000000000000000000000000000000000000161188557604051630b5b714560e11b815260040160405180910390fd5b6001600160a01b0385166118ac57604051639fabe1c160e01b815260040160405180910390fd5b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab16001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561190757600080fd5b505af115801561191b573d6000803e3d6000fd5b50505050506000349050611930878288613ae7565b505060016006555050505050565b600854604080516361d027b360e01b815290516000926001600160a01b0316916361d027b39160048083019260209291908290030181865afa158015611988573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ac9190614f37565b905090565b6001600160a01b03811660009081526016602052604081205481036119d857506000919050565b60176119e3836116ed565b815481106119f3576119f3614da6565b6000918252602090912060039091020154151592915050565b600084815260106020526040812054859060ff16611a3d576040516364638b8160e01b815260040160405180910390fd5b6000868152600f6020526040902054869060ff16611a6e5760405163974264a560e01b815260040160405180910390fd5b838787611a7a836119b1565b15611b235760006017611a8c856116ed565b81548110611a9c57611a9c614da6565b60009182526020918290206040805160608101825260039093029091018054835260018101546001600160a01b031693830193909352600290920154918101829052915083148015611b03575080518290611af78686610f50565b611b019190614eed565b105b15611b2157604051632b03aec760e01b815260040160405180910390fd5b505b600260065403611b455760405162461bcd60e51b8152600401610fb790614f00565b60026006556001600160a01b038816611b7157604051639fabe1c160e01b815260040160405180910390fd5b336001600160a01b03881614801590611b915750611b8f873361349b565b155b15611bc05760405163425da22160e11b81523360048201526001600160a01b0388166024820152604401610fb7565b611bcb878b8b613c75565b6000611bd78b8b6116c8565b60008c81526011602052604081205491925060ff90911615159003611c0757611c008b8b611509565b9650611c0b565b8996505b8615611c4557611c456001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1168a89613a65565b8015611c7f57611c7f6001600160a01b037f00000000000000000000000065c936f008bc34fe819bce9fa5afd9dc2d49977f168a83613a65565b604080513381526001600160a01b038b811660208301529181018c905260608101899052608081018390528c918a16907f3e77193b57691ea1ff89912476e90e2ff7221958af62459a9898e76b32fe77359060a00160405180910390a3505050600160065550919695505050505050565b600082815260106020526040902054829060ff16611d21576040516364638b8160e01b815260040160405180910390fd5b6000838152600e6020526040902054839064ffffffffff16421115611d59576040516326ddce9160e01b815260040160405180910390fd5b600260065403611d7b5760405162461bcd60e51b8152600401610fb790614f00565b60026006556000849003611da257604051630395a9c360e41b815260040160405180910390fd5b60175460008581526019602052604081205490829003611dd557604051635d95121160e11b815260040160405180910390fd5b81851180611deb575081611de98683614e06565b115b15611dfd57611dfa8183614eed565b94505b600a8054600f91600091611e1390600290614eed565b81548110611e2357611e23614da6565b6000918252602080832090910154835282019290925260400190205460ff16611e5f5760405163974264a560e01b815260040160405180910390fd5b600a8054879190611e7290600190614eed565b81548110611e8257611e82614da6565b906000526020600020015414611eab57604051630395a9c360e41b815260040160405180910390fd5b60006017805480602002602001604051908101604052809291908181526020016000905b82821015611f245760008481526020908190206040805160608101825260038602909201805483526001808201546001600160a01b031684860152600290910154918301919091529083529092019101611ecf565b505050509050600082905060005b87611f3d8386614eed565b101561237457600f6000848681518110611f5957611f59614da6565b602002602001015160400151815260200190815260200160002060009054906101000a900460ff168015611faa57506000838581518110611f9c57611f9c614da6565b602002602001015160000151115b15612362576000611ff5848681518110611fc657611fc6614da6565b602002602001015160400151858781518110611fe457611fe4614da6565b602002602001015160000151611509565b905083858151811061200957612009614da6565b602002602001015160000151811115612360576013548111612038578461202f81614ed4565b95505050611f32565b600061208485878151811061204f5761204f614da6565b60200260200101516040015186888151811061206d5761206d614da6565b60200260200101516000015184610f4b9190614eed565b85878151811061209657612096614da6565b6020026020010151600001516120ac9190614eed565b90506120f38587815181106120c3576120c3614da6565b6020026020010151602001518688815181106120e1576120e1614da6565b60200260200101516040015183613c75565b61216c85878151811061210857612108614da6565b60200260200101516020015161213b87898151811061212957612129614da6565b602002602001015160400151846116c8565b6001600160a01b037f00000000000000000000000065c936f008bc34fe819bce9fa5afd9dc2d49977f169190613a65565b8a85878151811061217f5761217f614da6565b6020026020010151602001516001600160a01b03167f3e77193b57691ea1ff89912476e90e2ff7221958af62459a9898e76b32fe773533888a815181106121c8576121c8614da6565b60200260200101516020015185876121fd8c8e815181106121eb576121eb614da6565b602002602001015160400151896116c8565b604080516001600160a01b039687168152959094166020860152928401919091526060830152608082015260a00160405180910390a3600060135486888151811061224a5761224a614da6565b6020026020010151600001516122609190614eed565b905061228a86888151811061227757612277614da6565b6020026020010151602001518d83613e0a565b8b86888151811061229d5761229d614da6565b6020026020010151602001516001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d733846040516122f79291906001600160a01b03929092168252602082015260400190565b60405180910390a3806017888154811061231357612313614da6565b9060005260206000209060030201600001819055508b6017888154811061233c5761233c614da6565b60009182526020909120600260039092020101558361235a81614ed4565b94505050505b505b8361236c81614ed4565b945050611f32565b801561238c5760008981526019602052604090208490555b60006013548261239c9190614f54565b11156123e5576123e533601354836123b49190614f54565b6001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1169190613a65565b604080518a8152602081018390527f8d4b7c83e8e9b0d8f4a5cc8dbe9ad5c61c9d347e581ced21717cce3f997141c4910160405180910390a15050600160065550505050505050565b6000805b601854811015612480576018818154811061244f5761244f614da6565b9060005260206000209060030201600001548261246c9190614e06565b91508061247881614ed4565b915050612432565b5090565b6008546001600160a01b031633146124b15760405163017bb92160e41b8152336004820152602401610fb7565b8015806124c3575064ffffffffff8316155b806124d3575064ffffffffff8216155b156124f15760405163d5b25b6360e01b815260040160405180910390fd5b60008181526010602052604090205460ff16151560010361252557604051631c1b415b60e11b815260040160405180910390fd5b8164ffffffffff168364ffffffffff161061255357604051631d02ec5360e11b815260040160405180910390fd5b6000818152601060209081526040808320805460ff19166001908117909155815160608101835264ffffffffff9788168152958716868401908152428816878401908152868652600e90945291842095518654925193518816600160501b0264ffffffffff60501b19948916650100000000000269ffffffffffffffffffff199094169190981617919091179190911694909417909255600a805493840181559091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910155565b6008546001600160a01b0316331461264a5760405163017bb92160e41b8152336004820152602401610fb7565b600082815260106020526040902054829060ff1661267b576040516364638b8160e01b815260040160405180910390fd5b506000918252601a602052604090912055565b6018818154811061269e57600080fd5b60009182526020909120600390910201805460018201546002909201549092506001600160a01b039091169083565b600082815260106020526040902054829060ff166126fe576040516364638b8160e01b815260040160405180910390fd5b6000838152600e6020526040902054839064ffffffffff16421115612736576040516326ddce9160e01b815260040160405180910390fd5b6002600654036127585760405162461bcd60e51b8152600401610fb790614f00565b600260068190555060006018805480602002602001604051908101604052809291908181526020016000905b828210156127d95760008481526020908190206040805160608101825260038602909201805483526001808201546001600160a01b031684860152600290910154918301919091529083529092019101612784565b50506018549293505050600086900361280557604051630395a9c360e41b815260040160405180910390fd5b8060000361282657604051635d95121160e11b815260040160405180910390fd5b80851115612832578094505b600061283f600183614eed565b905060005b8161284f8885614eed565b11612a0b57600084838151811061286857612868614da6565b6020026020010151600001519050600060145411156128d45760008061288e8b846130eb565b915091508092506128d16128a061193e565b6001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1169084613a65565b50505b6013548111156128f2576013546128eb9082614eed565b9050612911565b806013546129009190614eed565b61290a9083614e06565b9150600090505b61293985848151811061292657612926614da6565b6020026020010151602001518a83613e0a565b8885848151811061294c5761294c614da6565b6020026020010151602001516001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d733846040516129a69291906001600160a01b03929092168252602082015260400190565b60405180910390a360188054806129bf576129bf614f6b565b6000828152602081206003600019909301928302018181556001810180546001600160a01b031916905560020181905591558390036129fe5750612a0b565b5060001990910190612844565b60408051898152602081018990527f8d4b7c83e8e9b0d8f4a5cc8dbe9ad5c61c9d347e581ced21717cce3f997141c4910160405180910390a1612a6133826013548a612a579190614f54565b6123b49190614eed565b50506001600655505050505050565b600083815260106020526040902054839060ff16612aa1576040516364638b8160e01b815260040160405180910390fd5b6000848152600e6020526040902054849064ffffffffff16421115612ad9576040516326ddce9160e01b815260040160405180910390fd5b838580158015612aea575060155482105b15612b085760405163011bcd8360e41b815260040160405180910390fd5b600260065403612b2a5760405162461bcd60e51b8152600401610fb790614f00565b60026006556001600160a01b038516612b5657604051639fabe1c160e01b815260040160405180910390fd5b612b8b6001600160a01b037f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab116333089613e25565b611930878787613ae7565b6008546001600160a01b03163314612bc35760405163017bb92160e41b8152336004820152602401610fb7565b600a8054612bd390600190614eed565b81548110612be357612be3614da6565b6000918252602080832090910154808352600e90915260409091205464ffffffffff16421015612c26576040516333e7d47160e11b815260040160405180910390fd5b60005b8251811015612e0d576000838281518110612c4657612c46614da6565b60200260200101519050600060166000836001600160a01b03166001600160a01b0316815260200190815260200160002054905080600003612c89575050612dfb565b6000612c96600183614eed565b905060178181548110612cab57612cab614da6565b906000526020600020906003020160000154600003612df75760178054612cd490600190614eed565b81548110612ce457612ce4614da6565b906000526020600020906003020160178281548110612d0557612d05614da6565b60009182526020909120825460039092020190815560018083015490820180546001600160a01b0319166001600160a01b039092169190911790556002918201549101556017805480612d5a57612d5a614f6b565b600082815260208120600360001990930192830201818155600181810180546001600160a01b03191690556002909101919091559155612d9b908290614e06565b6016600060178481548110612db257612db2614da6565b60009182526020808320600160039093020191909101546001600160a01b03908116845283820194909452604092830182209490945591861682526016909252908120555b5050505b80612e0581614ed4565b915050612c29565b505050565b600080600060178481548110612e2a57612e2a614da6565b906000526020600020906003020160010160009054906101000a90046001600160a01b0316925060178481548110612e6457612e64614da6565b906000526020600020906003020160000154915060178481548110612e8b57612e8b614da6565b90600052602060002090600302016002015490509193909250565b600081815260036020526040812054610fe3565b600580546110c290614dbc565b6009546001600160a01b03163314612ef457604051632e91ff8760e21b8152336004820152602401610fb7565b600081815260106020526040902054819060ff16612f25576040516364638b8160e01b815260040160405180910390fd5b6000828152600e6020526040902054829064ffffffffff16421015612f5d576040516333e7d47160e11b815260040160405180910390fd5b6000838152600f602052604090205460ff1615612f8d57604051639a246e6f60e01b815260040160405180910390fd5b6000838152600f60205260409020805460ff19166001179055612faf83612ea6565b6000938452600b6020526040909320929092555050565b612fd1338383613e63565b5050565b6009546001600160a01b0316331461300257604051632e91ff8760e21b8152336004820152602401610fb7565b600081815260106020526040902054819060ff16613033576040516364638b8160e01b815260040160405180910390fd5b6000828152600f6020526040902054829060ff166130645760405163974264a560e01b815260040160405180910390fd5b6000838152601160209081526040808320805460ff19166001179055601a90915290205415612e0d576130d861309861193e565b6000858152601a60205260409020546001600160a01b037f00000000000000000000000065c936f008bc34fe819bce9fa5afd9dc2d49977f169190613a65565b50506000908152601a6020526040812055565b6000828152600e6020526040812054819064ffffffffff80821691600160501b900416826131198284611535565b90506131288682612710613ac8565b94506131348587614eed565b93505050509250929050565b600a818154811061315057600080fd5b600091825260209091200154905081565b6000805b6017548110156132da576000600f60006017848154811061318857613188614da6565b906000526020600020906003020160020154815260200190815260200160002060009054906101000a900460ff166131e457601782815481106131cd576131cd614da6565b906000526020600020906003020160000154613236565b613236601783815481106131fa576131fa614da6565b9060005260206000209060030201600201546017848154811061321f5761321f614da6565b906000526020600020906003020160000154611509565b9050836017838154811061324c5761324c614da6565b90600052602060002090600302016002015414801561328f57506017828154811061327957613279614da6565b9060005260206000209060030201600001548110155b156132c757601782815481106132a7576132a7614da6565b906000526020600020906003020160000154836132c49190614e06565b92505b50806132d281614ed4565b915050613165565b50919050565b6008546001600160a01b0316331461330d5760405163017bb92160e41b8152336004820152602401610fb7565b6001600160a01b03811661333457604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b03166000908152601260205260409020805460ff19811660ff90911615179055565b6000805b601754811015612480576000600f60006017848154811061338457613384614da6565b906000526020600020906003020160020154815260200190815260200160002060009054906101000a900460ff166133e057601782815481106133c9576133c9614da6565b9060005260206000209060030201600001546133f6565b6133f6601783815481106131fa576131fa614da6565b90506017828154811061340b5761340b614da6565b9060005260206000209060030201600001548110613456576017828154811061343657613436614da6565b906000526020600020906003020160000154836134539190614e06565b92505b508061346181614ed4565b915050613361565b6008546001600160a01b031633146134965760405163017bb92160e41b8152336004820152602401610fb7565b601455565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b600083815260106020526040902054839060ff166134fa576040516364638b8160e01b815260040160405180910390fd5b336001600160a01b0383161480159061351a5750613518823361349b565b155b156135495760405163425da22160e11b81523360048201526001600160a01b0383166024820152604401610fb7565b826135548386610f50565b101561357357604051631e9acf1760e31b815260040160405180910390fd5b6000848152600f602052604090205460ff16158015613593575060155483105b156135b15760405163011bcd8360e41b815260040160405180910390fd5b6000848152600f602052604090205460ff1680156135d957506015546135d78585611509565b105b156135f75760405163011bcd8360e41b815260040160405180910390fd5b6001600160a01b0382166000908152601660205260409020541561367a576000613620836116ed565b9050836017828154811061363657613636614da6565b906000526020600020906003020160000181905550846017828154811061365f5761365f614da6565b90600052602060002090600302016002018190555050613749565b604080516060810182528481526001600160a01b0384811660208084018281528486018a815260178054600181018255600082815297517fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1560039092029182015592517fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c16840180546001600160a01b0319169190971617909555517fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c179091015591549083526016909152919020555b60408051848152602081018690526001600160a01b038416917f5723e0c0d8d7df62467bd503cb8cbb2aa63075a8e4ea63cf1a62441cb3ce3bd9910160405180910390a250505050565b84838361379f836119b1565b1561384857600060176137b1856116ed565b815481106137c1576137c1614da6565b60009182526020918290206040805160608101825260039093029091018054835260018101546001600160a01b03169383019390935260029092015491810182905291508314801561382857508051829061381c8686610f50565b6138269190614eed565b105b1561384657604051632b03aec760e01b815260040160405180910390fd5b505b6001600160a01b0388163314806138645750613864883361349b565b6138c25760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2063616c6c6572206973206e6f74206f776e6572206e6f7260448201526808185c1c1c9bdd995960ba1b6064820152608401610fb7565b6138cf8888888888613f3b565b5050505050505050565b6060600a80548060200260200160405190810160405280929190818152602001828054801561392757602002820191906000526020600020905b815481526020019060010190808311613913575b5050505050905090565b61393a816119b1565b6139575760405163531d450560e01b815260040160405180910390fd5b336001600160a01b038216148015906139775750613975813361349b565b155b156139a65760405163425da22160e11b81523360048201526001600160a01b0382166024820152604401610fb7565b60006139b1826116ed565b90506000601782815481106139c8576139c8614da6565b9060005260206000209060030201600001819055506000601782815481106139f2576139f2614da6565b9060005260206000209060030201600201819055505050565b6017818154811061269e57600080fd5b6000828152600c602052604081205415613a5c576000838152600b6020908152604080832054600c90925290912054613a55918491613ac8565b9050610fe3565b50600092915050565b6040516001600160a01b038316602482015260448101829052612e0d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526140f4565b828202811515841585830485141716613ae057600080fd5b0492915050565b8215613b7057601454829015613b1957600080613b0486866130eb565b91509150809250613b166128a061193e565b50505b613b24828583613e0a565b604080513381526020810185905285916001600160a01b038516917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a350505050565b604080516060810182528381526001600160a01b0383811660208084018281528486018981526018805460018101825560009190915295517fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e60039097029687015590517fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2f860180546001600160a01b031916919095161790935591517fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d30909301929092558251868152908101859052909133917f4987482318beb9b0fe3a677f40a54caa3fe453449015e849c3e255444982dd8391015b60405180910390a3505050565b6001600160a01b038316613cd75760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610fb7565b336000613ce3846141c6565b90506000613cf0846141c6565b9050613d1083876000858560405180602001604052806000815250614211565b6000858152602081815260408083206001600160a01b038a16845290915290205484811015613d8d5760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610fb7565b6000868152602081815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46040805160208101909152600090525b50505050505050565b612e0d83838360405180602001604052806000815250614392565b6040516001600160a01b0380851660248301528316604482015260648101829052613e5d9085906323b872dd60e01b90608401613a91565b50505050565b816001600160a01b0316836001600160a01b031603613ed65760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610fb7565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101613c68565b6001600160a01b038416613f9f5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608401610fb7565b336000613fab856141c6565b90506000613fb8856141c6565b9050613fc8838989858589614211565b6000868152602081815260408083206001600160a01b038c1684529091529020548581101561404c5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610fb7565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290614089908490614e06565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46140e9848a8a8a8a8a6144a2565b505050505050505050565b6000614149826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661463e9092919063ffffffff16565b805190915015612e0d57808060200190518101906141679190614f81565b612e0d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610fb7565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061420057614200614da6565b602090810291909101015292915050565b6001600160a01b0385166142985760005b83518110156142965782818151811061423d5761423d614da6565b60200260200101516003600086848151811061425b5761425b614da6565b6020026020010151815260200190815260200160002060008282546142809190614e06565b9091555061428f905081614ed4565b9050614222565b505b6001600160a01b03841661438a5760005b8351811015613e015760008482815181106142c6576142c6614da6565b6020026020010151905060008483815181106142e4576142e4614da6565b60200260200101519050600060036000848152602001908152602001600020549050818110156143675760405162461bcd60e51b815260206004820152602860248201527f455243313135353a206275726e20616d6f756e74206578636565647320746f74604482015267616c537570706c7960c01b6064820152608401610fb7565b6000928352600360205260409092209103905561438381614ed4565b90506142a9565b505050505050565b6001600160a01b0384166143f25760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610fb7565b3360006143fe856141c6565b9050600061440b856141c6565b905061441c83600089858589614211565b6000868152602081815260408083206001600160a01b038b1684529091528120805487929061444c908490614e06565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4613e01565b6001600160a01b0384163b1561438a5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906144e69089908990889088908890600401614f9e565b6020604051808303816000875af1925050508015614521575060408051601f3d908101601f1916820190925261451e91810190614fd8565b60015b6145cd5761452d614ff5565b806308c379a0036145665750614541615011565b8061454c5750614568565b8060405162461bcd60e51b8152600401610fb79190614836565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e20455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610fb7565b6001600160e01b0319811663f23a6e6160e01b14613e015760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608401610fb7565b60606115968484600085856001600160a01b0385163b6146a05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610fb7565b600080866001600160a01b031685876040516146bc919061509b565b60006040518083038185875af1925050503d80600081146146f9576040519150601f19603f3d011682016040523d82523d6000602084013e6146fe565b606091505b509150915061470e828286614719565b979650505050505050565b6060831561472857508161152e565b8251156147385782518084602001fd5b8160405162461bcd60e51b8152600401610fb79190614836565b6001600160a01b038116811461476757600080fd5b50565b6000806040838503121561477d57600080fd5b823561478881614752565b946020939093013593505050565b6001600160e01b03198116811461476757600080fd5b6000602082840312156147be57600080fd5b813561152e81614796565b6000602082840312156147db57600080fd5b813561152e81614752565b60005b838110156148015781810151838201526020016147e9565b50506000910152565b600081518084526148228160208601602086016147e6565b601f01601f19169290920160200192915050565b60208152600061152e602083018461480a565b60006020828403121561485b57600080fd5b5035919050565b60008060006060848603121561487757600080fd5b8335925060208401359150604084013561489081614752565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff811182821017156148d7576148d761489b565b6040525050565b600067ffffffffffffffff8211156148f8576148f861489b565b5060051b60200190565b600082601f83011261491357600080fd5b81356020614920826148de565b60405161492d82826148b1565b83815260059390931b850182019282810191508684111561494d57600080fd5b8286015b848110156149685780358352918301918301614951565b509695505050505050565b600082601f83011261498457600080fd5b813567ffffffffffffffff81111561499e5761499e61489b565b6040516149b5601f8301601f1916602001826148b1565b8181528460208386010111156149ca57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a086880312156149ff57600080fd5b8535614a0a81614752565b94506020860135614a1a81614752565b9350604086013567ffffffffffffffff80821115614a3757600080fd5b614a4389838a01614902565b94506060880135915080821115614a5957600080fd5b614a6589838a01614902565b93506080880135915080821115614a7b57600080fd5b50614a8888828901614973565b9150509295509295909350565b60008060408385031215614aa857600080fd5b50508035926020909101359150565b600082601f830112614ac857600080fd5b81356020614ad5826148de565b604051614ae282826148b1565b83815260059390931b8501820192828101915086841115614b0257600080fd5b8286015b84811015614968578035614b1981614752565b8352918301918301614b06565b60008060408385031215614b3957600080fd5b823567ffffffffffffffff80821115614b5157600080fd5b614b5d86838701614ab7565b93506020850135915080821115614b7357600080fd5b50614b8085828601614902565b9150509250929050565b6020808252825182820181905260009190848201906040850190845b81811015614bc257835183529284019291840191600101614ba6565b50909695505050505050565b60008060408385031215614be157600080fd5b823591506020830135614bf381614752565b809150509250929050565b60008060008060808587031215614c1457600080fd5b84359350602085013592506040850135614c2d81614752565b91506060850135614c3d81614752565b939692955090935050565b803564ffffffffff81168114614c5d57600080fd5b919050565b600080600060608486031215614c7757600080fd5b614c8084614c48565b9250614c8e60208501614c48565b9150604084013590509250925092565b600060208284031215614cb057600080fd5b813567ffffffffffffffff811115614cc757600080fd5b61159684828501614ab7565b801515811461476757600080fd5b60008060408385031215614cf457600080fd5b8235614cff81614752565b91506020830135614bf381614cd3565b60008060408385031215614d2257600080fd5b8235614d2d81614752565b91506020830135614bf381614752565b600080600080600060a08688031215614d5557600080fd5b8535614d6081614752565b94506020860135614d7081614752565b93506040860135925060608601359150608086013567ffffffffffffffff811115614d9a57600080fd5b614a8888828901614973565b634e487b7160e01b600052603260045260246000fd5b600181811c90821680614dd057607f821691505b6020821081036132da57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610fe357610fe3614df0565b80820260008212600160ff1b84141615614e3557614e35614df0565b8181058314821517610fe357610fe3614df0565b8181036000831280158383131683831282161715614e6957614e69614df0565b5092915050565b600082614e8d57634e487b7160e01b600052601260045260246000fd5b600160ff1b821460001984141615614ea757614ea7614df0565b500590565b8082018281126000831280158216821582161715614ecc57614ecc614df0565b505092915050565b600060018201614ee657614ee6614df0565b5060010190565b81810381811115610fe357610fe3614df0565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208284031215614f4957600080fd5b815161152e81614752565b8082028115828204841417610fe357610fe3614df0565b634e487b7160e01b600052603160045260246000fd5b600060208284031215614f9357600080fd5b815161152e81614cd3565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061470e9083018461480a565b600060208284031215614fea57600080fd5b815161152e81614796565b600060033d111561500e5760046000803e5060005160e01c5b90565b600060443d101561501f5790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561504f57505050505090565b82850191508151818111156150675750505050505090565b843d87010160208285010111156150815750505050505090565b615090602082860101876148b1565b509095945050505050565b600082516150ad8184602087016147e6565b919091019291505056fea26469706673582212209105bf00d7efc7a28960e6255ed306446df04d9723342ad5c0e25621a2ae755664736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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.