FTM Testnet

Contract

0xDE6588a68CD6985F11965F44DCa900bD9Fcf0195
Source Code

Overview

FTM Balance

Fantom LogoFantom LogoFantom Logo0 FTM

Multi Chain

Multichain Addresses

0 address found via
Transaction Hash
Method
Block
From
To
Value
Burst228334642023-12-03 0:13:451 hr 25 mins ago1701562425IN
0xDE6588...9Fcf0195
1.77567739 FTM0.000681722.5
Burst228322362023-12-02 22:34:553 hrs 4 mins ago1701556495IN
0xDE6588...9Fcf0195
6.55069015 FTM0.000823892.5
Burst228282902023-12-02 18:21:287 hrs 17 mins ago1701541288IN
0xDE6588...9Fcf0195
0.03872171 FTM0.000575512
Burst228275582023-12-02 17:41:237 hrs 57 mins ago1701538883IN
0xDE6588...9Fcf0195
3.46761197 FTM0.00073572.5
Burst228259022023-12-02 15:54:199 hrs 45 mins ago1701532459IN
0xDE6588...9Fcf0195
3.52926195 FTM0.000730642.5
Burst228231532023-12-02 13:03:3112 hrs 35 mins ago1701522211IN
0xDE6588...9Fcf0195
3.59684146 FTM0.000811712.5
Burst228230712023-12-02 12:58:1112 hrs 41 mins ago1701521891IN
0xDE6588...9Fcf0195
3.59230451 FTM0.00074772.5
Burst228230622023-12-02 12:57:4412 hrs 41 mins ago1701521864IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000735492.5
Burst228188652023-12-02 8:35:0517 hrs 4 mins ago1701506105IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000873642.5
Burst228115502023-12-02 0:22:091 day 1 hr ago1701476529IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000747612.5
Burst228086492023-12-01 21:08:221 day 4 hrs ago1701464902IN
0xDE6588...9Fcf0195
0.03878555 FTM0.000681632.5
Burst228085392023-12-01 21:01:401 day 4 hrs ago1701464500IN
0xDE6588...9Fcf0195
3.59230451 FTM0.00109442.5
Burst228074372023-12-01 20:01:001 day 5 hrs ago1701460860IN
0xDE6588...9Fcf0195
2.0862298 FTM0.000972742.5
Burst228074362023-12-01 20:00:431 day 5 hrs ago1701460843IN
0xDE6588...9Fcf0195
2.0862298 FTM0.000690222.5
Burst228048512023-12-01 17:48:071 day 7 hrs ago1701452887IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000747672.5
Burst228048052023-12-01 17:45:341 day 7 hrs ago1701452734IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000747732.5
Burst228001712023-12-01 13:40:571 day 11 hrs ago1701438057IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000747552.5
Burst227987372023-12-01 12:22:491 day 13 hrs ago1701433369IN
0xDE6588...9Fcf0195
2.0862298 FTM0.000754282.5
Burst227984602023-12-01 12:09:181 day 13 hrs ago1701432558IN
0xDE6588...9Fcf0195
1.77567739 FTM0.000757872.5
Burst227984502023-12-01 12:08:381 day 13 hrs ago1701432518IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000735552.5
Burst227984442023-12-01 12:08:081 day 13 hrs ago1701432488IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000737342.5
Burst227976842023-12-01 11:23:381 day 14 hrs ago1701429818IN
0xDE6588...9Fcf0195
3.59230451 FTM0.001094282.5
Burst227924592023-12-01 7:29:561 day 18 hrs ago1701415796IN
0xDE6588...9Fcf0195
0.03842178 FTM0.000374081.3
Burst227924392023-12-01 7:28:461 day 18 hrs ago1701415726IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000599691.3
Burst227917162023-12-01 6:57:441 day 18 hrs ago1701413864IN
0xDE6588...9Fcf0195
3.59230451 FTM0.000922612
View all transactions

Latest 25 internal transactions (View All)

Parent Txn Hash Block From To Value
228334642023-12-03 0:13:451 hr 25 mins ago1701562425
0xDE6588...9Fcf0195
1.77567739 FTM
228322362023-12-02 22:34:553 hrs 4 mins ago1701556495
0xDE6588...9Fcf0195
6.55069015 FTM
228282902023-12-02 18:21:287 hrs 17 mins ago1701541288
0xDE6588...9Fcf0195
0.03872171 FTM
228275582023-12-02 17:41:237 hrs 57 mins ago1701538883
0xDE6588...9Fcf0195
3.46761197 FTM
228259022023-12-02 15:54:199 hrs 45 mins ago1701532459
0xDE6588...9Fcf0195
3.52926195 FTM
228231532023-12-02 13:03:3112 hrs 35 mins ago1701522211
0xDE6588...9Fcf0195
3.59684146 FTM
228230712023-12-02 12:58:1112 hrs 41 mins ago1701521891
0xDE6588...9Fcf0195
3.59230451 FTM
228230622023-12-02 12:57:4412 hrs 41 mins ago1701521864
0xDE6588...9Fcf0195
3.59230451 FTM
228188652023-12-02 8:35:0517 hrs 4 mins ago1701506105
0xDE6588...9Fcf0195
3.59230451 FTM
228115502023-12-02 0:22:091 day 1 hr ago1701476529
0xDE6588...9Fcf0195
3.59230451 FTM
228086492023-12-01 21:08:221 day 4 hrs ago1701464902
0xDE6588...9Fcf0195
0.03878555 FTM
228085392023-12-01 21:01:401 day 4 hrs ago1701464500
0xDE6588...9Fcf0195
3.59230451 FTM
228074372023-12-01 20:01:001 day 5 hrs ago1701460860
0xDE6588...9Fcf0195
2.0862298 FTM
228074362023-12-01 20:00:431 day 5 hrs ago1701460843
0xDE6588...9Fcf0195
2.0862298 FTM
228048512023-12-01 17:48:071 day 7 hrs ago1701452887
0xDE6588...9Fcf0195
3.59230451 FTM
228048052023-12-01 17:45:341 day 7 hrs ago1701452734
0xDE6588...9Fcf0195
3.59230451 FTM
228001712023-12-01 13:40:571 day 11 hrs ago1701438057
0xDE6588...9Fcf0195
3.59230451 FTM
227987372023-12-01 12:22:491 day 13 hrs ago1701433369
0xDE6588...9Fcf0195
2.0862298 FTM
227984602023-12-01 12:09:181 day 13 hrs ago1701432558
0xDE6588...9Fcf0195
1.77567739 FTM
227984502023-12-01 12:08:381 day 13 hrs ago1701432518
0xDE6588...9Fcf0195
3.59230451 FTM
227984442023-12-01 12:08:081 day 13 hrs ago1701432488
0xDE6588...9Fcf0195
3.59230451 FTM
227976842023-12-01 11:23:381 day 14 hrs ago1701429818
0xDE6588...9Fcf0195
3.59230451 FTM
227924592023-12-01 7:29:561 day 18 hrs ago1701415796
0xDE6588...9Fcf0195
0.03842178 FTM
227924392023-12-01 7:28:461 day 18 hrs ago1701415726
0xDE6588...9Fcf0195
3.59230451 FTM
227917162023-12-01 6:57:441 day 18 hrs ago1701413864
0xDE6588...9Fcf0195
3.59230451 FTM
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MagnetarV2

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 300 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 20 of 24 : MagnetarV2.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

//OZ
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

//TAPIOCA
import "./MagnetarV2Storage.sol";
import "./modules/MagnetarMarketModule.sol";

import "../interfaces/IPenrose.sol";

/*

__/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____        
 _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__       
  _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_      
   _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_     
    _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_    
     _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_   
      _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_  
       _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_ 
        _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__

*/

contract MagnetarV2 is Ownable, MagnetarV2Storage {
    using SafeERC20 for IERC20;
    using RebaseLibrary for Rebase;

    // ************ //
    // *** VARS *** //
    // ************ //
    enum Module {
        Market
    }

    /// @notice returns the Market module
    MagnetarMarketModule public marketModule;

    constructor(address _owner, address payable _marketModule) {
        transferOwnership(_owner);
        marketModule = MagnetarMarketModule(_marketModule);
    }

    // ******************** //
    // *** VIEW METHODS *** //
    // ******************** //
    /// @notice returns Singularity markets' information
    /// @param who user to return for
    /// @param markets the list of Singularity markets to query for
    function singularityMarketInfo(
        address who,
        ISingularity[] calldata markets
    ) external view returns (SingularityInfo[] memory) {
        return _singularityMarketInfo(who, markets);
    }

    /// @notice returns BigBang markets' information
    /// @param who user to return for
    /// @param markets the list of BigBang markets to query for
    function bigBangMarketInfo(
        address who,
        IBigBang[] calldata markets
    ) external view returns (BigBangInfo[] memory) {
        return _bigBangMarketInfo(who, markets);
    }

    /// @notice Calculate the collateral shares that are needed for `borrowPart`,
    /// taking the current exchange rate into account.
    /// @param market the Singularity or BigBang address
    /// @param borrowPart The borrow part.
    /// @return collateralShares The collateral shares.
    function getCollateralSharesForBorrowPart(
        IMarket market,
        uint256 borrowPart,
        uint256 liquidationMultiplierPrecision,
        uint256 exchangeRatePrecision
    ) public view returns (uint256 collateralShares) {
        Rebase memory _totalBorrowed;
        (uint128 totalBorrowElastic, uint128 totalBorrowBase) = market
            .totalBorrow();
        _totalBorrowed = Rebase(totalBorrowElastic, totalBorrowBase);

        IYieldBoxBase yieldBox = IYieldBoxBase(market.yieldBox());
        uint256 borrowAmount = _totalBorrowed.toElastic(borrowPart, false);
        return
            yieldBox.toShare(
                market.collateralId(),
                (borrowAmount *
                    market.liquidationMultiplier() *
                    market.exchangeRate()) /
                    (liquidationMultiplierPrecision * exchangeRatePrecision),
                false
            );
    }

    /// @notice Return the equivalent of borrow part in asset amount.
    /// @param market the Singularity or BigBang address
    /// @param borrowPart The amount of borrow part to convert.
    /// @return amount The equivalent of borrow part in asset amount.
    function getAmountForBorrowPart(
        IMarket market,
        uint256 borrowPart
    ) public view returns (uint256 amount) {
        Rebase memory _totalBorrowed;
        (uint128 totalBorrowElastic, uint128 totalBorrowBase) = market
            .totalBorrow();
        _totalBorrowed = Rebase(totalBorrowElastic, totalBorrowBase);

        return _totalBorrowed.toElastic(borrowPart, false);
    }

    /// @notice Return the equivalent of amount in borrow part.
    /// @param market the Singularity or BigBang address
    /// @param amount The amount to convert.
    /// @return part The equivalent of amount in borrow part.
    function getBorrowPartForAmount(
        IMarket market,
        uint256 amount
    ) public view returns (uint256 part) {
        Rebase memory _totalBorrowed;
        (uint128 totalBorrowElastic, uint128 totalBorrowBase) = market
            .totalBorrow();
        _totalBorrowed = Rebase(totalBorrowElastic, totalBorrowBase);

        return _totalBorrowed.toBase(amount, false);
    }

    /// @notice Compute the amount of `singularity.assetId` from `fraction`
    /// `fraction` can be `singularity.accrueInfo.feeFraction` or `singularity.balanceOf`
    /// @param singularity the singularity address
    /// @param fraction The fraction.
    /// @return amount The amount.
    function getAmountForAssetFraction(
        ISingularity singularity,
        uint256 fraction
    ) public view returns (uint256 amount) {
        (uint128 totalAssetElastic, uint128 totalAssetBase) = singularity
            .totalAsset();

        IYieldBoxBase yieldBox = IYieldBoxBase(singularity.yieldBox());
        return
            yieldBox.toAmount(
                singularity.assetId(),
                (fraction * totalAssetElastic) / totalAssetBase,
                false
            );
    }

    /// @notice Compute the fraction of `singularity.assetId` from `amount`
    /// `fraction` can be `singularity.accrueInfo.feeFraction` or `singularity.balanceOf`
    /// @param singularity the singularity address
    /// @param amount The amount.
    /// @return fraction The fraction.
    function getFractionForAmount(
        ISingularity singularity,
        uint256 amount
    ) public view returns (uint256 fraction) {
        (uint128 totalAssetShare, uint128 totalAssetBase) = singularity
            .totalAsset();
        (uint128 totalBorrowElastic, ) = singularity.totalBorrow();
        uint256 assetId = singularity.assetId();

        IYieldBoxBase yieldBox = IYieldBoxBase(singularity.yieldBox());

        uint256 share = yieldBox.toShare(assetId, amount, false);
        uint256 allShare = totalAssetShare +
            yieldBox.toShare(assetId, totalBorrowElastic, true);

        fraction = allShare == 0 ? share : (share * totalAssetBase) / allShare;
    }

    // ********************** //
    // *** PUBLIC METHODS *** //
    // ********************** //
    /// @notice Batch multiple calls together
    /// @param calls The list of actions to perform
    function burst(
        Call[] calldata calls
    ) external payable returns (Result[] memory returnData) {
        uint256 valAccumulator;

        uint256 length = calls.length;
        returnData = new Result[](length);

        for (uint256 i = 0; i < length; i++) {
            Call calldata _action = calls[i];
            if (!_action.allowFailure) {
                require(
                    _action.call.length > 0,
                    string.concat(
                        "MagnetarV2: Missing call for action with index",
                        string(abi.encode(i))
                    )
                );
            }

            unchecked {
                valAccumulator += _action.value;
            }

            if (_action.id == PERMIT_ALL) {
                _permit(
                    _action.target,
                    _action.call,
                    true,
                    _action.allowFailure
                );
            } else if (_action.id == PERMIT) {
                _permit(
                    _action.target,
                    _action.call,
                    false,
                    _action.allowFailure
                );
            } else if (_action.id == TOFT_WRAP) {
                WrapData memory data = abi.decode(_action.call[4:], (WrapData));
                _checkSender(data.from);
                if (_action.value > 0) {
                    unchecked {
                        valAccumulator += _action.value;
                    }
                    ITapiocaOFT(_action.target).wrapNative{
                        value: _action.value
                    }(data.to);
                } else {
                    ITapiocaOFT(_action.target).wrap(
                        msg.sender,
                        data.to,
                        data.amount
                    );
                }
            } else if (_action.id == TOFT_SEND_FROM) {
                (
                    address from,
                    uint16 dstChainId,
                    bytes32 to,
                    uint256 amount,
                    ISendFrom.LzCallParams memory lzCallParams
                ) = abi.decode(
                        _action.call[4:],
                        (
                            address,
                            uint16,
                            bytes32,
                            uint256,
                            (ISendFrom.LzCallParams)
                        )
                    );
                _checkSender(from);

                ISendFrom(_action.target).sendFrom{value: _action.value}(
                    msg.sender,
                    dstChainId,
                    to,
                    amount,
                    lzCallParams
                );
            } else if (_action.id == YB_DEPOSIT_ASSET) {
                YieldBoxDepositData memory data = abi.decode(
                    _action.call[4:],
                    (YieldBoxDepositData)
                );
                _checkSender(data.from);

                (uint256 amountOut, uint256 shareOut) = IYieldBoxBase(
                    _action.target
                ).depositAsset(
                        data.assetId,
                        msg.sender,
                        data.to,
                        data.amount,
                        data.share
                    );
                returnData[i] = Result({
                    success: true,
                    returnData: abi.encode(amountOut, shareOut)
                });
            } else if (_action.id == MARKET_ADD_COLLATERAL) {
                SGLAddCollateralData memory data = abi.decode(
                    _action.call[4:],
                    (SGLAddCollateralData)
                );
                _checkSender(data.from);

                IMarket(_action.target).addCollateral(
                    msg.sender,
                    data.to,
                    data.skim,
                    data.amount,
                    data.share
                );
            } else if (_action.id == MARKET_BORROW) {
                SGLBorrowData memory data = abi.decode(
                    _action.call[4:],
                    (SGLBorrowData)
                );
                _checkSender(data.from);

                (uint256 part, uint256 share) = IMarket(_action.target).borrow(
                    msg.sender,
                    data.to,
                    data.amount
                );
                returnData[i] = Result({
                    success: true,
                    returnData: abi.encode(part, share)
                });
            } else if (_action.id == YB_WITHDRAW_TO) {
                (
                    address yieldBox,
                    address from,
                    uint256 assetId,
                    uint16 dstChainId,
                    bytes32 receiver,
                    uint256 amount,
                    uint256 share,
                    bytes memory adapterParams,
                    address payable refundAddress
                ) = abi.decode(
                        _action.call[4:],
                        (
                            address,
                            address,
                            uint256,
                            uint16,
                            bytes32,
                            uint256,
                            uint256,
                            bytes,
                            address
                        )
                    );

                _executeModule(
                    Module.Market,
                    abi.encodeWithSelector(
                        MagnetarMarketModule.withdrawTo.selector,
                        yieldBox,
                        from,
                        assetId,
                        dstChainId,
                        receiver,
                        amount,
                        share,
                        adapterParams,
                        refundAddress,
                        _action.value
                    )
                );
            } else if (_action.id == MARKET_LEND) {
                SGLLendData memory data = abi.decode(
                    _action.call[4:],
                    (SGLLendData)
                );
                _checkSender(data.from);

                uint256 fraction = IMarket(_action.target).addAsset(
                    msg.sender,
                    data.to,
                    data.skim,
                    data.share
                );
                returnData[i] = Result({
                    success: true,
                    returnData: abi.encode(fraction)
                });
            } else if (_action.id == MARKET_REPAY) {
                SGLRepayData memory data = abi.decode(
                    _action.call[4:],
                    (SGLRepayData)
                );
                _checkSender(data.from);

                uint256 amount = IMarket(_action.target).repay(
                    msg.sender,
                    data.to,
                    data.skim,
                    data.part
                );
                returnData[i] = Result({
                    success: true,
                    returnData: abi.encode(amount)
                });
            } else if (_action.id == TOFT_SEND_AND_BORROW) {
                (
                    address from,
                    address to,
                    uint16 lzDstChainId,
                    bytes memory airdropAdapterParams,
                    ITapiocaOFT.IBorrowParams memory borrowParams,
                    ITapiocaOFT.IWithdrawParams memory withdrawParams,
                    ITapiocaOFT.ISendOptions memory options,
                    ITapiocaOFT.IApproval[] memory approvals
                ) = abi.decode(
                        _action.call[4:],
                        (
                            address,
                            address,
                            uint16,
                            bytes,
                            ITapiocaOFT.IBorrowParams,
                            ITapiocaOFT.IWithdrawParams,
                            ITapiocaOFT.ISendOptions,
                            ITapiocaOFT.IApproval[]
                        )
                    );
                _checkSender(from);

                ITapiocaOFT(_action.target).sendToYBAndBorrow{
                    value: _action.value
                }(
                    msg.sender,
                    to,
                    lzDstChainId,
                    airdropAdapterParams,
                    borrowParams,
                    withdrawParams,
                    options,
                    approvals
                );
            } else if (_action.id == TOFT_SEND_AND_LEND) {
                (
                    address from,
                    address to,
                    uint16 dstChainId,
                    address zroPaymentAddress,
                    IUSDOBase.ILendParams memory lendParams,
                    IUSDOBase.IApproval[] memory approvals,
                    IUSDOBase.IWithdrawParams memory withdrawParams,
                    bytes memory adapterParams
                ) = abi.decode(
                        _action.call[4:],
                        (
                            address,
                            address,
                            uint16,
                            address,
                            (IUSDOBase.ILendParams),
                            (IUSDOBase.IApproval[]),
                            (IUSDOBase.IWithdrawParams),
                            bytes
                        )
                    );
                _checkSender(from);

                IUSDOBase(_action.target).sendAndLendOrRepay{
                    value: _action.value
                }(
                    msg.sender,
                    to,
                    dstChainId,
                    zroPaymentAddress,
                    lendParams,
                    approvals,
                    withdrawParams,
                    adapterParams
                );
            } else if (_action.id == TOFT_DEPOSIT_TO_STRATEGY) {
                TOFTSendToStrategyData memory data = abi.decode(
                    _action.call[4:],
                    (TOFTSendToStrategyData)
                );
                _checkSender(data.from);

                ITapiocaOFT(_action.target).sendToStrategy{
                    value: _action.value
                }(
                    msg.sender,
                    data.to,
                    data.amount,
                    data.share,
                    data.assetId,
                    data.lzDstChainId,
                    data.options
                );
            } else if (_action.id == TOFT_RETRIEVE_FROM_STRATEGY) {
                (
                    address from,
                    uint256 amount,
                    uint256 share,
                    uint256 assetId,
                    uint16 lzDstChainId,
                    address zroPaymentAddress,
                    bytes memory airdropAdapterParam
                ) = abi.decode(
                        _action.call[4:],
                        (
                            address,
                            uint256,
                            uint256,
                            uint256,
                            uint16,
                            address,
                            bytes
                        )
                    );

                _checkSender(from);

                ITapiocaOFT(_action.target).retrieveFromStrategy{
                    value: _action.value
                }(
                    msg.sender,
                    amount,
                    share,
                    assetId,
                    lzDstChainId,
                    zroPaymentAddress,
                    airdropAdapterParam
                );
            } else if (_action.id == MARKET_YBDEPOSIT_AND_LEND) {
                HelperLendData memory data = abi.decode(
                    _action.call[4:],
                    (HelperLendData)
                );

                _executeModule(
                    Module.Market,
                    abi.encodeWithSelector(
                        MagnetarMarketModule.depositAndAddAsset.selector,
                        data.market,
                        data.from,
                        data.amount,
                        data.deposit,
                        false
                    )
                );
            } else if (_action.id == MARKET_YBDEPOSIT_COLLATERAL_AND_BORROW) {
                (
                    address market,
                    address user,
                    uint256 collateralAmount,
                    uint256 borrowAmount,
                    ,
                    bool deposit,
                    bool withdraw,
                    bytes memory withdrawData
                ) = abi.decode(
                        _action.call[4:],
                        (
                            address,
                            address,
                            uint256,
                            uint256,
                            bool,
                            bool,
                            bool,
                            bytes
                        )
                    );

                _executeModule(
                    Module.Market,
                    abi.encodeWithSelector(
                        MagnetarMarketModule
                            .depositAddCollateralAndBorrow
                            .selector,
                        market,
                        user,
                        collateralAmount,
                        borrowAmount,
                        false,
                        deposit,
                        withdraw,
                        withdrawData
                    )
                );
            } else if (_action.id == MARKET_REMOVE_ASSET) {
                HelperRemoveAssetData memory data = abi.decode(
                    _action.call[4:],
                    (HelperRemoveAssetData)
                );

                _executeModule(
                    Module.Market,
                    abi.encodeWithSelector(
                        MagnetarMarketModule.removeAsset.selector,
                        data.market,
                        data.user,
                        data.fraction
                    )
                );
            } else if (_action.id == MARKET_DEPOSIT_REPAY_REMOVE_COLLATERAL) {
                HelperDepositRepayRemoveCollateral memory data = abi.decode(
                    _action.call[4:],
                    (HelperDepositRepayRemoveCollateral)
                );

                _executeModule(
                    Module.Market,
                    abi.encodeWithSelector(
                        MagnetarMarketModule
                            .depositRepayAndRemoveCollateral
                            .selector,
                        data.market,
                        data.user,
                        data.depositAmount,
                        data.repayAmount,
                        data.collateralAmount,
                        data.deposit,
                        data.withdraw,
                        data.extractFromSender
                    )
                );
            } else {
                revert("MagnetarV2: action not valid");
            }
        }

        require(msg.value == valAccumulator, "MagnetarV2: value mismatch");
    }

    function withdrawTo(
        IYieldBoxBase yieldBox,
        address from,
        uint256 assetId,
        uint16 dstChainId,
        bytes32 receiver,
        uint256 amount,
        uint256 share,
        bytes memory adapterParams,
        address payable refundAddress,
        uint256 gas
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.withdrawTo.selector,
                yieldBox,
                from,
                assetId,
                dstChainId,
                receiver,
                amount,
                share,
                adapterParams,
                refundAddress,
                gas
            )
        );
    }

    function depositAddCollateralAndBorrow(
        IMarket market,
        address user,
        uint256 collateralAmount,
        uint256 borrowAmount,
        bool extractFromSender,
        bool deposit,
        bool withdraw,
        bytes memory withdrawData
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.depositAddCollateralAndBorrow.selector,
                market,
                user,
                collateralAmount,
                borrowAmount,
                extractFromSender,
                deposit,
                withdraw,
                withdrawData
            )
        );
    }

    function depositAndRepay(
        IMarket market,
        address user,
        uint256 depositAmount,
        uint256 repayAmount,
        bool deposit,
        bool extractFromSender
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.depositAndRepay.selector,
                market,
                user,
                depositAmount,
                repayAmount,
                deposit,
                extractFromSender
            )
        );
    }

    function depositRepayAndRemoveCollateral(
        IMarket market,
        address user,
        uint256 depositAmount,
        uint256 repayAmount,
        uint256 collateralAmount,
        bool deposit,
        bool withdraw,
        bool extractFromSender
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.depositRepayAndRemoveCollateral.selector,
                market,
                user,
                depositAmount,
                repayAmount,
                collateralAmount,
                deposit,
                withdraw,
                extractFromSender
            )
        );
    }

    function mintAndLend(
        ISingularity singularity,
        IMarket bingBang,
        address user,
        uint256 collateralAmount,
        uint256 borrowAmount,
        bool deposit,
        bool extractFromSender
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.mintAndLend.selector,
                singularity,
                bingBang,
                user,
                collateralAmount,
                borrowAmount,
                deposit,
                extractFromSender
            )
        );
    }

    function depositAndAddAsset(
        IMarket singularity,
        address user,
        uint256 amount,
        bool deposit,
        bool extractFromSender
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.depositAndAddAsset.selector,
                singularity,
                user,
                amount,
                deposit,
                extractFromSender
            )
        );
    }

    function removeAssetAndRepay(
        ISingularity singularity,
        IMarket bingBang,
        address user,
        uint256 removeShare, //slightly greater than _repayAmount to cover the interest
        uint256 repayAmount,
        uint256 collateralShare,
        bool withdraw,
        bytes calldata withdrawData
    ) external payable {
        _executeModule(
            Module.Market,
            abi.encodeWithSelector(
                MagnetarMarketModule.removeAssetAndRepay.selector,
                singularity,
                bingBang,
                user,
                removeShare,
                repayAmount,
                collateralShare,
                withdraw,
                withdrawData
            )
        );
    }

    // ********************** //
    // *** PRIVATE METHODS *** //
    // *********************** //
    function _commonInfo(
        address who,
        IMarket market
    ) private view returns (MarketInfo memory) {
        Rebase memory _totalBorrowed;
        MarketInfo memory info;

        info.collateral = market.collateral();
        info.asset = market.asset();
        info.oracle = IOracle(market.oracle());
        info.oracleData = market.oracleData();
        info.totalCollateralShare = market.totalCollateralShare();
        info.userCollateralShare = market.userCollateralShare(who);

        (uint128 totalBorrowElastic, uint128 totalBorrowBase) = market
            .totalBorrow();
        _totalBorrowed = Rebase(totalBorrowElastic, totalBorrowBase);
        info.totalBorrow = _totalBorrowed;
        info.userBorrowPart = market.userBorrowPart(who);

        info.currentExchangeRate = market.exchangeRate();
        (, info.oracleExchangeRate) = IOracle(market.oracle()).peek(
            market.oracleData()
        );
        info.spotExchangeRate = IOracle(market.oracle()).peekSpot(
            market.oracleData()
        );
        info.totalBorrowCap = market.totalBorrowCap();
        info.assetId = market.assetId();
        info.collateralId = market.collateralId();

        IYieldBoxBase yieldBox = IYieldBoxBase(market.yieldBox());

        (
            info.totalYieldBoxCollateralShare,
            info.totalYieldBoxCollateralAmount
        ) = yieldBox.assetTotals(info.collateralId);
        (info.totalYieldBoxAssetShare, info.totalYieldBoxAssetAmount) = yieldBox
            .assetTotals(info.assetId);

        (
            info.yieldBoxCollateralTokenType,
            info.yieldBoxCollateralContractAddress,
            info.yieldBoxCollateralStrategyAddress,
            info.yieldBoxCollateralTokenId
        ) = yieldBox.assets(info.collateralId);
        (
            info.yieldBoxAssetTokenType,
            info.yieldBoxAssetContractAddress,
            info.yieldBoxAssetStrategyAddress,
            info.yieldBoxAssetTokenId
        ) = yieldBox.assets(info.assetId);

        return info;
    }

    function _singularityMarketInfo(
        address who,
        ISingularity[] memory markets
    ) private view returns (SingularityInfo[] memory) {
        uint256 len = markets.length;
        SingularityInfo[] memory result = new SingularityInfo[](len);

        Rebase memory _totalAsset;
        ISingularity.AccrueInfo memory _accrueInfo;
        for (uint256 i = 0; i < len; i++) {
            ISingularity sgl = markets[i];

            result[i].market = _commonInfo(who, IMarket(address(sgl)));

            (uint128 totalAssetElastic, uint128 totalAssetBase) = sgl //
                .totalAsset(); //
            _totalAsset = Rebase(totalAssetElastic, totalAssetBase); //
            result[i].totalAsset = _totalAsset; //
            result[i].userAssetFraction = sgl.balanceOf(who); //

            (
                uint64 interestPerSecond,
                uint64 lastBlockAccrued,
                uint128 feesEarnedFraction
            ) = sgl.accrueInfo();
            _accrueInfo = ISingularity.AccrueInfo(
                interestPerSecond,
                lastBlockAccrued,
                feesEarnedFraction
            );
            result[i].accrueInfo = _accrueInfo;
        }

        return result;
    }

    function _bigBangMarketInfo(
        address who,
        IBigBang[] memory markets
    ) private view returns (BigBangInfo[] memory) {
        uint256 len = markets.length;
        BigBangInfo[] memory result = new BigBangInfo[](len);

        IBigBang.AccrueInfo memory _accrueInfo;
        for (uint256 i = 0; i < len; i++) {
            IBigBang bigBang = markets[i];
            result[i].market = _commonInfo(who, IMarket(address(bigBang)));

            (uint64 debtRate, uint64 lastAccrued) = bigBang.accrueInfo();
            _accrueInfo = IBigBang.AccrueInfo(debtRate, lastAccrued);
            result[i].accrueInfo = _accrueInfo;
            result[i].minDebtRate = bigBang.minDebtRate();
            result[i].maxDebtRate = bigBang.maxDebtRate();
            result[i].debtRateAgainstEthMarket = bigBang.debtRateAgainstEthMarket();
            result[i].currentDebtRate = bigBang.getDebtRate();

            IPenrose penrose = IPenrose(bigBang.penrose());
            result[i].mainBBMarket = penrose.bigBangEthMarket();
            result[i].mainBBDebtRate = penrose.bigBangEthDebtRate();

        }

        return result;
    }

    function _permit(
        address target,
        bytes calldata actionCalldata,
        bool permitAll,
        bool allowFailure
    ) private {
        if (permitAll) {
            PermitAllData memory permitData = abi.decode(
                actionCalldata[4:],
                (PermitAllData)
            );
            _checkSender(permitData.owner);
        } else {
            PermitData memory permitData = abi.decode(
                actionCalldata[4:],
                (PermitData)
            );
            _checkSender(permitData.owner);
        }

        (bool success, bytes memory returnData) = target.call(actionCalldata);
        if (!success && !allowFailure) {
            _getRevertMsg(returnData);
        }
    }

    function _extractModule(Module _module) private view returns (address) {
        address module;
        if (_module == Module.Market) {
            module = address(marketModule);
        }

        if (module == address(0)) {
            revert("MagnetarV2: module not found");
        }

        return module;
    }

    function _executeModule(
        Module _module,
        bytes memory _data
    ) private returns (bytes memory returnData) {
        bool success = true;
        address module = _extractModule(_module);

        (success, returnData) = module.delegatecall(_data);
        if (!success) {
            _getRevertMsg(returnData);
        }
    }

    function _getRevertMsg(bytes memory _returnData) private pure {
        // If the _res length is less than 68, then
        // the transaction failed with custom error or silently (without a revert message)
        if (_returnData.length < 68) revert("MagnetarV2: Reason unknown");

        assembly {
            // Slice the sighash.
            _returnData := add(_returnData, 0x04)
        }
        revert(abi.decode(_returnData, (string))); // All that remains is the revert string
    }
}

