ETH Price: $2,016.93 (-2.33%)

Contract

0x45e15d1e4F92f28A916F4f2971Ad9adc278e148B
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00
Transaction Hash
Method
Block
From
To
Init192155022024-02-13 0:25:11408 days ago1707783911IN
0x45e15d1e...c278e148B
0 ETH0.0146705440.89396457
Set Fee To192155022024-02-13 0:25:11408 days ago1707783911IN
0x45e15d1e...c278e148B
0 ETH0.0019338340.89396457
Claim191718062024-02-06 21:15:59414 days ago1707254159IN
0x45e15d1e...c278e148B
0 ETH0.0006733231.9657546
Claim190546042024-01-21 10:21:23431 days ago1705832483IN
0x45e15d1e...c278e148B
0 ETH0.0002372511.26350529
Claim189903552024-01-12 10:55:23440 days ago1705056923IN
0x45e15d1e...c278e148B
0 ETH0.0003601517.09796281
Claim189868022024-01-11 22:58:35440 days ago1705013915IN
0x45e15d1e...c278e148B
0 ETH0.0004732822.46886061
Claim189867962024-01-11 22:57:23440 days ago1705013843IN
0x45e15d1e...c278e148B
0 ETH0.0004634122.00021549
Claim189342562024-01-04 13:25:59447 days ago1704374759IN
0x45e15d1e...c278e148B
0 ETH0.0005166324.52698034
Claim189236222024-01-03 1:40:35449 days ago1704246035IN
0x45e15d1e...c278e148B
0 ETH0.0003297615.65516806
Claim189236192024-01-03 1:39:59449 days ago1704245999IN
0x45e15d1e...c278e148B
0 ETH0.0003330115.80958824
Claim189236162024-01-03 1:39:23449 days ago1704245963IN
0x45e15d1e...c278e148B
0 ETH0.0003719517.65826477
Claim189148292024-01-01 20:02:47450 days ago1704139367IN
0x45e15d1e...c278e148B
0 ETH0.0003297815.65649981
Claim188548112023-12-24 9:43:35459 days ago1703411015IN
0x45e15d1e...c278e148B
0 ETH0.000455821.63910946
Claim188087272023-12-17 22:31:11465 days ago1702852271IN
0x45e15d1e...c278e148B
0 ETH0.0007466335.44614737
Claim186896352023-12-01 5:59:47482 days ago1701410387IN
0x45e15d1e...c278e148B
0 ETH0.0006787232.2221107
Claim186748302023-11-29 4:16:47484 days ago1701231407IN
0x45e15d1e...c278e148B
0 ETH0.0006274629.78855054
Claim186501012023-11-25 17:08:35487 days ago1700932115IN
0x45e15d1e...c278e148B
0 ETH0.0006310629.95948939
Claim186500992023-11-25 17:08:11487 days ago1700932091IN
0x45e15d1e...c278e148B
0 ETH0.0006241729.63220091
Claim186339162023-11-23 10:44:47490 days ago1700736287IN
0x45e15d1e...c278e148B
0 ETH0.0005811827.59135468
Claim186339122023-11-23 10:43:59490 days ago1700736239IN
0x45e15d1e...c278e148B
0 ETH0.0005589126.53413484
Claim186075462023-11-19 18:08:35493 days ago1700417315IN
0x45e15d1e...c278e148B
0 ETH0.0005752827.31148308
Claim185784442023-11-15 16:21:35497 days ago1700065295IN
0x45e15d1e...c278e148B
0 ETH0.0009579445.47791647
Claim185594212023-11-13 0:30:59500 days ago1699835459IN
0x45e15d1e...c278e148B
0 ETH0.0005752927.31170829
Claim185575352023-11-12 18:11:35500 days ago1699812695IN
0x45e15d1e...c278e148B
0 ETH0.0007305934.68457479
Claim185538712023-11-12 5:52:35501 days ago1699768355IN
0x45e15d1e...c278e148B
0 ETH0.0004099719.46320893
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Chamber

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 18 : Chamber2.sol
// SPDX-License-Identifier: MIT
// Chamber
pragma solidity >=0.8.0;

import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "../contracts/interfaces/IMasterContract.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../contracts/libraries/BoringRebase.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "../contracts/interfaces/IOracle.sol";
import "../contracts/interfaces/ISwapperV2.sol";
import "../contracts/interfaces/IBentoBoxV1.sol";
import "./Constants.sol";