File 2 of 24 : BoringRebase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

struct Rebase {
    uint128 elastic;
    uint128 base;
}

/// @notice A rebasing library using overflow-/underflow-safe math.
library RebaseLibrary {
    /// @notice Calculates the base value in relationship to `elastic` and `total`.
    function toBase(
        Rebase memory total,
        uint256 elastic,
        bool roundUp
    ) internal pure returns (uint256 base) {
        if (total.elastic == 0) {
            base = elastic;
        } else {
            base = (elastic * total.base) / total.elastic;
            if (roundUp && (base * total.elastic) / total.base < elastic) {
                base++;
            }
        }
    }

    /// @notice Calculates the elastic value in relationship to `base` and `total`.
    function toElastic(
        Rebase memory total,
        uint256 base,
        bool roundUp
    ) internal pure returns (uint256 elastic) {
        if (total.base == 0) {
            elastic = base;
        } else {
            elastic = (base * total.elastic) / total.base;
            if (roundUp && (elastic * total.base) / total.elastic < base) {
                elastic++;
            }
        }
    }

    /// @notice Add `elastic` to `total` and doubles `total.base`.
    /// @return (Rebase) The new total.
    /// @return base in relationship to `elastic`.
    function add(
        Rebase memory total,
        uint256 elastic,
        bool roundUp
    ) internal pure returns (Rebase memory, uint256 base) {
        base = toBase(total, elastic, roundUp);
        total.elastic += uint128(elastic);
        total.base += uint128(base);
        return (total, base);
    }

    /// @notice Sub `base` from `total` and update `total.elastic`.
    /// @return (Rebase) The new total.
    /// @return elastic in relationship to `base`.
    function sub(
        Rebase memory total,
        uint256 base,
        bool roundUp
    ) internal pure returns (Rebase memory, uint256 elastic) {
        elastic = toElastic(total, base, roundUp);
        total.elastic -= uint128(elastic);
        total.base -= uint128(base);
        return (total, elastic);
    }

    /// @notice Add `elastic` and `base` to `total`.
    function add(
        Rebase memory total,
        uint256 elastic,
        uint256 base
    ) internal pure returns (Rebase memory) {
        total.elastic += uint128(elastic);
        total.base += uint128(base);
        return total;
    }

    /// @notice Subtract `elastic` and `base` to `total`.
    function sub(
        Rebase memory total,
        uint256 elastic,
        uint256 base
    ) internal pure returns (Rebase memory) {
        total.elastic -= uint128(elastic);
        total.base -= uint128(base);
        return total;
    }

    /// @notice Add `elastic` to `total` and update storage.
    /// @return newElastic Returns updated `elastic`.
    function addElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) {
        newElastic = total.elastic += uint128(elastic);
    }

    /// @notice Subtract `elastic` from `total` and update storage.
    /// @return newElastic Returns updated `elastic`.
    function subElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) {
        newElastic = total.elastic -= uint128(elastic);
    }
}

File 3 of 24 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 4 of 24 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

File 5 of 24 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 6 of 24 : IERC20.sol
// 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);
}

File 7 of 24 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.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));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

File 8 of 24 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

File 10 of 24 : IERC165.sol
// 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);
}

File 11 of 24 : IBigBang.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

interface IBigBang {
    struct AccrueInfo {
        uint64 debtRate;
        uint64 lastAccrued;
    }

    function accrueInfo()
        external
        view
        returns (uint64 debtRate, uint64 lastAccrued);


    function minDebtRate() external view returns (uint256);

    function maxDebtRate() external view returns (uint256);

    function debtRateAgainstEthMarket() external view returns (uint256);

    function penrose() external view returns (address);

    function getDebtRate() external view returns (uint256);
    
}

File 12 of 24 : IMarket.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

interface IMarket {
    function asset() external view returns (address);

    function assetId() external view returns (uint256);

    function collateral() external view returns (address);

    function collateralId() external view returns (uint256);

    function totalBorrowCap() external view returns (uint256);

    function totalCollateralShare() external view returns (uint256);

    function userBorrowPart(address) external view returns (uint256);

    function userCollateralShare(address) external view returns (uint256);

    function totalBorrow()
        external
        view
        returns (uint128 elastic, uint128 base);

    function oracle() external view returns (address);

    function oracleData() external view returns (bytes memory);

    function exchangeRate() external view returns (uint256);

    function yieldBox() external view returns (address payable);

    function liquidationMultiplier() external view returns (uint256);

    function addCollateral(
        address from,
        address to,
        bool skim,
        uint256 amount,
        uint256 share
    ) external;

    function removeCollateral(address from, address to, uint256 share) external;

    function addAsset(
        address from,
        address to,
        bool skim,
        uint256 share
    ) external returns (uint256 fraction);

    function repay(
        address from,
        address to,
        bool skim,
        uint256 part
    ) external returns (uint256 amount);

    function borrow(
        address from,
        address to,
        uint256 amount
    ) external returns (uint256 part, uint256 share);

    function execute(
        bytes[] calldata calls,
        bool revertOnFail
    ) external returns (bool[] memory successes, string[] memory results);

    function refreshPenroseFees(
        address feeTo
    ) external returns (uint256 feeShares);

    function penrose() external view returns (address);

    function owner() external view returns (address);
}

File 13 of 24 : IOracle.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

interface IOracle {
    // @notice Precision of the return value.
    function decimals() external view returns (uint8);

    /// @notice Get the latest exchange rate.
    /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.
    /// For example:
    /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
    /// @return success if no valid (recent) rate is available, return false else true.
    /// @return rate The rate of the requested asset / pair / pool.
    function get(
        bytes calldata data
    ) external returns (bool success, uint256 rate);

    /// @notice Check the last exchange rate without any state changes.
    /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.
    /// For example:
    /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
    /// @return success if no valid (recent) rate is available, return false else true.
    /// @return rate The rate of the requested asset / pair / pool.
    function peek(
        bytes calldata data
    ) external view returns (bool success, uint256 rate);

    /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek().
    /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.
    /// For example:
    /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
    /// @return rate The rate of the requested asset / pair / pool.
    function peekSpot(bytes calldata data) external view returns (uint256 rate);

    /// @notice Returns a human readable (short) name about this oracle.
    /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.
    /// For example:
    /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
    /// @return (string) A human readable symbol name about this oracle.
    function symbol(bytes calldata data) external view returns (string memory);

    /// @notice Returns a human readable name about this oracle.
    /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle.
    /// For example:
    /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
    /// @return (string) A human readable name about this oracle.
    function name(bytes calldata data) external view returns (string memory);
}

File 14 of 24 : IPenrose.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "./ISwapper.sol";

interface IPenrose {
    /// @notice swap extra data
    struct SwapData {
        uint256 minAssetAmount;
    }

    /// @notice Used to define the MasterContract's type
    enum ContractType {
        lowRisk,
        mediumRisk,
        highRisk
    }

    /// @notice MasterContract address and type
    struct MasterContract {
        address location;
        ContractType risk;
    }

    function bigBangEthMarket() external view returns (address);

    function bigBangEthDebtRate() external view returns (uint256);

    function swappers(ISwapper swapper) external view returns (bool);

    function yieldBox() external view returns (address payable);

    function tapToken() external view returns (address);

    function tapAssetId() external view returns (uint256);

    function usdoToken() external view returns (address);

    function usdoAssetId() external view returns (uint256);

    function feeTo() external view returns (address);

    function wethToken() external view returns (address);

    function wethAssetId() external view returns (uint256);

    function isMarketRegistered(address market) external view returns (bool);
}

File 15 of 24 : ISendFrom.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

interface ISendFrom {
    struct LzCallParams {
        address payable refundAddress;
        address zroPaymentAddress;
        bytes adapterParams;
    }

    function sendFrom(
        address _from,
        uint16 _dstChainId,
        bytes32 _toAddress,
        uint256 _amount,
        LzCallParams calldata _callParams
    ) external payable;