contract Chamber is Ownable2Step, IMasterContract, Pausable {
    using SafeMath for uint256;
    using SafeMath for uint128;
    using SafeCast for uint256;
    using SafeCast for uint128;
    using RebaseLibrary for Rebase;
    using SafeERC20 for IERC20;

    event PriceUpdateEvent(uint256 rate);
    event AccumulateInterestEvent(uint128 accruedAmount);
    event DepositCollateralEvent(address indexed from, address indexed to, uint256 share);
    event WithdrawCollateralEvent(address indexed from, address indexed to, uint256 share);
    event BorrowEvent(address indexed from, address indexed to, uint256 amount, uint256 part);
    event RepayEvent(address indexed from, address indexed to, uint256 amount, uint256 part);
    event FeeToEvent(address indexed newFeeTo);
    event WithdrawFeesEvent(address indexed feeTo, uint256 feesEarnedFraction);
    event InterestChangeEvent(uint64 oldInterestRate, uint64 newInterestRate);
    event ChangeBlacklistedEvent(address indexed account, bool blacklisted);
    event LogChangeBorrowLimit(uint128 newLimit, uint128 perAddressPart);

    event LogLiquidation(
        address indexed from,
        address indexed user,
        address indexed to,
        uint256 collateralShare,
        uint256 borrowAmount,
        uint256 borrowPart
    );

    // Immutables (for MasterContract and all clones)
    IBentoBoxV1 public immutable bentoBox;
    Chamber public immutable masterContract;
    IERC20 public immutable senUSD;

    // MasterContract variables
    address public feeTo;

    // Per clone variables
    // Clone init settings
    IERC20 public collateral;
    IOracle public oracle;
    bytes public oracleData;

    uint256 public COLLATERIZATION_RATE;
    uint256 public LIQUIDATION_MULTIPLIER; 
    uint256 public BORROW_OPENING_FEE;

    struct BorrowCap {
        uint128 total;
        uint128 borrowPartPerAddress;
    }

    BorrowCap public borrowLimit;

    // Total amounts
    uint256 public totalCollateralShare; // Total collateral supplied
    Rebase public totalBorrow; // elastic = Total token amount to be repayed by borrowers, base = Total parts of the debt held by borrowers

    // User balances
    mapping(address => uint256) public userCollateralShare;
    mapping(address => uint256) public userBorrowPart;

    // Caller restrictions
    mapping(address => bool) public blacklisted;
    
    /// @notice Exchange and interest rate tracking.
    /// This is 'cached' here because calls to Oracles can be very expensive.
    uint256 public exchangeRate;

    struct AccruedInfo {
        uint64 lastAccrued;
        uint128 feesEarned;
        uint64 INTEREST_PER_SECOND;
    }

    AccruedInfo public accruedInterest;

    /// @notice tracks last interest rate
    uint256 internal lastInterestUpdate;

    modifier onlyMasterContractOwner() {
        require(msg.sender == masterContract.owner(), "Caller is not the owner");
        _;
    }

    /// @notice The constructor is only used for the initial master contract. Subsequent clones are initialised via `init`.
    constructor(IBentoBoxV1 bentoBox_, IERC20 senUSD_) {
        bentoBox = bentoBox_;
        senUSD = senUSD_;
        masterContract = this;
        
        blacklisted[address(bentoBox)] = true;
        blacklisted[address(this)] = true;
        blacklisted[Ownable(address(bentoBox)).owner()] = true;
    }

    /// @notice Serves as the constructor for clones, as clones can't have a regular constructor
    /// @dev `data` is abi encoded in the format: (IERC20 collateral, IERC20 asset, IOracle oracle, bytes oracleData)
    function init(bytes calldata data) public virtual payable override {
        require(address(collateral) == address(0), "Chamber: already initialized");
        (collateral, oracle, oracleData, accruedInterest.INTEREST_PER_SECOND, LIQUIDATION_MULTIPLIER, COLLATERIZATION_RATE, BORROW_OPENING_FEE) = abi.decode(data, (IERC20, IOracle, bytes, uint64, uint256, uint256, uint256));
        borrowLimit = BorrowCap(type(uint128).max, type(uint128).max);
        require(address(collateral) != address(0), "Chamber: bad pair");

        blacklisted[address(bentoBox)] = true;
        blacklisted[address(this)] = true;
        blacklisted[Ownable(address(bentoBox)).owner()] = true;

        (, exchangeRate) = oracle.get(oracleData);

        accumulate();
    }

    /// @notice Accrues the interest on the borrowed tokens and handles the accumulation of fees.
    function accumulate() whenNotPaused public {
        AccruedInfo memory _accruedInterest = accruedInterest;
        // Number of seconds since accrue was called
        uint256 elapsedTime = block.timestamp - _accruedInterest.lastAccrued;
        if (elapsedTime == 0) {
            return;
        }
        _accruedInterest.lastAccrued = uint64(block.timestamp);

        Rebase memory _totalBorrow = totalBorrow;
        if (_totalBorrow.base == 0) {
            accruedInterest = _accruedInterest;
            return;
        }


        uint128 extraAmount = uint128(uint256(_totalBorrow.elastic).mul(_accruedInterest.INTEREST_PER_SECOND).mul(elapsedTime) / 1e18);
        _totalBorrow.elastic = uint128(_totalBorrow.elastic.add(extraAmount));

        _accruedInterest.feesEarned = uint128(_accruedInterest.feesEarned.add(extraAmount));
        totalBorrow = _totalBorrow;
        accruedInterest = _accruedInterest;

        emit AccumulateInterestEvent(extraAmount);
    }

    /// @notice Concrete implementation of `isSolvent`. Includes a third parameter to allow caching `exchangeRate`.
    /// @param _exchangeRate The exchange rate. Used to cache the `exchangeRate` between calls.
    function _isSolvent(address user, uint256 _exchangeRate) virtual internal view returns (bool) {
        // accrue must have already been called!
        uint256 borrowPart = userBorrowPart[user];
        if (borrowPart == 0) return true;
        uint256 collateralShare = userCollateralShare[user];
        if (collateralShare == 0) return false;

        Rebase memory _totalBorrow = totalBorrow;

        return
            bentoBox.toAmount(
                collateral,
                collateralShare.mul(Constants.EXCHANGE_RATE_PRECISION / Constants.COLLATERIZATION_RATE_PRECISION).mul(COLLATERIZATION_RATE),
                false
            ) >=
            // Moved exchangeRate here instead of dividing the other side to preserve more precision
            borrowPart.mul(_totalBorrow.elastic).mul(_exchangeRate) / _totalBorrow.base;
    }

    function isSolvent(address user) public view returns (bool) {
        return _isSolvent(user, exchangeRate);
    }
    
    /// @dev Checks if the user is solvent in the closed liquidation case at the end of the function body.
    modifier solvent() {
        _;
        (, uint256 _exchangeRate) = updatePrice();
        require(_isSolvent(msg.sender, _exchangeRate), "Chamber: user insolvent");
    }

    /// @notice Gets the exchange rate. I.e how much collateral to buy 1e18 asset.
    /// This function is supposed to be invoked if needed because Oracle queries can be expensive.
    /// @return updated True if `exchangeRate` was updated.
    /// @return rate The new exchange rate.
    function updatePrice() public returns (bool updated, uint256 rate) {
        (updated, rate) = oracle.get(oracleData);

        if (updated) {
            exchangeRate = rate;
            emit PriceUpdateEvent(rate);
        } else {
            // Return the old rate if fetching wasn't successful
            rate = exchangeRate;
        }
    }

    /// @dev Helper function to move tokens.
    /// @param token The ERC-20 token.
    /// @param share The amount in shares to add.
    /// @param total Grand total amount to deduct from this contract's balance. Only applicable if `skim` is True.
    /// Only used for accounting checks.
    /// @param skim If True, only does a balance check on this contract.
    /// False if tokens from msg.sender in `bentoBox` should be transferred.
    function _addTokens(
        IERC20 token,
        uint256 share,
        uint256 total,
        bool skim
    ) internal {
        if (skim) {
            require(share <= bentoBox.balanceOf(token, address(this)).sub(total), "Chamber: Skim too much");
        } else {
            bentoBox.transfer(token, msg.sender, address(this), share);
        }
    }

    function _afterAddCollateral(address user, uint256 collateralShare) internal virtual {}

    /// @notice Adds `collateral` from msg.sender to the account `to`.
    /// @param to The receiver of the tokens.
    /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.x
    /// False if tokens from msg.sender in `bentoBox` should be transferred.
    /// @param share The amount of shares to add for `to`.
    function depositCollateral(
        address to,
        bool skim,
        uint256 share
    ) whenNotPaused public virtual {
        userCollateralShare[to] = userCollateralShare[to].add(share);
        uint256 oldTotalCollateralShare = totalCollateralShare;
        totalCollateralShare = oldTotalCollateralShare.add(share);
        _addTokens(collateral, share, oldTotalCollateralShare, skim);
        _afterAddCollateral(to, share);
        emit DepositCollateralEvent(skim ? address(bentoBox) : msg.sender, to, share);
    }

    function _afterWithdrawnCollateral(address from, address to, uint256 collateralShare) internal virtual {}

    /// @dev Concrete implementation of `withdrawCollateral`.
    function _withdrawCollateral(address to, uint256 share) whenNotPaused internal virtual {
        userCollateralShare[msg.sender] = userCollateralShare[msg.sender].sub(share);
        totalCollateralShare = totalCollateralShare.sub(share);
        _afterWithdrawnCollateral(msg.sender, to, share);
        emit WithdrawCollateralEvent(msg.sender, to, share);
        bentoBox.transfer(collateral, address(this), to, share);
    }

    /// @notice Removes `share` amount of collateral and transfers it to `to`.
    /// @param to The receiver of the shares.
    /// @param share Amount of shares to remove.
    function removeCollateral(address to, uint256 share) whenNotPaused public solvent {
        // accrue must be called because we check solvency
        accumulate();
        _withdrawCollateral(to, share);
    }

    function _preBorrowAction(address to, uint256 amount, uint256 newBorrowPart, uint256 part) internal virtual {

    }

    /// @dev Concrete implementation of `borrow`.
    function _borrow(address to, uint256 amount) whenNotPaused internal returns (uint256 part, uint256 share) {
        uint256 feeAmount = amount.mul(BORROW_OPENING_FEE) / Constants.BORROW_OPENING_FEE_PRECISION; // A flat % fee is charged for any borrow
        (totalBorrow, part) = totalBorrow.add(amount.add(feeAmount), true);
        senUSD.safeApprove(address(bentoBox), amount);
        BorrowCap memory cap =  borrowLimit;

        require(totalBorrow.elastic <= cap.total, "Borrow Limit reached");

        accruedInterest.feesEarned = uint128(accruedInterest.feesEarned.add(uint128(feeAmount)));
        
        uint256 newBorrowPart = userBorrowPart[msg.sender].add(part);
        require(newBorrowPart <= cap.borrowPartPerAddress, "Borrow Limit reached");
        _preBorrowAction(to, amount, newBorrowPart, part);

        userBorrowPart[msg.sender] = newBorrowPart;

        // As long as there are tokens on this contract you can 'mint'... this enables limiting borrows
        share = bentoBox.toShare(senUSD, amount, false);
        bentoBox.transfer(senUSD, address(this), to, share);
        senUSD.approve(address(bentoBox), 0);
        emit BorrowEvent(msg.sender, to, amount.add(feeAmount), part);
    }

    /// @notice Sender borrows `amount` and transfers it to `to`.
    /// @return part Total part of the debt held by borrowers.
    /// @return share Total amount in shares borrowed.
    function borrow(address to, uint256 amount) whenNotPaused public solvent returns (uint256 part, uint256 share) {
        accumulate();
        (part, share) = _borrow(to, amount);
    }

    /// @dev Concrete implementation of `repay`.
    function _repay(
        address to,
        bool skim,
        uint256 part
    ) whenNotPaused internal returns (uint256 amount) {
        (totalBorrow, amount) = totalBorrow.sub(part, true);
        userBorrowPart[to] = userBorrowPart[to].sub(part);

        uint256 share = bentoBox.toShare(senUSD, amount, true);
        senUSD.safeApprove(address(bentoBox), amount);

        bentoBox.transfer(senUSD, skim ? address(bentoBox) : msg.sender, address(this), share);
        senUSD.approve(address(bentoBox), 0);
        emit RepayEvent(skim ? address(bentoBox) : msg.sender, to, amount, part);
    }

    /// @notice Repays a loan.
    /// @param to Address of the user this payment should go.
    /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
    /// False if tokens from msg.sender in `bentoBox` should be transferred.
    /// @param part The amount to repay. See `userBorrowPart`.
    /// @return amount The total amount repayed.
    function repay(
        address to,
        bool skim,
        uint256 part
    ) whenNotPaused public returns (uint256 amount) {
        accumulate();
        amount = _repay(to, skim, part);
    }

    /// @dev Helper function for choosing the correct value (`value1` or `value2`) depending on `inNum`.
    function _num(
        int256 inNum,
        uint256 value1,
        uint256 value2
    ) internal pure returns (uint256 outNum) {
        outNum = inNum >= 0 ? uint256(inNum) : (inNum == Constants.USE_PARAM1 ? value1 : value2);
    }

    /// @dev Helper function for depositing into `bentoBox`.
    function _bentoDeposit(
        bytes memory data,
        uint256 value,
        uint256 value1,
        uint256 value2
    ) whenNotPaused internal returns (uint256, uint256) {
        (IERC20 token, address to, int256 amount, int256 share) = abi.decode(data, (IERC20, address, int256, int256));
        amount = int256(_num(amount, value1, value2)); // Done this way to avoid stack too deep errors
        share = int256(_num(share, value1, value2));

        return bentoBox.deposit{value: value}(token, msg.sender, to, uint256(amount), uint256(share));
    }

    /// @dev Helper function to withdraw from the `bentoBox`.
    function _bentoWithdraw(
        bytes memory data,
        uint256 value1,
        uint256 value2
    ) whenNotPaused internal returns (uint256, uint256) {
        (IERC20 token, address to, int256 amount, int256 share) = abi.decode(data, (IERC20, address, int256, int256));

        return bentoBox.withdraw(token, msg.sender, to, _num(amount, value1, value2), _num(share, value1, value2));
    }

    /// @dev Helper function to perform a contract call and eventually extracting revert messages on failure.
    /// Calls to `bentoBox` are not allowed for obvious security reasons.
    /// This also means that calls made from this contract shall *not* be trusted.
    function _call(
        uint256 value,
        bytes memory data,
        uint256 value1,
        uint256 value2
    ) whenNotPaused internal returns (bytes memory, uint8) {
        (address callee, bytes memory callData, bool useValue1, bool useValue2, uint8 returnValues) =
            abi.decode(data, (address, bytes, bool, bool, uint8));

        if (useValue1 && !useValue2) {
            callData = abi.encodePacked(callData, value1);
        } else if (!useValue1 && useValue2) {
            callData = abi.encodePacked(callData, value2);
        } else if (useValue1 && useValue2) {
            callData = abi.encodePacked(callData, value1, value2);
        }

        require(!blacklisted[callee], "Chamber: can't call");

        (bool success, bytes memory returnData) = callee.call{value: value}(callData);
        require(success, "Chamber: call failed");
        return (returnData, returnValues);
    }

    struct OperationStatus {
        bool needsSolvencyCheck;
        bool hasAccrued;
    }

    function _extraOperation(uint8 action, OperationStatus memory, uint256 value, bytes memory data, uint256 value1, uint256 value2) internal virtual returns (bytes memory, uint8, OperationStatus memory) {}

    /// @notice Executes a set of actions and allows composability (contract calls) to other contracts.
    /// @param actions An array with a sequence of actions to execute (see OPERATION_ declarations).
    /// @param values A one-to-one mapped array to `actions`. ETH amounts to send along with the actions.
    /// Only applicable to `OPERATION`, `OPERATION_BENTO_DEPOSIT`.
    /// @param datas A one-to-one mapped array to `operations`. Contains abi encoded data of function arguments.
    /// @return value1 May contain the first positioned return value of the last executed action (if applicable).
    /// @return value2 May contain the second positioned return value of the last executed action which returns 2 values (if applicable).
    function performOperations(
        uint8[] calldata actions,
        uint256[] calldata values,
        bytes[] calldata datas
    ) whenNotPaused external payable returns (uint256 value1, uint256 value2) {
        OperationStatus memory status;
        uint256 actionsLength = actions.length;
        for (uint256 i = 0; i < actionsLength; i++) {
            uint8 action = actions[i];
            if (!status.hasAccrued && action < 10) {
                accumulate();
                status.hasAccrued = true;
            }
            if (action == Constants.OPERATION_ADD_COLLATERAL) {
                (int256 share, address to, bool skim) = abi.decode(datas[i], (int256, address, bool));
                depositCollateral(to, skim, _num(share, value1, value2));
            } else if (action == Constants.OPERATION_REPAY) {
                (int256 part, address to, bool skim) = abi.decode(datas[i], (int256, address, bool));
                _repay(to, skim, _num(part, value1, value2));
            } else if (action == Constants.OPERATION_REMOVE_COLLATERAL) {
                (int256 share, address to) = abi.decode(datas[i], (int256, address));
                _withdrawCollateral(to, _num(share, value1, value2));
                status.needsSolvencyCheck = true;
            } else if (action == Constants.OPERATION_BORROW) {
                (int256 amount, address to) = abi.decode(datas[i], (int256, address));
                (value1, value2) = _borrow(to, _num(amount, value1, value2));
                status.needsSolvencyCheck = true;
            } else if (action == Constants.OPERATION_UPDATE_PRICE) {
                (bool must_update, uint256 minRate, uint256 maxRate) = abi.decode(datas[i], (bool, uint256, uint256));
                (bool updated, uint256 rate) = updatePrice();
                require((!must_update || updated) && rate > minRate && (maxRate == 0 || rate < maxRate), "Chamber: rate not ok");
            } else if (action == Constants.OPERATION_BENTO_SETAPPROVAL) {
                (address user, address _masterContract, bool approved, uint8 v, bytes32 r, bytes32 s) =
                    abi.decode(datas[i], (address, address, bool, uint8, bytes32, bytes32));
                bentoBox.setMasterContractApproval(user, _masterContract, approved, v, r, s);
            } else if (action == Constants.OPERATION_BENTO_DEPOSIT) {
                (value1, value2) = _bentoDeposit(datas[i], values[i], value1, value2);
            } else if (action == Constants.OPERATION_BENTO_WITHDRAW) {
                (value1, value2) = _bentoWithdraw(datas[i], value1, value2);
            } else if (action == Constants.OPERATION_BENTO_TRANSFER) {
                (IERC20 token, address to, int256 share) = abi.decode(datas[i], (IERC20, address, int256));
                bentoBox.transfer(token, msg.sender, to, _num(share, value1, value2));
            } else if (action == Constants.OPERATION_BENTO_TRANSFER_MULTIPLE) {
                (IERC20 token, address[] memory tos, uint256[] memory shares) = abi.decode(datas[i], (IERC20, address[], uint256[]));
                bentoBox.transferMultiple(token, msg.sender, tos, shares);
            } else if (action == Constants.OPERATION_CALL) {
                (bytes memory returnData, uint8 returnValues) = _call(values[i], datas[i], value1, value2);

                if (returnValues == 1) {
                    (value1) = abi.decode(returnData, (uint256));
                } else if (returnValues == 2) {
                    (value1, value2) = abi.decode(returnData, (uint256, uint256));
                }
            } else if (action == Constants.OPERATION_GET_REPAY_SHARE) {
                int256 part = abi.decode(datas[i], (int256));
                value1 = bentoBox.toShare(senUSD, totalBorrow.toElastic(_num(part, value1, value2), true), true);
            } else if (action == Constants.OPERATION_GET_REPAY_PART) {
                int256 amount = abi.decode(datas[i], (int256));
                value1 = totalBorrow.toBase(_num(amount, value1, value2), false);
            } else if (action == Constants.OPERATION_LIQUIDATE) {
                _operationLiquidate(datas[i]);
            } else {
                (bytes memory returnData, uint8 returnValues, OperationStatus memory returnStatus) = _extraOperation(action, status, values[i], datas[i], value1, value2);
                status = returnStatus;
                
                if (returnValues == 1) {
                    (value1) = abi.decode(returnData, (uint256));
                } else if (returnValues == 2) {
                    (value1, value2) = abi.decode(returnData, (uint256, uint256));
                }
            }
        }

        if (status.needsSolvencyCheck) {
            (, uint256 _exchangeRate) = updatePrice();
            require(_isSolvent(msg.sender, _exchangeRate), "Chamber: user insolvent");
        }
    }

    function _operationLiquidate(bytes calldata data) internal {
        (address[] memory users, uint256[] memory maxBorrowParts, address to, ISwapperV2 swapper, bytes memory swapperData) = abi.decode(data, (address[], uint256[], address, ISwapperV2, bytes));
        liquidate(users, maxBorrowParts, to, swapper, swapperData);
    }

    function _beforeUsersLiquidated(address[] memory users, uint256[] memory maxBorrowPart) internal virtual {}

    function _beforeUserLiquidated(address user, uint256 borrowPart, uint256 borrowAmount, uint256 collateralShare) internal virtual {}

    function _afterUserLiquidated(address user, uint256 collateralShare) internal virtual {}

    /// @notice Handles the liquidation of users' balances, once the users' amount of collateral is too low.
    /// @param users An array of user addresses.
    /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
    /// @param to Address of the receiver in open liquidations if `swapper` is zero.
    function liquidate(
        address[] memory users,
        uint256[] memory maxBorrowParts,
        address to,
        ISwapperV2 swapper,
        bytes memory swapperData
    ) whenNotPaused public virtual {
        // Oracle can fail but we still need to allow liquidations
        (, uint256 _exchangeRate) = updatePrice();
        accumulate();

        uint256 allCollateralShare;
        uint256 allBorrowAmount;
        uint256 allBorrowPart;
        Rebase memory bentoBoxTotals = bentoBox.totals(collateral);
        _beforeUsersLiquidated(users, maxBorrowParts);
        uint256 usersLength = users.length;
        for (uint256 i = 0; i < usersLength; i++) {
            address user = users[i];
            if (!_isSolvent(user, _exchangeRate)) {
                uint256 borrowPart;
                uint256 availableBorrowPart = userBorrowPart[user];
                borrowPart = maxBorrowParts[i] > availableBorrowPart ? availableBorrowPart : maxBorrowParts[i];

                uint256 borrowAmount = totalBorrow.toElastic(borrowPart, false);
                uint256 collateralShare =
                    bentoBoxTotals.toBase(
                        borrowAmount.mul(LIQUIDATION_MULTIPLIER).mul(_exchangeRate) /
                            (Constants.LIQUIDATION_MULTIPLIER_PRECISION * Constants.EXCHANGE_RATE_PRECISION),
                        false
                    );

                _beforeUserLiquidated(user, borrowPart, borrowAmount, collateralShare);
                userBorrowPart[user] = availableBorrowPart.sub(borrowPart);
                userCollateralShare[user] = userCollateralShare[user].sub(collateralShare);
                _afterUserLiquidated(user, collateralShare);

                emit WithdrawCollateralEvent(user, to, collateralShare);
                emit RepayEvent(msg.sender, user, borrowAmount, borrowPart);
                emit LogLiquidation(msg.sender, user, to, collateralShare, borrowAmount, borrowPart);

                // Keep totals
                allCollateralShare = allCollateralShare.add(collateralShare);
                allBorrowAmount = allBorrowAmount.add(borrowAmount);
                allBorrowPart = allBorrowPart.add(borrowPart);
            }
        }
        require(allBorrowAmount != 0, "Chamber: all are solvent");
        totalBorrow.elastic = uint128(totalBorrow.elastic.sub(allBorrowAmount));
        totalBorrow.base = uint128(totalBorrow.base.sub(allBorrowPart));
        totalCollateralShare = totalCollateralShare.sub(allCollateralShare);

        {
            uint256 distributionAmount = (allBorrowAmount.mul(LIQUIDATION_MULTIPLIER) / Constants.LIQUIDATION_MULTIPLIER_PRECISION).sub(allBorrowAmount).mul(Constants.DISTRIBUTION_PART) / Constants.DISTRIBUTION_PRECISION; // Distribution Amount
            allBorrowAmount = allBorrowAmount.add(distributionAmount);
            accruedInterest.feesEarned = uint128(accruedInterest.feesEarned.add(distributionAmount));
        }

        uint256 allBorrowShare = bentoBox.toShare(senUSD, allBorrowAmount, true);

        // Swap using a swapper freely chosen by the caller
        // Open (flash) liquidation: get proceeds first and provide the borrow after
        bentoBox.transfer(collateral, address(this), to, allCollateralShare);
        if (swapper != ISwapperV2(address(0))) {
            swapper.swap(address(collateral), address(senUSD), msg.sender, allBorrowShare, allCollateralShare, swapperData);
        }

        allBorrowShare = bentoBox.toShare(senUSD, allBorrowAmount, true);
        bentoBox.transfer(senUSD, msg.sender, address(this), allBorrowShare);
    }

    /// @notice Withdraws the fees accumulated.
    function withdrawFees() public {
        accumulate();
        address _feeTo = masterContract.feeTo();
        uint256 _feesEarned = accruedInterest.feesEarned;
        uint256 share = bentoBox.toShare(senUSD, _feesEarned, false);
        bentoBox.transfer(senUSD, address(this), _feeTo, share);
        accruedInterest.feesEarned = 0;

        emit WithdrawFeesEvent(_feeTo, _feesEarned);
    }

    /// @notice Sets the beneficiary of interest accrued.
    /// MasterContract Only Admin function.
    /// @param newFeeTo The address of the receiver.
    function setFeeTo(address newFeeTo) public onlyOwner {
        require(newFeeTo != address(0), 'cannot be 0 address');
        feeTo = newFeeTo;
        emit FeeToEvent(newFeeTo);
    }

    /// @notice reduces the supply of SENUSD
    /// @param amount amount to reduce supply by
    function reduceSupply(uint256 amount) public onlyMasterContractOwner {
        uint256 maxAmount = bentoBox.toAmount(senUSD, bentoBox.balanceOf(senUSD, address(this)), false);
        amount = maxAmount > amount ? amount : maxAmount;
        bentoBox.withdraw(senUSD, address(this), msg.sender, amount, 0);
    }

    /// @notice allows to change the interest rate
    /// @param newInterestRateBps new interest rate in basis points
    function changeInterestRate(uint16 newInterestRateBps) public onlyMasterContractOwner {
        uint64 oldInterestRate = accruedInterest.INTEREST_PER_SECOND;

        uint64 newInterestRate = fromBps(newInterestRateBps);
        
        require(newInterestRate < oldInterestRate + oldInterestRate * 3 / 4 || newInterestRate <= ONE_PERCENT_RATE(), "Interest rate increase > 75%");
        require(lastInterestUpdate + 3 days < block.timestamp, "Update only every 3 days");

        lastInterestUpdate = block.timestamp;
        accruedInterest.INTEREST_PER_SECOND = newInterestRate;
        emit InterestChangeEvent(oldInterestRate, newInterestRate);
    }

    /// @notice allows to change the borrow limit
    /// @param newBorrowLimit new borrow limit
    /// @param perAddressPart new borrow limit per address
    function changeBorrowLimit(uint128 newBorrowLimit, uint128 perAddressPart) public onlyMasterContractOwner {
        borrowLimit = BorrowCap(newBorrowLimit, perAddressPart);
        emit LogChangeBorrowLimit(newBorrowLimit, perAddressPart);
    }

    /// @notice allows to change blacklisted callees
    /// @param callee callee to blacklist or not
    /// @param _blacklisted true when the callee cannot be used in call cook action
    function setBlacklistedCaller(address callee, bool _blacklisted) public onlyMasterContractOwner {
        require(callee != address(0), 'invalid callee');
        require(callee != address(bentoBox) && callee != address(this), "invalid callee");

        blacklisted[callee] = _blacklisted;
        emit ChangeBlacklistedEvent(callee, _blacklisted);
    }

    function fromBps(uint16 rate) internal pure returns (uint64) {
            return uint64(rate) * Constants.PERCENT_RATE / Constants.BASIS_POINTS_DENOM; 
    }

    function ONE_PERCENT_RATE() internal pure returns (uint64) {
            return Constants.PERCENT_RATE;
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

import "./Ownable.sol";

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

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

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

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

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

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

File 4 of 18 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 5 of 18 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/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 6 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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 18 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

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

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    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));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    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");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    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");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation 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).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // 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 cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 8 of 18 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [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://consensys.net/diligence/blog/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.8.0/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 18 : 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 18 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.2._
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v2.5._
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.2._
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v2.5._
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v2.5._
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v2.5._
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     *
     * _Available since v2.5._
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     *
     * _Available since v3.0._
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     *
     * _Available since v4.7._
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.7._
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     *
     * _Available since v3.0._
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 11 of 18 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 12 of 18 : Constants.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