    function useCustomAdapterParams() external view returns (bool);
}

File 16 of 24 : ISingularity.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "./IMarket.sol";

interface ISingularity is IMarket {
    struct AccrueInfo {
        uint64 interestPerSecond;
        uint64 lastAccrued;
        uint128 feesEarnedFraction;
    }

    function accrueInfo()
        external
        view
        returns (
            uint64 interestPerSecond,
            uint64 lastBlockAccrued,
            uint128 feesEarnedFraction
        );

    function totalAsset() external view returns (uint128 elastic, uint128 base);

    function removeAsset(
        address from,
        address to,
        uint256 fraction
    ) external returns (uint256 share);

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

    function nonces(address) external view returns (uint256);

    function permit(
        address owner_,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function allowance(address, address) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function balanceOf(address) external view returns (uint256);

    function liquidationQueue() external view returns (address payable);

    function computeAllowedLendShare(
        uint256 amount,
        uint256 tokenId
    ) external view returns (uint256 share);
}

File 17 of 24 : ISwapper.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

interface ISwapper {
    struct SwapTokensData {
        address tokenIn;
        uint256 tokenInId;
        address tokenOut;
        uint256 tokenOutId;
    }

    struct SwapAmountData {
        uint256 amountIn;
        uint256 shareIn;
        uint256 amountOut;
        uint256 shareOut;
    }

    struct YieldBoxData {
        bool withdrawFromYb;
        bool depositToYb;
    }

    struct SwapData {
        SwapTokensData tokensData;
        SwapAmountData amountData;
        YieldBoxData yieldBoxData;
    }

    //Add more overloads if needed
    function buildSwapData(
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 shareIn,
        bool withdrawFromYb,
        bool depositToYb
    ) external view returns (SwapData memory);

    function buildSwapData(
        uint256 tokenInId,
        uint256 tokenOutId,
        uint256 amountIn,
        uint256 shareIn,
        bool withdrawFromYb,
        bool depositToYb
    ) external view returns (SwapData memory);

    function getDefaultDexOptions() external view returns (bytes memory);

    function getOutputAmount(
        SwapData calldata swapData,
        bytes calldata dexOptions
    ) external view returns (uint256 amountOut);

    function getInputAmount(
        SwapData calldata swapData,
        bytes calldata dexOptions
    ) external view returns (uint256 amountIn);

    function swap(
        SwapData calldata swapData,
        uint256 amountOutMin,
        address to,
        bytes calldata dexOptions
    ) external returns (uint256 amountOut, uint256 shareOut);
}

interface ICurveSwapper is ISwapper {
    function curvePool() external view returns (address);
}

File 18 of 24 : ITapiocaOFT.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "./ISendFrom.sol";
import {IUSDOBase} from "./IUSDO.sol";

interface ITapiocaOFTBase {
    function hostChainID() external view returns (uint256);

    function wrap(
        address fromAddress,
        address toAddress,
        uint256 amount
    ) external;

    function wrapNative(address _toAddress) external payable;

    function unwrap(address _toAddress, uint256 _amount) external;

    function erc20() external view returns (address);

    function lzEndpoint() external view returns (address);
}

/// @dev used for generic TOFTs
interface ITapiocaOFT is ISendFrom, ITapiocaOFTBase {
    struct ISendOptions {
        uint256 extraGasLimit;
        address zroPaymentAddress;
    }

    struct IApproval {
        bool permitAll;
        bool allowFailure;
        address target;
        bool permitBorrow;
        address owner;
        address spender;
        uint256 value;
        uint256 deadline;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct IWithdrawParams {
        bool withdraw;
        uint256 withdrawLzFeeAmount;
        bool withdrawOnOtherChain;
        uint16 withdrawLzChainId;
        bytes withdrawAdapterParams;
    }

    struct IRemoveParams {
        uint256 share;
        address marketHelper;
        address market;
    }

    struct IBorrowParams {
        uint256 amount;
        uint256 borrowAmount;
        address marketHelper;
        address market;
    }

    function totalFees() external view returns (uint256);

    function erc20() external view returns (address);

    function wrappedAmount(uint256 _amount) external view returns (uint256);

    function isHostChain() external view returns (bool);

    function balanceOf(address _holder) external view returns (uint256);

    function isTrustedRemote(
        uint16 lzChainId,
        bytes calldata path
    ) external view returns (bool);

    function approve(address _spender, uint256 _amount) external returns (bool);

    function extractUnderlying(uint256 _amount) external;

    function harvestFees() external;

    /// OFT specific methods
    function sendToYBAndBorrow(
        address _from,
        address _to,
        uint16 lzDstChainId,
        bytes calldata airdropAdapterParams,
        IBorrowParams calldata borrowParams,
        IWithdrawParams calldata withdrawParams,
        ISendOptions calldata options,
        IApproval[] calldata approvals
    ) external payable;

    function sendToStrategy(
        address _from,
        address _to,
        uint256 amount,
        uint256 share,
        uint256 assetId,
        uint16 lzDstChainId,
        ISendOptions calldata options
    ) external payable;

    function retrieveFromStrategy(
        address _from,
        uint256 amount,
        uint256 share,
        uint256 assetId,
        uint16 lzDstChainId,
        address zroPaymentAddress,
        bytes memory airdropAdapterParam
    ) external payable;

    function sendForLeverage(
        uint256 amount,
        address leverageFor,
        IUSDOBase.ILeverageLZData calldata lzData,
        IUSDOBase.ILeverageSwapData calldata swapData,
        IUSDOBase.ILeverageExternalContractsData calldata externalData
    ) external payable;