library Constants {

    uint64 public constant PERCENT_RATE = 317097920;

    // Interest  
    uint16 public constant BASIS_POINTS_DENOM = 1e4; 

    // Core
    uint256 public constant COLLATERIZATION_RATE_PRECISION = 1e5;  

    // Rates 
    uint256 public constant EXCHANGE_RATE_PRECISION = 1e18;
    uint256 public constant LIQUIDATION_MULTIPLIER_PRECISION = 1e5;

    // Fees
    uint256 public constant BORROW_OPENING_FEE_PRECISION = 1e5;   

    // Distribution
    uint256 public constant DISTRIBUTION_PART = 10; 
    uint256 public constant DISTRIBUTION_PRECISION = 100;

    uint8 public constant OPERATION_REPAY = 2;
    uint8 public constant OPERATION_REMOVE_COLLATERAL = 4;
    uint8 public constant OPERATION_BORROW = 5;
    uint8 public constant OPERATION_GET_REPAY_SHARE = 6;
    uint8 public constant OPERATION_GET_REPAY_PART = 7;
    uint8 public constant OPERATION_ACCRUE = 8;
    uint8 public constant OPERATION_ADD_COLLATERAL = 10;
    uint8 public constant OPERATION_UPDATE_PRICE = 11;
    uint8 public constant OPERATION_BENTO_DEPOSIT = 20;
    uint8 public constant OPERATION_BENTO_WITHDRAW = 21;
    uint8 public constant OPERATION_BENTO_TRANSFER = 22;
    uint8 public constant OPERATION_BENTO_TRANSFER_MULTIPLE = 23;
    uint8 public constant OPERATION_BENTO_SETAPPROVAL = 24;
    uint8 public constant OPERATION_CALL = 30;
    uint8 public constant OPERATION_LIQUIDATE = 31;
    uint8 public constant OPERATION_CUSTOM_START_INDEX = 100;

    int256 public constant USE_PARAM1 = -1;
    int256 public constant USE_PARAM2 = -2;
}

File 13 of 18 : IBentoBoxV1.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../libraries/BoringRebase.sol";
import "./IStrategy.sol";

interface IFlashBorrower {
    /// @notice The flashloan callback. `amount` + `fee` needs to repayed to msg.sender before this call returns.
    /// @param sender The address of the invoker of this flashloan.
    /// @param token The address of the token that is loaned.
    /// @param amount of the `token` that is loaned.
    /// @param fee The fee that needs to be paid on top for this loan. Needs to be the same as `token`.
    /// @param data Additional data that was passed to the flashloan function.
    function onFlashLoan(
        address sender,
        IERC20 token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external;
}

interface IBatchFlashBorrower {
    /// @notice The callback for batched flashloans. Every amount + fee needs to repayed to msg.sender before this call returns.
    /// @param sender The address of the invoker of this flashloan.
    /// @param tokens Array of addresses for ERC-20 tokens that is loaned.
    /// @param amounts A one-to-one map to `tokens` that is loaned.
    /// @param fees A one-to-one map to `tokens` that needs to be paid on top for each loan. Needs to be the same token.
    /// @param data Additional data that was passed to the flashloan function.
    function onBatchFlashLoan(
        address sender,
        IERC20[] calldata tokens,
        uint256[] calldata amounts,
        uint256[] calldata fees,
        bytes calldata data
    ) external;
}

interface IBentoBoxV1 {
    function balanceOf(IERC20, address) external view returns (uint256);

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