    function removeCollateral(
        address from,
        address to,
        uint16 lzDstChainId,
        address zroPaymentAddress,
        ITapiocaOFT.IWithdrawParams calldata withdrawParams,
        ITapiocaOFT.IRemoveParams calldata removeParams,
        ITapiocaOFT.IApproval[] calldata approvals,
        bytes calldata adapterParams
    ) external payable;
}

File 19 of 24 : IUSDO.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IUSDOBase {
    struct IWithdrawParams {
        bool withdraw;
        uint256 withdrawLzFeeAmount;
        bool withdrawOnOtherChain;
        uint16 withdrawLzChainId;
        bytes withdrawAdapterParams;
    }

    struct IApproval {
        bool permitAll;
        bool allowFailure;
        address target;
        bool permitBorrow;
        address owner;
        address spender;
        uint256 value;
        uint256 deadline;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct IRemoveParams {
        uint256 share;
        address marketHelper;
        address market;
    }

    struct ILendParams {
        bool repay;
        uint256 depositAmount;
        uint256 repayAmount;
        address marketHelper;
        address market;
        bool removeCollateral;
        uint256 removeCollateralShare;
    }

    struct ISendOptions {
        uint256 extraGasLimit;
        address zroPaymentAddress;
    }

    struct ILeverageLZData {
        uint256 srcExtraGasLimit;
        uint16 lzSrcChainId;
        uint16 lzDstChainId;
        address zroPaymentAddress;
        bytes dstAirdropAdapterParam;
        bytes srcAirdropAdapterParam;
        address refundAddress;
    }

    struct ILeverageSwapData {
        address tokenOut;
        uint256 amountOutMin;
        bytes data;
    }
    struct ILeverageExternalContractsData {
        address swapper;
        address magnetar;
        address tOft;
        address srcMarket;
    }

    function mint(address _to, uint256 _amount) external;

    function burn(address _from, uint256 _amount) external;

    function sendAndLendOrRepay(
        address _from,
        address _to,
        uint16 lzDstChainId,
        address zroPaymentAddress,
        ILendParams calldata lendParams,
        IApproval[] calldata approvals,
        IWithdrawParams calldata withdrawParams,
        bytes calldata adapterParams
    ) external payable;

    function sendForLeverage(
        uint256 amount,
        address leverageFor,
        ILeverageLZData calldata lzData,
        ILeverageSwapData calldata swapData,
        ILeverageExternalContractsData calldata externalData
    ) external payable;
}

interface IUSDO is IUSDOBase, IERC20Metadata {}

File 20 of 24 : IYieldBoxBase.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "tapioca-sdk/dist/contracts/YieldBox/contracts/enums/YieldBoxTokenType.sol";

interface IYieldBoxBase {
    function depositAsset(
        uint256 assetId,
        address from,
        address to,
        uint256 amount,
        uint256 share
    ) external returns (uint256 amountOut, uint256 shareOut);

    function withdraw(
        uint256 assetId,
        address from,
        address to,
        uint256 amount,
        uint256 share
    ) external returns (uint256 amountOut, uint256 shareOut);

    function transfer(
        address from,
        address to,
        uint256 assetId,
        uint256 share
    ) external;

    function isApprovedForAll(
        address user,
        address spender
    ) external view returns (bool);

    function setApprovalForAll(address spender, bool status) external;

    function assets(
        uint256 assetId
    )
        external
        view
        returns (
            TokenType tokenType,
            address contractAddress,
            address strategy,
            uint256 tokenId
        );

    function assetTotals(
        uint256 assetId
    ) external view returns (uint256 totalShare, uint256 totalAmount);

    function toShare(
        uint256 assetId,
        uint256 amount,
        bool roundUp
    ) external view returns (uint256 share);

    function toAmount(
        uint256 assetId,
        uint256 share,
        bool roundUp
    ) external view returns (uint256 amount);

    function balanceOf(
        address user,
        uint256 assetId
    ) external view returns (uint256 share);
}

File 21 of 24 : MagnetarV2Storage.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

//Boring
import "@boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol";

//TAPIOCA
import "../interfaces/IOracle.sol";
import "../interfaces/ISingularity.sol";
import "../interfaces/IBigBang.sol";
import "../interfaces/ITapiocaOFT.sol";
import {IUSDOBase} from "../interfaces/IUSDO.sol";

//YIELDBOX
import "tapioca-sdk/dist/contracts/YieldBox/contracts/enums/YieldBoxTokenType.sol";

contract MagnetarV2Storage {
    // ************ //
    // *** VARS *** //
    // ************ //
    mapping(address => mapping(address => bool)) public isApprovedForAll;

    struct MarketInfo {
        address collateral;
        uint256 collateralId;
        address asset;
        uint256 assetId;
        IOracle oracle;
        bytes oracleData;
        uint256 totalCollateralShare;
        uint256 userCollateralShare;
        Rebase totalBorrow;
        uint256 userBorrowPart;
        uint256 currentExchangeRate;
        uint256 spotExchangeRate;
        uint256 oracleExchangeRate;
        uint256 totalBorrowCap;
        uint256 totalYieldBoxCollateralShare;
        uint256 totalYieldBoxCollateralAmount;
        uint256 totalYieldBoxAssetShare;
        uint256 totalYieldBoxAssetAmount;
        TokenType yieldBoxCollateralTokenType;
        address yieldBoxCollateralContractAddress;
        address yieldBoxCollateralStrategyAddress;
        uint256 yieldBoxCollateralTokenId;
        TokenType yieldBoxAssetTokenType;
        address yieldBoxAssetContractAddress;
        address yieldBoxAssetStrategyAddress;
        uint256 yieldBoxAssetTokenId;
    }
    struct SingularityInfo {
        MarketInfo market;
        Rebase totalAsset;
        uint256 userAssetFraction;
        ISingularity.AccrueInfo accrueInfo;
    }
    struct BigBangInfo {
        MarketInfo market;
        IBigBang.AccrueInfo accrueInfo;
        uint256 minDebtRate;
        uint256 maxDebtRate;
        uint256 debtRateAgainstEthMarket;
        address mainBBMarket;
        uint256 mainBBDebtRate;
        uint256 currentDebtRate;
    }

    // --- ACTIONS DATA ----
    struct Call {
        uint16 id;
        address target;
        uint256 value;
        bool allowFailure;
        bytes call;
    }

    struct Result {
        bool success;
        bytes returnData;
    }

    struct PermitData {
        address owner;
        address spender;
        uint256 value;
        uint256 deadline;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct PermitAllData {
        address owner;
        address spender;
        uint256 deadline;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct WrapData {
        address from;
        address to;
        uint256 amount;
    }

    struct WrapNativeData {
        address to;
    }

    struct TOFTSendAndBorrowData {
        address from;
        address to;
        uint16 lzDstChainId;
        bytes airdropAdapterParams;
        ITapiocaOFT.IBorrowParams borrowParams;
        ITapiocaOFT.IWithdrawParams withdrawParams;
        ITapiocaOFT.ISendOptions options;
        ITapiocaOFT.IApproval[] approvals;
    }

    struct TOFTSendAndLendData {
        address from;
        address to;
        uint16 lzDstChainId;
        IUSDOBase.ILendParams lendParams;
        IUSDOBase.ISendOptions options;
        IUSDOBase.IApproval[] approvals;
    }

    struct TOFTSendToStrategyData {
        address from;
        address to;
        uint256 amount;
        uint256 share;
        uint256 assetId;
        uint16 lzDstChainId;
        ITapiocaOFT.ISendOptions options;
    }

    struct TOFTRetrieveFromStrategyData {
        address from;
        uint256 amount;
        uint256 share;
        uint256 assetId;
        uint16 lzDstChainId;
        address zroPaymentAddress;
        bytes airdropAdapterParam;
    }

    struct YieldBoxDepositData {
        uint256 assetId;
        address from;
        address to;
        uint256 amount;
        uint256 share;
    }

    struct SGLAddCollateralData {
        address from;
        address to;
        bool skim;
        uint256 amount;
        uint256 share;
    }

    struct SGLBorrowData {
        address from;
        address to;
        uint256 amount;
    }

    struct SGLLendData {
        address from;
        address to;
        bool skim;
        uint256 share;
    }

    struct SGLRepayData {
        address from;
        address to;
        bool skim;
        uint256 part;
    }

    struct HelperRemoveAssetData {
        address market;
        address user;
        uint256 fraction;
    }

    struct HelperLendData {
        address market;
        address from;
        uint256 amount;
        bool deposit;
        bool extractFromSender;
    }

    struct HelperBorrowData {
        address market;
        address user;
        uint256 collateralAmount;
        uint256 borrowAmount;
        bool extractFromSender;
        bool deposit;
        bool withdraw;
        bytes withdrawData;
    }

    struct HelperDepositRepayRemoveCollateral {
        address market;
        address user;
        uint256 depositAmount;
        uint256 repayAmount;
        uint256 collateralAmount;
        bool deposit;
        bool withdraw;
        bool extractFromSender;
    }

    // --- ACTIONS IDS ----
    uint16 internal constant PERMIT_ALL = 1;
    uint16 internal constant PERMIT = 2;

    uint16 internal constant YB_DEPOSIT_ASSET = 100;
    uint16 internal constant YB_WITHDRAW_TO = 102;

    uint16 internal constant MARKET_ADD_COLLATERAL = 200;
    uint16 internal constant MARKET_BORROW = 201;
    uint16 internal constant MARKET_LEND = 203;
    uint16 internal constant MARKET_REPAY = 204;
    uint16 internal constant MARKET_YBDEPOSIT_AND_LEND = 205;
    uint16 internal constant MARKET_YBDEPOSIT_COLLATERAL_AND_BORROW = 206;
    uint16 internal constant MARKET_REMOVE_ASSET = 207;
    uint16 internal constant MARKET_DEPOSIT_REPAY_REMOVE_COLLATERAL = 208;

    uint16 internal constant TOFT_WRAP = 300;
    uint16 internal constant TOFT_SEND_FROM = 301;
    uint16 internal constant TOFT_SEND_APPROVAL = 302;
    uint16 internal constant TOFT_SEND_AND_BORROW = 303;
    uint16 internal constant TOFT_SEND_AND_LEND = 304;
    uint16 internal constant TOFT_DEPOSIT_TO_STRATEGY = 305;
    uint16 internal constant TOFT_RETRIEVE_FROM_STRATEGY = 306;

    // ************** //
    // *** EVENTS *** //
    // ************** //
    event ApprovalForAll(address owner, address operator, bool approved);

    // ************************ //
    // *** INTERNAL METHODS *** //
    // ************************ //
    function _checkSender(address _from) internal view {
        require(_from == msg.sender, "MagnetarV2: operator not approved");
    }

    receive() external payable virtual {}
}

File 22 of 24 : MagnetarMarketModule.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

//LZ
import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";

//OZ
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

//TAPIOCA
import "../../interfaces/IYieldBoxBase.sol";

import "../MagnetarV2Storage.sol";

contract MagnetarMarketModule is MagnetarV2Storage {
    using SafeERC20 for IERC20;
    using RebaseLibrary for Rebase;

    function withdrawTo(
        IYieldBoxBase yieldBox,
        address from,
        uint256 assetId,
        uint16 dstChainId,
        bytes32 receiver,
        uint256 amount,
        uint256 share,
        bytes memory adapterParams,
        address payable refundAddress,
        uint256 gas
    ) external payable {
        _withdrawTo(
            yieldBox,
            from,
            assetId,
            dstChainId,
            receiver,
            amount,
            share,
            adapterParams,
            refundAddress,
            gas
        );
    }

    function depositAddCollateralAndBorrow(
        IMarket market,
        address user,
        uint256 collateralAmount,
        uint256 borrowAmount,
        bool extractFromSender,
        bool deposit,
        bool withdraw,
        bytes memory withdrawData
    ) external payable {
        _depositAddCollateralAndBorrow(
            market,
            user,
            collateralAmount,
            borrowAmount,
            extractFromSender,
            deposit,
            withdraw,
            withdrawData
        );
    }

    function depositAndRepay(
        IMarket market,
        address user,
        uint256 depositAmount,
        uint256 repayAmount,
        bool deposit,
        bool extractFromSender
    ) external payable {
        _depositAndRepay(
            market,
            user,
            depositAmount,
            repayAmount,
            deposit,
            extractFromSender
        );
    }

    function depositRepayAndRemoveCollateral(
        IMarket market,
        address user,
        uint256 depositAmount,
        uint256 repayAmount,
        uint256 collateralAmount,
        bool deposit,
        bool withdraw,
        bool extractFromSender
    ) external payable {
        _depositRepayAndRemoveCollateral(
            market,
            user,
            depositAmount,
            repayAmount,
            collateralAmount,
            deposit,
            withdraw,
            extractFromSender
        );
    }

    function removeAsset(
        ISingularity singularity,
        address user,
        uint256 fraction
    ) external payable {
        _removeAsset(singularity, user, fraction);
    }

    function mintAndLend(
        ISingularity singularity,
        IMarket bingBang,
        address user,
        uint256 collateralAmount,
        uint256 borrowAmount,
        bool deposit,
        bool extractFromSender
    ) external payable {
        _mintAndLend(
            singularity,
            bingBang,
            user,
            collateralAmount,
            borrowAmount,
            deposit,
            extractFromSender
        );
    }

    function depositAndAddAsset(
        IMarket singularity,
        address user,
        uint256 amount,
        bool deposit_,
        bool extractFromSender
    ) external payable {
        _depositAndAddAsset(
            singularity,
            user,
            amount,
            deposit_,
            extractFromSender
        );
    }

    function removeAssetAndRepay(
        ISingularity singularity,
        IMarket bingBang,
        address user,
        uint256 removeShare, //slightly greater than _repayAmount to cover the interest
        uint256 repayAmount,
        uint256 collateralShare,
        bool withdraw,
        bytes calldata withdrawData
    ) external payable {
        _removeAssetAndRepay(
            singularity,
            bingBang,
            user,
            removeShare,
            repayAmount,
            collateralShare,
            withdraw,
            withdrawData
        );
    }

    // *********************** //
    // *** PRIVATE METHODS *** //
    // *********************** //
    function _depositAddCollateralAndBorrow(
        IMarket market,
        address user,
        uint256 collateralAmount,
        uint256 borrowAmount,
        bool extractFromSender,
        bool deposit,
        bool withdraw,
        bytes memory withdrawData
    ) private {
        IYieldBoxBase yieldBox = IYieldBoxBase(market.yieldBox());

        uint256 collateralId = market.collateralId();

        (, address collateralAddress, , ) = yieldBox.assets(collateralId);

        //deposit into the yieldbox
        uint256 _share = yieldBox.toShare(
            collateralId,
            collateralAmount,
            false
        );
        if (deposit) {
            if (!extractFromSender) {
                _checkSender(user);
            }
            _extractTokens(
                extractFromSender ? msg.sender : user,
                collateralAddress,
                collateralAmount
            );
            IERC20(collateralAddress).approve(
                address(yieldBox),
                collateralAmount
            );
            yieldBox.depositAsset(
                collateralId,
                address(this),
                address(this),
                0,
                _share
            );
        }

        //add collateral
        if (collateralAmount > 0) {
            _setApprovalForYieldBox(market, yieldBox);
            market.addCollateral(
                deposit ? address(this) : user,
                user,
                false,
                collateralAmount,
                _share
            );
        }

        //borrow
        if (borrowAmount > 0) {
            address borrowReceiver = withdraw ? address(this) : user;
            market.borrow(user, borrowReceiver, borrowAmount);

            if (withdraw) {
                _withdraw(
                    borrowReceiver,
                    withdrawData,
                    market,
                    yieldBox,
                    borrowAmount,
                    0,
                    false
                );
            }
        }

        _revertYieldBoxApproval(market, yieldBox);
    }

    function _depositAndRepay(
        IMarket market,
        address user,
        uint256 depositAmount,
        uint256 repayAmount,
        bool deposit,
        bool extractFromSender
    ) private {
        uint256 assetId = market.assetId();
        IYieldBoxBase yieldBox = IYieldBoxBase(market.yieldBox());

        (, address assetAddress, , ) = yieldBox.assets(assetId);

        //deposit into the yieldbox
        if (deposit) {
            _extractTokens(
                extractFromSender ? msg.sender : user,
                assetAddress,
                depositAmount
            );
            IERC20(assetAddress).approve(address(yieldBox), depositAmount);
            yieldBox.depositAsset(
                assetId,
                address(this),
                address(this),
                depositAmount,
                0
            );
        }

        //repay
        if (repayAmount > 0) {
            _setApprovalForYieldBox(market, yieldBox);
            market.repay(
                deposit ? address(this) : user,
                user,
                false,
                repayAmount
            );
            _revertYieldBoxApproval(market, yieldBox);
        }
    }

    function _depositRepayAndRemoveCollateral(
        IMarket market,
        address user,
        uint256 depositAmount,
        uint256 repayAmount,
        uint256 collateralAmount,
        bool deposit,
        bool withdraw,
        bool extractFromSender
    ) private {
        IYieldBoxBase yieldBox = IYieldBoxBase(market.yieldBox());

        _depositAndRepay(
            market,
            user,
            depositAmount,
            repayAmount,
            deposit,
            extractFromSender
        );

        //remove collateral
        if (collateralAmount > 0) {
            address receiver = withdraw ? address(this) : user;
            uint256 collateralShare = yieldBox.toShare(
                market.collateralId(),
                collateralAmount,
                false
            );
            market.removeCollateral(user, receiver, collateralShare);

            //withdraw
            if (withdraw) {
                yieldBox.withdraw(
                    market.collateralId(),
                    address(this),
                    user,
                    collateralAmount,
                    0
                );
            }
        }
    }

    function _removeAsset(
        ISingularity singularity,
        address user,
        uint256 fraction
    ) private {
        singularity.removeAsset(user, user, fraction);
    }

    function _mintAndLend(
        ISingularity singularity,
        IMarket bingBang,
        address user,
        uint256 collateralAmount,
        uint256 borrowAmount,
        bool deposit,
        bool extractFromSender
    ) private {
        uint256 collateralId = bingBang.collateralId();
        IYieldBoxBase yieldBox = IYieldBoxBase(singularity.yieldBox());

        (, address collateralAddress, , ) = yieldBox.assets(collateralId);
        uint256 _share = yieldBox.toShare(
            collateralId,
            collateralAmount,
            false
        );

        if (deposit) {
            //deposit to YieldBox
            _extractTokens(
                extractFromSender ? msg.sender : user,
                collateralAddress,
                collateralAmount
            );
            IERC20(collateralAddress).approve(
                address(yieldBox),
                collateralAmount
            );
            yieldBox.depositAsset(
                collateralId,
                address(this),
                address(this),
                0,
                _share
            );
        }

        if (collateralAmount > 0) {
            //add collateral to BingBang
            _setApprovalForYieldBox(bingBang, yieldBox);
            bingBang.addCollateral(
                address(this),
                user,
                false,
                collateralAmount,
                _share
            );
        }

        //borrow from BingBang
        if (borrowAmount > 0) {
            bingBang.borrow(user, user, borrowAmount);

            //lend to Singularity
            uint256 assetId = singularity.assetId();
            uint256 borrowShare = yieldBox.toShare(
                assetId,
                borrowAmount,
                false
            );
            _setApprovalForYieldBox(singularity, yieldBox);
            singularity.addAsset(user, user, false, borrowShare);
            _revertYieldBoxApproval(singularity, yieldBox);
        }
        _revertYieldBoxApproval(bingBang, yieldBox);
    }

    function _depositAndAddAsset(
        IMarket singularity,
        address _user,
        uint256 _amount,
        bool deposit_,
        bool extractFromSender
    ) private {
        uint256 assetId = singularity.assetId();
        IYieldBoxBase yieldBox = IYieldBoxBase(singularity.yieldBox());

        (, address assetAddress, , ) = yieldBox.assets(assetId);

        uint256 _share = yieldBox.toShare(assetId, _amount, false);
        if (deposit_) {
            if (!extractFromSender) {
                _checkSender(_user);
            }
            //deposit into the yieldbox
            _extractTokens(
                extractFromSender ? msg.sender : _user,
                assetAddress,
                _amount
            );
            IERC20(assetAddress).approve(address(yieldBox), _amount);
            yieldBox.depositAsset(
                assetId,
                address(this),
                address(this),
                0,
                _share
            );
        }

        //add asset
        _setApprovalForYieldBox(singularity, yieldBox);
        singularity.addAsset(address(this), _user, false, _share);
        _setApprovalForYieldBox(singularity, yieldBox);
    }

    function _removeAssetAndRepay(
        ISingularity singularity,
        IMarket bigBang,
        address user,
        uint256 removeShare, //slightly greater than _repayAmount to cover the interest
        uint256 repayAmount,
        uint256 collateralShare,
        bool withdraw,
        bytes calldata withdrawData
    ) private {
        IYieldBoxBase yieldBox = IYieldBoxBase(singularity.yieldBox());

        //remove asset
        uint256 bbAssetId = bigBang.assetId();
        uint256 _removeAmount = yieldBox.toAmount(
            bbAssetId,
            removeShare,
            false
        );
        singularity.removeAsset(user, address(this), removeShare);

        //repay
        _setApprovalForYieldBox(bigBang, yieldBox);
        uint256 repayed = bigBang.repay(
            address(this),
            user,
            false,
            repayAmount
        );
        if (repayed < _removeAmount) {
            yieldBox.transfer(
                address(this),
                user,
                bbAssetId,
                yieldBox.toShare(bbAssetId, _removeAmount - repayed, false)
            );
        }

        //remove collateral
        if (collateralShare > 0) {
            bigBang.removeCollateral(
                user,
                withdraw ? address(this) : user,
                collateralShare
            );

            //withdraw
            if (withdraw) {
                _withdraw(
                    address(this),
                    withdrawData,
                    singularity,
                    yieldBox,
                    0,
                    collateralShare,
                    true
                );
            }
        }
        _revertYieldBoxApproval(bigBang, yieldBox);
    }

    function _withdrawTo(
        IYieldBoxBase yieldBox,
        address from,
        uint256 assetId,
        uint16 dstChainId,
        bytes32 receiver,
        uint256 amount,
        uint256 share,
        bytes memory adapterParams,
        address payable refundAddress,
        uint256 gas
    ) private {
        if (dstChainId == 0) {
            yieldBox.withdraw(
                assetId,
                from,
                LzLib.bytes32ToAddress(receiver),
                amount,
                share
            );
            return;
        }
        (, address asset, , ) = yieldBox.assets(assetId);
        try
            IERC165(address(asset)).supportsInterface(
                type(ISendFrom).interfaceId
            )
        {} catch {
            return;
        }

        yieldBox.withdraw(assetId, from, address(this), amount, 0);
        bytes memory _adapterParams;
        ISendFrom.LzCallParams memory callParams = ISendFrom.LzCallParams({
            refundAddress: msg.value > 0 ? refundAddress : payable(this),
            zroPaymentAddress: address(0),
            adapterParams: ISendFrom(address(asset)).useCustomAdapterParams()
                ? adapterParams
                : _adapterParams
        });
        ISendFrom(address(asset)).sendFrom{value: gas}(
            address(this),
            dstChainId,
            receiver,
            amount,
            callParams
        );
    }

    function _withdraw(
        address from,
        bytes memory withdrawData,
        IMarket market,
        IYieldBoxBase yieldBox,
        uint256 amount,
        uint256 share,
        bool withdrawCollateral
    ) private {
        require(withdrawData.length > 0, "MagnetarV2: withdrawData is empty");
        (
            bool withdrawOnOtherChain,
            uint16 destChain,
            bytes32 receiver,
            bytes memory adapterParams
        ) = abi.decode(withdrawData, (bool, uint16, bytes32, bytes));

        uint256 gas = msg.value > 0 ? msg.value : address(this).balance;
        _withdrawTo(
            yieldBox,
            from,
            withdrawCollateral ? market.collateralId() : market.assetId(),
            withdrawOnOtherChain ? destChain : 0,
            receiver,
            amount,
            share,
            adapterParams,
            gas > 0 ? payable(msg.sender) : payable(this),
            gas
        );
    }

    function _setApprovalForYieldBox(
        IMarket market,
        IYieldBoxBase yieldBox
    ) private {
        bool isApproved = yieldBox.isApprovedForAll(
            address(this),
            address(market)
        );
        if (!isApproved) {
            yieldBox.setApprovalForAll(address(market), true);
        }
    }

    function _revertYieldBoxApproval(
        IMarket market,
        IYieldBoxBase yieldBox
    ) private {
        bool isApproved = yieldBox.isApprovedForAll(
            address(this),
            address(market)
        );
        if (isApproved) {
            yieldBox.setApprovalForAll(address(market), false);
        }
    }

    function _extractTokens(
        address _from,
        address _token,
        uint256 _amount
    ) private {
        IERC20(_token).safeTransferFrom(_from, address(this), _amount);
    }
}

File 23 of 24 : LzLib.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.6.0;
pragma experimental ABIEncoderV2;

library LzLib {
    // LayerZero communication
    struct CallParams {
        address payable refundAddress;
        address zroPaymentAddress;
    }

    //---------------------------------------------------------------------------
    // Address type handling

    struct AirdropParams {
        uint airdropAmount;
        bytes32 airdropAddress;
    }

    function buildAdapterParams(LzLib.AirdropParams memory _airdropParams, uint _uaGasLimit) internal pure returns (bytes memory adapterParams) {
        if (_airdropParams.airdropAmount == 0 && _airdropParams.airdropAddress == bytes32(0x0)) {
            adapterParams = buildDefaultAdapterParams(_uaGasLimit);
        } else {
            adapterParams = buildAirdropAdapterParams(_uaGasLimit, _airdropParams);
        }
    }

    // Build Adapter Params
    function buildDefaultAdapterParams(uint _uaGas) internal pure returns (bytes memory) {
        // txType 1
        // bytes  [2       32      ]
        // fields [txType  extraGas]
        return abi.encodePacked(uint16(1), _uaGas);
    }

    function buildAirdropAdapterParams(uint _uaGas, AirdropParams memory _params) internal pure returns (bytes memory) {
        require(_params.airdropAmount > 0, "Airdrop amount must be greater than 0");
        require(_params.airdropAddress != bytes32(0x0), "Airdrop address must be set");

        // txType 2
        // bytes  [2       32        32            bytes[]         ]
        // fields [txType  extraGas  dstNativeAmt  dstNativeAddress]
        return abi.encodePacked(uint16(2), _uaGas, _params.airdropAmount, _params.airdropAddress);
    }

    function getGasLimit(bytes memory _adapterParams) internal pure returns (uint gasLimit) {
        require(_adapterParams.length == 34 || _adapterParams.length > 66, "Invalid adapterParams");
        assembly {
            gasLimit := mload(add(_adapterParams, 34))
        }
    }

    // Decode Adapter Params
    function decodeAdapterParams(bytes memory _adapterParams) internal pure returns (uint16 txType, uint uaGas, uint airdropAmount, address payable airdropAddress) {
        require(_adapterParams.length == 34 || _adapterParams.length > 66, "Invalid adapterParams");
        assembly {
            txType := mload(add(_adapterParams, 2))
            uaGas := mload(add(_adapterParams, 34))
        }
        require(txType == 1 || txType == 2, "Unsupported txType");
        require(uaGas > 0, "Gas too low");

        if (txType == 2) {
            assembly {
                airdropAmount := mload(add(_adapterParams, 66))
                airdropAddress := mload(add(_adapterParams, 86))
            }
        }
    }

    //---------------------------------------------------------------------------
    // Address type handling
    function bytes32ToAddress(bytes32 _bytes32Address) internal pure returns (address _address) {
        return address(uint160(uint(_bytes32Address)));
    }

    function addressToBytes32(address _address) internal pure returns (bytes32 _bytes32Address) {
        return bytes32(uint(uint160(_address)));
    }
}

File 24 of 24 : YieldBoxTokenType.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

/// @title TokenType
/// @author BoringCrypto (@Boring_Crypto)
/// @notice The YieldBox can hold different types of tokens:
/// Native: These are ERC1155 tokens native to YieldBox. Protocols using YieldBox should use these is possible when simple token creation is needed.
/// ERC20: ERC20 tokens (including rebasing tokens) can be added to the YieldBox.
/// ERC1155: ERC1155 tokens are also supported. This can also be used to add YieldBox Native tokens to strategies since they are ERC1155 tokens.
enum TokenType {
    Native,
    ERC20,
    ERC721,
    ERC1155,
    None
}

Settings
{
  "viaIR": true,
  "optimizer": {
    "enabled": true,
    "runs": 300
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address payable","name":"_marketModule","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"contract IBigBang[]","name":"markets","type":"address[]"}],"name":"bigBangMarketInfo","outputs":[{"components":[{"components":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"collateralId","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"contract IOracle","name":"oracle","type":"address"},{"internalType":"bytes","name":"oracleData","type":"bytes"},{"internalType":"uint256","name":"totalCollateralShare","type":"uint256"},{"internalType":"uint256","name":"userCollateralShare","type":"uint256"},{"components":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"internalType":"struct Rebase","name":"totalBorrow","type":"tuple"},{"internalType":"uint256","name":"userBorrowPart","type":"uint256"},{"internalType":"uint256","name":"currentExchangeRate","type":"uint256"},{"internalType":"uint256","name":"spotExchangeRate","type":"uint256"},{"internalType":"uint256","name":"oracleExchangeRate","type":"uint256"},{"internalType":"uint256","name":"totalBorrowCap","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxCollateralShare","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxCollateralAmount","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxAssetShare","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxAssetAmount","type":"uint256"},{"internalType":"enum TokenType","name":"yieldBoxCollateralTokenType","type":"uint8"},{"internalType":"address","name":"yieldBoxCollateralContractAddress","type":"address"},{"internalType":"address","name":"yieldBoxCollateralStrategyAddress","type":"address"},{"internalType":"uint256","name":"yieldBoxCollateralTokenId","type":"uint256"},{"internalType":"enum TokenType","name":"yieldBoxAssetTokenType","type":"uint8"},{"internalType":"address","name":"yieldBoxAssetContractAddress","type":"address"},{"internalType":"address","name":"yieldBoxAssetStrategyAddress","type":"address"},{"internalType":"uint256","name":"yieldBoxAssetTokenId","type":"uint256"}],"internalType":"struct MagnetarV2Storage.MarketInfo","name":"market","type":"tuple"},{"components":[{"internalType":"uint64","name":"debtRate","type":"uint64"},{"internalType":"uint64","name":"lastAccrued","type":"uint64"}],"internalType":"struct IBigBang.AccrueInfo","name":"accrueInfo","type":"tuple"},{"internalType":"uint256","name":"minDebtRate","type":"uint256"},{"internalType":"uint256","name":"maxDebtRate","type":"uint256"},{"internalType":"uint256","name":"debtRateAgainstEthMarket","type":"uint256"},{"internalType":"address","name":"mainBBMarket","type":"address"},{"internalType":"uint256","name":"mainBBDebtRate","type":"uint256"},{"internalType":"uint256","name":"currentDebtRate","type":"uint256"}],"internalType":"struct MagnetarV2Storage.BigBangInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"id","type":"uint16"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bool","name":"allowFailure","type":"bool"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct MagnetarV2Storage.Call[]","name":"calls","type":"tuple[]"}],"name":"burst","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct MagnetarV2Storage.Result[]","name":"returnData","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"market","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"bool","name":"extractFromSender","type":"bool"},{"internalType":"bool","name":"deposit","type":"bool"},{"internalType":"bool","name":"withdraw","type":"bool"},{"internalType":"bytes","name":"withdrawData","type":"bytes"}],"name":"depositAddCollateralAndBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"singularity","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"deposit","type":"bool"},{"internalType":"bool","name":"extractFromSender","type":"bool"}],"name":"depositAndAddAsset","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"market","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"bool","name":"deposit","type":"bool"},{"internalType":"bool","name":"extractFromSender","type":"bool"}],"name":"depositAndRepay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"market","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"bool","name":"deposit","type":"bool"},{"internalType":"bool","name":"withdraw","type":"bool"},{"internalType":"bool","name":"extractFromSender","type":"bool"}],"name":"depositRepayAndRemoveCollateral","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ISingularity","name":"singularity","type":"address"},{"internalType":"uint256","name":"fraction","type":"uint256"}],"name":"getAmountForAssetFraction","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"market","type":"address"},{"internalType":"uint256","name":"borrowPart","type":"uint256"}],"name":"getAmountForBorrowPart","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"market","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBorrowPartForAmount","outputs":[{"internalType":"uint256","name":"part","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMarket","name":"market","type":"address"},{"internalType":"uint256","name":"borrowPart","type":"uint256"},{"internalType":"uint256","name":"liquidationMultiplierPrecision","type":"uint256"},{"internalType":"uint256","name":"exchangeRatePrecision","type":"uint256"}],"name":"getCollateralSharesForBorrowPart","outputs":[{"internalType":"uint256","name":"collateralShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISingularity","name":"singularity","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getFractionForAmount","outputs":[{"internalType":"uint256","name":"fraction","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketModule","outputs":[{"internalType":"contract MagnetarMarketModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISingularity","name":"singularity","type":"address"},{"internalType":"contract IMarket","name":"bingBang","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"bool","name":"deposit","type":"bool"},{"internalType":"bool","name":"extractFromSender","type":"bool"}],"name":"mintAndLend","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISingularity","name":"singularity","type":"address"},{"internalType":"contract IMarket","name":"bingBang","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"removeShare","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"collateralShare","type":"uint256"},{"internalType":"bool","name":"withdraw","type":"bool"},{"internalType":"bytes","name":"withdrawData","type":"bytes"}],"name":"removeAssetAndRepay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"contract ISingularity[]","name":"markets","type":"address[]"}],"name":"singularityMarketInfo","outputs":[{"components":[{"components":[{"internalType":"address","name":"collateral","type":"address"},{"internalType":"uint256","name":"collateralId","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"contract IOracle","name":"oracle","type":"address"},{"internalType":"bytes","name":"oracleData","type":"bytes"},{"internalType":"uint256","name":"totalCollateralShare","type":"uint256"},{"internalType":"uint256","name":"userCollateralShare","type":"uint256"},{"components":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"internalType":"struct Rebase","name":"totalBorrow","type":"tuple"},{"internalType":"uint256","name":"userBorrowPart","type":"uint256"},{"internalType":"uint256","name":"currentExchangeRate","type":"uint256"},{"internalType":"uint256","name":"spotExchangeRate","type":"uint256"},{"internalType":"uint256","name":"oracleExchangeRate","type":"uint256"},{"internalType":"uint256","name":"totalBorrowCap","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxCollateralShare","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxCollateralAmount","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxAssetShare","type":"uint256"},{"internalType":"uint256","name":"totalYieldBoxAssetAmount","type":"uint256"},{"internalType":"enum TokenType","name":"yieldBoxCollateralTokenType","type":"uint8"},{"internalType":"address","name":"yieldBoxCollateralContractAddress","type":"address"},{"internalType":"address","name":"yieldBoxCollateralStrategyAddress","type":"address"},{"internalType":"uint256","name":"yieldBoxCollateralTokenId","type":"uint256"},{"internalType":"enum TokenType","name":"yieldBoxAssetTokenType","type":"uint8"},{"internalType":"address","name":"yieldBoxAssetContractAddress","type":"address"},{"internalType":"address","name":"yieldBoxAssetStrategyAddress","type":"address"},{"internalType":"uint256","name":"yieldBoxAssetTokenId","type":"uint256"}],"internalType":"struct MagnetarV2Storage.MarketInfo","name":"market","type":"tuple"},{"components":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"internalType":"struct Rebase","name":"totalAsset","type":"tuple"},{"internalType":"uint256","name":"userAssetFraction","type":"uint256"},{"components":[{"internalType":"uint64","name":"interestPerSecond","type":"uint64"},{"internalType":"uint64","name":"lastAccrued","type":"uint64"},{"internalType":"uint128","name":"feesEarnedFraction","type":"uint128"}],"internalType":"struct ISingularity.AccrueInfo","name":"accrueInfo","type":"tuple"}],"internalType":"struct MagnetarV2Storage.SingularityInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IYieldBoxBase","name":"yieldBox","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"bytes32","name":"receiver","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"share","type":"uint256"},{"internalType":"bytes","name":"adapterParams","type":"bytes"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"uint256","name":"gas","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080346200014c57601f62004c6038819003918201601f19168301916001600160401b03831184841017620001515780849260409485528339810103126200014c5780516001600160a01b0391828216908183036200014c5760200151928084168094036200014c57620000733362000167565b33906000541603620001085715620000b457620000909062000167565b600280546001600160a01b031916919091179055604051614ab19081620001af8239f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c8063013546e11461015b5780630e8fd73b1461015657806314ecf5a8146101515780632ed48e481461014c578063411628d914610147578063443c73a714610142578063664653ac1461013d5780636dd55c0b14610138578063715018a614610133578063815c12ea1461012e5780638da5cb5b146101295780639cc6ef1414610124578063a306dfd51461011f578063cc5e31631461011a578063cfd8b3d814610115578063dedd6b8014610110578063e4e802e81461010b578063e9212b7214610106578063e985e9c5146101015763f2fde38b0361000e57612a59565b6129fa565b612949565b6126d6565b61257a565b612553565b6124c0565b612409565b61231b565b6122dd565b61224f565b6121f1565b611e31565b611a8e565b611869565b611790565b6114b5565b611314565b611092565b610254565b9181601f84011215610190578235916001600160401b038311610190576020808501948460051b01011161019057565b600080fd5b60005b8381106101a85750506000910152565b8181015183820152602001610198565b906020916101d181518092818552858086019101610195565b601f01601f1916010190565b602080820190808352835180925260409283810182858560051b8401019601946000925b858410610212575050505050505090565b909192939495968580610243600193603f1986820301885286838d51805115158452015191818582015201906101b8565b990194019401929594939190610201565b6020806003193601126101905760049081356001600160401b038111610190576102819036908401610160565b9260009261028e85612cab565b94845b8181106102b7576102b3876102a7883414613b14565b604051918291826101dd565b0390f35b6102c2818387612d22565b606096878201906102d96102d583612d49565b1590565b611042575b6040808401358092019960016102fd6102f687612e2d565b61ffff1690565b0361034257505050816103326103389261032a61031f8961033d9897016130bb565b936080810190612d53565b929091612d49565b9261484a565b612c5e565b610291565b61ffff60028161035188612e2d565b160361037b5750505050816103756103389261032a61031f8961033d9897016130bb565b92614776565b90919295949a935061012c816103908d612e2d565b16036105025750506103ba6103b26103ab60808c018c612d53565b8091612e37565b810190612ede565b916103d46103cf84516001600160a01b031690565b614a1a565b841561047a57866103fe6103f26103f2838961040d96019e016130bb565b6001600160a01b031690565b9301516001600160a01b031690565b91803b15610190579051632479d86360e01b81526001600160a01b039092168783019081529193600092859291839182906020015b03925af19182156104755761033d9261045c575b50612c5e565b8061046961046f926115c0565b806121e6565b38610456565b612be0565b98610490919294506103f2876103f292016130bb565b816104a4878601516001600160a01b031690565b94015190803b15610190579151630c46aac760e31b8152338882019081526001600160a01b039095166020860152604085019190915292600091849182908490829060600103925af19182156104755761033d9261045c5750612c5e565b908161012d8c97936105168b96979e612e2d565b160361058f5750509061055e6001600160a01b03926105646103f26103f261054f6105476103ab60808d018d612d53565b810190613a1b565b99939d9298919a909d16614a1a565b016130bb565b92833b15610190576104428b9160009751998a978896879563695ef6bf60e01b875233908701613abb565b60648161059f8995949699612e2d565b16036106f25750509082918860006105ea6103f26103f28a60809661055e6103cf6105da6105d26103ab8c860186612d53565b8101906139dc565b9e8f01516001600160a01b031690565b92610652895191610604888c01516001600160a01b031690565b968b01519a01518751634d4d7cbd60e11b81529485019283523360208401526001600160a01b0390961660408301526060820199909952608081019490945290968793849291839160a00190565b03925af180156104755761033d9360009081926106ba575b5091518681019283526020830191909152906106949082906040015b03601f1981018352826116b3565b61069c6116d4565b6001815290858201526106af828a613871565b526104568189613871565b610694925061068691506106e390843d86116106eb575b6106db81836116b3565b810190613965565b92509061066a565b503d6106d1565b60c88161070185999495612e2d565b16036107c35750505060806107456103f26103f2896107306107286103ab878c018c612d53565b81019061397b565b9861055e6103cf8b516001600160a01b031690565b90610759888701516001600160a01b031690565b9061076685880151151590565b9387015196015193823b1561019057516374d2492960e11b815233818b019081526001600160a01b03909216602083015292151560408201526060810195909552608085019290925292600091849182908490829060a001610442565b60c9816107d38996949596612e2d565b16036108c8575050829150936108146103f26103f2610868976107ff6103b26103ab6080880188612d53565b9461055e6103cf87516001600160a01b031690565b82610828898401516001600160a01b031690565b92015183516314890dcb60e21b815233818c019081526001600160a01b039094166020850152604084019190915295869283916000918391606090910190565b03925af180156104755761033d9360009081926108a0575b509151868101928352602083019190915290610694908290604001610686565b610694925061068691506108c090843d86116106eb576106db81836116b3565b925090610880565b6066816108d789959699612e2d565b160361093f575050610456929161068661033d9661090a6109026103ab86608061093a980190612d53565b810190613885565b9790969c959195949294519c8d9b632731bbc560e21b908d01526001600160a01b03809116911660248c01613902565b6148eb565b60cb8161094e85999499612e2d565b1603610a3757505061097b6103f26103f2846107ff6109736103ab6080880188612d53565b81019061381a565b818301516001600160a01b03169561099585840151151590565b9201518451630cb0f5b760e31b815233818c019081526001600160a01b039098166020890152921515604088015260608701529094859190829060009082906080015b03925af19283156104755761033d936106869261069492600092610a08575b505187810191825292839160200190565b610a29919250883d8a11610a30575b610a2181836116b3565b810190612c01565b90386109f7565b503d610a17565b60cc81610a4385612e2d565b1603610ac9575050610a686103f26103f2846107ff6109736103ab6080880188612d53565b818301516001600160a01b031695610a8285840151151590565b920151845163cd0211eb60e01b815233818c019081526001600160a01b039098166020890152921515604088015260608701529094859190829060009082906080016109d8565b61012f81610adb859994969795612e2d565b1603610b5857505091610b2a6103f2926103f294610b0a610b026103ab60808b018b612d53565b8101906136d7565b95979699939b929c919a90949e61055e6001600160a01b03809c16614a1a565b96873b15610190576000998f9961044295519d8e9b8c9a8b99630cdc41b960e11b8b52169033908a01613776565b61013081610b6889969599612e2d565b1603610bea57505091816103f295936103f2610b98610b906103ab6080610bb8980186612d53565b81019061342b565b959c969b9397929e919a90949961055e6001600160a01b03809e16614a1a565b96873b15610190578e9b60009a8a9861044296519e8f9c8d9b8c9a635620549760e01b8c521693169033908a016135da565b61013181610bfa86979496612e2d565b1603610c9f575050608094610c3e6103f26103f28a610c29610c216103ab8c8b018b612d53565b81019061313b565b9761055e6103cf8a516001600160a01b031690565b91610c52898601516001600160a01b031690565b918086015194860151978601519060c0610c7160a089015161ffff1690565b970151853b15610190576000978d9361044293519b8c998a988997634663f85d60e11b8952339089016131b9565b61013281610cb1879596949997612e2d565b1603610d2d575050916103f2610cff9284610ce1610cd96103ab60806103f29b990184612d53565b810190613057565b949a939d929598919b909661055e6001600160a01b03809b16614a1a565b95863b1561019057600098610442938f92519c8d9a8b998a986323c8387760e11b8a521694339089016130c5565b909591925060cd81610d3e85612e2d565b1603610ded5750509261093a61045692610686610d70610d686103ab89608061033d9b0190612d53565b810190612fed565b91610d8283516001600160a01b031690565b92610da6610d998c8301516001600160a01b031690565b9683830151920151151590565b91516301bdbad760e71b8c8201526001600160a01b03948516602482015295909316604486015260648501929092529015156084840152600060a4840152829060c4820190565b909460ce82610dfb85612e2d565b1603610e5a5750509061093a61033d94610686610e2d610e256103ab876080610456990190612d53565b810190612f21565b9691949250949951998a9863411628d960e01b908a01526001600160a01b03809116911660248901612fa0565b90945060cf85610e6984612e2d565b1603610ef6575061033d93509061093a610e906103b26103ab856080610456970190612d53565b91610686610ea584516001600160a01b031690565b9180610eba8b8701516001600160a01b031690565b950151905163f4d9375360e01b8b8201526001600160a01b03938416602482015292909416604483015260648201939093529182906084820190565b929360d090610f0483612e2d565b1603610ff3579161093a866106866104569461033d9796610f38610f306103ab60809384810190612d53565b810190612e54565b90610f4a82516001600160a01b031690565b96610f5e868401516001600160a01b031690565b9184840151918401519084015191610f7960a0860151151590565b93610f9460e0610f8c60c0890151151590565b970151151590565b96519a8b9963749095b960e11b908b015260248a019693909260e09693999895929961010089019a6001600160a01b038092168a52166020890152604088015260608701526080860152151560a0850152151560c08401521515910152565b815162461bcd60e51b81526020818901818152601c918101919091527f4d61676e6574617256323a20616374696f6e206e6f742076616c696400000000604082015281906060010390fd5b0390fd5b61107c6110526080850185612d53565b905061107460405161106f816106868a8d83019190602083019252565b612d85565b901515612e01565b6102de565b6001600160a01b0381160361019057565b3461019057604080600319360112610190576004908135916110b383611081565b815163f9557ccb60e01b81526001600160a01b039384169083818481855afa9081156104755760009081926112f4575b50845163020a17bd60e61b81529585878681875afa968715610475576000976112c4575b50855163226f120560e11b81526020919082818881895afa9586156104755787916000976112a3575b50839089519283809263de40657760e01b82525afa90811561047557600091611276575b501693865194638eb22cdd60e01b9687875283878061118b6024358786840160409060009294936060820195825260208201520152565b0381855afa96871561047557600097611253575b5083949596976111d68a519b8c9586948594855284016040906001600160801b036001939594606083019683521660208201520152565b03915afa8015610475576102b39661120292600092611236575b50506001600160801b03809316612c9e565b918261121b57505050905b519081529081906020820190565b9261122b91611230941690612c26565b612c3e565b9061120d565b61124c9250803d10610a3057610a2181836116b3565b38806111f0565b849596975061126e90853d8711610a3057610a2181836116b3565b96959461119f565b6112969150833d851161129c575b61128e81836116b3565b810190612bec565b38611154565b503d611284565b849197506112bd90823d8411610a3057610a2181836116b3565b9690611130565b6112e5919750863d88116112ed575b6112dd81836116b3565b810190612bbc565b509538611107565b503d6112d3565b905061130d9150843d86116112ed576112dd81836116b3565b90386110e3565b34610190576040806003193601126101905760043561133281611081565b815163f9557ccb60e01b8152916001600160a01b039182168184600481845afa928315610475576000948594611490575b50825163de40657760e01b81526020958682600481875afa918215610475576004948891600094611471575b50865163226f120560e11b815295869182905afa801561047557611409968895600092611450575b506113db91926113d36001600160801b03809216602435612c26565b911690612c3e565b855163442c159960e01b81526004810192909252602482015260006044820152948592839182906064820190565b0392165afa918215610475576102b393600093611431575b5050519081529081906020820190565b611448929350803d10610a3057610a2181836116b3565b903880611421565b6113db925061146b90873d8911610a3057610a2181836116b3565b916113b7565b611489919450823d841161129c5761128e81836116b3565b923861138f565b9093506114ab919450823d84116112ed576112dd81836116b3565b9390939238611363565b3461019057604080600319360112610190576001600160a01b03906004356114dc81611081565b81602435916114e9612b8f565b50600482518096819363020a17bd60e61b8352165afa8015610475576102b3936000908192611568575b50835191611520836115d8565b6001600160801b0380809316918285521690816020850152156000146115525750505090519081529081906020820190565b61155f9061123094612c26565b91511690612c3e565b90506115819150833d85116112ed576112dd81836116b3565b9038611513565b359061159382611081565b565b8015150361019057565b359061159382611595565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116115d357604052565b6115aa565b604081019081106001600160401b038211176115d357604052565b61010081019081106001600160401b038211176115d357604052565b606081019081106001600160401b038211176115d357604052565b60a081019081106001600160401b038211176115d357604052565b60e081019081106001600160401b038211176115d357604052565b608081019081106001600160401b038211176115d357604052565b61012081019081106001600160401b038211176115d357604052565b61014081019081106001600160401b038211176115d357604052565b90601f801991011681019081106001600160401b038211176115d357604052565b60405190611593826115d8565b604051906115938261160f565b6040519061016082018281106001600160401b038211176115d357604052565b6040519061034082018281106001600160401b038211176115d357604052565b6001600160401b0381116115d357601f01601f191660200190565b81601f82011215610190578035906117608261172e565b9261176e60405194856116b3565b8284526020838301011161019057816000926020809301838601378301015290565b61010080600319360112610190576004356117aa81611081565b602435916117b783611081565b608435926117c484611595565b60a435916117d183611595565b60c435946117de86611595565b60e435916001600160401b038311610190576100199661093a95611809610686953690600401611749565b9360405198899763411628d960e01b60208a01526001600160a01b0380921660248a015216604488015260443560648801526064356084880152151560a4870152151560c4860152151560e48501526101048401526101248301906101b8565b3461019057608036600319011261019057600480359061188882611081565b611890612b8f565b506040805163020a17bd60e61b8152926001600160a01b039081169082858581855afa948515610475576000908196611a6c575b506118df6118d06116d4565b6001600160801b039092168252565b6118f6602096878301906001600160801b03169052565b835163de40657760e01b81529086828781875afa91821561047557600092611a49575b506119279060243590612c6d565b84516377607a1760e11b8152909287828881885afa91821561047557600092611a2a575b50855163294c4c7960e11b81529388858981895afa9485156104755788958a9261197d92600092611a12575b50612c26565b95875198898092633ba0b9a960e01b82525afa948515610475576119b189966119c5926114099a6000926119f35750612c26565b6119bf606435604435612c26565b90612c3e565b8651638eb22cdd60e01b81529485019283526020830152600060408301529295869384929091839160600190565b611a0b919250893d8b11610a3057610a2181836116b3565b9038611977565b611a0b919250843d8611610a3057610a2181836116b3565b611a42919250883d8a11610a3057610a2181836116b3565b903861194b565b611927919250611a6590883d8a1161129c5761128e81836116b3565b9190611919565b9050611a86919550833d85116112ed576112dd81836116b3565b9490386118c4565b60e036600319011261019057610019600435611aa981611081565b602435611ab581611081565b60443590611ac282611081565b60a43590611acf82611595565b60c43592611adc84611595565b6040519463199194eb60e21b60208701526001600160a01b0392838092166024880152166044860152166064840152606435608484015260843560a4840152151560c4830152151560e482015260e4815261093a8161167b565b90604060031983011261019057600435611b4f81611081565b91602435906001600160401b03821161019057611b6e91600401610160565b9091565b634e487b7160e01b600052602160045260246000fd5b906005821015611b955752565b611b72565b80516001600160a01b031682529060208201516020820152611bcc604083015160408301906001600160a01b03169052565b60608201516060820152611bf0608083015160808301906001600160a01b03169052565b610340611c0c60a08401516103608060a08601528401906101b8565b9260c081015160c084015260e081015160e0840152611c4a6101008083015190850190602090816001600160801b0391828151168552015116910152565b6101208101516101409081850152810151610160908185015281015161018090818501528101516101a090818501528101516101c090818501528101516101e09081850152810151610200908185015281015161022090818501528101516102409081850152810151611cc36102609182860190611b88565b810151611cde61028091828601906001600160a01b03169052565b810151611cf96102a091828601906001600160a01b03169052565b8101516102c09081850152810151611d176102e09182860190611b88565b810151611d3261030091828601906001600160a01b03169052565b81015190611d4e61032092838601906001600160a01b03169052565b015191015290565b602080820190808352835180925260409283810182858560051b8401019601946000925b858410611d8b575050505050505090565b909192939495968580600192603f198582030187528a5190610100611db98351610120808552840190611b9a565b9284810151856001600160401b039182815116828701520151168984015288810151606090818501528101516080908185015281015160a09081850152810151611e1060c091828601906001600160a01b03169052565b8101519060e091828501520151910152990194019401929594939190611d7a565b3461019057611e3f36611b36565b90611e4982612b78565b91604091611e59835194856116b3565b8184526020918285019060051b820191368311610190578390915b8383106121cc5750505050825190611e8b82614681565b93611e94612b8f565b5060005b838110611eac578451806102b38882611d56565b611ec96103f2611ebc8385613871565b516001600160a01b031690565b906001600160a01b03611ede8184168a613e58565b611ee8838a613871565b51528651632c9f039d60e21b81526004939088818681855afa8015610475576000918291612199575b50611f3f90611f30611f216116d4565b6001600160401b039094168452565b6001600160401b031682890152565b86611f4a858c613871565b510152875163f791395d60e01b815286818681855afa9081156104755760009161217c575b5088611f7b858c613871565b510152875163358cd68b60e11b815286818681855afa9081156104755760009161215f575b506060611fad858c613871565b510152875163bde39c5d60e01b815286818681855afa90811561047557600091612142575b506080611fdf858c613871565b510152875163c1ad5c8d60e01b815286818681855afa918215610475578592858c8a9460009361211a575b5060e09161201791613871565b5101528951636c3d8b8f60e01b815292839182905afa908115610475576000916120fd575b508751631848f2bf60e31b8152911685828581845afa918215610475578692612084916000916120e0575b5060a0612074868d613871565b5101906001600160a01b03169052565b875163e6abad4960e01b815293849182905afa8015610475576120be926000916120c3575b5060c06120b6838a613871565b510152612c5e565b611e98565b6120da9150853d8711610a3057610a2181836116b3565b386120a9565b6120f79150843d861161129c5761128e81836116b3565b38612067565b6121149150863d881161129c5761128e81836116b3565b3861203c565b6120179193509161213960e093873d8911610a3057610a2181836116b3565b9391509161200a565b6121599150873d8911610a3057610a2181836116b3565b38611fd2565b6121769150873d8911610a3057610a2181836116b3565b38611fa0565b6121939150873d8911610a3057610a2181836116b3565b38611f6f565b611f3f92506121be91508a3d8c116121c5575b6121b681836116b3565b810190614717565b9091611f11565b503d6121ac565b819083356121d981611081565b8152019101908390611e74565b600091031261019057565b346101905760008060031936011261224c5761220b612b20565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b6101003660031901126101905760043561226881611081565b60243561227481611081565b6044359161228183611081565b60c43561228d81611595565b60e435936001600160401b0393848611610190573660238701121561019057856004013594851161019057366024868801011161019057602461001996019360a435926084359260643592613b60565b346101905760003660031901126101905760206001600160a01b0360005416604051908152f35b61ffff81160361019057565b359061159382612304565b610140806003193601126101905760043561233581611081565b60243561234181611081565b6064359161234e83612304565b60e435916001600160401b03831161019057610019946123ea61237861093a953690600401611749565b6101049283359361238885611081565b61ffff604051998a98632731bbc560e21b60208b01526001600160a01b03988980921660248c01521660448a015260443560648a015216608488015260843560a488015260a43560c488015260c43560e48801528601526101648501906101b8565b916101249116818401523561014483015203601f1981018352826116b3565b346101905760408060031936011261019057806001600160a01b039160043561243181611081565b612439612b8f565b50600482518095819363020a17bd60e61b8352165afa918215610475576102b3926124919160009081926124a0575b50835191612475836115d8565b6001600160801b03809216835216602082015260243590612c6d565b90519081529081906020820190565b90506124b99150833d85116112ed576112dd81836116b3565b9038612468565b60c0366003190112610190576100196004356124db81611081565b602435906124e882611081565b6084356124f481611595565b60a4359161250183611595565b6040519363cc5e316360e01b60208601526001600160a01b03809216602486015216604484015260443560648401526064356084840152151560a4830152151560c482015260c4815261093a816115f3565b346101905760003660031901126101905760206001600160a01b0360025416604051908152f35b60a03660031901126101905761001960043561259581611081565b602435906125a282611081565b6064356125ae81611595565b608435916125bb83611595565b604051936301bdbad760e71b60208601526001600160a01b038092166024860152166044840152604435606484015215156084830152151560a482015260a4815261093a81611645565b602080820190808352835180925260409283810182858560051b8401019601946000925b85841061263a575050505050505090565b909192939495968580600192603f198582030187528a519060c06001600160801b038861266f855160e0808752860190611b9a565b946126968782015188870190602090816001600160801b0391828151168552015116910152565b81810151906060918287015201516001600160401b03808251166080870152878201511660a0860152015116910152990194019401929594939190612629565b34610190576126e436611b36565b90916126ef82612b78565b916040936126ff855194856116b3565b8184526020918285019060051b820191368311610190578390915b83831061292f575050505082519161273183613ccf565b9361273a612b8f565b50612743613cb0565b5060005b84811061275b578651806102b38882612605565b61276b6103f2611ebc8385613871565b9061277f6001600160a01b03831685613e58565b6127898289613871565b5152875163f9557ccb60e01b815260049089818381875afa801561047557600091829161290c575b506127df906127d06127c16116d4565b6001600160801b039094168452565b6001600160801b031682890152565b866127ea848b613871565b51015288516370a0823160e01b81526001600160a01b0386168282019081528790829081906020010381875afa908115610475576000916128ef575b5089612832848b613871565b510152885192838092632c9f039d60e21b825260609586935afa928315610475576128ae93600092839084926128b3575b50906128956128a4926128866128776116e1565b6001600160401b039097168752565b6001600160401b0316858b0152565b6001600160801b0316838c0152565b6120b6838a613871565b612747565b61289594506128a492506128dd9150833d85116128e8575b6128d581836116b3565b810190613d65565b919490919250612863565b503d6128cb565b6129069150873d8911610a3057610a2181836116b3565b38612826565b6127df925061292891508b3d8d116112ed576112dd81836116b3565b90916127b1565b8190833561293c81611081565b815201910190839061271a565b6101003660031901126101905761001960043561296581611081565b6024359061297282611081565b60a43561297e81611595565b60c4359061298b82611595565b60e4359261299884611595565b6040519463749095b960e11b60208701526001600160a01b0380921660248701521660448501526044356064850152606435608485015260843560a4850152151560c4840152151560e483015261010490151581830152815261093a81611697565b3461019057604036600319011261019057600435612a1781611081565b60243590612a2482611081565b6001600160a01b03809116600052600160205260406000209116600052602052602060ff604060002054166040519015158152f35b3461019057602036600319011261019057600435612a7681611081565b612a7e612b20565b6001600160a01b038091168015612acc57600080546001600160a01b03198116831782559092167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b6001600160a01b03600054163303612b3457565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160401b0381116115d35760051b60200190565b60405190612b9c826115d8565b60006020838281520152565b51906001600160801b038216820361019057565b919082604091031261019057612bdd6020612bd684612ba8565b9301612ba8565b90565b6040513d6000823e3d90fd5b908160209103126101905751612bdd81611081565b90816020910312610190575190565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715612c3957565b612c10565b8115612c48570490565b634e487b7160e01b600052601260045260246000fd5b6000198114612c395760010190565b60208101906001600160801b03908183511615600014612c8d5750505090565b612bdd938261155f92511690612c26565b91908201809211612c3957565b90612cb582612b78565b6040612cc3815192836116b3565b8382528193612cd4601f1991612b78565b0191600091825b848110612ce9575050505050565b6020908251612cf7816115d8565b85815282606081830152828601015201612cdb565b634e487b7160e01b600052603260045260246000fd5b9190811015612d445760051b81013590609e1981360301821215610190570190565b612d0c565b35612bdd81611595565b903590601e198136030182121561019057018035906001600160401b0382116101905760200191813603831361019057565b90611593604e60405180947f4d61676e6574617256323a204d697373696e672063616c6c20666f722061637460208301526d0d2dedc40eed2e8d040d2dcc8caf60931b6040830152612de08151809260208686019101610195565b810103602e8101855201836116b3565b906020612bdd9281815201906101b8565b15612e095750565b60405162461bcd60e51b81526020600482015290819061103e9060248301906101b8565b35612bdd81612304565b909291928360041161019057831161019057600401916003190190565b908161010091031261019057612ed660e060405192612e72846115f3565b8035612e7d81611081565b8452612e8b60208201611588565b6020850152604081013560408501526060810135606085015260808101356080850152612eba60a0820161159f565b60a0850152612ecb60c0820161159f565b60c08501520161159f565b60e082015290565b90816060910312610190576040805191612ef78361160f565b8035612f0281611081565b83526020810135612f1281611081565b60208401520135604082015290565b91909161010081840312610190578035612f3a81611081565b926020820135612f4981611081565b926040830135926060810135926080820135612f6481611595565b9260a0830135612f7381611595565b9260c0810135612f8281611595565b9260e08201356001600160401b03811161019057612bdd9201611749565b949290612bdd979694926001600160a01b0380921687521660208601526040850152606084015260006080840152151560a0830152151560c0820152610100908160e082015201906101b8565b908160a0910312610190576080604051916130078361162a565b803561301281611081565b8352602081013561302281611081565b602084015260408101356040840152606081013561303f81611595565b6060840152013561304f81611595565b608082015290565b9060e08282031261019057813561306d81611081565b92602083013592604081013592606082013592608083013561308e81612304565b9260a081013561309d81611081565b9260c08201356001600160401b03811161019057612bdd9201611749565b35612bdd81611081565b939460e09561ffff9294612bdd9998946001600160a01b0380971688526020880152604087015260608601521660808401521660a08201528160c082015201906101b8565b919082604091031261019057604051613122816115d8565b60208082948035845201359161313783611081565b0152565b9061010082820312610190576131b19060c06040519361315a85611645565b803561316581611081565b8552602081013561317581611081565b602086015260408101356040860152606081013560608601526080810135608086015260a08101356131a681612304565b60a08601520161310a565b60c082015290565b929460c09461ffff93999896611593989361010087019b6001600160a01b0380921688521660208701526040860152606085015260808401521660a082015201906001600160a01b036020809280518552015116910152565b91908260e09103126101905760405161322a81611645565b60c0808294803561323a81611595565b84526020810135602085015260408101356040850152606081013561325e81611081565b6060850152608081013561327181611081565b608085015260a081013561328481611595565b60a08501520135910152565b359060ff8216820361019057565b81601f82011215610190578035906132b582612b78565b926040906132c5825195866116b3565b838552602091828601918361016080970286010194818611610190578401925b8584106132f6575050505050505090565b86848303126101905784879161330a6116ee565b6133138761159f565b815261332083880161159f565b8382015261332f868801611588565b86820152606061334081890161159f565b908201526080613351818901611588565b9082015260a0613362818901611588565b9082015260c0808801359082015260e08088013590820152610100613388818901613290565b90820152610120808801359082015261014080880135908201528152019301926132e5565b919060a08382031261019057604051906133c68261162a565b819380356133d381611595565b83526020810135602084015260408101356133ed81611595565b6040840152606081013561340081612304565b60608401526080810135916001600160401b038311610190576080926134269201611749565b910152565b91906101c0838203126101905761344183611588565b9261344e60208201611588565b9261345b60408301612310565b9261346860608401611588565b926134768260808301613212565b926001600160401b0391610160810135838111610190578461349991830161329e565b9361018082013584811161019057816134b39184016133ad565b936101a083013590811161019057612bdd9201611749565b90815180825260208080930193019160005b8281106134eb575050505090565b9091929382610160600192875161350482825115159052565b808401511515828501526040818101516001600160a01b0316908301526060818101511515908301526080818101516001600160a01b03169083015260a0818101516001600160a01b03169083015260c0818101519083015260e080820151908301526101008082015160ff169083015261012081810151908301526101409081015190820152019501939291016134dd565b9060a06080612bdd938051151584526020810151602085015260408101511515604085015261ffff606082015116606085015201519181608082015201906101b8565b969394612bdd98969260c09261367e9761ffff61366f978c60206001600160a01b038097818098168452169101521660408c01521660608a01528151151560808a0152602082015160a08a01526040820151838a01528060608301511660e08a015260808201511661010089015260a0810151151561012089015201516101408701526101c0806101608801528601906134cb565b90848203610180860152613597565b916101a08184039101526101b8565b9190826080910312610190576040516136a581611660565b6060808294803584526020810135602085015260408101356136c681611081565b604085015201359161313783611081565b9061018082820312610190576136ec82611588565b926136f960208401611588565b9261370660408201612310565b926001600160401b0360608301358181116101905782613727918501611749565b93613735836080860161368d565b93610100810135838111610190578461374f9183016133ad565b9361375e81610120840161310a565b9361016083013590811161019057612bdd920161329e565b949160606137b961380c9661ffff6137ed97612bdd9d9b966001600160a01b0396878092168d521660208c01521660408a015261018080848b01528901906101b8565b9380516080890152602081015160a08901528260408201511660c089015201511660e0860152848203610100860152613597565b84516101208401526020909401516001600160a01b0316610140830152565b6101608184039101526134cb565b908160809103126101905760606040519161383483611660565b803561383f81611081565b8352602081013561384f81611081565b6020840152604081013561386281611595565b60408401520135606082015290565b8051821015612d445760209160051b010190565b90916101208284031261019057813561389d81611081565b9260208301356138ac81611081565b9260408101359260608201356138c181612304565b9260808301359260a08101359260c08201359260e08301356001600160401b03811161019057610100916138f6918501611749565b920135612bdd81611081565b9692610120989461ffff9161395997939d9c9b9d9894986001600160a01b03998a8092168c521660208b015260408a0152166060880152608087015260a086015260c08501526101408060e08601528401906101b8565b95166101008201520152565b9190826040910312610190576020825192015190565b908160a0910312610190576080604051916139958361162a565b80356139a081611081565b835260208101356139b081611081565b602084015260408101356139c381611595565b6040840152606081013560608401520135608082015290565b908160a0910312610190576080604051916139f68361162a565b803583526020810135613a0881611081565b602084015260408101356139c381611081565b91909160a081840312610190578035613a3381611081565b926020820135613a4281612304565b9260408301359260608101359260808201356001600160401b03928382116101905701906060828203126101905760405192613a7d8461160f565b8235613a8881611081565b84526020830135613a9881611081565b6020850152604083013590811161019057613ab39201611749565b604082015290565b9390612bdd95916101009461ffff6040956001600160a01b03809516895216602088015284870152606086015260a060808601528082511660a086015260208201511660c0850152015191606060e082015201906101b8565b15613b1b57565b60405162461bcd60e51b815260206004820152601a60248201527f4d61676e6574617256323a2076616c7565206d69736d617463680000000000006044820152606490fd5b96949192613bee98949161093a9794604051996340ae097560e11b60208c01526001600160a01b03928380921660248d01521660448b0152166064890152608488015260a487015260c4860152151560e4850152610100610104850152836101249180838301528061014494858401376000828201850152601f01601f1916810103908101845201826116b3565b50565b613bf961170e565b906000808352806020840152806040840152806060840152806080840152606060a08401528060c08401528060e0840152613c32612b8f565b61010084015280610120840152806101408401528061016084015280610180840152806101a0840152806101c0840152806101e08401528061020084015280610220840152806102408401528061026084015280610280840152806102a0840152806102c0840152806102e084015280610300840152610320830152565b60405190613cbd8261160f565b60006040838281528260208201520152565b90613cd982612b78565b604090613ce8825191826116b3565b8381528093613cf9601f1991612b78565b0191600091825b848110613d0e575050505050565b6020908351613d1c81611660565b613d24613bf1565b8152613d2e612b8f565b8390818301528686830152613d41613cb0565b6060830152828501015201613d00565b51906001600160401b038216820361019057565b9081606091031261019057613d7981613d51565b91612bdd6040612bd660208501613d51565b90929192613d988161172e565b91613da660405193846116b3565b829482845282820111610190576020611593930190610195565b602081830312610190578051906001600160401b03821161019057019080601f83011215610190578151612bdd92602001613d8b565b91908260409103126101905760208251613e0f81611595565b92015190565b9190826080910312610190578151600581101561019057916020810151613e3b81611081565b9160606040830151613e0f81611081565b6005821015611b955752565b613e60613bf1565b50613e69612b8f565b50613e72613bf1565b916001600160a01b03809116604080519163d8dfeb4560e01b835260209360049385818681865afa801561047557613eba91600091614664575b506001600160a01b03168852565b82516338d52e0f60e01b815285818681865afa801561047557613eef91600091614647575b506001600160a01b031688850152565b82516307dc0d1d60e41b808252909686888781875afa97881561047557600098614628575b50613f2e8360809916898b01906001600160a01b03169052565b84516374645ff360e01b80825291906000818981895afa9081156104755760009161460f575b5060a08b0152855163473e3ce760e01b815288818981895afa908115610475576000916145f2575b5060c08b01528551631c9e379b60e01b81526001600160a01b0382168882019081528990829081906020010381895afa908115610475576000916145d5575b5060e08b0152855163020a17bd60e61b81529086828981895afa90811561047557614039928a9260009182916145b2575b5061400b90613ffc6127c16116d4565b6001600160801b031682850152565b6101008d01528751809381926324720b1f60e11b83528b83019190916001600160a01b036020820193169052565b0381885afa90811561047557600091614595575b506101208a01528451633ba0b9a960e01b815287818881885afa90811561047557600091614578575b506101408a0152845182815287818881885afa9081156104755760009161455b575b5085518281526000818981895afa8015610475576140d6928892600092614540575b508987845180968195829463eeb8a8d360e01b84528301612df0565b0392165afa90811561047557600091614511575b506101808a0152845191825286828781875afa918215610475576000926144f2575b5084519081526000818781875afa908115610475578392889261414c926000916144d1575b508751948580948193630d39bbef60e41b83528c8301612df0565b0392165afa908115610475576000916144b4575b5061016088015282516340626d8b60e01b815285818681865afa90811561047557600091614497575b506101a0880152825163226f120560e11b81529480868681865afa95861561047557600096614478575b506060880195865283516377607a1760e11b815281818781875afa938415610475578691600095614457575b508290818b0195865286519283809263de40657760e01b82525afa9182156104755760009261443a575b50501690805183519084828061423163092ada2b60e31b948583528a83019190602083019252565b0381875afa90811561047557614273928692600091829161441b575b506101e08c01526101c08b01528751908251938492839283528983019190602083019252565b0381865afa80156104755760009182916143fc575b50610220890152610200880152518251630cf35bdd60e41b8082528186019283529094918790869081906020010381865afa9586156104755761431888966143309860009081908d839184906143c6575b61430e94955081610280916102a06142fd9594015201906001600160a01b03169052565b6001600160a01b03166102608d0152565b6102408b01613e4c565b51935195869485938493845283019190602083019252565b03915afa90811561047557612bdd92600092839284928592614384575b50506103208601526001600160a01b031661030085015261437a905b6001600160a01b03166102e0850152565b6102c08301613e4c565b614369955061437a94506143b1935080919250903d106143bf575b6143a981836116b3565b810190613e15565b92949193509190829061434d565b503d61439f565b5091505061430e91506142fd6143eb610280948c8d3d106143bf576143a981836116b3565b9296508695509093909250906142d9565b90506144159150843d86116106eb576106db81836116b3565b38614288565b90506144349150833d85116106eb576106db81836116b3565b3861424d565b6144509250803d1061129c5761128e81836116b3565b3880614209565b8391955061447190823d8411610a3057610a2181836116b3565b94906141df565b816144909297503d8811610a3057610a2181836116b3565b94386141b3565b6144ae9150863d8811610a3057610a2181836116b3565b38614189565b6144cb9150863d8811610a3057610a2181836116b3565b38614160565b6144ec913d8091833e6144e481836116b3565b810190613dc0565b38614131565b61450a919250873d891161129c5761128e81836116b3565b903861410c565b6145319150863d8811614539575b61452981836116b3565b810190613df6565b9050386140ea565b503d61451f565b61455491923d8091833e6144e481836116b3565b90386140ba565b6145729150883d8a1161129c5761128e81836116b3565b38614098565b61458f9150883d8a11610a3057610a2181836116b3565b38614076565b6145ac9150883d8a11610a3057610a2181836116b3565b3861404d565b61400b92506145ce91508a3d8c116112ed576112dd81836116b3565b9091613fec565b6145ec9150893d8b11610a3057610a2181836116b3565b38613fbb565b6146099150893d8b11610a3057610a2181836116b3565b38613f7c565b614622913d8091833e6144e481836116b3565b38613f54565b614640919850873d891161129c5761128e81836116b3565b9638613f14565b61465e9150873d891161129c5761128e81836116b3565b38613edf565b61467b9150873d891161129c5761128e81836116b3565b38613eac565b9061468b82612b78565b60409061469a825191826116b3565b83815280936146ab601f1991612b78565b019160005b8381106146bd5750505050565b60209082516146cb816115f3565b6146d3613bf1565b81526146dd612b8f565b8390818301526000858301526000606083015260006080830152600060a0830152600060c0830152600060e08301528286010152016146b0565b919082604091031261019057612bdd602061473184613d51565b9301613d51565b908092918237016000815290565b3d15614771573d906147578261172e565b9161476560405193846116b3565b82523d6000602084013e565b606090565b826004116101905760e0600319838581010301126101905760009283809361480f6001600160a01b036040516147ab81611645565b6004840135906147ba82611081565b81815260248501356147cb81611081565b602082015260448501356040820152606485013560608201526147f060848601613290565b608082015260a485013560a082015260c060c486013591015216614a1a565b61481e60405180948193614738565b03925af19061482b614746565b91159081614841575b5061483c5750565b614968565b90501538614834565b60c092614858818085612e37565b9080959181010312610190576040519360c08501938585106001600160401b038611176115d35761480f6001600160a01b0360009793889794889560405260a0808335936148a585611081565b84845260208101356148b681611081565b6020850152604081013560408501526148d160608201613290565b606085015260808101356080850152013591015216614a1a565b6001600160a01b0360025416801561492357816000929160208493519201905af490614915614746565b911561491d57565b50614968565b60405162461bcd60e51b815260206004820152601c60248201527f4d61676e6574617256323a206d6f64756c65206e6f7420666f756e64000000006044820152606490fd5b60448151106149d557600481015181019060208160248401930312610190576024810151906001600160401b0382116101905701816043820112156101905761103e9181604460246149bd9401519101613d8b565b60405162461bcd60e51b815291829160048301612df0565b60405162461bcd60e51b815260206004820152601a60248201527f4d61676e6574617256323a20526561736f6e20756e6b6e6f776e0000000000006044820152606490fd5b6001600160a01b0333911603614a2c57565b60405162461bcd60e51b815260206004820152602160248201527f4d61676e6574617256323a206f70657261746f72206e6f7420617070726f76656044820152601960fa1b6064820152608490fdfea26469706673582212201b9dd699ad9f6b8cfd79256a23a6fc6db67afce56354eb7fbe38f448c03d4f2264736f6c6343000812003300000000000000000000000040282d3cf4890d9806bc1853e97a59c93d8136530000000000000000000000000880d1ee15cf3d63e729e1cbb87df0e515b1af09

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c8063013546e11461015b5780630e8fd73b1461015657806314ecf5a8146101515780632ed48e481461014c578063411628d914610147578063443c73a714610142578063664653ac1461013d5780636dd55c0b14610138578063715018a614610133578063815c12ea1461012e5780638da5cb5b146101295780639cc6ef1414610124578063a306dfd51461011f578063cc5e31631461011a578063cfd8b3d814610115578063dedd6b8014610110578063e4e802e81461010b578063e9212b7214610106578063e985e9c5146101015763f2fde38b0361000e57612a59565b6129fa565b612949565b6126d6565b61257a565b612553565b6124c0565b612409565b61231b565b6122dd565b61224f565b6121f1565b611e31565b611a8e565b611869565b611790565b6114b5565b611314565b611092565b610254565b9181601f84011215610190578235916001600160401b038311610190576020808501948460051b01011161019057565b600080fd5b60005b8381106101a85750506000910152565b8181015183820152602001610198565b906020916101d181518092818552858086019101610195565b601f01601f1916010190565b602080820190808352835180925260409283810182858560051b8401019601946000925b858410610212575050505050505090565b909192939495968580610243600193603f1986820301885286838d51805115158452015191818582015201906101b8565b990194019401929594939190610201565b6020806003193601126101905760049081356001600160401b038111610190576102819036908401610160565b9260009261028e85612cab565b94845b8181106102b7576102b3876102a7883414613b14565b604051918291826101dd565b0390f35b6102c2818387612d22565b606096878201906102d96102d583612d49565b1590565b611042575b6040808401358092019960016102fd6102f687612e2d565b61ffff1690565b0361034257505050816103326103389261032a61031f8961033d9897016130bb565b936080810190612d53565b929091612d49565b9261484a565b612c5e565b610291565b61ffff60028161035188612e2d565b160361037b5750505050816103756103389261032a61031f8961033d9897016130bb565b92614776565b90919295949a935061012c816103908d612e2d565b16036105025750506103ba6103b26103ab60808c018c612d53565b8091612e37565b810190612ede565b916103d46103cf84516001600160a01b031690565b614a1a565b841561047a57866103fe6103f26103f2838961040d96019e016130bb565b6001600160a01b031690565b9301516001600160a01b031690565b91803b15610190579051632479d86360e01b81526001600160a01b039092168783019081529193600092859291839182906020015b03925af19182156104755761033d9261045c575b50612c5e565b8061046961046f926115c0565b806121e6565b38610456565b612be0565b98610490919294506103f2876103f292016130bb565b816104a4878601516001600160a01b031690565b94015190803b15610190579151630c46aac760e31b8152338882019081526001600160a01b039095166020860152604085019190915292600091849182908490829060600103925af19182156104755761033d9261045c5750612c5e565b908161012d8c97936105168b96979e612e2d565b160361058f5750509061055e6001600160a01b03926105646103f26103f261054f6105476103ab60808d018d612d53565b810190613a1b565b99939d9298919a909d16614a1a565b016130bb565b92833b15610190576104428b9160009751998a978896879563695ef6bf60e01b875233908701613abb565b60648161059f8995949699612e2d565b16036106f25750509082918860006105ea6103f26103f28a60809661055e6103cf6105da6105d26103ab8c860186612d53565b8101906139dc565b9e8f01516001600160a01b031690565b92610652895191610604888c01516001600160a01b031690565b968b01519a01518751634d4d7cbd60e11b81529485019283523360208401526001600160a01b0390961660408301526060820199909952608081019490945290968793849291839160a00190565b03925af180156104755761033d9360009081926106ba575b5091518681019283526020830191909152906106949082906040015b03601f1981018352826116b3565b61069c6116d4565b6001815290858201526106af828a613871565b526104568189613871565b610694925061068691506106e390843d86116106eb575b6106db81836116b3565b810190613965565b92509061066a565b503d6106d1565b60c88161070185999495612e2d565b16036107c35750505060806107456103f26103f2896107306107286103ab878c018c612d53565b81019061397b565b9861055e6103cf8b516001600160a01b031690565b90610759888701516001600160a01b031690565b9061076685880151151590565b9387015196015193823b1561019057516374d2492960e11b815233818b019081526001600160a01b03909216602083015292151560408201526060810195909552608085019290925292600091849182908490829060a001610442565b60c9816107d38996949596612e2d565b16036108c8575050829150936108146103f26103f2610868976107ff6103b26103ab6080880188612d53565b9461055e6103cf87516001600160a01b031690565b82610828898401516001600160a01b031690565b92015183516314890dcb60e21b815233818c019081526001600160a01b039094166020850152604084019190915295869283916000918391606090910190565b03925af180156104755761033d9360009081926108a0575b509151868101928352602083019190915290610694908290604001610686565b610694925061068691506108c090843d86116106eb576106db81836116b3565b925090610880565b6066816108d789959699612e2d565b160361093f575050610456929161068661033d9661090a6109026103ab86608061093a980190612d53565b810190613885565b9790969c959195949294519c8d9b632731bbc560e21b908d01526001600160a01b03809116911660248c01613902565b6148eb565b60cb8161094e85999499612e2d565b1603610a3757505061097b6103f26103f2846107ff6109736103ab6080880188612d53565b81019061381a565b818301516001600160a01b03169561099585840151151590565b9201518451630cb0f5b760e31b815233818c019081526001600160a01b039098166020890152921515604088015260608701529094859190829060009082906080015b03925af19283156104755761033d936106869261069492600092610a08575b505187810191825292839160200190565b610a29919250883d8a11610a30575b610a2181836116b3565b810190612c01565b90386109f7565b503d610a17565b60cc81610a4385612e2d565b1603610ac9575050610a686103f26103f2846107ff6109736103ab6080880188612d53565b818301516001600160a01b031695610a8285840151151590565b920151845163cd0211eb60e01b815233818c019081526001600160a01b039098166020890152921515604088015260608701529094859190829060009082906080016109d8565b61012f81610adb859994969795612e2d565b1603610b5857505091610b2a6103f2926103f294610b0a610b026103ab60808b018b612d53565b8101906136d7565b95979699939b929c919a90949e61055e6001600160a01b03809c16614a1a565b96873b15610190576000998f9961044295519d8e9b8c9a8b99630cdc41b960e11b8b52169033908a01613776565b61013081610b6889969599612e2d565b1603610bea57505091816103f295936103f2610b98610b906103ab6080610bb8980186612d53565b81019061342b565b959c969b9397929e919a90949961055e6001600160a01b03809e16614a1a565b96873b15610190578e9b60009a8a9861044296519e8f9c8d9b8c9a635620549760e01b8c521693169033908a016135da565b61013181610bfa86979496612e2d565b1603610c9f575050608094610c3e6103f26103f28a610c29610c216103ab8c8b018b612d53565b81019061313b565b9761055e6103cf8a516001600160a01b031690565b91610c52898601516001600160a01b031690565b918086015194860151978601519060c0610c7160a089015161ffff1690565b970151853b15610190576000978d9361044293519b8c998a988997634663f85d60e11b8952339089016131b9565b61013281610cb1879596949997612e2d565b1603610d2d575050916103f2610cff9284610ce1610cd96103ab60806103f29b990184612d53565b810190613057565b949a939d929598919b909661055e6001600160a01b03809b16614a1a565b95863b1561019057600098610442938f92519c8d9a8b998a986323c8387760e11b8a521694339089016130c5565b909591925060cd81610d3e85612e2d565b1603610ded5750509261093a61045692610686610d70610d686103ab89608061033d9b0190612d53565b810190612fed565b91610d8283516001600160a01b031690565b92610da6610d998c8301516001600160a01b031690565b9683830151920151151590565b91516301bdbad760e71b8c8201526001600160a01b03948516602482015295909316604486015260648501929092529015156084840152600060a4840152829060c4820190565b909460ce82610dfb85612e2d565b1603610e5a5750509061093a61033d94610686610e2d610e256103ab876080610456990190612d53565b810190612f21565b9691949250949951998a9863411628d960e01b908a01526001600160a01b03809116911660248901612fa0565b90945060cf85610e6984612e2d565b1603610ef6575061033d93509061093a610e906103b26103ab856080610456970190612d53565b91610686610ea584516001600160a01b031690565b9180610eba8b8701516001600160a01b031690565b950151905163f4d9375360e01b8b8201526001600160a01b03938416602482015292909416604483015260648201939093529182906084820190565b929360d090610f0483612e2d565b1603610ff3579161093a866106866104569461033d9796610f38610f306103ab60809384810190612d53565b810190612e54565b90610f4a82516001600160a01b031690565b96610f5e868401516001600160a01b031690565b9184840151918401519084015191610f7960a0860151151590565b93610f9460e0610f8c60c0890151151590565b970151151590565b96519a8b9963749095b960e11b908b015260248a019693909260e09693999895929961010089019a6001600160a01b038092168a52166020890152604088015260608701526080860152151560a0850152151560c08401521515910152565b815162461bcd60e51b81526020818901818152601c918101919091527f4d61676e6574617256323a20616374696f6e206e6f742076616c696400000000604082015281906060010390fd5b0390fd5b61107c6110526080850185612d53565b905061107460405161106f816106868a8d83019190602083019252565b612d85565b901515612e01565b6102de565b6001600160a01b0381160361019057565b3461019057604080600319360112610190576004908135916110b383611081565b815163f9557ccb60e01b81526001600160a01b039384169083818481855afa9081156104755760009081926112f4575b50845163020a17bd60e61b81529585878681875afa968715610475576000976112c4575b50855163226f120560e11b81526020919082818881895afa9586156104755787916000976112a3575b50839089519283809263de40657760e01b82525afa90811561047557600091611276575b501693865194638eb22cdd60e01b9687875283878061118b6024358786840160409060009294936060820195825260208201520152565b0381855afa96871561047557600097611253575b5083949596976111d68a519b8c9586948594855284016040906001600160801b036001939594606083019683521660208201520152565b03915afa8015610475576102b39661120292600092611236575b50506001600160801b03809316612c9e565b918261121b57505050905b519081529081906020820190565b9261122b91611230941690612c26565b612c3e565b9061120d565b61124c9250803d10610a3057610a2181836116b3565b38806111f0565b849596975061126e90853d8711610a3057610a2181836116b3565b96959461119f565b6112969150833d851161129c575b61128e81836116b3565b810190612bec565b38611154565b503d611284565b849197506112bd90823d8411610a3057610a2181836116b3565b9690611130565b6112e5919750863d88116112ed575b6112dd81836116b3565b810190612bbc565b509538611107565b503d6112d3565b905061130d9150843d86116112ed576112dd81836116b3565b90386110e3565b34610190576040806003193601126101905760043561133281611081565b815163f9557ccb60e01b8152916001600160a01b039182168184600481845afa928315610475576000948594611490575b50825163de40657760e01b81526020958682600481875afa918215610475576004948891600094611471575b50865163226f120560e11b815295869182905afa801561047557611409968895600092611450575b506113db91926113d36001600160801b03809216602435612c26565b911690612c3e565b855163442c159960e01b81526004810192909252602482015260006044820152948592839182906064820190565b0392165afa918215610475576102b393600093611431575b5050519081529081906020820190565b611448929350803d10610a3057610a2181836116b3565b903880611421565b6113db925061146b90873d8911610a3057610a2181836116b3565b916113b7565b611489919450823d841161129c5761128e81836116b3565b923861138f565b9093506114ab919450823d84116112ed576112dd81836116b3565b9390939238611363565b3461019057604080600319360112610190576001600160a01b03906004356114dc81611081565b81602435916114e9612b8f565b50600482518096819363020a17bd60e61b8352165afa8015610475576102b3936000908192611568575b50835191611520836115d8565b6001600160801b0380809316918285521690816020850152156000146115525750505090519081529081906020820190565b61155f9061123094612c26565b91511690612c3e565b90506115819150833d85116112ed576112dd81836116b3565b9038611513565b359061159382611081565b565b8015150361019057565b359061159382611595565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116115d357604052565b6115aa565b604081019081106001600160401b038211176115d357604052565b61010081019081106001600160401b038211176115d357604052565b606081019081106001600160401b038211176115d357604052565b60a081019081106001600160401b038211176115d357604052565b60e081019081106001600160401b038211176115d357604052565b608081019081106001600160401b038211176115d357604052565b61012081019081106001600160401b038211176115d357604052565b61014081019081106001600160401b038211176115d357604052565b90601f801991011681019081106001600160401b038211176115d357604052565b60405190611593826115d8565b604051906115938261160f565b6040519061016082018281106001600160401b038211176115d357604052565b6040519061034082018281106001600160401b038211176115d357604052565b6001600160401b0381116115d357601f01601f191660200190565b81601f82011215610190578035906117608261172e565b9261176e60405194856116b3565b8284526020838301011161019057816000926020809301838601378301015290565b61010080600319360112610190576004356117aa81611081565b602435916117b783611081565b608435926117c484611595565b60a435916117d183611595565b60c435946117de86611595565b60e435916001600160401b038311610190576100199661093a95611809610686953690600401611749565b9360405198899763411628d960e01b60208a01526001600160a01b0380921660248a015216604488015260443560648801526064356084880152151560a4870152151560c4860152151560e48501526101048401526101248301906101b8565b3461019057608036600319011261019057600480359061188882611081565b611890612b8f565b506040805163020a17bd60e61b8152926001600160a01b039081169082858581855afa948515610475576000908196611a6c575b506118df6118d06116d4565b6001600160801b039092168252565b6118f6602096878301906001600160801b03169052565b835163de40657760e01b81529086828781875afa91821561047557600092611a49575b506119279060243590612c6d565b84516377607a1760e11b8152909287828881885afa91821561047557600092611a2a575b50855163294c4c7960e11b81529388858981895afa9485156104755788958a9261197d92600092611a12575b50612c26565b95875198898092633ba0b9a960e01b82525afa948515610475576119b189966119c5926114099a6000926119f35750612c26565b6119bf606435604435612c26565b90612c3e565b8651638eb22cdd60e01b81529485019283526020830152600060408301529295869384929091839160600190565b611a0b919250893d8b11610a3057610a2181836116b3565b9038611977565b611a0b919250843d8611610a3057610a2181836116b3565b611a42919250883d8a11610a3057610a2181836116b3565b903861194b565b611927919250611a6590883d8a1161129c5761128e81836116b3565b9190611919565b9050611a86919550833d85116112ed576112dd81836116b3565b9490386118c4565b60e036600319011261019057610019600435611aa981611081565b602435611ab581611081565b60443590611ac282611081565b60a43590611acf82611595565b60c43592611adc84611595565b6040519463199194eb60e21b60208701526001600160a01b0392838092166024880152166044860152166064840152606435608484015260843560a4840152151560c4830152151560e482015260e4815261093a8161167b565b90604060031983011261019057600435611b4f81611081565b91602435906001600160401b03821161019057611b6e91600401610160565b9091565b634e487b7160e01b600052602160045260246000fd5b906005821015611b955752565b611b72565b80516001600160a01b031682529060208201516020820152611bcc604083015160408301906001600160a01b03169052565b60608201516060820152611bf0608083015160808301906001600160a01b03169052565b610340611c0c60a08401516103608060a08601528401906101b8565b9260c081015160c084015260e081015160e0840152611c4a6101008083015190850190602090816001600160801b0391828151168552015116910152565b6101208101516101409081850152810151610160908185015281015161018090818501528101516101a090818501528101516101c090818501528101516101e09081850152810151610200908185015281015161022090818501528101516102409081850152810151611cc36102609182860190611b88565b810151611cde61028091828601906001600160a01b03169052565b810151611cf96102a091828601906001600160a01b03169052565b8101516102c09081850152810151611d176102e09182860190611b88565b810151611d3261030091828601906001600160a01b03169052565b81015190611d4e61032092838601906001600160a01b03169052565b015191015290565b602080820190808352835180925260409283810182858560051b8401019601946000925b858410611d8b575050505050505090565b909192939495968580600192603f198582030187528a5190610100611db98351610120808552840190611b9a565b9284810151856001600160401b039182815116828701520151168984015288810151606090818501528101516080908185015281015160a09081850152810151611e1060c091828601906001600160a01b03169052565b8101519060e091828501520151910152990194019401929594939190611d7a565b3461019057611e3f36611b36565b90611e4982612b78565b91604091611e59835194856116b3565b8184526020918285019060051b820191368311610190578390915b8383106121cc5750505050825190611e8b82614681565b93611e94612b8f565b5060005b838110611eac578451806102b38882611d56565b611ec96103f2611ebc8385613871565b516001600160a01b031690565b906001600160a01b03611ede8184168a613e58565b611ee8838a613871565b51528651632c9f039d60e21b81526004939088818681855afa8015610475576000918291612199575b50611f3f90611f30611f216116d4565b6001600160401b039094168452565b6001600160401b031682890152565b86611f4a858c613871565b510152875163f791395d60e01b815286818681855afa9081156104755760009161217c575b5088611f7b858c613871565b510152875163358cd68b60e11b815286818681855afa9081156104755760009161215f575b506060611fad858c613871565b510152875163bde39c5d60e01b815286818681855afa90811561047557600091612142575b506080611fdf858c613871565b510152875163c1ad5c8d60e01b815286818681855afa918215610475578592858c8a9460009361211a575b5060e09161201791613871565b5101528951636c3d8b8f60e01b815292839182905afa908115610475576000916120fd575b508751631848f2bf60e31b8152911685828581845afa918215610475578692612084916000916120e0575b5060a0612074868d613871565b5101906001600160a01b03169052565b875163e6abad4960e01b815293849182905afa8015610475576120be926000916120c3575b5060c06120b6838a613871565b510152612c5e565b611e98565b6120da9150853d8711610a3057610a2181836116b3565b386120a9565b6120f79150843d861161129c5761128e81836116b3565b38612067565b6121149150863d881161129c5761128e81836116b3565b3861203c565b6120179193509161213960e093873d8911610a3057610a2181836116b3565b9391509161200a565b6121599150873d8911610a3057610a2181836116b3565b38611fd2565b6121769150873d8911610a3057610a2181836116b3565b38611fa0565b6121939150873d8911610a3057610a2181836116b3565b38611f6f565b611f3f92506121be91508a3d8c116121c5575b6121b681836116b3565b810190614717565b9091611f11565b503d6121ac565b819083356121d981611081565b8152019101908390611e74565b600091031261019057565b346101905760008060031936011261224c5761220b612b20565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b6101003660031901126101905760043561226881611081565b60243561227481611081565b6044359161228183611081565b60c43561228d81611595565b60e435936001600160401b0393848611610190573660238701121561019057856004013594851161019057366024868801011161019057602461001996019360a435926084359260643592613b60565b346101905760003660031901126101905760206001600160a01b0360005416604051908152f35b61ffff81160361019057565b359061159382612304565b610140806003193601126101905760043561233581611081565b60243561234181611081565b6064359161234e83612304565b60e435916001600160401b03831161019057610019946123ea61237861093a953690600401611749565b6101049283359361238885611081565b61ffff604051998a98632731bbc560e21b60208b01526001600160a01b03988980921660248c01521660448a015260443560648a015216608488015260843560a488015260a43560c488015260c43560e48801528601526101648501906101b8565b916101249116818401523561014483015203601f1981018352826116b3565b346101905760408060031936011261019057806001600160a01b039160043561243181611081565b612439612b8f565b50600482518095819363020a17bd60e61b8352165afa918215610475576102b3926124919160009081926124a0575b50835191612475836115d8565b6001600160801b03809216835216602082015260243590612c6d565b90519081529081906020820190565b90506124b99150833d85116112ed576112dd81836116b3565b9038612468565b60c0366003190112610190576100196004356124db81611081565b602435906124e882611081565b6084356124f481611595565b60a4359161250183611595565b6040519363cc5e316360e01b60208601526001600160a01b03809216602486015216604484015260443560648401526064356084840152151560a4830152151560c482015260c4815261093a816115f3565b346101905760003660031901126101905760206001600160a01b0360025416604051908152f35b60a03660031901126101905761001960043561259581611081565b602435906125a282611081565b6064356125ae81611595565b608435916125bb83611595565b604051936301bdbad760e71b60208601526001600160a01b038092166024860152166044840152604435606484015215156084830152151560a482015260a4815261093a81611645565b602080820190808352835180925260409283810182858560051b8401019601946000925b85841061263a575050505050505090565b909192939495968580600192603f198582030187528a519060c06001600160801b038861266f855160e0808752860190611b9a565b946126968782015188870190602090816001600160801b0391828151168552015116910152565b81810151906060918287015201516001600160401b03808251166080870152878201511660a0860152015116910152990194019401929594939190612629565b34610190576126e436611b36565b90916126ef82612b78565b916040936126ff855194856116b3565b8184526020918285019060051b820191368311610190578390915b83831061292f575050505082519161273183613ccf565b9361273a612b8f565b50612743613cb0565b5060005b84811061275b578651806102b38882612605565b61276b6103f2611ebc8385613871565b9061277f6001600160a01b03831685613e58565b6127898289613871565b5152875163f9557ccb60e01b815260049089818381875afa801561047557600091829161290c575b506127df906127d06127c16116d4565b6001600160801b039094168452565b6001600160801b031682890152565b866127ea848b613871565b51015288516370a0823160e01b81526001600160a01b0386168282019081528790829081906020010381875afa908115610475576000916128ef575b5089612832848b613871565b510152885192838092632c9f039d60e21b825260609586935afa928315610475576128ae93600092839084926128b3575b50906128956128a4926128866128776116e1565b6001600160401b039097168752565b6001600160401b0316858b0152565b6001600160801b0316838c0152565b6120b6838a613871565b612747565b61289594506128a492506128dd9150833d85116128e8575b6128d581836116b3565b810190613d65565b919490919250612863565b503d6128cb565b6129069150873d8911610a3057610a2181836116b3565b38612826565b6127df925061292891508b3d8d116112ed576112dd81836116b3565b90916127b1565b8190833561293c81611081565b815201910190839061271a565b6101003660031901126101905761001960043561296581611081565b6024359061297282611081565b60a43561297e81611595565b60c4359061298b82611595565b60e4359261299884611595565b6040519463749095b960e11b60208701526001600160a01b0380921660248701521660448501526044356064850152606435608485015260843560a4850152151560c4840152151560e483015261010490151581830152815261093a81611697565b3461019057604036600319011261019057600435612a1781611081565b60243590612a2482611081565b6001600160a01b03809116600052600160205260406000209116600052602052602060ff604060002054166040519015158152f35b3461019057602036600319011261019057600435612a7681611081565b612a7e612b20565b6001600160a01b038091168015612acc57600080546001600160a01b03198116831782559092167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b6001600160a01b03600054163303612b3457565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160401b0381116115d35760051b60200190565b60405190612b9c826115d8565b60006020838281520152565b51906001600160801b038216820361019057565b919082604091031261019057612bdd6020612bd684612ba8565b9301612ba8565b90565b6040513d6000823e3d90fd5b908160209103126101905751612bdd81611081565b90816020910312610190575190565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715612c3957565b612c10565b8115612c48570490565b634e487b7160e01b600052601260045260246000fd5b6000198114612c395760010190565b60208101906001600160801b03908183511615600014612c8d5750505090565b612bdd938261155f92511690612c26565b91908201809211612c3957565b90612cb582612b78565b6040612cc3815192836116b3565b8382528193612cd4601f1991612b78565b0191600091825b848110612ce9575050505050565b6020908251612cf7816115d8565b85815282606081830152828601015201612cdb565b634e487b7160e01b600052603260045260246000fd5b9190811015612d445760051b81013590609e1981360301821215610190570190565b612d0c565b35612bdd81611595565b903590601e198136030182121561019057018035906001600160401b0382116101905760200191813603831361019057565b90611593604e60405180947f4d61676e6574617256323a204d697373696e672063616c6c20666f722061637460208301526d0d2dedc40eed2e8d040d2dcc8caf60931b6040830152612de08151809260208686019101610195565b810103602e8101855201836116b3565b906020612bdd9281815201906101b8565b15612e095750565b60405162461bcd60e51b81526020600482015290819061103e9060248301906101b8565b35612bdd81612304565b909291928360041161019057831161019057600401916003190190565b908161010091031261019057612ed660e060405192612e72846115f3565b8035612e7d81611081565b8452612e8b60208201611588565b6020850152604081013560408501526060810135606085015260808101356080850152612eba60a0820161159f565b60a0850152612ecb60c0820161159f565b60c08501520161159f565b60e082015290565b90816060910312610190576040805191612ef78361160f565b8035612f0281611081565b83526020810135612f1281611081565b60208401520135604082015290565b91909161010081840312610190578035612f3a81611081565b926020820135612f4981611081565b926040830135926060810135926080820135612f6481611595565b9260a0830135612f7381611595565b9260c0810135612f8281611595565b9260e08201356001600160401b03811161019057612bdd9201611749565b949290612bdd979694926001600160a01b0380921687521660208601526040850152606084015260006080840152151560a0830152151560c0820152610100908160e082015201906101b8565b908160a0910312610190576080604051916130078361162a565b803561301281611081565b8352602081013561302281611081565b602084015260408101356040840152606081013561303f81611595565b6060840152013561304f81611595565b608082015290565b9060e08282031261019057813561306d81611081565b92602083013592604081013592606082013592608083013561308e81612304565b9260a081013561309d81611081565b9260c08201356001600160401b03811161019057612bdd9201611749565b35612bdd81611081565b939460e09561ffff9294612bdd9998946001600160a01b0380971688526020880152604087015260608601521660808401521660a08201528160c082015201906101b8565b919082604091031261019057604051613122816115d8565b60208082948035845201359161313783611081565b0152565b9061010082820312610190576131b19060c06040519361315a85611645565b803561316581611081565b8552602081013561317581611081565b602086015260408101356040860152606081013560608601526080810135608086015260a08101356131a681612304565b60a08601520161310a565b60c082015290565b929460c09461ffff93999896611593989361010087019b6001600160a01b0380921688521660208701526040860152606085015260808401521660a082015201906001600160a01b036020809280518552015116910152565b91908260e09103126101905760405161322a81611645565b60c0808294803561323a81611595565b84526020810135602085015260408101356040850152606081013561325e81611081565b6060850152608081013561327181611081565b608085015260a081013561328481611595565b60a08501520135910152565b359060ff8216820361019057565b81601f82011215610190578035906132b582612b78565b926040906132c5825195866116b3565b838552602091828601918361016080970286010194818611610190578401925b8584106132f6575050505050505090565b86848303126101905784879161330a6116ee565b6133138761159f565b815261332083880161159f565b8382015261332f868801611588565b86820152606061334081890161159f565b908201526080613351818901611588565b9082015260a0613362818901611588565b9082015260c0808801359082015260e08088013590820152610100613388818901613290565b90820152610120808801359082015261014080880135908201528152019301926132e5565b919060a08382031261019057604051906133c68261162a565b819380356133d381611595565b83526020810135602084015260408101356133ed81611595565b6040840152606081013561340081612304565b60608401526080810135916001600160401b038311610190576080926134269201611749565b910152565b91906101c0838203126101905761344183611588565b9261344e60208201611588565b9261345b60408301612310565b9261346860608401611588565b926134768260808301613212565b926001600160401b0391610160810135838111610190578461349991830161329e565b9361018082013584811161019057816134b39184016133ad565b936101a083013590811161019057612bdd9201611749565b90815180825260208080930193019160005b8281106134eb575050505090565b9091929382610160600192875161350482825115159052565b808401511515828501526040818101516001600160a01b0316908301526060818101511515908301526080818101516001600160a01b03169083015260a0818101516001600160a01b03169083015260c0818101519083015260e080820151908301526101008082015160ff169083015261012081810151908301526101409081015190820152019501939291016134dd565b9060a06080612bdd938051151584526020810151602085015260408101511515604085015261ffff606082015116606085015201519181608082015201906101b8565b969394612bdd98969260c09261367e9761ffff61366f978c60206001600160a01b038097818098168452169101521660408c01521660608a01528151151560808a0152602082015160a08a01526040820151838a01528060608301511660e08a015260808201511661010089015260a0810151151561012089015201516101408701526101c0806101608801528601906134cb565b90848203610180860152613597565b916101a08184039101526101b8565b9190826080910312610190576040516136a581611660565b6060808294803584526020810135602085015260408101356136c681611081565b604085015201359161313783611081565b9061018082820312610190576136ec82611588565b926136f960208401611588565b9261370660408201612310565b926001600160401b0360608301358181116101905782613727918501611749565b93613735836080860161368d565b93610100810135838111610190578461374f9183016133ad565b9361375e81610120840161310a565b9361016083013590811161019057612bdd920161329e565b949160606137b961380c9661ffff6137ed97612bdd9d9b966001600160a01b0396878092168d521660208c01521660408a015261018080848b01528901906101b8565b9380516080890152602081015160a08901528260408201511660c089015201511660e0860152848203610100860152613597565b84516101208401526020909401516001600160a01b0316610140830152565b6101608184039101526134cb565b908160809103126101905760606040519161383483611660565b803561383f81611081565b8352602081013561384f81611081565b6020840152604081013561386281611595565b60408401520135606082015290565b8051821015612d445760209160051b010190565b90916101208284031261019057813561389d81611081565b9260208301356138ac81611081565b9260408101359260608201356138c181612304565b9260808301359260a08101359260c08201359260e08301356001600160401b03811161019057610100916138f6918501611749565b920135612bdd81611081565b9692610120989461ffff9161395997939d9c9b9d9894986001600160a01b03998a8092168c521660208b015260408a0152166060880152608087015260a086015260c08501526101408060e08601528401906101b8565b95166101008201520152565b9190826040910312610190576020825192015190565b908160a0910312610190576080604051916139958361162a565b80356139a081611081565b835260208101356139b081611081565b602084015260408101356139c381611595565b6040840152606081013560608401520135608082015290565b908160a0910312610190576080604051916139f68361162a565b803583526020810135613a0881611081565b602084015260408101356139c381611081565b91909160a081840312610190578035613a3381611081565b926020820135613a4281612304565b9260408301359260608101359260808201356001600160401b03928382116101905701906060828203126101905760405192613a7d8461160f565b8235613a8881611081565b84526020830135613a9881611081565b6020850152604083013590811161019057613ab39201611749565b604082015290565b9390612bdd95916101009461ffff6040956001600160a01b03809516895216602088015284870152606086015260a060808601528082511660a086015260208201511660c0850152015191606060e082015201906101b8565b15613b1b57565b60405162461bcd60e51b815260206004820152601a60248201527f4d61676e6574617256323a2076616c7565206d69736d617463680000000000006044820152606490fd5b96949192613bee98949161093a9794604051996340ae097560e11b60208c01526001600160a01b03928380921660248d01521660448b0152166064890152608488015260a487015260c4860152151560e4850152610100610104850152836101249180838301528061014494858401376000828201850152601f01601f1916810103908101845201826116b3565b50565b613bf961170e565b906000808352806020840152806040840152806060840152806080840152606060a08401528060c08401528060e0840152613c32612b8f565b61010084015280610120840152806101408401528061016084015280610180840152806101a0840152806101c0840152806101e08401528061020084015280610220840152806102408401528061026084015280610280840152806102a0840152806102c0840152806102e084015280610300840152610320830152565b60405190613cbd8261160f565b60006040838281528260208201520152565b90613cd982612b78565b604090613ce8825191826116b3565b8381528093613cf9601f1991612b78565b0191600091825b848110613d0e575050505050565b6020908351613d1c81611660565b613d24613bf1565b8152613d2e612b8f565b8390818301528686830152613d41613cb0565b6060830152828501015201613d00565b51906001600160401b038216820361019057565b9081606091031261019057613d7981613d51565b91612bdd6040612bd660208501613d51565b90929192613d988161172e565b91613da660405193846116b3565b829482845282820111610190576020611593930190610195565b602081830312610190578051906001600160401b03821161019057019080601f83011215610190578151612bdd92602001613d8b565b91908260409103126101905760208251613e0f81611595565b92015190565b9190826080910312610190578151600581101561019057916020810151613e3b81611081565b9160606040830151613e0f81611081565b6005821015611b955752565b613e60613bf1565b50613e69612b8f565b50613e72613bf1565b916001600160a01b03809116604080519163d8dfeb4560e01b835260209360049385818681865afa801561047557613eba91600091614664575b506001600160a01b03168852565b82516338d52e0f60e01b815285818681865afa801561047557613eef91600091614647575b506001600160a01b031688850152565b82516307dc0d1d60e41b808252909686888781875afa97881561047557600098614628575b50613f2e8360809916898b01906001600160a01b03169052565b84516374645ff360e01b80825291906000818981895afa9081156104755760009161460f575b5060a08b0152855163473e3ce760e01b815288818981895afa908115610475576000916145f2575b5060c08b01528551631c9e379b60e01b81526001600160a01b0382168882019081528990829081906020010381895afa908115610475576000916145d5575b5060e08b0152855163020a17bd60e61b81529086828981895afa90811561047557614039928a9260009182916145b2575b5061400b90613ffc6127c16116d4565b6001600160801b031682850152565b6101008d01528751809381926324720b1f60e11b83528b83019190916001600160a01b036020820193169052565b0381885afa90811561047557600091614595575b506101208a01528451633ba0b9a960e01b815287818881885afa90811561047557600091614578575b506101408a0152845182815287818881885afa9081156104755760009161455b575b5085518281526000818981895afa8015610475576140d6928892600092614540575b508987845180968195829463eeb8a8d360e01b84528301612df0565b0392165afa90811561047557600091614511575b506101808a0152845191825286828781875afa918215610475576000926144f2575b5084519081526000818781875afa908115610475578392889261414c926000916144d1575b508751948580948193630d39bbef60e41b83528c8301612df0565b0392165afa908115610475576000916144b4575b5061016088015282516340626d8b60e01b815285818681865afa90811561047557600091614497575b506101a0880152825163226f120560e11b81529480868681865afa95861561047557600096614478575b506060880195865283516377607a1760e11b815281818781875afa938415610475578691600095614457575b508290818b0195865286519283809263de40657760e01b82525afa9182156104755760009261443a575b50501690805183519084828061423163092ada2b60e31b948583528a83019190602083019252565b0381875afa90811561047557614273928692600091829161441b575b506101e08c01526101c08b01528751908251938492839283528983019190602083019252565b0381865afa80156104755760009182916143fc575b50610220890152610200880152518251630cf35bdd60e41b8082528186019283529094918790869081906020010381865afa9586156104755761431888966143309860009081908d839184906143c6575b61430e94955081610280916102a06142fd9594015201906001600160a01b03169052565b6001600160a01b03166102608d0152565b6102408b01613e4c565b51935195869485938493845283019190602083019252565b03915afa90811561047557612bdd92600092839284928592614384575b50506103208601526001600160a01b031661030085015261437a905b6001600160a01b03166102e0850152565b6102c08301613e4c565b614369955061437a94506143b1935080919250903d106143bf575b6143a981836116b3565b810190613e15565b92949193509190829061434d565b503d61439f565b5091505061430e91506142fd6143eb610280948c8d3d106143bf576143a981836116b3565b9296508695509093909250906142d9565b90506144159150843d86116106eb576106db81836116b3565b38614288565b90506144349150833d85116106eb576106db81836116b3565b3861424d565b6144509250803d1061129c5761128e81836116b3565b3880614209565b8391955061447190823d8411610a3057610a2181836116b3565b94906141df565b816144909297503d8811610a3057610a2181836116b3565b94386141b3565b6144ae9150863d8811610a3057610a2181836116b3565b38614189565b6144cb9150863d8811610a3057610a2181836116b3565b38614160565b6144ec913d8091833e6144e481836116b3565b810190613dc0565b38614131565b61450a919250873d891161129c5761128e81836116b3565b903861410c565b6145319150863d8811614539575b61452981836116b3565b810190613df6565b9050386140ea565b503d61451f565b61455491923d8091833e6144e481836116b3565b90386140ba565b6145729150883d8a1161129c5761128e81836116b3565b38614098565b61458f9150883d8a11610a3057610a2181836116b3565b38614076565b6145ac9150883d8a11610a3057610a2181836116b3565b3861404d565b61400b92506145ce91508a3d8c116112ed576112dd81836116b3565b9091613fec565b6145ec9150893d8b11610a3057610a2181836116b3565b38613fbb565b6146099150893d8b11610a3057610a2181836116b3565b38613f7c565b614622913d8091833e6144e481836116b3565b38613f54565b614640919850873d891161129c5761128e81836116b3565b9638613f14565b61465e9150873d891161129c5761128e81836116b3565b38613edf565b61467b9150873d891161129c5761128e81836116b3565b38613eac565b9061468b82612b78565b60409061469a825191826116b3565b83815280936146ab601f1991612b78565b019160005b8381106146bd5750505050565b60209082516146cb816115f3565b6146d3613bf1565b81526146dd612b8f565b8390818301526000858301526000606083015260006080830152600060a0830152600060c0830152600060e08301528286010152016146b0565b919082604091031261019057612bdd602061473184613d51565b9301613d51565b908092918237016000815290565b3d15614771573d906147578261172e565b9161476560405193846116b3565b82523d6000602084013e565b606090565b826004116101905760e0600319838581010301126101905760009283809361480f6001600160a01b036040516147ab81611645565b6004840135906147ba82611081565b81815260248501356147cb81611081565b602082015260448501356040820152606485013560608201526147f060848601613290565b608082015260a485013560a082015260c060c486013591015216614a1a565b61481e60405180948193614738565b03925af19061482b614746565b91159081614841575b5061483c5750565b614968565b90501538614834565b60c092614858818085612e37565b9080959181010312610190576040519360c08501938585106001600160401b038611176115d35761480f6001600160a01b0360009793889794889560405260a0808335936148a585611081565b84845260208101356148b681611081565b6020850152604081013560408501526148d160608201613290565b606085015260808101356080850152013591015216614a1a565b6001600160a01b0360025416801561492357816000929160208493519201905af490614915614746565b911561491d57565b50614968565b60405162461bcd60e51b815260206004820152601c60248201527f4d61676e6574617256323a206d6f64756c65206e6f7420666f756e64000000006044820152606490fd5b60448151106149d557600481015181019060208160248401930312610190576024810151906001600160401b0382116101905701816043820112156101905761103e9181604460246149bd9401519101613d8b565b60405162461bcd60e51b815291829160048301612df0565b60405162461bcd60e51b815260206004820152601a60248201527f4d61676e6574617256323a20526561736f6e20756e6b6e6f776e0000000000006044820152606490fd5b6001600160a01b0333911603614a2c57565b60405162461bcd60e51b815260206004820152602160248201527f4d61676e6574617256323a206f70657261746f72206e6f7420617070726f76656044820152601960fa1b6064820152608490fdfea26469706673582212201b9dd699ad9f6b8cfd79256a23a6fc6db67afce56354eb7fbe38f448c03d4f2264736f6c63430008120033

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

00000000000000000000000040282d3cf4890d9806bc1853e97a59c93d8136530000000000000000000000000880d1ee15cf3d63e729e1cbb87df0e515b1af09

-----Decoded View---------------
Arg [0] : _owner (address): 0x40282d3Cf4890D9806BC1853e97a59C93D813653
Arg [1] : _marketModule (address): 0x0880d1EE15CF3D63E729e1cBb87Df0e515B1AF09

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000040282d3cf4890d9806bc1853e97a59c93d813653
Arg [1] : 0000000000000000000000000880d1ee15cf3d63e729e1cbb87df0e515b1af09


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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