    function batchFlashLoan(
        IBatchFlashBorrower borrower,
        address[] calldata receivers,
        IERC20[] calldata tokens,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;

    function claimOwnership() external;

    function flashLoan(
        IFlashBorrower borrower,
        address receiver,
        IERC20 token,
        uint256 amount,
        bytes calldata data
    ) external;

    function deploy(
        address masterContract,
        bytes calldata data,
        bool useCreate2
    ) external payable returns (address);

    function deposit(
        IERC20 token_,
        address from,
        address to,
        uint256 amount,
        uint256 share
    ) external payable returns (uint256 amountOut, uint256 shareOut);

    function harvest(
        IERC20 token,
        bool balance,
        uint256 maxChangeAmount
    ) external;

    function masterContractApproved(address, address) external view returns (bool);

    function masterContractOf(address) external view returns (address);

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

    function owner() external view returns (address);

    function pendingOwner() external view returns (address);

    function pendingStrategy(IERC20) external view returns (IStrategy);

    function permitToken(
        IERC20 token,
        address from,
        address to,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function registerProtocol() external;

    function setMasterContractApproval(
        address user,
        address masterContract,
        bool approved,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function setStrategy(IERC20 token, IStrategy newStrategy) external;

    function setStrategyTargetPercentage(IERC20 token, uint64 targetPercentage_) external;

    function strategy(IERC20) external view returns (IStrategy);

    function strategyData(IERC20)
        external
        view
        returns (
            uint64 strategyStartDate,
            uint64 targetPercentage,
            uint128 balance
        );

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

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

    function totals(IERC20) external view returns (Rebase memory totals_);

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

    function transferMultiple(
        IERC20 token,
        address from,
        address[] calldata tos,
        uint256[] calldata shares
    ) external;

    function transferOwnership(
        address newOwner,
        bool direct,
        bool renounce
    ) external;

    function whitelistMasterContract(address masterContract, bool approved) external;

    function whitelistedMasterContracts(address) external view returns (bool);

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

File 14 of 18 : IMasterContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IMasterContract {
    /// @notice Init function that gets called from `BoringFactory.deploy`.
    /// Also kown as the constructor for cloned contracts.
    /// Any ETH send to `BoringFactory.deploy` ends up here.
    /// @param data Can be abi encoded arguments or anything else.
    function init(bytes calldata data) external payable;
}

File 15 of 18 : IOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface IOracle {
    /// @notice Get the decimals of the oracle.
    /// @return decimals The decimals.
    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 16 of 18 : IStrategy.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface IStrategy {
    /// @notice Send the assets to the Strategy and call skim to invest them.
    /// @param amount The amount of tokens to invest.
    function skim(uint256 amount) external;

    /// @notice Harvest any profits made converted to the asset and pass them to the caller.
    /// @param balance The amount of tokens the caller thinks it has invested.
    /// @param sender The address of the initiator of this transaction. Can be used for reimbursements, etc.
    /// @return amountAdded The delta (+profit or -loss) that occured in contrast to `balance`.
    function harvest(uint256 balance, address sender) external returns (int256 amountAdded);

    /// @notice Withdraw assets. The returned amount can differ from the requested amount due to rounding.
    /// @dev The `actualAmount` should be very close to the amount.
    /// The difference should NOT be used to report a loss. That's what harvest is for.
    /// @param amount The requested amount the caller wants to withdraw.
    /// @return actualAmount The real amount that is withdrawn.
    function withdraw(uint256 amount) external returns (uint256 actualAmount);

    /// @notice Withdraw all assets in the safest way possible. This shouldn't fail.
    /// @param balance The amount of tokens the caller thinks it has invested.
    /// @return amountAdded The delta (+profit or -loss) that occured in contrast to `balance`.
    function exit(uint256 balance) external returns (int256 amountAdded);
}

File 17 of 18 : ISwapperV2.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface ISwapperV2 {
    /// @notice Withdraws 'amountFrom' of token 'from' from the BentoBox account for this swapper.
    /// Swaps it for at least 'amountToMin' of token 'to'.
    /// Transfers the swapped tokens of 'to' into the BentoBox using a plain IERC20 transfer.
    /// Returns the amount of tokens 'to' transferred to BentoBox.
    /// (The BentoBox skim function will be used by the caller to get the swapped funds).
    function swap(
        address fromToken,
        address toToken,
        address recipient,
        uint256 shareToMin,
        uint256 shareFrom,
        bytes calldata data
    ) external returns (uint256 extraShare, uint256 shareReturned);
}

File 18 of 18 : 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);
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IBentoBoxV1","name":"bentoBox_","type":"address"},{"internalType":"contract IERC20","name":"senUSD_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"accruedAmount","type":"uint128"}],"name":"AccumulateInterestEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"part","type":"uint256"}],"name":"BorrowEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"blacklisted","type":"bool"}],"name":"ChangeBlacklistedEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"share","type":"uint256"}],"name":"DepositCollateralEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newFeeTo","type":"address"}],"name":"FeeToEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"oldInterestRate","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newInterestRate","type":"uint64"}],"name":"InterestChangeEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newLimit","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"perAddressPart","type":"uint128"}],"name":"LogChangeBorrowLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowPart","type":"uint256"}],"name":"LogLiquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"PriceUpdateEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"part","type":"uint256"}],"name":"RepayEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"share","type":"uint256"}],"name":"WithdrawCollateralEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"feesEarnedFraction","type":"uint256"}],"name":"WithdrawFeesEvent","type":"event"},{"inputs":[],"name":"BORROW_OPENING_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLLATERIZATION_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDATION_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accruedInterest","outputs":[{"internalType":"uint64","name":"lastAccrued","type":"uint64"},{"internalType":"uint128","name":"feesEarned","type":"uint128"},{"internalType":"uint64","name":"INTEREST_PER_SECOND","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bentoBox","outputs":[{"internalType":"contract IBentoBoxV1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"part","type":"uint256"},{"internalType":"uint256","name":"share","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowLimit","outputs":[{"internalType":"uint128","name":"total","type":"uint128"},{"internalType":"uint128","name":"borrowPartPerAddress","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"newBorrowLimit","type":"uint128"},{"internalType":"uint128","name":"perAddressPart","type":"uint128"}],"name":"changeBorrowLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newInterestRateBps","type":"uint16"}],"name":"changeInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"skim","type":"bool"},{"internalType":"uint256","name":"share","type":"uint256"}],"name":"depositCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"init","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isSolvent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[]","name":"maxBorrowParts","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"contract ISwapperV2","name":"swapper","type":"address"},{"internalType":"bytes","name":"swapperData","type":"bytes"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"masterContract","outputs":[{"internalType":"contract Chamber","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"actions","type":"uint8[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"}],"name":"performOperations","outputs":[{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"uint256","name":"value2","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reduceSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"skim","type":"bool"},{"internalType":"uint256","name":"part","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"senUSD","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"callee","type":"address"},{"internalType":"bool","name":"_blacklisted","type":"bool"}],"name":"setBlacklistedCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalBorrow","outputs":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCollateralShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updatePrice","outputs":[{"internalType":"bool","name":"updated","type":"bool"},{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBorrowPart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userCollateralShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b5060405162005cda38038062005cda8339810160408190526200003491620001aa565b6200003f3362000126565b6001805460ff60a01b191681556001600160a01b03808416608081905290831660c0523060a08190526000828152600e60208181526040808420805460ff199081168917909155948452808420805490951687179094558351638da5cb5b60e01b8152935191949293638da5cb5b92600480830193928290030181865afa158015620000cf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000f59190620001e9565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905550620002109050565b600180546001600160a01b0319169055620001418162000144565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200014157600080fd5b60008060408385031215620001be57600080fd5b8251620001cb8162000194565b6020840151909250620001de8162000194565b809150509250929050565b600060208284031215620001fc57600080fd5b8151620002098162000194565b9392505050565b60805160a05160c051615920620003ba6000396000818161070b01528181610cc201528181610d9b01528181611c1f015281816122190152818161237e01528181612eaa0152818161301c015281816130bc01528181613174015281816134e0015281816135920152818161360a0152818161370701528181613a1c01528181613bda01528181613c950152613d770152600081816107550152818161097d01528181610c30015281816111fc0152818161212a01526128510152600081816105810152818161091301528181610d1901528181610ddb0152818161108501528181611334015281816117c40152818161197c01528181611a7a01528181611bf001528181612253015281816123c3015281816129fb01528181612ee301528181612f8a015281816130f2015281816131b2015281816132bc015281816133ad01528181613516015281816135b4015281816135db01528181613636015281816136d80152818161378e015281816138ae01528181613a3e01528181613c1101528181613cd501528181613d4801528181613f1e0152818161401c01526140cc01526159206000f3fe6080604052600436106102bb5760003560e01c806374645ff31161016e578063c7ee2a7b116100cb578063e551d11d1161007f578063f46901ed11610064578063f46901ed14610830578063f7dad43414610850578063ff6ff84b1461087057600080fd5b8063e551d11d146107e5578063f2fde38b1461081057600080fd5b8063d8dfeb45116100b0578063d8dfeb4514610777578063dbac26e914610797578063e30c3978146107c757600080fd5b8063c7ee2a7b1461072d578063cd446e221461074357600080fd5b8063876467f811610122578063a53aeb4e11610107578063a53aeb4e146106ce578063aba024f4146106e3578063b6f173d1146106f957600080fd5b8063876467f8146106905780638da5cb5b146106b057600080fd5b80637dc0d1d0116101535780637dc0d1d01461060557806380623444146106255780638285ef401461064557600080fd5b806374645ff3146105ce57806379ba5097146105f057600080fd5b806348e4163e1161021c5780635c975abb116101d05780636b2ace87116101b55780636b2ace871461056f5780636ec097fb146105a3578063715018a6146105b957600080fd5b80635c975abb14610524578063673a7e281461054357600080fd5b80634ddf47d4116102015780634ddf47d4146104de578063517cf6a3146104f1578063568d8cd91461051157600080fd5b806348e4163e1461047c5780634b8a3529146104a957600080fd5b806338b51ce11161027357806345fe329f1161025857806345fe329f146103e0578063473e3ce714610451578063476343ee1461046757600080fd5b806338b51ce11461039a5780633ba0b9a9146103ca57600080fd5b80630ed6f9be116102a45780630ed6f9be1461031f57806315294c401461033f5780631c9e379b1461036d57600080fd5b8063017e7e58146102c057806302c1a42b146102fd575b600080fd5b3480156102cc57600080fd5b506002546102e0906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561030957600080fd5b5061031d610318366004614a28565b610890565b005b34801561032b57600080fd5b5061031d61033a366004614a69565b61097b565b34801561034b57600080fd5b5061035f61035a366004614a28565b610beb565b6040519081526020016102f4565b34801561037957600080fd5b5061035f610388366004614a8d565b600c6020526000908152604090205481565b3480156103a657600080fd5b506103ba6103b5366004614a8d565b610c10565b60405190151581526020016102f4565b3480156103d657600080fd5b5061035f600f5481565b3480156103ec57600080fd5b5060105461041e9067ffffffffffffffff808216916001600160801b03600160401b82041691600160c01b9091041683565b6040805167ffffffffffffffff94851681526001600160801b0390931660208401529216918101919091526060016102f4565b34801561045d57600080fd5b5061035f600a5481565b34801561047357600080fd5b5061031d610c24565b34801561048857600080fd5b5061035f610497366004614a8d565b600d6020526000908152604090205481565b3480156104b557600080fd5b506104c96104c4366004614aaa565b610e9d565b604080519283526020830191909152016102f4565b61031d6104ec366004614ad6565b610f2a565b3480156104fd57600080fd5b5061031d61050c366004614b48565b6111fa565b6104c961051f366004614bcd565b611428565b34801561053057600080fd5b50600154600160a01b900460ff166103ba565b34801561054f57600080fd5b50610558611f34565b6040805192151583526020830191909152016102f4565b34801561057b57600080fd5b506102e07f000000000000000000000000000000000000000000000000000000000000000081565b3480156105af57600080fd5b5061035f60075481565b3480156105c557600080fd5b5061031d611ff8565b3480156105da57600080fd5b506105e361200c565b6040516102f49190614cb7565b3480156105fc57600080fd5b5061031d61209a565b34801561061157600080fd5b506004546102e0906001600160a01b031681565b34801561063157600080fd5b5061031d610640366004614cca565b612128565b34801561065157600080fd5b50600b54610670906001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016102f4565b34801561069c57600080fd5b5061031d6106ab366004614aaa565b612437565b3480156106bc57600080fd5b506000546001600160a01b03166102e0565b3480156106da57600080fd5b5061031d6124b9565b3480156106ef57600080fd5b5061035f60085481565b34801561070557600080fd5b506102e07f000000000000000000000000000000000000000000000000000000000000000081565b34801561073957600080fd5b5061035f60065481565b34801561074f57600080fd5b506102e07f000000000000000000000000000000000000000000000000000000000000000081565b34801561078357600080fd5b506003546102e0906001600160a01b031681565b3480156107a357600080fd5b506103ba6107b2366004614a8d565b600e6020526000908152604090205460ff1681565b3480156107d357600080fd5b506001546001600160a01b03166102e0565b3480156107f157600080fd5b50600954610670906001600160801b0380821691600160801b90041682565b34801561081c57600080fd5b5061031d61082b366004614a8d565b61271c565b34801561083c57600080fd5b5061031d61084b366004614a8d565b61279a565b34801561085c57600080fd5b5061031d61086b366004614cf8565b61284f565b34801561087c57600080fd5b5061031d61088b366004614ed9565b61299a565b61089861321e565b6001600160a01b0383166000908152600c60205260409020546108bb9082613278565b6001600160a01b0384166000908152600c6020526040902055600a546108e18183613278565b600a556003546108fc906001600160a01b031683838661328b565b836001600160a01b0316836109115733610933565b7f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b03167f6278fc0b0b834dd63a777a95fa7ad401bb418e9abd9e2d2fea56de8d614544c98460405161096d91815260200190565b60405180910390a350505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fd9190614f8b565b6001600160a01b0316336001600160a01b031614610a625760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b601054600160c01b900467ffffffffffffffff166000610a818361340f565b90506004610a90836003614fbe565b610a9a9190615000565b610aa49083615027565b67ffffffffffffffff168167ffffffffffffffff161080610ad357506312e687c067ffffffffffffffff821611155b610b1f5760405162461bcd60e51b815260206004820152601c60248201527f496e746572657374207261746520696e637265617365203e20373525000000006044820152606401610a59565b426011546203f480610b31919061504f565b10610b7e5760405162461bcd60e51b815260206004820152601860248201527f557064617465206f6e6c792065766572792033206461797300000000000000006044820152606401610a59565b42601155601080546001600160c01b0316600160c01b67ffffffffffffffff8481169182029290921790925560408051918516825260208201929092527fa085058b12d3bd9dd32f87f0105f1996237757c583720c194afdd544ab736baa910160405180910390a1505050565b6000610bf561321e565b610bfd6124b9565b610c08848484613430565b949350505050565b6000610c1e82600f54613801565b92915050565b610c2c6124b9565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663017e7e586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190614f8b565b601054604051636d289ce560e11b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166004830152600160401b9092046001600160801b03166024820181905260006044830181905293945092917f0000000000000000000000000000000000000000000000000000000000000000169063da5139ca90606401602060405180830381865afa158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d849190615062565b604051633c6340f360e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301523060248301528581166044830152606482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063f18d03cc90608401600060405180830381600087803b158015610e2157600080fd5b505af1158015610e35573d6000803e3d6000fd5b50506010805477ffffffffffffffffffffffffffffffff00000000000000001916905550506040518281526001600160a01b038416907f51396202093d5d912cb0ed4b8b0b54a6b6fca25abdb7f87eb8027dd11e8bffa99060200160405180910390a2505050565b600080610ea861321e565b610eb06124b9565b610eba848461397c565b90925090506000610ec9611f34565b915050610ed63382613801565b610f225760405162461bcd60e51b815260206004820152601760248201527f4368616d6265723a207573657220696e736f6c76656e740000000000000000006044820152606401610a59565b509250929050565b6003546001600160a01b031615610f835760405162461bcd60e51b815260206004820152601c60248201527f4368616d6265723a20616c726561647920696e697469616c697a6564000000006044820152606401610a59565b610f8f8183018361507b565b600881905560068290556007839055601080546001600160c01b0316600160c01b67ffffffffffffffff871602179055600360006004816005610fd28a82615193565b50815461010091820a6001600160a01b03818102199092169b8216029a909a17909155825491900a8089021990911698881602979097179096555050604080518082019091526001600160801b0380825260209091015250506000196009556003541690506110835760405162461bcd60e51b815260206004820152601160248201527f4368616d6265723a2062616420706169720000000000000000000000000000006044820152606401610a59565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166000818152600e602081815260408084208054600160ff19918216811790925530865282862080549091168217905581517f8da5cb5b0000000000000000000000000000000000000000000000000000000081529151909593949392638da5cb5b92600480820193918290030181865afa15801561112f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111539190614f8b565b6001600160a01b03908116825260208201929092526040908101600020805460ff19169315159390931790925560048054925163d6d7d52560e01b8152929091169163d6d7d525916111a89160059101615253565b60408051808303816000875af11580156111c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ea91906152ee565b600f55506111f66124b9565b5050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c9190614f8b565b6001600160a01b0316336001600160a01b0316146112dc5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610a59565b6001600160a01b0382166113325760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642063616c6c65650000000000000000000000000000000000006044820152606401610a59565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415801561137d57506001600160a01b0382163014155b6113c95760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642063616c6c65650000000000000000000000000000000000006044820152606401610a59565b6001600160a01b0382166000818152600e6020908152604091829020805460ff191685151590811790915591519182527f2e07fc793c38fb148513d7ce2598eade436b44d3062703d7380944a8bf6e9d18910160405180910390a25050565b60008061143361321e565b60408051808201909152600080825260208201528760005b81811015611eba5760008b8b838181106114675761146761531c565b905060200201602081019061147c9190615341565b905083602001511580156114935750600a8160ff16105b156114a8576114a06124b9565b600160208501525b60091960ff8216016115085760008060008a8a868181106114cb576114cb61531c565b90506020028101906114dd919061535e565b8101906114ea91906153a5565b9250925092506115008282610318868d8d613e3e565b505050611ea7565b60011960ff82160161156e5760008060008a8a8681811061152b5761152b61531c565b905060200281019061153d919061535e565b81019061154a91906153a5565b9250925092506115658282611560868d8d613e3e565b613430565b50505050611ea7565b60031960ff8216016115d15760008089898581811061158f5761158f61531c565b90506020028101906115a1919061535e565b8101906115ae91906153e7565b915091506115c6816115c1848b8b613e3e565b613e65565b505060018452611ea7565b60041960ff82160161163a576000808989858181106115f2576115f261531c565b9050602002810190611604919061535e565b81019061161191906153e7565b9150915061162981611624848b8b613e3e565b61397c565b600188529098509650611ea7915050565b600a1960ff82160161170f5760008060008a8a8681811061165d5761165d61531c565b905060200281019061166f919061535e565b81019061167c919061540c565b92509250925060008061168d611f34565b9150915084158061169b5750815b80156116a657508381115b80156116b957508215806116b957508281105b6117055760405162461bcd60e51b815260206004820152601460248201527f4368616d6265723a2072617465206e6f74206f6b0000000000000000000000006044820152606401610a59565b5050505050611ea7565b60171960ff82160161182d576000806000806000808d8d898181106117365761173661531c565b9050602002810190611748919061535e565b8101906117559190615441565b6040517fc0a47c930000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301528681166024830152851515604483015260ff851660648301526084820184905260a48201839052969c50949a50929850909650945092507f00000000000000000000000000000000000000000000000000000000000000009091169063c0a47c939060c401600060405180830381600087803b15801561180a57600080fd5b505af115801561181e573d6000803e3d6000fd5b50505050505050505050611ea7565b60131960ff8216016118c1576118b788888481811061184e5761184e61531c565b9050602002810190611860919061535e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d91508690508181106118a9576118a961531c565b905060200201358888613f80565b9096509450611ea7565b60141960ff821601611932576118b78888848181106118e2576118e261531c565b90506020028101906118f4919061535e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a925089915061409d9050565b60151960ff821601611a305760008060008a8a868181106119555761195561531c565b9050602002810190611967919061535e565b81019061197491906154af565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f18d03cc8433856119b7868f8f613e3e565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015292841660248401529216604482015260648101919091526084015b600060405180830381600087803b158015611a1057600080fd5b505af1158015611a24573d6000803e3d6000fd5b50505050505050611ea7565b60161960ff821601611aca5760008060008a8a86818110611a5357611a5361531c565b9050602002810190611a65919061535e565b810190611a7291906154df565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630fca8843843385856040518563ffffffff1660e01b81526004016119f69493929190615555565b601d1960ff821601611bad57600080611b578c8c86818110611aee57611aee61531c565b905060200201358b8b87818110611b0757611b0761531c565b9050602002810190611b19919061535e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d92508c91506141a99050565b915091508060ff16600103611b815781806020019051810190611b7a9190615062565b9750611ba6565b8060ff16600203611ba65781806020019051810190611ba091906155f1565b90985096505b5050611ea7565b60051960ff821601611cf8576000888884818110611bcd57611bcd61531c565b9050602002810190611bdf919061535e565b810190611bec9190614cca565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663da5139ca7f0000000000000000000000000000000000000000000000000000000000000000611c7c611c4c858c8c613e3e565b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152906001614398565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260016044820152606401602060405180830381865afa158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf09190615062565b965050611ea7565b60061960ff821601611d77576000888884818110611d1857611d1861531c565b9050602002810190611d2a919061535e565b810190611d379190614cca565b9050611cf0611d47828989613e3e565b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152906000614434565b601e1960ff821601611db457611daf888884818110611d9857611d9861531c565b9050602002810190611daa919061535e565b6144a9565b611ea7565b6000806000611e4f84888f8f89818110611dd057611dd061531c565b905060200201358e8e8a818110611de957611de961531c565b9050602002810190611dfb919061535e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060408051808201909152818152602081018290526060999198509650945050505050565b9250925092508096508160ff16600103611e7e5782806020019051810190611e779190615062565b9850611ea3565b8160ff16600203611ea35782806020019051810190611e9d91906155f1565b90995097505b5050505b5080611eb281615615565b91505061144b565b50815115611f27576000611ecc611f34565b915050611ed93382613801565b611f255760405162461bcd60e51b815260206004820152601760248201527f4368616d6265723a207573657220696e736f6c76656e740000000000000000006044820152606401610a59565b505b5050965096945050505050565b6004805460405163d6d7d52560e01b815260009283926001600160a01b03169163d6d7d52591611f679160059101615253565b60408051808303816000875af1158015611f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa991906152ee565b90925090508115611ff057600f8190556040518181527fa4f3423f4dd10872d278f5fffb845f3639844d295fc8f472ce40b132406d49449060200160405180910390a19091565b50600f549091565b6120006144db565b61200a6000614535565b565b6005805461201990615113565b80601f016020809104026020016040519081016040528092919081815260200182805461204590615113565b80156120925780601f1061206757610100808354040283529160200191612092565b820191906000526020600020905b81548152906001019060200180831161207557829003601f168201915b505050505081565b60015433906001600160a01b0316811461211c5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610a59565b61212581614535565b50565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121aa9190614f8b565b6001600160a01b0316336001600160a01b03161461220a5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610a59565b604051633de222bb60e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381811660048401523060248401526000927f00000000000000000000000000000000000000000000000000000000000000009190911691635662311891839063f7888aec90604401602060405180830381865afa1580156122a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c99190615062565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260006044820152606401602060405180830381865afa158015612319573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233d9190615062565b905081811161234c578061234e565b815b6040517f97da6d300000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015230602483015233604483015260648201839052600060848301529193507f0000000000000000000000000000000000000000000000000000000000000000909116906397da6d309060a40160408051808303816000875af115801561240d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243191906155f1565b50505050565b61243f61321e565b6124476124b9565b6124518282613e65565b600061245b611f34565b9150506124683382613801565b6124b45760405162461bcd60e51b815260206004820152601760248201527f4368616d6265723a207573657220696e736f6c76656e740000000000000000006044820152606401610a59565b505050565b6124c161321e565b6040805160608101825260105467ffffffffffffffff8082168084526001600160801b03600160401b8404166020850152600160c01b909204169282019290925290600090612510904261562e565b90508060000361251e575050565b67ffffffffffffffff4216825260408051808201909152600b546001600160801b038082168352600160801b90910416602082018190526000036125cd575050805160108054602084015160409094015167ffffffffffffffff908116600160c01b026001600160c01b036001600160801b03909616600160401b027fffffffffffffffff00000000000000000000000000000000000000000000000090931691909416171792909216179055565b6000670de0b6b3a76400006126108461260a876040015167ffffffffffffffff1686600001516001600160801b031661455b90919063ffffffff16565b9061455b565b61261a9190615641565b8251909150612636906001600160801b03908116908316613278565b6001600160801b039081168352602085015161265791908116908316613278565b6001600160801b0390811660208681018290528451858201518416600160801b0290841617600b558651601080546040808b015167ffffffffffffffff908116600160c01b026001600160c01b03600160401b9098027fffffffffffffffff00000000000000000000000000000000000000000000000090941691909516179190911794909416919091179055905191831682527f757b29336b38e0454cafcaa1fee2fc9e8677248c1cb1ba37dd3e2c60a87ab3ab910160405180910390a150505050565b6127246144db565b600180546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff1990911681179091556127626000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6127a26144db565b6001600160a01b0381166127f85760405162461bcd60e51b815260206004820152601360248201527f63616e6e6f7420626520302061646472657373000000000000000000000000006044820152606401610a59565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f8bc25725ca4ea10a36558b30cebb3baa6f7551e3fe58208d839e44189bdbe3e090600090a250565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d19190614f8b565b6001600160a01b0316336001600160a01b0316146129315760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610a59565b6040805180820182526001600160801b038481168083529084166020928301819052600160801b810282176009558351918252918101919091527ff1fce436bc22563026222b3b2bdc088cb69d25192974264114df12ab812628f6910160405180910390a15050565b6129a261321e565b60006129ac611f34565b9150506129b76124b9565b6003546040517f4ffe34db0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000918291829182917f000000000000000000000000000000000000000000000000000000000000000090911690634ffe34db906024016040805180830381865afa158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190615655565b9050895160005b81811015612d0d5760008c8281518110612a8a57612a8a61531c565b60200260200101519050612a9e8189613801565b612cfa576001600160a01b0381166000908152600d60205260408120548d5181908f9086908110612ad157612ad161531c565b602002602001015111612afd578d8481518110612af057612af061531c565b6020026020010151612aff565b805b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152909250600090612b38908483614398565b90506000612b80612b54670de0b6b3a7640000620186a06156b4565b612b6d8e61260a6007548761455b90919063ffffffff16565b612b779190615641565b89906000614434565b9050612b8c8385614567565b6001600160a01b0386166000908152600d6020908152604080832093909355600c90522054612bbb9082614567565b6001600160a01b0386166000908152600c60205260409020558e6001600160a01b0316856001600160a01b03167f77f19d2489899bac4076fc1c140f57208d84c91aca70c5bfce9460130bcc5c5583604051612c1991815260200190565b60405180910390a360408051838152602081018690526001600160a01b0387169133917fa7489af36ce0dad0b30ae45d2d29c07e996839e7ad59e955a9d33ec30372fdeb910160405180910390a38e6001600160a01b0316856001600160a01b0316336001600160a01b03167f66b108dc29b952efc76dccea9b82dce6b59fab4d9af73d8dcc9789afcad5daf6848689604051612cc9939291909283526020830191909152604082015260600190565b60405180910390a4612cdb8b82613278565b9a50612ce78a83613278565b9950612cf38985613278565b9850505050505b5080612d0581615615565b915050612a6e565b5083600003612d5e5760405162461bcd60e51b815260206004820152601860248201527f4368616d6265723a20616c6c2061726520736f6c76656e7400000000000000006044820152606401610a59565b600b54612d74906001600160801b031685614567565b600b80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166001600160801b039283161790819055612dbd91600160801b9091041684614567565b600b80546001600160801b03928316600160801b029216919091179055600a54612de79086614567565b600a8190555060006064612e23600a61260a88620186a0612e136007548c61455b90919063ffffffff16565b612e1d9190615641565b90614567565b612e2d9190615641565b9050612e398582613278565b601054909550612e5990600160401b90046001600160801b031682613278565b601080546001600160801b0392909216600160401b0277ffffffffffffffffffffffffffffffff00000000000000001990921691909117905550604051636d289ce560e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201869052600160448301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063da5139ca90606401602060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f509190615062565b600354604051633c6340f360e21b81526001600160a01b0391821660048201523060248201528c82166044820152606481018990529192507f0000000000000000000000000000000000000000000000000000000000000000169063f18d03cc90608401600060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506001600160a01b038916156130a557886001600160a01b031663a5d4096b600360009054906101000a90046001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000033858b8e6040518763ffffffff1660e01b8152600401613060969594939291906156cb565b60408051808303816000875af115801561307e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a291906155f1565b50505b604051636d289ce560e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201879052600160448301527f0000000000000000000000000000000000000000000000000000000000000000169063da5139ca90606401602060405180830381865afa158015613139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315d9190615062565b604051633c6340f360e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152336024830152306044830152606482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063f18d03cc90608401600060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b50505050505050505050505050505050565b600154600160a01b900460ff161561200a5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a59565b6000613284828461504f565b9392505050565b801561337b57604051633de222bb60e21b81526001600160a01b0385811660048301523060248301526133279184917f0000000000000000000000000000000000000000000000000000000000000000169063f7888aec90604401602060405180830381865afa158015613303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1d9190615062565b8311156133765760405162461bcd60e51b815260206004820152601660248201527f4368616d6265723a20536b696d20746f6f206d756368000000000000000000006044820152606401610a59565b612431565b604051633c6340f360e21b81526001600160a01b038581166004830152336024830152306044830152606482018590527f0000000000000000000000000000000000000000000000000000000000000000169063f18d03cc90608401600060405180830381600087803b1580156133f157600080fd5b505af1158015613405573d6000803e3d6000fd5b5050505050505050565b60006127106134266312e687c061ffff8516614fbe565b610c1e9190615000565b600061343a61321e565b60408051808201909152600b546001600160801b038082168352600160801b90910416602082015261346e90836001614573565b81516020928301516001600160801b03908116600160801b02911617600b556001600160a01b0386166000908152600d9092526040909120549091506134b49083614567565b6001600160a01b038581166000908152600d6020526040808220939093559151636d289ce560e11b81527f00000000000000000000000000000000000000000000000000000000000000008216600482015260248101849052600160448201527f00000000000000000000000000000000000000000000000000000000000000009091169063da5139ca90606401602060405180830381865afa15801561355f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135839190615062565b90506135d96001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000846145dc565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f18d03cc7f0000000000000000000000000000000000000000000000000000000000000000866136345733613656565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015230604482015260648101849052608401600060405180830381600087803b1580156136ab57600080fd5b505af11580156136bf573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152600060248301527f000000000000000000000000000000000000000000000000000000000000000016925063095ea7b391506044016020604051808303816000875af1158015613752573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137769190615717565b50846001600160a01b03168461378c57336137ae565b7f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b03167fa7489af36ce0dad0b30ae45d2d29c07e996839e7ad59e955a9d33ec30372fdeb84866040516137f1929190918252602082015260400190565b60405180910390a3509392505050565b6001600160a01b0382166000908152600d602052604081205480820361382b576001915050610c1e565b6001600160a01b0384166000908152600c60205260408120549081900361385757600092505050610c1e565b60408051808201909152600b546001600160801b03808216808452600160801b90920416602083018190529061389490879061260a90879061455b565b61389e9190615641565b6003546006546001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116926356623118929116906138fc9061260a6138f5620186a0670de0b6b3a7640000615641565b899061455b565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260006044820152606401602060405180830381865afa15801561394c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139709190615062565b10159695505050505050565b60008061398761321e565b6000620186a06139a26008548661455b90919063ffffffff16565b6139ac9190615641565b90506139eb6139bb8583613278565b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152906001614748565b81516020909201516001600160801b03908116600160801b02921691909117600b559250613a636001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f0000000000000000000000000000000000000000000000000000000000000000866145dc565b604080518082019091526009546001600160801b03808216808452600160801b90920481166020840152600b54161115613adf5760405162461bcd60e51b815260206004820152601460248201527f426f72726f77204c696d697420726561636865640000000000000000000000006044820152606401610a59565b601054613b0090600160401b90046001600160801b03908116908416613278565b601080546001600160801b0392909216600160401b0277ffffffffffffffffffffffffffffffff000000000000000019909216919091179055336000908152600d6020526040812054613b539086613278565b905081602001516001600160801b0316811115613bb25760405162461bcd60e51b815260206004820152601460248201527f426f72726f77204c696d697420726561636865640000000000000000000000006044820152606401610a59565b336000908152600d602052604080822083905551636d289ce560e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820189905260448201929092527f00000000000000000000000000000000000000000000000000000000000000009091169063da5139ca90606401602060405180830381865afa158015613c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c7e9190615062565b604051633c6340f360e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301523060248301528981166044830152606482018390529195507f00000000000000000000000000000000000000000000000000000000000000009091169063f18d03cc90608401600060405180830381600087803b158015613d1b57600080fd5b505af1158015613d2f573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152600060248301527f000000000000000000000000000000000000000000000000000000000000000016925063095ea7b391506044016020604051808303816000875af1158015613dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de69190615717565b506001600160a01b038716337f1298465c3dfc2aaba2a18da010d6b969a7e06f6f9dbcc96798660535389d1e7c613e1d8987613278565b60408051918252602082018a90520160405180910390a35050509250929050565b600080841215613e5d576000198414613e575781610c08565b82610c08565b509192915050565b613e6d61321e565b336000908152600c6020526040902054613e879082614567565b336000908152600c6020526040902055600a54613ea49082614567565b600a556040518181526001600160a01b0383169033907f77f19d2489899bac4076fc1c140f57208d84c91aca70c5bfce9460130bcc5c559060200160405180910390a3600354604051633c6340f360e21b81526001600160a01b0391821660048201523060248201528382166044820152606481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063f18d03cc90608401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050565b600080613f8b61321e565b60008060008089806020019051810190613fa59190615734565b9350935093509350613fb8828989613e3e565b9150613fc5818989613e3e565b6040517f02b9446c0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152336024830152858116604483015260648201859052608482018390529192507f0000000000000000000000000000000000000000000000000000000000000000909116906302b9446c908b9060a401604080518083038185885af1158015614067573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061408c91906155f1565b955095505050505094509492505050565b6000806140a861321e565b600080600080888060200190518101906140c29190615734565b93509350935093507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166397da6d30853386614107878e8e613e3e565b614112878f8f613e3e565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015293851660248501529390911660448301526064820152608481019190915260a40160408051808303816000875af1158015614175573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061419991906155f1565b9550955050505050935093915050565b606060006141b561321e565b6000806000806000898060200190518101906141d19190615787565b945094509450945094508280156141e6575081155b156142145783896040516020016141fe929190615845565b604051602081830303815290604052935061426d565b8215801561421f5750815b156142375783886040516020016141fe929190615845565b8280156142415750815b1561426d5783898960405160200161425b93929190615867565b60405160208183030381529060405293505b6001600160a01b0385166000908152600e602052604090205460ff16156142d65760405162461bcd60e51b815260206004820152601360248201527f4368616d6265723a2063616e27742063616c6c000000000000000000000000006044820152606401610a59565b600080866001600160a01b03168d876040516142f2919061588e565b60006040518083038185875af1925050503d806000811461432f576040519150601f19603f3d011682016040523d82523d6000602084013e614334565b606091505b5091509150816143865760405162461bcd60e51b815260206004820152601460248201527f4368616d6265723a2063616c6c206661696c65640000000000000000000000006044820152606401610a59565b9c919b50909950505050505050505050565b600083602001516001600160801b03166000036143b6575081613284565b602084015184516001600160801b03918216916143d49116856156b4565b6143de9190615641565b905081801561441c57508284600001516001600160801b031685602001516001600160801b03168361441091906156b4565b61441a9190615641565b105b15613284578061442b81615615565b95945050505050565b82516000906001600160801b0316810361444f575081613284565b835160208501516001600160801b039182169161446d9116856156b4565b6144779190615641565b905081801561441c57508284602001516001600160801b031685600001516001600160801b03168361441091906156b4565b6000808080806144bb86880188614ed9565b945094509450945094506144d2858585858561299a565b50505050505050565b6000546001600160a01b0316331461200a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a59565b6001805473ffffffffffffffffffffffffffffffffffffffff191690556121258161479d565b600061328482846156b4565b6000613284828461562e565b60408051808201909152600080825260208201526000614594858585614398565b905080856000018181516145a891906158aa565b6001600160801b03169052506020850180518591906145c89083906158aa565b6001600160801b0316905250939492505050565b80158061466f57506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061466d9190615062565b155b6146e15760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610a59565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b1790526124b49084906147fa565b60408051808201909152600080825260208201526000614769858585614434565b9050838560000181815161477d91906158ca565b6001600160801b03169052506020850180518291906145c89083906158ca565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061484f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148e29092919063ffffffff16565b90508051600014806148705750808060200190518101906148709190615717565b6124b45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a59565b6060610c08848460008585600080866001600160a01b03168587604051614909919061588e565b60006040518083038185875af1925050503d8060008114614946576040519150601f19603f3d011682016040523d82523d6000602084013e61494b565b606091505b509150915061495c87838387614967565b979650505050505050565b606083156149d65782516000036149cf576001600160a01b0385163b6149cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a59565b5081610c08565b610c0883838151156149eb5781518083602001fd5b8060405162461bcd60e51b8152600401610a599190614cb7565b6001600160a01b038116811461212557600080fd5b801515811461212557600080fd5b600080600060608486031215614a3d57600080fd5b8335614a4881614a05565b92506020840135614a5881614a1a565b929592945050506040919091013590565b600060208284031215614a7b57600080fd5b813561ffff8116811461328457600080fd5b600060208284031215614a9f57600080fd5b813561328481614a05565b60008060408385031215614abd57600080fd5b8235614ac881614a05565b946020939093013593505050565b60008060208385031215614ae957600080fd5b823567ffffffffffffffff80821115614b0157600080fd5b818501915085601f830112614b1557600080fd5b813581811115614b2457600080fd5b866020828501011115614b3657600080fd5b60209290920196919550909350505050565b60008060408385031215614b5b57600080fd5b8235614b6681614a05565b91506020830135614b7681614a1a565b809150509250929050565b60008083601f840112614b9357600080fd5b50813567ffffffffffffffff811115614bab57600080fd5b6020830191508360208260051b8501011115614bc657600080fd5b9250929050565b60008060008060008060608789031215614be657600080fd5b863567ffffffffffffffff80821115614bfe57600080fd5b614c0a8a838b01614b81565b90985096506020890135915080821115614c2357600080fd5b614c2f8a838b01614b81565b90965094506040890135915080821115614c4857600080fd5b50614c5589828a01614b81565b979a9699509497509295939492505050565b60005b83811015614c82578181015183820152602001614c6a565b50506000910152565b60008151808452614ca3816020860160208601614c67565b601f01601f19169290920160200192915050565b6020815260006132846020830184614c8b565b600060208284031215614cdc57600080fd5b5035919050565b6001600160801b038116811461212557600080fd5b60008060408385031215614d0b57600080fd5b8235614d1681614ce3565b91506020830135614b7681614ce3565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614d6557614d65614d26565b604052919050565b600067ffffffffffffffff821115614d8757614d87614d26565b5060051b60200190565b600082601f830112614da257600080fd5b81356020614db7614db283614d6d565b614d3c565b82815260059290921b84018101918181019086841115614dd657600080fd5b8286015b84811015614dfa578035614ded81614a05565b8352918301918301614dda565b509695505050505050565b600082601f830112614e1657600080fd5b81356020614e26614db283614d6d565b82815260059290921b84018101918181019086841115614e4557600080fd5b8286015b84811015614dfa5780358352918301918301614e49565b600067ffffffffffffffff821115614e7a57614e7a614d26565b50601f01601f191660200190565b600082601f830112614e9957600080fd5b8135614ea7614db282614e60565b818152846020838601011115614ebc57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215614ef157600080fd5b853567ffffffffffffffff80821115614f0957600080fd5b614f1589838a01614d91565b96506020880135915080821115614f2b57600080fd5b614f3789838a01614e05565b955060408801359150614f4982614a05565b909350606087013590614f5b82614a05565b90925060808701359080821115614f7157600080fd5b50614f7e88828901614e88565b9150509295509295909350565b600060208284031215614f9d57600080fd5b815161328481614a05565b634e487b7160e01b600052601160045260246000fd5b67ffffffffffffffff818116838216028082169190828114614fe257614fe2614fa8565b505092915050565b634e487b7160e01b600052601260045260246000fd5b600067ffffffffffffffff8084168061501b5761501b614fea565b92169190910492915050565b67ffffffffffffffff81811683821601908082111561504857615048614fa8565b5092915050565b80820180821115610c1e57610c1e614fa8565b60006020828403121561507457600080fd5b5051919050565b600080600080600080600060e0888a03121561509657600080fd5b87356150a181614a05565b965060208801356150b181614a05565b9550604088013567ffffffffffffffff808211156150ce57600080fd5b6150da8b838c01614e88565b965060608a0135915080821682146150f157600080fd5b509699959850939660808101359560a0820135955060c0909101359350915050565b600181811c9082168061512757607f821691505b60208210810361514757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156124b457600081815260208120601f850160051c810160208610156151745750805b601f850160051c820191505b81811015613f7857828155600101615180565b815167ffffffffffffffff8111156151ad576151ad614d26565b6151c1816151bb8454615113565b8461514d565b602080601f8311600181146151f657600084156151de5750858301515b600019600386901b1c1916600185901b178555613f78565b600085815260208120601f198616915b8281101561522557888601518255948401946001909101908401615206565b50858210156152435787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083526000845461526781615113565b8084870152604060018084166000811461528857600181146152a2576152d0565b60ff1985168984015283151560051b8901830195506152d0565b896000528660002060005b858110156152c85781548b82018601529083019088016152ad565b8a0184019650505b509398975050505050505050565b80516152e981614a1a565b919050565b6000806040838503121561530157600080fd5b825161530c81614a1a565b6020939093015192949293505050565b634e487b7160e01b600052603260045260246000fd5b60ff8116811461212557600080fd5b60006020828403121561535357600080fd5b813561328481615332565b6000808335601e1984360301811261537557600080fd5b83018035915067ffffffffffffffff82111561539057600080fd5b602001915036819003821315614bc657600080fd5b6000806000606084860312156153ba57600080fd5b8335925060208401356153cc81614a05565b915060408401356153dc81614a1a565b809150509250925092565b600080604083850312156153fa57600080fd5b823591506020830135614b7681614a05565b60008060006060848603121561542157600080fd5b833561542c81614a1a565b95602085013595506040909401359392505050565b60008060008060008060c0878903121561545a57600080fd5b863561546581614a05565b9550602087013561547581614a05565b9450604087013561548581614a1a565b9350606087013561549581615332565b9598949750929560808101359460a0909101359350915050565b6000806000606084860312156154c457600080fd5b83356154cf81614a05565b92506020840135614a5881614a05565b6000806000606084860312156154f457600080fd5b83356154ff81614a05565b9250602084013567ffffffffffffffff8082111561551c57600080fd5b61552887838801614d91565b9350604086013591508082111561553e57600080fd5b5061554b86828701614e05565b9150509250925092565b6000608082016001600160a01b0380881684526020818816818601526080604086015282875180855260a087019150828901945060005b818110156155aa57855185168352948301949183019160010161558c565b5050858103606087015286518082529082019350915080860160005b838110156155e2578151855293820193908201906001016155c6565b50929998505050505050505050565b6000806040838503121561560457600080fd5b505080516020909101519092909150565b60006001820161562757615627614fa8565b5060010190565b81810381811115610c1e57610c1e614fa8565b60008261565057615650614fea565b500490565b60006040828403121561566757600080fd5b6040516040810181811067ffffffffffffffff8211171561568a5761568a614d26565b604052825161569881614ce3565b815260208301516156a881614ce3565b60208201529392505050565b8082028115828204841417610c1e57610c1e614fa8565b60006001600160a01b038089168352808816602084015280871660408401525084606083015283608083015260c060a083015261570b60c0830184614c8b565b98975050505050505050565b60006020828403121561572957600080fd5b815161328481614a1a565b6000806000806080858703121561574a57600080fd5b845161575581614a05565b602086015190945061576681614a05565b6040860151606090960151949790965092505050565b80516152e981615332565b600080600080600060a0868803121561579f57600080fd5b85516157aa81614a05565b602087015190955067ffffffffffffffff8111156157c757600080fd5b8601601f810188136157d857600080fd5b80516157e6614db282614e60565b8181528960208385010111156157fb57600080fd5b61580c826020830160208601614c67565b955061581d915050604087016152de565b925061582b606087016152de565b91506158396080870161577c565b90509295509295909350565b60008351615857818460208801614c67565b9190910191825250602001919050565b60008451615879818460208901614c67565b91909101928352506020820152604001919050565b600082516158a0818460208701614c67565b9190910192915050565b6001600160801b0382811682821603908082111561504857615048614fa8565b6001600160801b0381811683821601908082111561504857615048614fa856fea2646970667358221220fe38e6173e208d58a4aef3ddca55a4b42f09c43eca87ea6b80ee8386e2903b5764736f6c63430008130033000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8

Deployed Bytecode

0x6080604052600436106102bb5760003560e01c806374645ff31161016e578063c7ee2a7b116100cb578063e551d11d1161007f578063f46901ed11610064578063f46901ed14610830578063f7dad43414610850578063ff6ff84b1461087057600080fd5b8063e551d11d146107e5578063f2fde38b1461081057600080fd5b8063d8dfeb45116100b0578063d8dfeb4514610777578063dbac26e914610797578063e30c3978146107c757600080fd5b8063c7ee2a7b1461072d578063cd446e221461074357600080fd5b8063876467f811610122578063a53aeb4e11610107578063a53aeb4e146106ce578063aba024f4146106e3578063b6f173d1146106f957600080fd5b8063876467f8146106905780638da5cb5b146106b057600080fd5b80637dc0d1d0116101535780637dc0d1d01461060557806380623444146106255780638285ef401461064557600080fd5b806374645ff3146105ce57806379ba5097146105f057600080fd5b806348e4163e1161021c5780635c975abb116101d05780636b2ace87116101b55780636b2ace871461056f5780636ec097fb146105a3578063715018a6146105b957600080fd5b80635c975abb14610524578063673a7e281461054357600080fd5b80634ddf47d4116102015780634ddf47d4146104de578063517cf6a3146104f1578063568d8cd91461051157600080fd5b806348e4163e1461047c5780634b8a3529146104a957600080fd5b806338b51ce11161027357806345fe329f1161025857806345fe329f146103e0578063473e3ce714610451578063476343ee1461046757600080fd5b806338b51ce11461039a5780633ba0b9a9146103ca57600080fd5b80630ed6f9be116102a45780630ed6f9be1461031f57806315294c401461033f5780631c9e379b1461036d57600080fd5b8063017e7e58146102c057806302c1a42b146102fd575b600080fd5b3480156102cc57600080fd5b506002546102e0906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561030957600080fd5b5061031d610318366004614a28565b610890565b005b34801561032b57600080fd5b5061031d61033a366004614a69565b61097b565b34801561034b57600080fd5b5061035f61035a366004614a28565b610beb565b6040519081526020016102f4565b34801561037957600080fd5b5061035f610388366004614a8d565b600c6020526000908152604090205481565b3480156103a657600080fd5b506103ba6103b5366004614a8d565b610c10565b60405190151581526020016102f4565b3480156103d657600080fd5b5061035f600f5481565b3480156103ec57600080fd5b5060105461041e9067ffffffffffffffff808216916001600160801b03600160401b82041691600160c01b9091041683565b6040805167ffffffffffffffff94851681526001600160801b0390931660208401529216918101919091526060016102f4565b34801561045d57600080fd5b5061035f600a5481565b34801561047357600080fd5b5061031d610c24565b34801561048857600080fd5b5061035f610497366004614a8d565b600d6020526000908152604090205481565b3480156104b557600080fd5b506104c96104c4366004614aaa565b610e9d565b604080519283526020830191909152016102f4565b61031d6104ec366004614ad6565b610f2a565b3480156104fd57600080fd5b5061031d61050c366004614b48565b6111fa565b6104c961051f366004614bcd565b611428565b34801561053057600080fd5b50600154600160a01b900460ff166103ba565b34801561054f57600080fd5b50610558611f34565b6040805192151583526020830191909152016102f4565b34801561057b57600080fd5b506102e07f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd64396681565b3480156105af57600080fd5b5061035f60075481565b3480156105c557600080fd5b5061031d611ff8565b3480156105da57600080fd5b506105e361200c565b6040516102f49190614cb7565b3480156105fc57600080fd5b5061031d61209a565b34801561061157600080fd5b506004546102e0906001600160a01b031681565b34801561063157600080fd5b5061031d610640366004614cca565b612128565b34801561065157600080fd5b50600b54610670906001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016102f4565b34801561069c57600080fd5b5061031d6106ab366004614aaa565b612437565b3480156106bc57600080fd5b506000546001600160a01b03166102e0565b3480156106da57600080fd5b5061031d6124b9565b3480156106ef57600080fd5b5061035f60085481565b34801561070557600080fd5b506102e07f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd881565b34801561073957600080fd5b5061035f60065481565b34801561074f57600080fd5b506102e07f00000000000000000000000045e15d1e4f92f28a916f4f2971ad9adc278e148b81565b34801561078357600080fd5b506003546102e0906001600160a01b031681565b3480156107a357600080fd5b506103ba6107b2366004614a8d565b600e6020526000908152604090205460ff1681565b3480156107d357600080fd5b506001546001600160a01b03166102e0565b3480156107f157600080fd5b50600954610670906001600160801b0380821691600160801b90041682565b34801561081c57600080fd5b5061031d61082b366004614a8d565b61271c565b34801561083c57600080fd5b5061031d61084b366004614a8d565b61279a565b34801561085c57600080fd5b5061031d61086b366004614cf8565b61284f565b34801561087c57600080fd5b5061031d61088b366004614ed9565b61299a565b61089861321e565b6001600160a01b0383166000908152600c60205260409020546108bb9082613278565b6001600160a01b0384166000908152600c6020526040902055600a546108e18183613278565b600a556003546108fc906001600160a01b031683838661328b565b836001600160a01b0316836109115733610933565b7f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439665b6001600160a01b03167f6278fc0b0b834dd63a777a95fa7ad401bb418e9abd9e2d2fea56de8d614544c98460405161096d91815260200190565b60405180910390a350505050565b7f00000000000000000000000045e15d1e4f92f28a916f4f2971ad9adc278e148b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fd9190614f8b565b6001600160a01b0316336001600160a01b031614610a625760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e657200000000000000000060448201526064015b60405180910390fd5b601054600160c01b900467ffffffffffffffff166000610a818361340f565b90506004610a90836003614fbe565b610a9a9190615000565b610aa49083615027565b67ffffffffffffffff168167ffffffffffffffff161080610ad357506312e687c067ffffffffffffffff821611155b610b1f5760405162461bcd60e51b815260206004820152601c60248201527f496e746572657374207261746520696e637265617365203e20373525000000006044820152606401610a59565b426011546203f480610b31919061504f565b10610b7e5760405162461bcd60e51b815260206004820152601860248201527f557064617465206f6e6c792065766572792033206461797300000000000000006044820152606401610a59565b42601155601080546001600160c01b0316600160c01b67ffffffffffffffff8481169182029290921790925560408051918516825260208201929092527fa085058b12d3bd9dd32f87f0105f1996237757c583720c194afdd544ab736baa910160405180910390a1505050565b6000610bf561321e565b610bfd6124b9565b610c08848484613430565b949350505050565b6000610c1e82600f54613801565b92915050565b610c2c6124b9565b60007f00000000000000000000000045e15d1e4f92f28a916f4f2971ad9adc278e148b6001600160a01b031663017e7e586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190614f8b565b601054604051636d289ce560e11b81527f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd86001600160a01b039081166004830152600160401b9092046001600160801b03166024820181905260006044830181905293945092917f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966169063da5139ca90606401602060405180830381865afa158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d849190615062565b604051633c6340f360e21b81526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8811660048301523060248301528581166044830152606482018390529192507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063f18d03cc90608401600060405180830381600087803b158015610e2157600080fd5b505af1158015610e35573d6000803e3d6000fd5b50506010805477ffffffffffffffffffffffffffffffff00000000000000001916905550506040518281526001600160a01b038416907f51396202093d5d912cb0ed4b8b0b54a6b6fca25abdb7f87eb8027dd11e8bffa99060200160405180910390a2505050565b600080610ea861321e565b610eb06124b9565b610eba848461397c565b90925090506000610ec9611f34565b915050610ed63382613801565b610f225760405162461bcd60e51b815260206004820152601760248201527f4368616d6265723a207573657220696e736f6c76656e740000000000000000006044820152606401610a59565b509250929050565b6003546001600160a01b031615610f835760405162461bcd60e51b815260206004820152601c60248201527f4368616d6265723a20616c726561647920696e697469616c697a6564000000006044820152606401610a59565b610f8f8183018361507b565b600881905560068290556007839055601080546001600160c01b0316600160c01b67ffffffffffffffff871602179055600360006004816005610fd28a82615193565b50815461010091820a6001600160a01b03818102199092169b8216029a909a17909155825491900a8089021990911698881602979097179096555050604080518082019091526001600160801b0380825260209091015250506000196009556003541690506110835760405162461bcd60e51b815260206004820152601160248201527f4368616d6265723a2062616420706169720000000000000000000000000000006044820152606401610a59565b7f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b03166000818152600e602081815260408084208054600160ff19918216811790925530865282862080549091168217905581517f8da5cb5b0000000000000000000000000000000000000000000000000000000081529151909593949392638da5cb5b92600480820193918290030181865afa15801561112f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111539190614f8b565b6001600160a01b03908116825260208201929092526040908101600020805460ff19169315159390931790925560048054925163d6d7d52560e01b8152929091169163d6d7d525916111a89160059101615253565b60408051808303816000875af11580156111c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ea91906152ee565b600f55506111f66124b9565b5050565b7f00000000000000000000000045e15d1e4f92f28a916f4f2971ad9adc278e148b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c9190614f8b565b6001600160a01b0316336001600160a01b0316146112dc5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610a59565b6001600160a01b0382166113325760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642063616c6c65650000000000000000000000000000000000006044820152606401610a59565b7f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b0316826001600160a01b03161415801561137d57506001600160a01b0382163014155b6113c95760405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642063616c6c65650000000000000000000000000000000000006044820152606401610a59565b6001600160a01b0382166000818152600e6020908152604091829020805460ff191685151590811790915591519182527f2e07fc793c38fb148513d7ce2598eade436b44d3062703d7380944a8bf6e9d18910160405180910390a25050565b60008061143361321e565b60408051808201909152600080825260208201528760005b81811015611eba5760008b8b838181106114675761146761531c565b905060200201602081019061147c9190615341565b905083602001511580156114935750600a8160ff16105b156114a8576114a06124b9565b600160208501525b60091960ff8216016115085760008060008a8a868181106114cb576114cb61531c565b90506020028101906114dd919061535e565b8101906114ea91906153a5565b9250925092506115008282610318868d8d613e3e565b505050611ea7565b60011960ff82160161156e5760008060008a8a8681811061152b5761152b61531c565b905060200281019061153d919061535e565b81019061154a91906153a5565b9250925092506115658282611560868d8d613e3e565b613430565b50505050611ea7565b60031960ff8216016115d15760008089898581811061158f5761158f61531c565b90506020028101906115a1919061535e565b8101906115ae91906153e7565b915091506115c6816115c1848b8b613e3e565b613e65565b505060018452611ea7565b60041960ff82160161163a576000808989858181106115f2576115f261531c565b9050602002810190611604919061535e565b81019061161191906153e7565b9150915061162981611624848b8b613e3e565b61397c565b600188529098509650611ea7915050565b600a1960ff82160161170f5760008060008a8a8681811061165d5761165d61531c565b905060200281019061166f919061535e565b81019061167c919061540c565b92509250925060008061168d611f34565b9150915084158061169b5750815b80156116a657508381115b80156116b957508215806116b957508281105b6117055760405162461bcd60e51b815260206004820152601460248201527f4368616d6265723a2072617465206e6f74206f6b0000000000000000000000006044820152606401610a59565b5050505050611ea7565b60171960ff82160161182d576000806000806000808d8d898181106117365761173661531c565b9050602002810190611748919061535e565b8101906117559190615441565b6040517fc0a47c930000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301528681166024830152851515604483015260ff851660648301526084820184905260a48201839052969c50949a50929850909650945092507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063c0a47c939060c401600060405180830381600087803b15801561180a57600080fd5b505af115801561181e573d6000803e3d6000fd5b50505050505050505050611ea7565b60131960ff8216016118c1576118b788888481811061184e5761184e61531c565b9050602002810190611860919061535e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d91508690508181106118a9576118a961531c565b905060200201358888613f80565b9096509450611ea7565b60141960ff821601611932576118b78888848181106118e2576118e261531c565b90506020028101906118f4919061535e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a925089915061409d9050565b60151960ff821601611a305760008060008a8a868181106119555761195561531c565b9050602002810190611967919061535e565b81019061197491906154af565b9250925092507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b031663f18d03cc8433856119b7868f8f613e3e565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015292841660248401529216604482015260648101919091526084015b600060405180830381600087803b158015611a1057600080fd5b505af1158015611a24573d6000803e3d6000fd5b50505050505050611ea7565b60161960ff821601611aca5760008060008a8a86818110611a5357611a5361531c565b9050602002810190611a65919061535e565b810190611a7291906154df565b9250925092507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b0316630fca8843843385856040518563ffffffff1660e01b81526004016119f69493929190615555565b601d1960ff821601611bad57600080611b578c8c86818110611aee57611aee61531c565b905060200201358b8b87818110611b0757611b0761531c565b9050602002810190611b19919061535e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d92508c91506141a99050565b915091508060ff16600103611b815781806020019051810190611b7a9190615062565b9750611ba6565b8060ff16600203611ba65781806020019051810190611ba091906155f1565b90985096505b5050611ea7565b60051960ff821601611cf8576000888884818110611bcd57611bcd61531c565b9050602002810190611bdf919061535e565b810190611bec9190614cca565b90507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b031663da5139ca7f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8611c7c611c4c858c8c613e3e565b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152906001614398565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260016044820152606401602060405180830381865afa158015611ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf09190615062565b965050611ea7565b60061960ff821601611d77576000888884818110611d1857611d1861531c565b9050602002810190611d2a919061535e565b810190611d379190614cca565b9050611cf0611d47828989613e3e565b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152906000614434565b601e1960ff821601611db457611daf888884818110611d9857611d9861531c565b9050602002810190611daa919061535e565b6144a9565b611ea7565b6000806000611e4f84888f8f89818110611dd057611dd061531c565b905060200201358e8e8a818110611de957611de961531c565b9050602002810190611dfb919061535e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060408051808201909152818152602081018290526060999198509650945050505050565b9250925092508096508160ff16600103611e7e5782806020019051810190611e779190615062565b9850611ea3565b8160ff16600203611ea35782806020019051810190611e9d91906155f1565b90995097505b5050505b5080611eb281615615565b91505061144b565b50815115611f27576000611ecc611f34565b915050611ed93382613801565b611f255760405162461bcd60e51b815260206004820152601760248201527f4368616d6265723a207573657220696e736f6c76656e740000000000000000006044820152606401610a59565b505b5050965096945050505050565b6004805460405163d6d7d52560e01b815260009283926001600160a01b03169163d6d7d52591611f679160059101615253565b60408051808303816000875af1158015611f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa991906152ee565b90925090508115611ff057600f8190556040518181527fa4f3423f4dd10872d278f5fffb845f3639844d295fc8f472ce40b132406d49449060200160405180910390a19091565b50600f549091565b6120006144db565b61200a6000614535565b565b6005805461201990615113565b80601f016020809104026020016040519081016040528092919081815260200182805461204590615113565b80156120925780601f1061206757610100808354040283529160200191612092565b820191906000526020600020905b81548152906001019060200180831161207557829003601f168201915b505050505081565b60015433906001600160a01b0316811461211c5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610a59565b61212581614535565b50565b7f00000000000000000000000045e15d1e4f92f28a916f4f2971ad9adc278e148b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121aa9190614f8b565b6001600160a01b0316336001600160a01b03161461220a5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610a59565b604051633de222bb60e21b81527f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd86001600160a01b0381811660048401523060248401526000927f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669190911691635662311891839063f7888aec90604401602060405180830381865afa1580156122a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c99190615062565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260006044820152606401602060405180830381865afa158015612319573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233d9190615062565b905081811161234c578061234e565b815b6040517f97da6d300000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd88116600483015230602483015233604483015260648201839052600060848301529193507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966909116906397da6d309060a40160408051808303816000875af115801561240d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243191906155f1565b50505050565b61243f61321e565b6124476124b9565b6124518282613e65565b600061245b611f34565b9150506124683382613801565b6124b45760405162461bcd60e51b815260206004820152601760248201527f4368616d6265723a207573657220696e736f6c76656e740000000000000000006044820152606401610a59565b505050565b6124c161321e565b6040805160608101825260105467ffffffffffffffff8082168084526001600160801b03600160401b8404166020850152600160c01b909204169282019290925290600090612510904261562e565b90508060000361251e575050565b67ffffffffffffffff4216825260408051808201909152600b546001600160801b038082168352600160801b90910416602082018190526000036125cd575050805160108054602084015160409094015167ffffffffffffffff908116600160c01b026001600160c01b036001600160801b03909616600160401b027fffffffffffffffff00000000000000000000000000000000000000000000000090931691909416171792909216179055565b6000670de0b6b3a76400006126108461260a876040015167ffffffffffffffff1686600001516001600160801b031661455b90919063ffffffff16565b9061455b565b61261a9190615641565b8251909150612636906001600160801b03908116908316613278565b6001600160801b039081168352602085015161265791908116908316613278565b6001600160801b0390811660208681018290528451858201518416600160801b0290841617600b558651601080546040808b015167ffffffffffffffff908116600160c01b026001600160c01b03600160401b9098027fffffffffffffffff00000000000000000000000000000000000000000000000090941691909516179190911794909416919091179055905191831682527f757b29336b38e0454cafcaa1fee2fc9e8677248c1cb1ba37dd3e2c60a87ab3ab910160405180910390a150505050565b6127246144db565b600180546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff1990911681179091556127626000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6127a26144db565b6001600160a01b0381166127f85760405162461bcd60e51b815260206004820152601360248201527f63616e6e6f7420626520302061646472657373000000000000000000000000006044820152606401610a59565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f8bc25725ca4ea10a36558b30cebb3baa6f7551e3fe58208d839e44189bdbe3e090600090a250565b7f00000000000000000000000045e15d1e4f92f28a916f4f2971ad9adc278e148b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d19190614f8b565b6001600160a01b0316336001600160a01b0316146129315760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610a59565b6040805180820182526001600160801b038481168083529084166020928301819052600160801b810282176009558351918252918101919091527ff1fce436bc22563026222b3b2bdc088cb69d25192974264114df12ab812628f6910160405180910390a15050565b6129a261321e565b60006129ac611f34565b9150506129b76124b9565b6003546040517f4ffe34db0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000918291829182917f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd64396690911690634ffe34db906024016040805180830381865afa158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190615655565b9050895160005b81811015612d0d5760008c8281518110612a8a57612a8a61531c565b60200260200101519050612a9e8189613801565b612cfa576001600160a01b0381166000908152600d60205260408120548d5181908f9086908110612ad157612ad161531c565b602002602001015111612afd578d8481518110612af057612af061531c565b6020026020010151612aff565b805b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152909250600090612b38908483614398565b90506000612b80612b54670de0b6b3a7640000620186a06156b4565b612b6d8e61260a6007548761455b90919063ffffffff16565b612b779190615641565b89906000614434565b9050612b8c8385614567565b6001600160a01b0386166000908152600d6020908152604080832093909355600c90522054612bbb9082614567565b6001600160a01b0386166000908152600c60205260409020558e6001600160a01b0316856001600160a01b03167f77f19d2489899bac4076fc1c140f57208d84c91aca70c5bfce9460130bcc5c5583604051612c1991815260200190565b60405180910390a360408051838152602081018690526001600160a01b0387169133917fa7489af36ce0dad0b30ae45d2d29c07e996839e7ad59e955a9d33ec30372fdeb910160405180910390a38e6001600160a01b0316856001600160a01b0316336001600160a01b03167f66b108dc29b952efc76dccea9b82dce6b59fab4d9af73d8dcc9789afcad5daf6848689604051612cc9939291909283526020830191909152604082015260600190565b60405180910390a4612cdb8b82613278565b9a50612ce78a83613278565b9950612cf38985613278565b9850505050505b5080612d0581615615565b915050612a6e565b5083600003612d5e5760405162461bcd60e51b815260206004820152601860248201527f4368616d6265723a20616c6c2061726520736f6c76656e7400000000000000006044820152606401610a59565b600b54612d74906001600160801b031685614567565b600b80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166001600160801b039283161790819055612dbd91600160801b9091041684614567565b600b80546001600160801b03928316600160801b029216919091179055600a54612de79086614567565b600a8190555060006064612e23600a61260a88620186a0612e136007548c61455b90919063ffffffff16565b612e1d9190615641565b90614567565b612e2d9190615641565b9050612e398582613278565b601054909550612e5990600160401b90046001600160801b031682613278565b601080546001600160801b0392909216600160401b0277ffffffffffffffffffffffffffffffff00000000000000001990921691909117905550604051636d289ce560e11b81526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd88116600483015260248201869052600160448301526000917f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063da5139ca90606401602060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f509190615062565b600354604051633c6340f360e21b81526001600160a01b0391821660048201523060248201528c82166044820152606481018990529192507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966169063f18d03cc90608401600060405180830381600087803b158015612fce57600080fd5b505af1158015612fe2573d6000803e3d6000fd5b505050506001600160a01b038916156130a557886001600160a01b031663a5d4096b600360009054906101000a90046001600160a01b03167f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd833858b8e6040518763ffffffff1660e01b8152600401613060969594939291906156cb565b60408051808303816000875af115801561307e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a291906155f1565b50505b604051636d289ce560e11b81526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd88116600483015260248201879052600160448301527f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966169063da5139ca90606401602060405180830381865afa158015613139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315d9190615062565b604051633c6340f360e21b81526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd881166004830152336024830152306044830152606482018390529192507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063f18d03cc90608401600060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b50505050505050505050505050505050565b600154600160a01b900460ff161561200a5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a59565b6000613284828461504f565b9392505050565b801561337b57604051633de222bb60e21b81526001600160a01b0385811660048301523060248301526133279184917f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966169063f7888aec90604401602060405180830381865afa158015613303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1d9190615062565b8311156133765760405162461bcd60e51b815260206004820152601660248201527f4368616d6265723a20536b696d20746f6f206d756368000000000000000000006044820152606401610a59565b612431565b604051633c6340f360e21b81526001600160a01b038581166004830152336024830152306044830152606482018590527f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966169063f18d03cc90608401600060405180830381600087803b1580156133f157600080fd5b505af1158015613405573d6000803e3d6000fd5b5050505050505050565b60006127106134266312e687c061ffff8516614fbe565b610c1e9190615000565b600061343a61321e565b60408051808201909152600b546001600160801b038082168352600160801b90910416602082015261346e90836001614573565b81516020928301516001600160801b03908116600160801b02911617600b556001600160a01b0386166000908152600d9092526040909120549091506134b49083614567565b6001600160a01b038581166000908152600d6020526040808220939093559151636d289ce560e11b81527f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd88216600482015260248101849052600160448201527f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063da5139ca90606401602060405180830381865afa15801561355f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135839190615062565b90506135d96001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8167f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966846145dc565b7f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b031663f18d03cc7f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8866136345733613656565b7f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439665b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015230604482015260648101849052608401600060405180830381600087803b1580156136ab57600080fd5b505af11580156136bf573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd64396681166004830152600060248301527f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd816925063095ea7b391506044016020604051808303816000875af1158015613752573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137769190615717565b50846001600160a01b03168461378c57336137ae565b7f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439665b6001600160a01b03167fa7489af36ce0dad0b30ae45d2d29c07e996839e7ad59e955a9d33ec30372fdeb84866040516137f1929190918252602082015260400190565b60405180910390a3509392505050565b6001600160a01b0382166000908152600d602052604081205480820361382b576001915050610c1e565b6001600160a01b0384166000908152600c60205260408120549081900361385757600092505050610c1e565b60408051808201909152600b546001600160801b03808216808452600160801b90920416602083018190529061389490879061260a90879061455b565b61389e9190615641565b6003546006546001600160a01b037f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439668116926356623118929116906138fc9061260a6138f5620186a0670de0b6b3a7640000615641565b899061455b565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260006044820152606401602060405180830381865afa15801561394c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139709190615062565b10159695505050505050565b60008061398761321e565b6000620186a06139a26008548661455b90919063ffffffff16565b6139ac9190615641565b90506139eb6139bb8583613278565b60408051808201909152600b546001600160801b038082168352600160801b909104166020820152906001614748565b81516020909201516001600160801b03908116600160801b02921691909117600b559250613a636001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8167f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966866145dc565b604080518082019091526009546001600160801b03808216808452600160801b90920481166020840152600b54161115613adf5760405162461bcd60e51b815260206004820152601460248201527f426f72726f77204c696d697420726561636865640000000000000000000000006044820152606401610a59565b601054613b0090600160401b90046001600160801b03908116908416613278565b601080546001600160801b0392909216600160401b0277ffffffffffffffffffffffffffffffff000000000000000019909216919091179055336000908152600d6020526040812054613b539086613278565b905081602001516001600160801b0316811115613bb25760405162461bcd60e51b815260206004820152601460248201527f426f72726f77204c696d697420726561636865640000000000000000000000006044820152606401610a59565b336000908152600d602052604080822083905551636d289ce560e11b81526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8811660048301526024820189905260448201929092527f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063da5139ca90606401602060405180830381865afa158015613c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c7e9190615062565b604051633c6340f360e21b81526001600160a01b037f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8811660048301523060248301528981166044830152606482018390529195507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063f18d03cc90608401600060405180830381600087803b158015613d1b57600080fd5b505af1158015613d2f573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd64396681166004830152600060248301527f000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd816925063095ea7b391506044016020604051808303816000875af1158015613dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de69190615717565b506001600160a01b038716337f1298465c3dfc2aaba2a18da010d6b969a7e06f6f9dbcc96798660535389d1e7c613e1d8987613278565b60408051918252602082018a90520160405180910390a35050509250929050565b600080841215613e5d576000198414613e575781610c08565b82610c08565b509192915050565b613e6d61321e565b336000908152600c6020526040902054613e879082614567565b336000908152600c6020526040902055600a54613ea49082614567565b600a556040518181526001600160a01b0383169033907f77f19d2489899bac4076fc1c140f57208d84c91aca70c5bfce9460130bcc5c559060200160405180910390a3600354604051633c6340f360e21b81526001600160a01b0391821660048201523060248201528382166044820152606481018390527f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439669091169063f18d03cc90608401600060405180830381600087803b158015613f6457600080fd5b505af1158015613f78573d6000803e3d6000fd5b505050505050565b600080613f8b61321e565b60008060008089806020019051810190613fa59190615734565b9350935093509350613fb8828989613e3e565b9150613fc5818989613e3e565b6040517f02b9446c0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152336024830152858116604483015260648201859052608482018390529192507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966909116906302b9446c908b9060a401604080518083038185885af1158015614067573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061408c91906155f1565b955095505050505094509492505050565b6000806140a861321e565b600080600080888060200190518101906140c29190615734565b93509350935093507f000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd6439666001600160a01b03166397da6d30853386614107878e8e613e3e565b614112878f8f613e3e565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015293851660248501529390911660448301526064820152608481019190915260a40160408051808303816000875af1158015614175573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061419991906155f1565b9550955050505050935093915050565b606060006141b561321e565b6000806000806000898060200190518101906141d19190615787565b945094509450945094508280156141e6575081155b156142145783896040516020016141fe929190615845565b604051602081830303815290604052935061426d565b8215801561421f5750815b156142375783886040516020016141fe929190615845565b8280156142415750815b1561426d5783898960405160200161425b93929190615867565b60405160208183030381529060405293505b6001600160a01b0385166000908152600e602052604090205460ff16156142d65760405162461bcd60e51b815260206004820152601360248201527f4368616d6265723a2063616e27742063616c6c000000000000000000000000006044820152606401610a59565b600080866001600160a01b03168d876040516142f2919061588e565b60006040518083038185875af1925050503d806000811461432f576040519150601f19603f3d011682016040523d82523d6000602084013e614334565b606091505b5091509150816143865760405162461bcd60e51b815260206004820152601460248201527f4368616d6265723a2063616c6c206661696c65640000000000000000000000006044820152606401610a59565b9c919b50909950505050505050505050565b600083602001516001600160801b03166000036143b6575081613284565b602084015184516001600160801b03918216916143d49116856156b4565b6143de9190615641565b905081801561441c57508284600001516001600160801b031685602001516001600160801b03168361441091906156b4565b61441a9190615641565b105b15613284578061442b81615615565b95945050505050565b82516000906001600160801b0316810361444f575081613284565b835160208501516001600160801b039182169161446d9116856156b4565b6144779190615641565b905081801561441c57508284602001516001600160801b031685600001516001600160801b03168361441091906156b4565b6000808080806144bb86880188614ed9565b945094509450945094506144d2858585858561299a565b50505050505050565b6000546001600160a01b0316331461200a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a59565b6001805473ffffffffffffffffffffffffffffffffffffffff191690556121258161479d565b600061328482846156b4565b6000613284828461562e565b60408051808201909152600080825260208201526000614594858585614398565b905080856000018181516145a891906158aa565b6001600160801b03169052506020850180518591906145c89083906158aa565b6001600160801b0316905250939492505050565b80158061466f57506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061466d9190615062565b155b6146e15760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610a59565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b1790526124b49084906147fa565b60408051808201909152600080825260208201526000614769858585614434565b9050838560000181815161477d91906158ca565b6001600160801b03169052506020850180518291906145c89083906158ca565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600061484f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148e29092919063ffffffff16565b90508051600014806148705750808060200190518101906148709190615717565b6124b45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a59565b6060610c08848460008585600080866001600160a01b03168587604051614909919061588e565b60006040518083038185875af1925050503d8060008114614946576040519150601f19603f3d011682016040523d82523d6000602084013e61494b565b606091505b509150915061495c87838387614967565b979650505050505050565b606083156149d65782516000036149cf576001600160a01b0385163b6149cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a59565b5081610c08565b610c0883838151156149eb5781518083602001fd5b8060405162461bcd60e51b8152600401610a599190614cb7565b6001600160a01b038116811461212557600080fd5b801515811461212557600080fd5b600080600060608486031215614a3d57600080fd5b8335614a4881614a05565b92506020840135614a5881614a1a565b929592945050506040919091013590565b600060208284031215614a7b57600080fd5b813561ffff8116811461328457600080fd5b600060208284031215614a9f57600080fd5b813561328481614a05565b60008060408385031215614abd57600080fd5b8235614ac881614a05565b946020939093013593505050565b60008060208385031215614ae957600080fd5b823567ffffffffffffffff80821115614b0157600080fd5b818501915085601f830112614b1557600080fd5b813581811115614b2457600080fd5b866020828501011115614b3657600080fd5b60209290920196919550909350505050565b60008060408385031215614b5b57600080fd5b8235614b6681614a05565b91506020830135614b7681614a1a565b809150509250929050565b60008083601f840112614b9357600080fd5b50813567ffffffffffffffff811115614bab57600080fd5b6020830191508360208260051b8501011115614bc657600080fd5b9250929050565b60008060008060008060608789031215614be657600080fd5b863567ffffffffffffffff80821115614bfe57600080fd5b614c0a8a838b01614b81565b90985096506020890135915080821115614c2357600080fd5b614c2f8a838b01614b81565b90965094506040890135915080821115614c4857600080fd5b50614c5589828a01614b81565b979a9699509497509295939492505050565b60005b83811015614c82578181015183820152602001614c6a565b50506000910152565b60008151808452614ca3816020860160208601614c67565b601f01601f19169290920160200192915050565b6020815260006132846020830184614c8b565b600060208284031215614cdc57600080fd5b5035919050565b6001600160801b038116811461212557600080fd5b60008060408385031215614d0b57600080fd5b8235614d1681614ce3565b91506020830135614b7681614ce3565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614d6557614d65614d26565b604052919050565b600067ffffffffffffffff821115614d8757614d87614d26565b5060051b60200190565b600082601f830112614da257600080fd5b81356020614db7614db283614d6d565b614d3c565b82815260059290921b84018101918181019086841115614dd657600080fd5b8286015b84811015614dfa578035614ded81614a05565b8352918301918301614dda565b509695505050505050565b600082601f830112614e1657600080fd5b81356020614e26614db283614d6d565b82815260059290921b84018101918181019086841115614e4557600080fd5b8286015b84811015614dfa5780358352918301918301614e49565b600067ffffffffffffffff821115614e7a57614e7a614d26565b50601f01601f191660200190565b600082601f830112614e9957600080fd5b8135614ea7614db282614e60565b818152846020838601011115614ebc57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215614ef157600080fd5b853567ffffffffffffffff80821115614f0957600080fd5b614f1589838a01614d91565b96506020880135915080821115614f2b57600080fd5b614f3789838a01614e05565b955060408801359150614f4982614a05565b909350606087013590614f5b82614a05565b90925060808701359080821115614f7157600080fd5b50614f7e88828901614e88565b9150509295509295909350565b600060208284031215614f9d57600080fd5b815161328481614a05565b634e487b7160e01b600052601160045260246000fd5b67ffffffffffffffff818116838216028082169190828114614fe257614fe2614fa8565b505092915050565b634e487b7160e01b600052601260045260246000fd5b600067ffffffffffffffff8084168061501b5761501b614fea565b92169190910492915050565b67ffffffffffffffff81811683821601908082111561504857615048614fa8565b5092915050565b80820180821115610c1e57610c1e614fa8565b60006020828403121561507457600080fd5b5051919050565b600080600080600080600060e0888a03121561509657600080fd5b87356150a181614a05565b965060208801356150b181614a05565b9550604088013567ffffffffffffffff808211156150ce57600080fd5b6150da8b838c01614e88565b965060608a0135915080821682146150f157600080fd5b509699959850939660808101359560a0820135955060c0909101359350915050565b600181811c9082168061512757607f821691505b60208210810361514757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156124b457600081815260208120601f850160051c810160208610156151745750805b601f850160051c820191505b81811015613f7857828155600101615180565b815167ffffffffffffffff8111156151ad576151ad614d26565b6151c1816151bb8454615113565b8461514d565b602080601f8311600181146151f657600084156151de5750858301515b600019600386901b1c1916600185901b178555613f78565b600085815260208120601f198616915b8281101561522557888601518255948401946001909101908401615206565b50858210156152435787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083526000845461526781615113565b8084870152604060018084166000811461528857600181146152a2576152d0565b60ff1985168984015283151560051b8901830195506152d0565b896000528660002060005b858110156152c85781548b82018601529083019088016152ad565b8a0184019650505b509398975050505050505050565b80516152e981614a1a565b919050565b6000806040838503121561530157600080fd5b825161530c81614a1a565b6020939093015192949293505050565b634e487b7160e01b600052603260045260246000fd5b60ff8116811461212557600080fd5b60006020828403121561535357600080fd5b813561328481615332565b6000808335601e1984360301811261537557600080fd5b83018035915067ffffffffffffffff82111561539057600080fd5b602001915036819003821315614bc657600080fd5b6000806000606084860312156153ba57600080fd5b8335925060208401356153cc81614a05565b915060408401356153dc81614a1a565b809150509250925092565b600080604083850312156153fa57600080fd5b823591506020830135614b7681614a05565b60008060006060848603121561542157600080fd5b833561542c81614a1a565b95602085013595506040909401359392505050565b60008060008060008060c0878903121561545a57600080fd5b863561546581614a05565b9550602087013561547581614a05565b9450604087013561548581614a1a565b9350606087013561549581615332565b9598949750929560808101359460a0909101359350915050565b6000806000606084860312156154c457600080fd5b83356154cf81614a05565b92506020840135614a5881614a05565b6000806000606084860312156154f457600080fd5b83356154ff81614a05565b9250602084013567ffffffffffffffff8082111561551c57600080fd5b61552887838801614d91565b9350604086013591508082111561553e57600080fd5b5061554b86828701614e05565b9150509250925092565b6000608082016001600160a01b0380881684526020818816818601526080604086015282875180855260a087019150828901945060005b818110156155aa57855185168352948301949183019160010161558c565b5050858103606087015286518082529082019350915080860160005b838110156155e2578151855293820193908201906001016155c6565b50929998505050505050505050565b6000806040838503121561560457600080fd5b505080516020909101519092909150565b60006001820161562757615627614fa8565b5060010190565b81810381811115610c1e57610c1e614fa8565b60008261565057615650614fea565b500490565b60006040828403121561566757600080fd5b6040516040810181811067ffffffffffffffff8211171561568a5761568a614d26565b604052825161569881614ce3565b815260208301516156a881614ce3565b60208201529392505050565b8082028115828204841417610c1e57610c1e614fa8565b60006001600160a01b038089168352808816602084015280871660408401525084606083015283608083015260c060a083015261570b60c0830184614c8b565b98975050505050505050565b60006020828403121561572957600080fd5b815161328481614a1a565b6000806000806080858703121561574a57600080fd5b845161575581614a05565b602086015190945061576681614a05565b6040860151606090960151949790965092505050565b80516152e981615332565b600080600080600060a0868803121561579f57600080fd5b85516157aa81614a05565b602087015190955067ffffffffffffffff8111156157c757600080fd5b8601601f810188136157d857600080fd5b80516157e6614db282614e60565b8181528960208385010111156157fb57600080fd5b61580c826020830160208601614c67565b955061581d915050604087016152de565b925061582b606087016152de565b91506158396080870161577c565b90509295509295909350565b60008351615857818460208801614c67565b9190910191825250602001919050565b60008451615879818460208901614c67565b91909101928352506020820152604001919050565b600082516158a0818460208701614c67565b9190910192915050565b6001600160801b0382811682821603908082111561504857615048614fa8565b6001600160801b0381811683821601908082111561504857615048614fa856fea2646970667358221220fe38e6173e208d58a4aef3ddca55a4b42f09c43eca87ea6b80ee8386e2903b5764736f6c63430008130033

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

000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8

-----Decoded View---------------
Arg [0] : bentoBox_ (address): 0xF5BCE5077908a1b7370B9ae04AdC565EBd643966
Arg [1] : senUSD_ (address): 0x922406EAFC3CcEb32b0256F287fB977c426EDbd8

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966
Arg [1] : 000000000000000000000000922406eafc3cceb32b0256f287fb977c426edbd8


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.