ETH Price: $2,684.12 (+10.28%)
Gas: 1 Gwei

Contract

0x528D205b9521a5e5193b3da9be940c6A18D32a4d
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040147106602022-05-04 11:27:22827 days ago1651663642IN
 Create: LoanTokenLogicStandard
0 ETH0.131338931

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LoanTokenLogicStandard

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license
File 1 of 18 : LoanTokenLogicStandard.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;

import "AdvancedToken.sol";
import "StorageExtension.sol";
import "IBZx.sol";
import "IPriceFeeds.sol";

contract LoanTokenLogicStandard is AdvancedToken, StorageExtension {
    using SafeMath for uint256;
    using SignedSafeMath for int256;


    //// CONSTANTS ////

    uint256 public constant VERSION = 7;

    address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF; // mainnet
    //address internal constant arbitraryCaller = 0x81e7dddFAD37E6FAb0eccE95f0B508fd40996e6d; // bsc
    // address internal constant arbitraryCaller = 0x81e7dddFAD37E6FAb0eccE95f0B508fd40996e6d; // polygon
    // address internal constant arbitraryCaller = 0x01207468F48822f8535BC96D1Cf18EddDE4A2392; // arbitrum

    address public constant bZxContract = 0xD8Ee69652E4e4838f2531732a46d1f7F584F0b7f; // mainnet
    address public constant wethToken = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // mainnet

    //address public constant bZxContract = 0x5cfba2639a3db0D9Cc264Aa27B2E6d134EeA486a; // kovan
    //address public constant wethToken = 0xd0A1E359811322d97991E03f863a0C30C2cF029C; // kovan

    //address public constant bZxContract = 0xD154eE4982b83a87b0649E5a7DDA1514812aFE1f; // bsc
    //address public constant wethToken = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; // bsc

    // address public constant bZxContract = 0x059D60a9CEfBc70b9Ea9FFBb9a041581B1dFA6a8; // polygon
    // address public constant wethToken = 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270; // polygon

    // address public constant bZxContract = 0x37407F3178ffE07a6cF5C847F8f680FEcf319FAB; // arbitrum
    // address public constant wethToken = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; // arbitrum

    bytes32 internal constant iToken_ProfitSoFar = 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6;          // keccak256("iToken_ProfitSoFar")
    bytes32 internal constant iToken_LowerAdminAddress = 0x7ad06df6a0af6bd602d90db766e0d5f253b45187c3717a0f9026ea8b10ff0d4b;    // keccak256("iToken_LowerAdminAddress")
    bytes32 internal constant iToken_LowerAdminContract = 0x34b31cff1dbd8374124bd4505521fc29cab0f9554a5386ba7d784a4e611c7e31;   // keccak256("iToken_LowerAdminContract")

    constructor()
        public
    {
        renounceOwnership();
    }

    function()
        external
        payable
    {
        require(msg.sender == wethToken, "fallback not allowed");
    }

    /* Public functions */

    function mint(
        address receiver,
        uint256 depositAmount)
        external
        nonReentrant
        pausable
        returns (uint256) // mintAmount
    {
        return _mintToken(
            receiver,
            depositAmount
        );
    }

    function burn(
        address receiver,
        uint256 burnAmount)
        external
        nonReentrant
        pausable
        returns (uint256 loanAmountPaid)
    {
        loanAmountPaid = _burnToken(
            burnAmount
        );

        if (loanAmountPaid != 0) {
            _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, "5");
        }
    }

    function flashBorrow(
        uint256 borrowAmount,
        address borrower,
        address target,
        string calldata signature,
        bytes calldata data)
        external
        payable
        nonReentrant
        pausable
        returns (bytes memory)
    {
        require(borrowAmount != 0, "38");

        _settleInterest(0);

        // save before balances
        uint256 beforeEtherBalance = address(this).balance.sub(msg.value);
        uint256 beforeAssetsBalance = _underlyingBalance()
            .add(_totalAssetBorrowStored());

        // lock totalAssetSupply for duration of flash loan
        _flTotalAssetSupply = beforeAssetsBalance;

        // transfer assets to calling contract
        _safeTransfer(loanTokenAddress, borrower, borrowAmount, "39");

        emit FlashBorrow(borrower, target, loanTokenAddress, borrowAmount);

        bytes memory callData;
        if (bytes(signature).length == 0) {
            callData = data;
        } else {
            callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
        }

        // arbitrary call
        (bool success, bytes memory returnData) = arbitraryCaller.call.value(msg.value)(
            abi.encodeWithSelector(
                0xde064e0d, // sendCall(address,bytes)
                target,
                callData
            )
        );
        require(success, "call failed");

        // unlock totalAssetSupply
        _flTotalAssetSupply = 0;
		
		// pay flash borrow fees
        IBZx(bZxContract).payFlashBorrowFees(
            borrower,
            borrowAmount,
            flashBorrowFeePercent
        );
	
        // verifies return of flash loan
        require(
            address(this).balance >= beforeEtherBalance &&
            _underlyingBalance()
                .add(_totalAssetBorrowStored()) >= beforeAssetsBalance,
            "40"
        );

        return returnData;
    }

    function borrow(
        bytes32 loanId,                 // 0 if new loan
        uint256 withdrawAmount,
        uint256 initialLoanDuration,    // duration in seconds
        uint256 collateralTokenSent,    // if 0, loanId must be provided; any ETH sent must equal this value
        address collateralTokenAddress, // if address(0), this means ETH and ETH must be sent with the call or loanId must be provided
        address borrower,
        address receiver,
        bytes memory /*loanDataBytes*/) // arbitrary order data
        public
        payable
        nonReentrant
        pausable
        returns (IBZx.LoanOpenData memory)
    {
        return _borrow(
            loanId,
            withdrawAmount,
            initialLoanDuration,
            collateralTokenSent,
            collateralTokenAddress,
            borrower,
            receiver,
            ""
        );
    }

    // Called to borrow and immediately get into a position
    function marginTrade(
        bytes32 loanId,                 // 0 if new loan
        uint256 leverageAmount,
        uint256 loanTokenSent,
        uint256 collateralTokenSent,
        address collateralTokenAddress,
        address trader,
        bytes memory loanDataBytes)     // arbitrary order data
        public
        payable
        nonReentrant
        pausable
        returns (IBZx.LoanOpenData memory)
    {
        return _marginTrade(
            loanId,
            leverageAmount,
            loanTokenSent,
            collateralTokenSent,
            collateralTokenAddress,
            trader,
            loanDataBytes
        );
    }

    function transfer(
        address _to,
        uint256 _value)
        external
        returns (bool)
    {
        return _internalTransferFrom(
            msg.sender,
            _to,
            _value,
            uint256(-1)
        );
    }

    function transferFrom(
        address _from,
        address _to,
        uint256 _value)
        external
        returns (bool)
    {
        return _internalTransferFrom(
            _from,
            _to,
            _value,
            allowed[_from][msg.sender]
            /*IBZx(bZxContract).isLoanPool(msg.sender) ?
                uint256(-1) :
                allowed[_from][msg.sender]*/
        );
    }

    function _internalTransferFrom(
        address _from,
        address _to,
        uint256 _value,
        uint256 _allowanceAmount)
        internal
        returns (bool)
    {
        if (_allowanceAmount != uint256(-1)) {
            allowed[_from][msg.sender] = _allowanceAmount.sub(_value, "14");
        }

        require(_to != address(0), "15");

        uint256 _balancesFrom = balances[_from];
        uint256 _balancesFromNew = _balancesFrom
            .sub(_value, "16");
        balances[_from] = _balancesFromNew;

        uint256 _balancesTo = balances[_to];
        uint256 _balancesToNew = _balancesTo
            .add(_value);
        balances[_to] = _balancesToNew;

        // handle checkpoint update
        uint256 _currentPrice = tokenPrice();

        _updateCheckpoints(
            _from,
            _balancesFrom,
            _balancesFromNew,
            _currentPrice
        );
        _updateCheckpoints(
            _to,
            _balancesTo,
            _balancesToNew,
            _currentPrice
        );

        emit Transfer(_from, _to, _value);
        return true;
    }

    function _updateCheckpoints(
        address _user,
        uint256 _oldBalance,
        uint256 _newBalance,
        uint256 _currentPrice)
        internal
    {
        bytes32 slot = keccak256(
            abi.encodePacked(_user, iToken_ProfitSoFar)
        );

        int256 _currentProfit;
        if (_newBalance == 0) {
            _currentPrice = 0;
        } else if (_oldBalance != 0) {
            _currentProfit = _profitOf(
                slot,
                _oldBalance,
                _currentPrice,
                checkpointPrices_[_user]
            );
        }

        assembly {
            sstore(slot, _currentProfit)
        }

        checkpointPrices_[_user] = _currentPrice;
    }

    /* Public View functions */

    function profitOf(
        address user)
        public
        view
        returns (int256)
    {
        bytes32 slot = keccak256(
            abi.encodePacked(user, iToken_ProfitSoFar)
        );

        return _profitOf(
            slot,
            balances[user],
            tokenPrice(),
            checkpointPrices_[user]
        );
    }

    function _profitOf(
        bytes32 slot,
        uint256 _balance,
        uint256 _currentPrice,
        uint256 _checkpointPrice)
        internal
        view
        returns (int256 profitSoFar)
    {
        if (_checkpointPrice == 0) {
            return 0;
        }

        assembly {
            profitSoFar := sload(slot)
        }

        profitSoFar = int256(_currentPrice)
            .sub(int256(_checkpointPrice))
            .mul(int256(_balance))
            .div(sWEI_PRECISION)
            .add(profitSoFar);
    }

    function tokenPrice()
        public
        view
        returns (uint256) // price
    {
        return _tokenPrice(_totalAssetSupply(totalAssetBorrow()));
    }

    function checkpointPrice(
        address _user)
        public
        view
        returns (uint256) // price
    {
        return checkpointPrices_[_user];
    }

    // the current rate being paid by borrowers in active loans
    function borrowInterestRate()
        public
        view
        returns (uint256)
    {
        return _nextBorrowInterestRate(
            _totalAssetBorrowStored(),
            0,
            poolTWAI()
        );
    }

    // the minimum rate that new and existing borrowers will pay after the next borrow
    function nextBorrowInterestRate(
        uint256 borrowAmount)
        external
        view
        returns (uint256)
    {
        return _nextBorrowInterestRate(
            totalAssetBorrow(),
            borrowAmount,
            poolTWAI()
        );
    }

    // the current rate being received by suppliers
    function supplyInterestRate()
        external
        view
        returns (uint256)
    {
        uint256 assetBorrow = _totalAssetBorrowStored();
        return _nextSupplyInterestRate(
            _nextBorrowInterestRate(assetBorrow, 0, poolTWAI()),
            assetBorrow,
            _totalAssetSupply(assetBorrow)
        );
    }

    // the minimum rate new and existing suppliers will receive after the next supply
    function nextSupplyInterestRate(
        int256 supplyAmount)
        external
        view
        returns (uint256)
    {
        uint256 assetBorrow = totalAssetBorrow();
        uint256 totalSupply = _totalAssetSupply(assetBorrow);

        if(supplyAmount >= 0)
            totalSupply = totalSupply.add(uint256(supplyAmount));
        else
            totalSupply = totalSupply.sub(uint256(-supplyAmount));

        return _nextSupplyInterestRate(
            _nextBorrowInterestRate(assetBorrow, 0, poolTWAI()),
            assetBorrow,
            totalSupply
        );
    }


    function totalAssetBorrow()
        public
        view
        returns (uint256)
    {
        return IBZx(bZxContract).getTotalPrincipal(
            address(this),
            address(0) // loanTokenAddress (depreciated)
        );
    }

    function _totalAssetBorrowStored()
        internal
        view
        returns (uint256)
    {
        return IBZx(bZxContract).getPoolPrincipalStored(address(this));
    }

    function totalAssetSupply()
        external
        view
        returns (uint256)
    {
        return _totalAssetSupply(totalAssetBorrow());
    }

    function poolLastInterestRate()
        public
        view
        returns (uint256)
    {
        return IBZx(bZxContract).getPoolLastInterestRate(address(this));
    }

    function poolTWAI()
        public
        view
        returns (uint256)
    {
        return IBZx(bZxContract).getTWAI(address(this));
    }

    // returns the user's balance of underlying token
    function assetBalanceOf(
        address _owner)
        external
        view
        returns (uint256)
    {
        return balanceOf(_owner)
            .mul(tokenPrice())
            .div(WEI_PRECISION);
    }

    function getDepositAmountForBorrow(
        uint256 borrowAmount,
        uint256 initialLoanDuration,        // duration in seconds
        address collateralTokenAddress)     // address(0) means ETH
        external
        view
        returns (uint256) // depositAmount
    {
        if (borrowAmount != 0) {
            if (borrowAmount <= _underlyingBalance()) {
                if (collateralTokenAddress == address(0)) {
                    collateralTokenAddress = wethToken;
                }
                return IBZx(bZxContract).getRequiredCollateralByParams(
                    loanParamsIds[uint256(keccak256(abi.encodePacked(
                        collateralTokenAddress,
                        true
                    )))],
                    borrowAmount
                ).add(10); // some dust to compensate for rounding errors
            }
        }
    }

    function getBorrowAmountForDeposit(
        uint256 depositAmount,
        uint256 initialLoanDuration,        // duration in seconds
        address collateralTokenAddress)     // address(0) means ETH
        external
        view
        returns (uint256 borrowAmount)
    {
        if (depositAmount != 0) {
            if (collateralTokenAddress == address(0)) {
                collateralTokenAddress = wethToken;
            }
            borrowAmount = IBZx(bZxContract).getBorrowAmountByParams(
                loanParamsIds[uint256(keccak256(abi.encodePacked(
                    collateralTokenAddress,
                    true
                )))],
                depositAmount
            );

            if (borrowAmount > _underlyingBalance()) {
                borrowAmount = 0;
            }
        }
    }

    function getPoolUtilization()
        external
        view
        returns (uint256)
    {
        uint256 totalBorrow = totalAssetBorrow();
        return _utilizationRate(
            totalBorrow,
            _totalAssetSupply(totalBorrow)
        );
    }

    /* Internal functions */

    function _mintToken(
        address receiver,
        uint256 depositAmount)
        internal
        pausable
        returns (uint256 mintAmount)
    {
        require (depositAmount != 0, "17");

        _settleInterest(0);

        uint256 currentPrice = _tokenPrice(_totalAssetSupply(_totalAssetBorrowStored()));
        mintAmount = depositAmount
            .mul(WEI_PRECISION)
            .div(currentPrice);

        if (msg.value == 0) {
            _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, "18");
        } else {
            require(msg.value == depositAmount, "18");
            IWeth(wethToken).deposit.value(depositAmount)();
        }

        _updateCheckpoints(
            receiver,
            balances[receiver],
            _mint(receiver, mintAmount, depositAmount, currentPrice), // newBalance
            currentPrice
        );
    }

    function _burnToken(
        uint256 burnAmount)
        internal
        pausable
        returns (uint256 loanAmountPaid)
    {
        require(burnAmount != 0, "19");

        _settleInterest(0);

        if (burnAmount > balanceOf(msg.sender)) {
            require(burnAmount == uint256(-1), "32");
            burnAmount = balanceOf(msg.sender);
        }

        uint256 currentPrice = _tokenPrice(_totalAssetSupply(_totalAssetBorrowStored()));

        uint256 loanAmountOwed = burnAmount
            .mul(currentPrice)
            .div(WEI_PRECISION);
        uint256 loanAmountAvailableInContract = _underlyingBalance();

        loanAmountPaid = loanAmountOwed;
        require(loanAmountPaid <= loanAmountAvailableInContract, "37");

        _updateCheckpoints(
            msg.sender,
            balances[msg.sender],
            _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice), // newBalance
            currentPrice
        );
    }

    function _borrow(
        bytes32 loanId,                 // 0 if new loan
        uint256 withdrawAmount,
        uint256 initialLoanDuration,    // duration in seconds
        uint256 collateralTokenSent,    // if 0, loanId must be provided; any ETH sent must equal this value
        address collateralTokenAddress, // if address(0), this means ETH and ETH must be sent with the call or loanId must be provided
        address borrower,
        address receiver,
        bytes memory /*loanDataBytes*/) // arbitrary order data
        internal
        pausable
        returns (IBZx.LoanOpenData memory)
    {
        require(withdrawAmount != 0, "6");

        require(msg.value == 0 || msg.value == collateralTokenSent, "7");
        require(collateralTokenSent != 0 || loanId != 0, "8");
        require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, "9");

        // ensures authorized use of existing loan
        require(loanId == 0 || msg.sender == borrower, "13");

        _settleInterest(loanId);

        if (loanId == 0) {
            loanId = keccak256(abi.encodePacked(
                collateralTokenAddress,
                address(this),
                msg.sender,
                borrower,
                block.timestamp
            ));
        }

        if (collateralTokenAddress == address(0)) {
            collateralTokenAddress = wethToken;
        }
        require(collateralTokenAddress != loanTokenAddress, "10");

        address[4] memory sentAddresses;
        uint256[5] memory sentAmounts;

        sentAddresses[0] = address(this); // lender
        sentAddresses[1] = borrower;
        sentAddresses[2] = receiver;
        //sentAddresses[3] = address(0); // manager

        //sentAmounts[0] = 0; // interestRate (found later)
        //sentAmounts[1] = 0; // borrowAmount (found later)
        //sentAmounts[2] = 0; // interestInitialAmount (found later)
        //sentAmounts[3] = 0; // loanTokenSent
        sentAmounts[4] = collateralTokenSent;

        sentAmounts[1] = withdrawAmount;
        sentAmounts[2] = 0; // interestInitialAmount (depreciated)

        return _borrowOrTrade(
            loanId,
            withdrawAmount,
            0, // leverageAmount (calculated later)
            collateralTokenAddress,
            sentAddresses,
            sentAmounts,
            "" // loanDataBytes
        );
    }

    function _marginTrade(
        bytes32 loanId,                 // 0 if new loan
        uint256 leverageAmount,
        uint256 loanTokenSent,
        uint256 collateralTokenSent,
        address collateralTokenAddress,
        address trader,
        bytes memory loanDataBytes)
        internal
        pausable
        returns (IBZx.LoanOpenData memory loanOpenData)
    {
        // ensures authorized use of existing loan
        require(loanId == 0 || msg.sender == trader, "13");

        _settleInterest(loanId);

        if (loanId == 0) {
            loanId = keccak256(abi.encodePacked(
                collateralTokenAddress,
                address(this),
                msg.sender,
                trader,
                block.timestamp
            ));
        }

        if (collateralTokenAddress == address(0)) {
            collateralTokenAddress = wethToken;
        }
        require(collateralTokenAddress != loanTokenAddress, "11");

        address[4] memory sentAddresses;
        uint256[5] memory sentAmounts;

        sentAddresses[0] = address(this); // lender
        sentAddresses[1] = trader;
        sentAddresses[2] = trader;
        //sentAddresses[3] = address(0); // manager

        //sentAmounts[0] = 0; // interestRate (found later)
        //sentAmounts[1] = 0; // borrowAmount (found later)
        //sentAmounts[2] = 0; // interestInitialAmount (interest is calculated based on fixed-term loan)
        sentAmounts[3] = loanTokenSent;
        sentAmounts[4] = collateralTokenSent;

        uint256 totalDeposit;
        uint256 collateralToLoanRate;
        (sentAmounts[1],, totalDeposit, collateralToLoanRate) = _getPreMarginData( // borrowAmount, interestRate, totalDeposit, collateralToLoanRate
            collateralTokenAddress,
            collateralTokenSent,
            loanTokenSent,
            leverageAmount
        );
        require(totalDeposit != 0, "12");

        loanOpenData = _borrowOrTrade(
            loanId,
            0, // withdrawAmount
            leverageAmount,
            collateralTokenAddress,
            sentAddresses,
            sentAmounts,
            loanDataBytes
        );

        IBZx(bZxContract).setDepositAmount(
            loanOpenData.loanId,
            totalDeposit,
            totalDeposit
                .mul(WEI_PRECISION)
                .div(collateralToLoanRate)
        );

        return loanOpenData;
    }

    function _settleInterest(
        bytes32 loanId)
        internal
    {   
        IBZx(bZxContract).settleInterest(loanId);
    }

    function _totalDeposit(
        address collateralTokenAddress,
        uint256 collateralTokenSent,
        uint256 loanTokenSent)
        internal
        view
        returns (uint256 totalDeposit, uint256 collateralToLoanRate)
    {
        uint256 collateralToLoanPrecision;
        (collateralToLoanRate, collateralToLoanPrecision) = IPriceFeeds(IBZx(bZxContract).priceFeeds()).queryRate(
            collateralTokenAddress,
            loanTokenAddress
        );
        require(collateralToLoanRate != 0 && collateralToLoanPrecision != 0, "20");
        collateralToLoanRate = collateralToLoanRate
            .mul(WEI_PRECISION)
            .div(collateralToLoanPrecision);

        totalDeposit = loanTokenSent;
        if (collateralTokenSent != 0) {
            totalDeposit = collateralTokenSent
                .mul(collateralToLoanRate)
                .div(WEI_PRECISION)
                .add(totalDeposit);
        }
    }

    // returns newPrincipal
    function _borrowOrTrade(
        bytes32 loanId,
        uint256 withdrawAmount,
        uint256 leverageAmount,
        address collateralTokenAddress,
        address[4] memory sentAddresses,
        uint256[5] memory sentAmounts,
        bytes memory loanDataBytes)
        internal
        returns (IBZx.LoanOpenData memory)
    {
        require (sentAmounts[1] <= _underlyingBalance() && // newPrincipal
            sentAddresses[1] != address(0), // borrower
            "24"
        );

	    if (sentAddresses[2] == address(0)) {
            sentAddresses[2] = sentAddresses[1]; // receiver = borrower
        }

        // handle transfers prior to adding newPrincipal to loanTokenSent
        uint256 msgValue = _verifyTransfers(
            collateralTokenAddress,
            sentAddresses,
            sentAmounts,
            withdrawAmount
        );

        // adding the loan token portion from the lender to loanTokenSent
        sentAmounts[3] = sentAmounts[3]
            .add(sentAmounts[1]); // newPrincipal

        if (withdrawAmount != 0) {
            // withdrawAmount already sent to the borrower, so we aren't sending it to the protocol
            sentAmounts[3] = sentAmounts[3]
                .sub(withdrawAmount);
        }

        bool isTorqueLoan = withdrawAmount != 0 ?
            true :
            false;

        bytes32 loanParamsId = loanParamsIds[uint256(keccak256(abi.encodePacked(
            collateralTokenAddress,
            isTorqueLoan
        )))];

        // converting to initialMargin
        if (leverageAmount != 0) {
            leverageAmount = SafeMath.div(WEI_PRECISION * WEI_PERCENT_PRECISION, leverageAmount);
        }

        return IBZx(bZxContract).borrowOrTradeFromPool.value(msgValue)(
            loanParamsId,
            loanId,
            isTorqueLoan,
            leverageAmount, // initialMargin
            sentAddresses,
            sentAmounts,
            loanDataBytes
        );
    }

    // sentAddresses[0]: lender
    // sentAddresses[1]: borrower
    // sentAddresses[2]: receiver
    // sentAddresses[3]: manager
    // sentAmounts[0]: interestRate
    // sentAmounts[1]: newPrincipal
    // sentAmounts[2]: interestInitialAmount
    // sentAmounts[3]: loanTokenSent
    // sentAmounts[4]: collateralTokenSent
    function _verifyTransfers(
        address collateralTokenAddress,
        address[4] memory sentAddresses,
        uint256[5] memory sentAmounts,
        uint256 withdrawalAmount)
        internal
        returns (uint256 msgValue)
    {
        address _wethToken = wethToken;
        address _loanTokenAddress = loanTokenAddress;
        address receiver = sentAddresses[2];
        uint256 newPrincipal = sentAmounts[1];
        uint256 loanTokenSent = sentAmounts[3];
        uint256 collateralTokenSent = sentAmounts[4];

        require(_loanTokenAddress != collateralTokenAddress, "26");

        msgValue = msg.value;

        if (withdrawalAmount != 0) { // withdrawOnOpen == true
            _safeTransfer(_loanTokenAddress, receiver, withdrawalAmount, "27");
            if (newPrincipal > withdrawalAmount) {
                _safeTransfer(_loanTokenAddress, bZxContract, newPrincipal - withdrawalAmount, "27");
            }
        } else {
            _safeTransfer(_loanTokenAddress, bZxContract, newPrincipal, "27");
        }

        if (collateralTokenSent != 0) {
            if (collateralTokenAddress == _wethToken && msgValue != 0 && msgValue >= collateralTokenSent) {
                IWeth(_wethToken).deposit.value(collateralTokenSent)();
                _safeTransfer(collateralTokenAddress, bZxContract, collateralTokenSent, "28");
                msgValue -= collateralTokenSent;
            } else {
                _safeTransferFrom(collateralTokenAddress, msg.sender, bZxContract, collateralTokenSent, "28");
            }
        }

        if (loanTokenSent != 0) {
            _safeTransferFrom(_loanTokenAddress, msg.sender, bZxContract, loanTokenSent, "29");
        }
    }

    function _safeTransfer(
        address token,
        address to,
        uint256 amount,
        string memory errorMsg)
        internal
    {
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),
            errorMsg
        );
    }

    function _safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 amount,
        string memory errorMsg)
        internal
    {
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),
            errorMsg
        );
    }

    function _callOptionalReturn(
        address token,
        bytes memory data,
        string memory errorMsg)
        internal
    {
        (bool success, bytes memory returndata) = token.call(data);
        require(success, errorMsg);

        if (returndata.length != 0) {
            require(abi.decode(returndata, (bool)), errorMsg);
        }
    }

    function _underlyingBalance()
        internal
        view
        returns (uint256)
    {
        return IERC20(loanTokenAddress).balanceOf(address(this));
    }

    function _nextSupplyInterestRate(
        uint256 nextBorrowRate,
        uint256 assetBorrow,
        uint256 assetSupply)
        public
        view
        returns (uint256)
    {
        if (assetBorrow != 0 && assetSupply >= assetBorrow) {
            return nextBorrowRate
                .mul(_utilizationRate(assetBorrow, assetSupply))
                .mul(SafeMath.sub(WEI_PERCENT_PRECISION, IBZx(bZxContract).lendingFeePercent()))
                .div(WEI_PERCENT_PRECISION * WEI_PERCENT_PRECISION);
        }
    }

    function _nextBorrowInterestRate(
        uint256 totalBorrow,
        uint256 newBorrowNotYetRealized,
        uint256 lastIR)
        public
        view
        returns (uint256 nextRate)
    {
        uint256 utilRate = _utilizationRate(
            totalBorrow.add(newBorrowNotYetRealized),
            _totalAssetSupply(totalBorrow)
        );

        //utilRate from 0e18 to 100e18
        nextRate = rateHelper.calculateIR(utilRate, lastIR);
    }

    /* Internal View functions */

    function _tokenPrice(
        uint256 assetSupply)
        internal
        view
        returns (uint256)
    {
        uint256 totalTokenSupply = totalSupply_;

        return totalTokenSupply != 0 ?
            assetSupply
                .mul(WEI_PRECISION)
                .div(totalTokenSupply) : initialPrice;
    }

    function _getPreMarginData(
        address collateralTokenAddress,
        uint256 collateralTokenSent,
        uint256 loanTokenSent,
        uint256 leverageAmount)
        internal
        view
        returns (uint256 borrowAmount, uint256 interestRate, uint256 totalDeposit, uint256 collateralToLoanRate)
    {
        (totalDeposit, collateralToLoanRate) = _totalDeposit(
            collateralTokenAddress,
            collateralTokenSent,
            loanTokenSent
        );

        uint256 initialMargin = SafeMath.div(WEI_PRECISION * WEI_PERCENT_PRECISION, leverageAmount);

        // assumes that loan and collateral token are the same
        borrowAmount = totalDeposit
            .mul(WEI_PERCENT_PRECISION)
            .div(initialMargin);
    }

    function _totalAssetSupply(
        uint256 totalBorrow)
        internal
        view
        returns (uint256 totalSupply)
    {
        totalSupply = _flTotalAssetSupply; // temporary locked totalAssetSupply during a flash loan transaction
        if (totalSupply == 0) {
            totalSupply = _underlyingBalance()
                .add(totalBorrow);
        }
    }

    function _utilizationRate(
        uint256 assetBorrow,
        uint256 assetSupply)
        internal
        pure
        returns (uint256)
    {
        if (assetSupply != 0) {
            // U = total_borrow / total_supply
            return assetBorrow
                .mul(WEI_PERCENT_PRECISION)
                .div(assetSupply);
        }
    }


    /* Owner-Only functions */

    function updateSettings(
        address settingsTarget,
        bytes memory callData)
        public
    {
        if (msg.sender != owner()) {
            address _lowerAdmin;
            address _lowerAdminContract;
            assembly {
                _lowerAdmin := sload(iToken_LowerAdminAddress)
                _lowerAdminContract := sload(iToken_LowerAdminContract)
            }
            require(msg.sender == _lowerAdmin && settingsTarget == _lowerAdminContract);
        }

        address currentTarget = target_;
        target_ = settingsTarget;

        (bool result,) = address(this).call(callData);

        uint256 size;
        uint256 ptr;
        assembly {
            size := returndatasize
            ptr := mload(0x40)
            returndatacopy(ptr, 0, size)
            if eq(result, 0) { revert(ptr, size) }
        }

        target_ = currentTarget;

        assembly {
            return(ptr, size)
        }
    }

    function updateFlashBorrowFeePercent(uint256 newFeePercent) public onlyOwner {
        flashBorrowFeePercent = newFeePercent;
    }
}

/*
pragma solidity 0.5.16;

contract ArbitraryCaller {
    function sendCall(
        address target,
        bytes calldata callData)
        external
        payable
    {
        (bool success,) = target.call.value(msg.value)(callData);
        assembly {
            let size := returndatasize()
            let ptr := mload(0x40)
            returndatacopy(ptr, 0, size)
            if eq(success, 0) { revert(ptr, size) }
            return(ptr, size)
        }
    }
}
*/

File 2 of 18 : AdvancedToken.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;

import "AdvancedTokenStorage.sol";


contract AdvancedToken is AdvancedTokenStorage {
    using SafeMath for uint256;

    function approve(
        address _spender,
        uint256 _value)
        public
        returns (bool)
    {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function increaseApproval(
        address _spender,
        uint256 _addedValue)
        public
        returns (bool)
    {
        uint256 _allowed = allowed[msg.sender][_spender]
            .add(_addedValue);
        allowed[msg.sender][_spender] = _allowed;

        emit Approval(msg.sender, _spender, _allowed);
        return true;
    }

    function decreaseApproval(
        address _spender,
        uint256 _subtractedValue)
        public
        returns (bool)
    {
        uint256 _allowed = allowed[msg.sender][_spender];
        if (_subtractedValue >= _allowed) {
            _allowed = 0;
        } else {
            _allowed -= _subtractedValue;
        }
        allowed[msg.sender][_spender] = _allowed;

        emit Approval(msg.sender, _spender, _allowed);
        return true;
    }

    function _mint(
        address _to,
        uint256 _tokenAmount,
        uint256 _assetAmount,
        uint256 _price)
        internal
        returns (uint256)
    {
        require(_to != address(0), "15");

        uint256 _balance = balances[_to]
            .add(_tokenAmount);
        balances[_to] = _balance;

        totalSupply_ = totalSupply_
            .add(_tokenAmount);

        emit Mint(_to, _tokenAmount, _assetAmount, _price);
        emit Transfer(address(0), _to, _tokenAmount);

        return _balance;
    }

    function _burn(
        address _who,
        uint256 _tokenAmount,
        uint256 _assetAmount,
        uint256 _price)
        internal
        returns (uint256)
    {
        uint256 _balance = balances[_who].sub(_tokenAmount, "16");
        
        // a rounding error may leave dust behind, so we clear this out
        if (_balance <= 10) {
            _tokenAmount = _tokenAmount.add(_balance);
            _balance = 0;
        }
        balances[_who] = _balance;

        totalSupply_ = totalSupply_.sub(_tokenAmount);

        emit Burn(_who, _tokenAmount, _assetAmount, _price);
        emit Transfer(_who, address(0), _tokenAmount);

        return _balance;
    }
}

File 3 of 18 : AdvancedTokenStorage.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;

import "LoanTokenBase.sol";


contract AdvancedTokenStorage is LoanTokenBase {
    using SafeMath for uint256;

    event Transfer(
        address indexed from,
        address indexed to,
        uint256 value
    );

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    event Mint(
        address indexed minter,
        uint256 tokenAmount,
        uint256 assetAmount,
        uint256 price
    );

    event Burn(
        address indexed burner,
        uint256 tokenAmount,
        uint256 assetAmount,
        uint256 price
    );

    event FlashBorrow(
        address borrower,
        address target,
        address loanToken,
        uint256 loanAmount
    );

    mapping(address => uint256) internal balances;
    mapping (address => mapping (address => uint256)) internal allowed;
    uint256 internal totalSupply_;

    function totalSupply()
        public
        view
        returns (uint256)
    {
        return totalSupply_;
    }

    function balanceOf(
        address _owner)
        public
        view
        returns (uint256)
    {
        return balances[_owner];
    }

    function allowance(
        address _owner,
        address _spender)
        public
        view
        returns (uint256)
    {
        return allowed[_owner][_spender];
    }
}

File 4 of 18 : LoanTokenBase.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;

import "SafeMath.sol";
import "SignedSafeMath.sol";
import "ReentrancyGuard.sol";
import "Ownable.sol";
import "Address.sol";
import "IWethERC20.sol";
import "PausableGuardian.sol";


contract LoanTokenBase is ReentrancyGuard, Ownable, PausableGuardian {

    uint256 internal constant WEI_PRECISION = 10**18;
    uint256 internal constant WEI_PERCENT_PRECISION = 10**20;

    int256 internal constant sWEI_PRECISION = 10**18;

    string public name;
    string public symbol;
    uint8 public decimals;

    // uint88 for tight packing -> 8 + 88 + 160 = 256
    uint88 internal lastSettleTime_;

    address public loanTokenAddress;

    uint256 internal baseRate_UNUSED;
    uint256 internal rateMultiplier_UNUSED;
    uint256 internal lowUtilBaseRate_UNUSED;
    uint256 internal lowUtilRateMultiplier_UNUSED;
    uint256 internal targetLevel_UNUSED;
    uint256 internal kinkLevel_UNUSED;
    uint256 internal maxScaleRate_UNUSED;

    uint256 internal _flTotalAssetSupply;
    uint256 internal checkpointSupply_UNUSED;
    uint256 public initialPrice;

    mapping (uint256 => bytes32) public loanParamsIds; // mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId
    mapping (address => uint256) internal checkpointPrices_; // price of token at last user checkpoint
}

File 5 of 18 : SafeMath.sol
pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when 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.
 */
library SafeMath {
    /**
     * @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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @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 sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

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

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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 mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 6 of 18 : SignedSafeMath.sol
pragma solidity >=0.5.0 <0.6.0;

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library SignedSafeMath {
    int256 constant private _INT256_MIN = -2**255;

        /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        // 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 0;
        }

        require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");

        int256 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts 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(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");

        int256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}

File 7 of 18 : ReentrancyGuard.sol
pragma solidity >=0.5.0 <0.6.0;


/**
 * @title Helps contracts guard against reentrancy attacks.
 * @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]>
 * @dev If you mark a function `nonReentrant`, you should also
 * mark it `external`.
 */
contract ReentrancyGuard {

    /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.
    /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056
    uint256 internal constant REENTRANCY_GUARD_FREE = 1;

    /// @dev Constant for locked guard state
    uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;

    /**
    * @dev We use a single lock for the whole contract.
    */
    uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;

    /**
    * @dev Prevents a contract from calling itself, directly or indirectly.
    * If you mark a function `nonReentrant`, you should also
    * mark it `external`. Calling one `nonReentrant` function from
    * another is not supported. Instead, you can implement a
    * `private` function doing the actual work, and an `external`
    * wrapper marked as `nonReentrant`.
    */
    modifier nonReentrant() {
        require(reentrancyLock == REENTRANCY_GUARD_FREE, "nonReentrant");
        reentrancyLock = REENTRANCY_GUARD_LOCKED;
        _;
        reentrancyLock = REENTRANCY_GUARD_FREE;
    }

}

File 8 of 18 : Ownable.sol
pragma solidity ^0.5.0;

import "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.
 *
 * 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.
 */
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 () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = 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 onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 9 of 18 : Context.sol
pragma solidity ^0.5.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 GSN 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.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 10 of 18 : Address.sol
pragma solidity ^0.5.5;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

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

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

File 11 of 18 : IWethERC20.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity >=0.5.0 <0.6.0;

import "IWeth.sol";
import "IERC20.sol";


contract IWethERC20 is IWeth, IERC20 {}

File 12 of 18 : IWeth.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity >=0.5.0 <0.6.0;


interface IWeth {
    function deposit() external payable;
    function withdraw(uint256 wad) external;
}

File 13 of 18 : IERC20.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

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

File 14 of 18 : PausableGuardian.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;

import "Ownable.sol";


contract PausableGuardian is Ownable {

    // keccak256("Pausable_FunctionPause")
    bytes32 internal constant Pausable_FunctionPause = 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;

    // keccak256("Pausable_GuardianAddress")
    bytes32 internal constant Pausable_GuardianAddress = 0x80e6706973d0c59541550537fd6a33b971efad732635e6c3b99fb01006803cdf;

    modifier pausable {
        require(!_isPaused(msg.sig), "paused");
        _;
    }

    modifier onlyGuardian {
        require(msg.sender == getGuardian() || msg.sender == owner(), "unauthorized");
        _;
    }

    function _isPaused(bytes4 sig) public view returns (bool isPaused) {
        bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));
        assembly {
            isPaused := sload(slot)
        }
    }

    function toggleFunctionPause(bytes4 sig) public onlyGuardian {
        bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));
        assembly {
            sstore(slot, 1)
        }
    }

    function toggleFunctionUnPause(bytes4 sig) public onlyGuardian {
        // only DAO can unpause, and adding guardian temporarily
        bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));
        assembly {
            sstore(slot, 0)
        }
    }

    function changeGuardian(address newGuardian) public onlyGuardian {
        assembly {
            sstore(Pausable_GuardianAddress, newGuardian)
        }
    }

    function getGuardian() public view returns (address guardian) {
        assembly {
            guardian := sload(Pausable_GuardianAddress)
        }
    }

    function pause(bytes4 [] calldata sig)
        external
        onlyGuardian
    {
        for(uint256 i = 0; i < sig.length; ++i){
            toggleFunctionPause(sig[i]);
        }
    }

    function unpause(bytes4 [] calldata sig)
        external
        onlyGuardian
    {
        for(uint256 i = 0; i < sig.length; ++i){
            toggleFunctionUnPause(sig[i]);
        }
    }
}

File 15 of 18 : StorageExtension.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;

import "ICurvedInterestRate.sol";


contract StorageExtension {

    address internal target_;
    uint256 public flashBorrowFeePercent; // set to 0.03%
    ICurvedInterestRate rateHelper;
}

File 16 of 18 : ICurvedInterestRate.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

// SPDX-License-Identifier: Apache-2.0

pragma solidity >=0.5.0 <0.9.0;

interface ICurvedInterestRate {
    function getInterestRate(
        uint256 _U,
        uint256 _a,
        uint256 _b
    ) external pure returns (uint256 interestRate);

    function getAB(uint256 _IR1) external pure returns (uint256 a, uint256 b);

    function getAB(
        uint256 _IR1,
        uint256 _IR2,
        uint256 _UR1,
        uint256 _UR2
    ) external pure returns (uint256 a, uint256 b);

    function calculateIR(uint256 _U, uint256 _IR1) external pure returns (uint256 interestRate);
}

File 17 of 18 : IBZx.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache-2.0
 */
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.5.0 <0.9.0;
pragma experimental ABIEncoderV2;

/// @title A proxy interface for The Protocol
/// @author bZeroX
/// @notice This is just an interface, not to be deployed itself.
/// @dev This interface is to be used for the protocol interactions.
interface IBZx {
    ////// Protocol //////

    /// @dev adds or replaces existing proxy module
    /// @param target target proxy module address
    function replaceContract(address target) external;

    /// @dev updates all proxy modules addreses and function signatures.
    /// sigsArr and targetsArr should be of equal length
    /// @param sigsArr array of function signatures
    /// @param targetsArr array of target proxy module addresses
    function setTargets(
        string[] calldata sigsArr,
        address[] calldata targetsArr
    ) external;

    /// @dev returns protocol module address given a function signature
    /// @return module address
    function getTarget(string calldata sig) external view returns (address);

    ////// Protocol Settings //////

    /// @dev sets price feed contract address. The contract on the addres should implement IPriceFeeds interface
    /// @param newContract module address for the IPriceFeeds implementation
    function setPriceFeedContract(address newContract) external;

    /// @dev sets swaps contract address. The contract on the addres should implement ISwapsImpl interface
    /// @param newContract module address for the ISwapsImpl implementation
    function setSwapsImplContract(address newContract) external;

    /// @dev sets loan pool with assets. Accepts two arrays of equal length
    /// @param pools array of address of pools
    /// @param assets array of addresses of assets
    function setLoanPool(address[] calldata pools, address[] calldata assets)
        external;

    /// @dev updates list of supported tokens, it can be use also to disable or enable particualr token
    /// @param addrs array of address of pools
    /// @param toggles array of addresses of assets
    /// @param withApprovals resets tokens to unlimited approval with the swaps integration (kyber, etc.)
    function setSupportedTokens(
        address[] calldata addrs,
        bool[] calldata toggles,
        bool withApprovals
    ) external;

    /// @dev sets lending fee with WEI_PERCENT_PRECISION
    /// @param newValue lending fee percent
    function setLendingFeePercent(uint256 newValue) external;

    /// @dev sets trading fee with WEI_PERCENT_PRECISION
    /// @param newValue trading fee percent
    function setTradingFeePercent(uint256 newValue) external;

    /// @dev sets borrowing fee with WEI_PERCENT_PRECISION
    /// @param newValue borrowing fee percent
    function setBorrowingFeePercent(uint256 newValue) external;

    /// @dev sets affiliate fee with WEI_PERCENT_PRECISION
    /// @param newValue affiliate fee percent
    function setAffiliateFeePercent(uint256 newValue) external;

    /// @dev sets liquidation inncetive percent per loan per token. This is the profit percent
    /// that liquidator gets in the process of liquidating.
    /// @param loanTokens array list of loan tokens
    /// @param collateralTokens array list of collateral tokens
    /// @param amounts array list of liquidation inncetive amount
    function setLiquidationIncentivePercent(
        address[] calldata loanTokens,
        address[] calldata collateralTokens,
        uint256[] calldata amounts
    ) external;

    /// @dev sets max swap rate slippage percent.
    /// @param newAmount max swap rate slippage percent.
    function setMaxDisagreement(uint256 newAmount) external;

    /// TODO
    function setSourceBufferPercent(uint256 newAmount) external;

    /// @dev sets maximum supported swap size in ETH
    /// @param newAmount max swap size in ETH.
    function setMaxSwapSize(uint256 newAmount) external;

    /// @dev sets fee controller address
    /// @param newController address of the new fees controller
    function setFeesController(address newController) external;

    /// @dev withdraws lending fees to receiver. Only can be called by feesController address
    /// @param tokens array of token addresses.
    /// @param receiver fees receiver address
    /// @return amounts array of amounts withdrawn
    function withdrawFees(
        address[] calldata tokens,
        address receiver,
        FeeClaimType feeType
    ) external returns (uint256[] memory amounts);

    /*
    Targets still exist, but functions are decommissioned:

    /// @dev withdraw protocol token (BZRX) from vesting contract vBZRX
    /// @param receiver address of BZRX tokens claimed
    /// @param amount of BZRX token to be claimed. max is claimed if amount is greater than balance.
    /// @return rewardToken reward token address
    /// @return withdrawAmount amount
    function withdrawProtocolToken(address receiver, uint256 amount)
        external
        returns (address rewardToken, uint256 withdrawAmount);

    /// @dev depozit protocol token (BZRX)
    /// @param amount address of BZRX tokens to deposit
    function depositProtocolToken(uint256 amount) external;

    function grantRewards(address[] calldata users, uint256[] calldata amounts)
        external
        returns (uint256 totalAmount);*/

    // NOTE: this doesn't sanitize inputs -> inaccurate values may be returned if there are duplicate token inputs
    function queryFees(address[] calldata tokens, FeeClaimType feeType)
        external
        view
        returns (uint256[] memory amountsHeld, uint256[] memory amountsPaid);

    function priceFeeds() external view returns (address);

    function swapsImpl() external view returns (address);

    function logicTargets(bytes4) external view returns (address);

    function loans(bytes32) external view returns (Loan memory);

    function loanParams(bytes32) external view returns (LoanParams memory);

    // we don't use this yet
    // function lenderOrders(address, bytes32) external returns (Order memory);
    // function borrowerOrders(address, bytes32) external returns (Order memory);

    function delegatedManagers(bytes32, address) external view returns (bool);

    function lenderInterest(address, address)
        external
        view
        returns (LenderInterest memory);

    function loanInterest(bytes32) external view returns (LoanInterest memory);

    function feesController() external view returns (address);

    function lendingFeePercent() external view returns (uint256);

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

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

    function borrowingFeePercent() external view returns (uint256);

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

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

    function protocolTokenHeld() external view returns (uint256);

    function protocolTokenPaid() external view returns (uint256);

    function affiliateFeePercent() external view returns (uint256);

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

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

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

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

    function maxDisagreement() external view returns (uint256);

    function sourceBufferPercent() external view returns (uint256);

    function maxSwapSize() external view returns (uint256);

    /// @dev get list of loan pools in the system. Ordering is not guaranteed
    /// @param start start index
    /// @param count number of pools to return
    /// @return loanPoolsList array of loan pools
    function getLoanPoolsList(uint256 start, uint256 count)
        external
        view
        returns (address[] memory loanPoolsList);

    /// @dev checks whether addreess is a loan pool address
    /// @return boolean
    function isLoanPool(address loanPool) external view returns (bool);

    ////// Loan Settings //////

    /// @dev creates new loan param settings
    /// @param loanParamsList array of LoanParams
    /// @return loanParamsIdList array of loan ids created
    function setupLoanParams(LoanParams[] calldata loanParamsList)
        external
        returns (bytes32[] memory loanParamsIdList);

    function setupLoanPoolTWAI(address pool) external;

    function setTWAISettings(uint32 delta, uint32 secondsAgo) external;

    /// @dev Deactivates LoanParams for future loans. Active loans using it are unaffected.
    /// @param loanParamsIdList array of loan ids
    function disableLoanParams(bytes32[] calldata loanParamsIdList) external;

    /// @dev gets array of LoanParams by given ids
    /// @param loanParamsIdList array of loan ids
    /// @return loanParamsList array of LoanParams
    function getLoanParams(bytes32[] calldata loanParamsIdList)
        external
        view
        returns (LoanParams[] memory loanParamsList);

    /// @dev Enumerates LoanParams in the system by owner
    /// @param owner of the loan params
    /// @param start number of loans to return
    /// @param count total number of the items
    /// @return loanParamsList array of LoanParams
    function getLoanParamsList(
        address owner,
        uint256 start,
        uint256 count
    ) external view returns (bytes32[] memory loanParamsList);

    /// @dev returns total loan principal for token address
    /// @param lender address
    /// @param loanToken address
    /// @return total principal of the loan
    function getTotalPrincipal(address lender, address loanToken)
        external
        view
        returns (uint256);

    /// @dev returns total principal for a loan pool that was last settled
    /// @param pool address
    /// @return total stored principal of the loan
    function getPoolPrincipalStored(address pool)
        external
        view
        returns (uint256);

    /// @dev returns the last interest rate founnd during interest settlement
    /// @param pool address
    /// @return the last interset rate
    function getPoolLastInterestRate(address pool)
        external
        view
        returns (uint256);

    ////// Loan Openings //////

    /// @dev This is THE function that borrows or trades on the protocol
    /// @param loanParamsId id of the LoanParam created beforehand by setupLoanParams function
    /// @param loanId id of existing loan, if 0, start a new loan
    /// @param isTorqueLoan boolean whether it is toreque or non torque loan
    /// @param initialMargin in WEI_PERCENT_PRECISION
    /// @param sentAddresses array of size 4:
    ///         lender: must match loan if loanId provided
    ///         borrower: must match loan if loanId provided
    ///         receiver: receiver of funds (address(0) assumes borrower address)
    ///         manager: delegated manager of loan unless address(0)
    /// @param sentValues array of size 5:
    ///         newRate: new loan interest rate
    ///         newPrincipal: new loan size (borrowAmount + any borrowed interest)
    ///         torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)
    ///         loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)
    ///         collateralTokenReceived: total collateralToken deposit
    /// @param loanDataBytes required when sending ether
    /// @return principal of the loan and collateral amount
    function borrowOrTradeFromPool(
        bytes32 loanParamsId,
        bytes32 loanId,
        bool isTorqueLoan,
        uint256 initialMargin,
        address[4] calldata sentAddresses,
        uint256[5] calldata sentValues,
        bytes calldata loanDataBytes
    ) external payable returns (LoanOpenData memory);

    /// @dev sets/disables/enables the delegated manager for the loan
    /// @param loanId id of the loan
    /// @param delegated delegated manager address
    /// @param toggle boolean set enabled or disabled
    function setDelegatedManager(
        bytes32 loanId,
        address delegated,
        bool toggle
    ) external;

    /// @dev calculates required collateral for simulated position
    /// @param loanToken address of loan token
    /// @param collateralToken address of collateral token
    /// @param newPrincipal principal amount of the loan
    /// @param marginAmount margin amount of the loan
    /// @param isTorqueLoan boolean torque or non torque loan
    /// @return collateralAmountRequired amount required
    function getRequiredCollateral(
        address loanToken,
        address collateralToken,
        uint256 newPrincipal,
        uint256 marginAmount,
        bool isTorqueLoan
    ) external view returns (uint256 collateralAmountRequired);

    function getRequiredCollateralByParams(
        bytes32 loanParamsId,
        uint256 newPrincipal
    ) external view returns (uint256 collateralAmountRequired);

    /// @dev calculates borrow amount for simulated position
    /// @param loanToken address of loan token
    /// @param collateralToken address of collateral token
    /// @param collateralTokenAmount amount of collateral token sent
    /// @param marginAmount margin amount
    /// @param isTorqueLoan boolean torque or non torque loan
    /// @return borrowAmount possible borrow amount
    function getBorrowAmount(
        address loanToken,
        address collateralToken,
        uint256 collateralTokenAmount,
        uint256 marginAmount,
        bool isTorqueLoan
    ) external view returns (uint256 borrowAmount);

    function getBorrowAmountByParams(
        bytes32 loanParamsId,
        uint256 collateralTokenAmount
    ) external view returns (uint256 borrowAmount);

    ////// Loan Closings //////

    /// @dev liquidates unhealty loans
    /// @param loanId id of the loan
    /// @param receiver address receiving liquidated loan collateral
    /// @param closeAmount amount to close denominated in loanToken
    /// @return loanCloseAmount amount of the collateral token of the loan
    /// @return seizedAmount sezied amount in the collateral token
    /// @return seizedToken loan token address
    function liquidate(
        bytes32 loanId,
        address receiver,
        uint256 closeAmount
    )
        external
        payable
        returns (
            uint256 loanCloseAmount,
            uint256 seizedAmount,
            address seizedToken
        );

    /// @dev close position with loan token deposit
    /// @param loanId id of the loan
    /// @param receiver collateral token reciever address
    /// @param depositAmount amount of loan token to deposit
    /// @return loanCloseAmount loan close amount
    /// @return withdrawAmount loan token withdraw amount
    /// @return withdrawToken loan token address
    function closeWithDeposit(
        bytes32 loanId,
        address receiver,
        uint256 depositAmount // denominated in loanToken
    )
        external
        payable
        returns (
            uint256 loanCloseAmount,
            uint256 withdrawAmount,
            address withdrawToken
        );

    /// @dev close position with swap
    /// @param loanId id of the loan
    /// @param receiver collateral token reciever address
    /// @param swapAmount amount of loan token to swap
    /// @param returnTokenIsCollateral boolean whether to return tokens is collateral
    /// @param loanDataBytes custom payload for specifying swap implementation and data to pass
    /// @return loanCloseAmount loan close amount
    /// @return withdrawAmount loan token withdraw amount
    /// @return withdrawToken loan token address
    function closeWithSwap(
        bytes32 loanId,
        address receiver,
        uint256 swapAmount, // denominated in collateralToken
        bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken
        bytes calldata loanDataBytes
    )
        external
        returns (
            uint256 loanCloseAmount,
            uint256 withdrawAmount,
            address withdrawToken
        );

    ////// Loan Closings With Gas Token //////

    /// @dev liquidates unhealty loans by using Gas token
    /// @param loanId id of the loan
    /// @param receiver address receiving liquidated loan collateral
    /// @param gasTokenUser user address of the GAS token
    /// @param closeAmount amount to close denominated in loanToken
    /// @return loanCloseAmount loan close amount
    /// @return seizedAmount loan token withdraw amount
    /// @return seizedToken loan token address
    function liquidateWithGasToken(
        bytes32 loanId,
        address receiver,
        address gasTokenUser,
        uint256 closeAmount // denominated in loanToken
    )
        external
        payable
        returns (
            uint256 loanCloseAmount,
            uint256 seizedAmount,
            address seizedToken
        );

    /// @dev close position with loan token deposit
    /// @param loanId id of the loan
    /// @param receiver collateral token reciever address
    /// @param gasTokenUser user address of the GAS token
    /// @param depositAmount amount of loan token to deposit denominated in loanToken
    /// @return loanCloseAmount loan close amount
    /// @return withdrawAmount loan token withdraw amount
    /// @return withdrawToken loan token address
    function closeWithDepositWithGasToken(
        bytes32 loanId,
        address receiver,
        address gasTokenUser,
        uint256 depositAmount
    )
        external
        payable
        returns (
            uint256 loanCloseAmount,
            uint256 withdrawAmount,
            address withdrawToken
        );

    /// @dev close position with swap
    /// @param loanId id of the loan
    /// @param receiver collateral token reciever address
    /// @param gasTokenUser user address of the GAS token
    /// @param swapAmount amount of loan token to swap denominated in collateralToken
    /// @param returnTokenIsCollateral  true: withdraws collateralToken, false: withdraws loanToken
    /// @return loanCloseAmount loan close amount
    /// @return withdrawAmount loan token withdraw amount
    /// @return withdrawToken loan token address
    function closeWithSwapWithGasToken(
        bytes32 loanId,
        address receiver,
        address gasTokenUser,
        uint256 swapAmount,
        bool returnTokenIsCollateral,
        bytes calldata loanDataBytes
    )
        external
        returns (
            uint256 loanCloseAmount,
            uint256 withdrawAmount,
            address withdrawToken
        );

    ////// Loan Maintenance //////

    /// @dev deposit collateral to existing loan
    /// @param loanId existing loan id
    /// @param depositAmount amount to deposit which must match msg.value if ether is sent
    function depositCollateral(bytes32 loanId, uint256 depositAmount)
        external
        payable;

    /// @dev withdraw collateral from existing loan
    /// @param loanId existing loan id
    /// @param receiver address of withdrawn tokens
    /// @param withdrawAmount amount to withdraw
    /// @return actualWithdrawAmount actual amount withdrawn
    function withdrawCollateral(
        bytes32 loanId,
        address receiver,
        uint256 withdrawAmount
    ) external returns (uint256 actualWithdrawAmount);

    /// @dev settles accrued interest for all active loans from a loan pool
    /// @param loanId existing loan id
    function settleInterest(bytes32 loanId) external;

    function setDepositAmount(
        bytes32 loanId,
        uint256 depositValueAsLoanToken,
        uint256 depositValueAsCollateralToken
    ) external;

    function transferLoan(bytes32 loanId, address newOwner) external;

    // Decommissioned function, but leave interface to allow remaining claims
    function claimRewards(address receiver)
        external
        returns (uint256 claimAmount);

    // Decommissioned function, but leave interface to allow remaining claims
    function rewardsBalanceOf(address user)
        external
        view
        returns (uint256 rewardsBalance);

    function getInterestModelValues(
        address pool,
        bytes32 loanId)
        external
        view
        returns (
        uint256 _poolLastUpdateTime,
        uint256 _poolPrincipalTotal,
        uint256 _poolInterestTotal,
        uint256 _poolRatePerTokenStored,
        uint256 _poolLastInterestRate,
        uint256 _loanPrincipalTotal,
        uint256 _loanInterestTotal,
        uint256 _loanRatePerTokenPaid
        );
    
    function getTWAI(
        address pool)
        external
        view returns (
            uint256 benchmarkRate
        );

    /// @dev gets list of loans of particular user address
    /// @param user address of the loans
    /// @param start of the index
    /// @param count number of loans to return
    /// @param loanType type of the loan: All(0), Margin(1), NonMargin(2)
    /// @param isLender whether to list lender loans or borrower loans
    /// @param unsafeOnly booleat if true return only unsafe loans that are open for liquidation
    /// @return loansData LoanReturnData array of loans
    function getUserLoans(
        address user,
        uint256 start,
        uint256 count,
        LoanType loanType,
        bool isLender,
        bool unsafeOnly
    ) external view returns (LoanReturnData[] memory loansData);

    function getUserLoansCount(address user, bool isLender)
        external
        view
        returns (uint256);

    /// @dev gets existing loan
    /// @param loanId id of existing loan
    /// @return loanData array of loans
    function getLoan(bytes32 loanId)
        external
        view
        returns (LoanReturnData memory loanData);

    /// @dev gets loan principal including interest
    /// @param loanId id of existing loan
    /// @return principal
    function getLoanPrincipal(bytes32 loanId)
        external
        view
        returns (uint256 principal);

    /// @dev gets loan outstanding interest
    /// @param loanId id of existing loan
    /// @return interest
    function getLoanInterestOutstanding(bytes32 loanId)
        external
        view
        returns (uint256 interest);


    /// @dev get current active loans in the system
    /// @param start of the index
    /// @param count number of loans to return
    /// @param unsafeOnly boolean if true return unsafe loan only (open for liquidation)
    function getActiveLoans(
        uint256 start,
        uint256 count,
        bool unsafeOnly
    ) external view returns (LoanReturnData[] memory loansData);

    /// @dev get current active loans in the system
    /// @param start of the index
    /// @param count number of loans to return
    /// @param unsafeOnly boolean if true return unsafe loan only (open for liquidation)
    /// @param isLiquidatable boolean if true return liquidatable loans only
    function getActiveLoansAdvanced(
        uint256 start,
        uint256 count,
        bool unsafeOnly,
        bool isLiquidatable
    ) external view returns (LoanReturnData[] memory loansData);

    function getActiveLoansCount() external view returns (uint256);

    ////// Swap External //////

    /// @dev swap thru external integration
    /// @param sourceToken source token address
    /// @param destToken destintaion token address
    /// @param receiver address to receive tokens
    /// @param returnToSender TODO
    /// @param sourceTokenAmount source token amount
    /// @param requiredDestTokenAmount destination token amount
    /// @param swapData TODO
    /// @return destTokenAmountReceived destination token received
    /// @return sourceTokenAmountUsed source token amount used
    function swapExternal(
        address sourceToken,
        address destToken,
        address receiver,
        address returnToSender,
        uint256 sourceTokenAmount,
        uint256 requiredDestTokenAmount,
        bytes calldata swapData
    )
        external
        payable
        returns (
            uint256 destTokenAmountReceived,
            uint256 sourceTokenAmountUsed
        );

    /// @dev swap thru external integration using GAS
    /// @param sourceToken source token address
    /// @param destToken destintaion token address
    /// @param receiver address to receive tokens
    /// @param returnToSender TODO
    /// @param gasTokenUser user address of the GAS token
    /// @param sourceTokenAmount source token amount
    /// @param requiredDestTokenAmount destination token amount
    /// @param swapData TODO
    /// @return destTokenAmountReceived destination token received
    /// @return sourceTokenAmountUsed source token amount used
    function swapExternalWithGasToken(
        address sourceToken,
        address destToken,
        address receiver,
        address returnToSender,
        address gasTokenUser,
        uint256 sourceTokenAmount,
        uint256 requiredDestTokenAmount,
        bytes calldata swapData
    )
        external
        payable
        returns (
            uint256 destTokenAmountReceived,
            uint256 sourceTokenAmountUsed
        );

    /// @dev calculate simulated return of swap
    /// @param sourceToken source token address
    /// @param destToken destination token address
    /// @param sourceTokenAmount source token amount
    /// @return amoun denominated in destination token
    function getSwapExpectedReturn(
        address sourceToken,
        address destToken,
        uint256 sourceTokenAmount,
        bytes calldata swapData
    ) external view returns (uint256);

    function owner() external view returns (address);

    function transferOwnership(address newOwner) external;


    /// Guardian Interface

    function _isPaused(bytes4 sig) external view returns (bool isPaused);

    function toggleFunctionPause(bytes4 sig) external;

    function toggleFunctionUnPause(bytes4 sig) external;

    function pause(bytes4 [] calldata sig) external;

    function unpause(bytes4 [] calldata sig) external;

    function changeGuardian(address newGuardian) external;

    function getGuardian() external view returns (address guardian);

    /// Loan Cleanup Interface

    function cleanupLoans(
        address loanToken,
        bytes32[] calldata loanIds)
        external
        payable
        returns (uint256 totalPrincipalIn);

    struct LoanParams {
        bytes32 id;
        bool active;
        address owner;
        address loanToken;
        address collateralToken;
        uint256 minInitialMargin;
        uint256 maintenanceMargin;
        uint256 maxLoanTerm;
    }

    struct LoanOpenData {
        bytes32 loanId;
        uint256 principal;
        uint256 collateral;
    }

    enum LoanType {
        All,
        Margin,
        NonMargin
    }

    struct LoanReturnData {
        bytes32 loanId;
        uint96 endTimestamp;
        address loanToken;
        address collateralToken;
        uint256 principal;
        uint256 collateral;
        uint256 interestOwedPerDay;
        uint256 interestDepositRemaining;
        uint256 startRate;
        uint256 startMargin;
        uint256 maintenanceMargin;
        uint256 currentMargin;
        uint256 maxLoanTerm;
        uint256 maxLiquidatable;
        uint256 maxSeizable;
        uint256 depositValueAsLoanToken;
        uint256 depositValueAsCollateralToken;
    }

    enum FeeClaimType {
        All,
        Lending,
        Trading,
        Borrowing
    }

    struct Loan {
        bytes32 id; // id of the loan
        bytes32 loanParamsId; // the linked loan params id
        bytes32 pendingTradesId; // the linked pending trades id
        uint256 principal; // total borrowed amount outstanding
        uint256 collateral; // total collateral escrowed for the loan
        uint256 startTimestamp; // loan start time
        uint256 endTimestamp; // for active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time
        uint256 startMargin; // initial margin when the loan opened
        uint256 startRate; // reference rate when the loan opened for converting collateralToken to loanToken
        address borrower; // borrower of this loan
        address lender; // lender of this loan
        bool active; // if false, the loan has been fully closed
    }

    struct LenderInterest {
        uint256 principalTotal; // total borrowed amount outstanding of asset
        uint256 owedPerDay; // interest owed per day for all loans of asset
        uint256 owedTotal; // total interest owed for all loans of asset (assuming they go to full term)
        uint256 paidTotal; // total interest paid so far for asset
        uint256 updatedTimestamp; // last update
    }

    struct LoanInterest {
        uint256 owedPerDay; // interest owed per day for loan
        uint256 depositTotal; // total escrowed interest for loan
        uint256 updatedTimestamp; // last update
    }
	
	////// Flash Borrow Fees //////
    function payFlashBorrowFees(
        address user,
        uint256 borrowAmount,
        uint256 flashBorrowFeePercent)
        external;
}

File 18 of 18 : IPriceFeeds.sol
/**
 * Copyright 2017-2022, OokiDao. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity >=0.5.0 <0.9.0;


interface IPriceFeeds {
    function queryRate(
        address sourceToken,
        address destToken)
        external
        view
        returns (uint256 rate, uint256 precision);

    function queryPrecision(
        address sourceToken,
        address destToken)
        external
        view
        returns (uint256 precision);

    function queryReturn(
        address sourceToken,
        address destToken,
        uint256 sourceAmount)
        external
        view
        returns (uint256 destAmount);

    function checkPriceDisagreement(
        address sourceToken,
        address destToken,
        uint256 sourceAmount,
        uint256 destAmount,
        uint256 maxSlippage)
        external
        view
        returns (uint256 sourceToDestSwapRate);

    function amountInEth(
        address Token,
        uint256 amount)
        external
        view
        returns (uint256 ethAmount);

    function getMaxDrawdown(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount,
        uint256 maintenanceMargin)
        external
        view
        returns (uint256);

    function getCurrentMarginAndCollateralSize(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount)
        external
        view
        returns (uint256 currentMargin, uint256 collateralInEthAmount);

    function getCurrentMargin(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount)
        external
        view
        returns (uint256 currentMargin, uint256 collateralToLoanRate);

    function shouldLiquidate(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount,
        uint256 maintenanceMargin)
        external
        view
        returns (bool);

    function getFastGasPrice(
        address payToken)
        external
        view
        returns (uint256);
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "libraries": {
    "LoanTokenLogicStandard.sol": {}
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burner","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"loanToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"loanAmount","type":"uint256"}],"name":"FlashBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"sig","type":"bytes4"}],"name":"_isPaused","outputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"newBorrowNotYetRealized","type":"uint256"},{"internalType":"uint256","name":"lastIR","type":"uint256"}],"name":"_nextBorrowInterestRate","outputs":[{"internalType":"uint256","name":"nextRate","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"nextBorrowRate","type":"uint256"},{"internalType":"uint256","name":"assetBorrow","type":"uint256"},{"internalType":"uint256","name":"assetSupply","type":"uint256"}],"name":"_nextSupplyInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"assetBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bZxContract","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"internalType":"uint256","name":"initialLoanDuration","type":"uint256"},{"internalType":"uint256","name":"collateralTokenSent","type":"uint256"},{"internalType":"address","name":"collateralTokenAddress","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"borrow","outputs":[{"components":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"}],"internalType":"struct IBZx.LoanOpenData","name":"","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"borrowInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"burnAmount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"loanAmountPaid","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newGuardian","type":"address"}],"name":"changeGuardian","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"checkpointPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"string","name":"signature","type":"string"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashBorrow","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"flashBorrowFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"initialLoanDuration","type":"uint256"},{"internalType":"address","name":"collateralTokenAddress","type":"address"}],"name":"getBorrowAmountForDeposit","outputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"initialLoanDuration","type":"uint256"},{"internalType":"address","name":"collateralTokenAddress","type":"address"}],"name":"getDepositAmountForBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getGuardian","outputs":[{"internalType":"address","name":"guardian","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getPoolUtilization","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initialPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"loanParamsIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"loanTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"leverageAmount","type":"uint256"},{"internalType":"uint256","name":"loanTokenSent","type":"uint256"},{"internalType":"uint256","name":"collateralTokenSent","type":"uint256"},{"internalType":"address","name":"collateralTokenAddress","type":"address"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"bytes","name":"loanDataBytes","type":"bytes"}],"name":"marginTrade","outputs":[{"components":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"}],"internalType":"struct IBZx.LoanOpenData","name":"","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"nextBorrowInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"int256","name":"supplyAmount","type":"int256"}],"name":"nextSupplyInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes4[]","name":"sig","type":"bytes4[]"}],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"poolLastInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"poolTWAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"profitOf","outputs":[{"internalType":"int256","name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"supplyInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes4","name":"sig","type":"bytes4"}],"name":"toggleFunctionPause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes4","name":"sig","type":"bytes4"}],"name":"toggleFunctionUnPause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalAssetBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalAssetSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes4[]","name":"sig","type":"bytes4[]"}],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newFeePercent","type":"uint256"}],"name":"updateFlashBorrowFeePercent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"settingsTarget","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"updateSettings","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"wethToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]

608060405260016000553480156200001657600080fd5b5060006200002c6001600160e01b036200008216565b600180546001600160a01b0319166001600160a01b0383169081179091556040519192509060009060008051602062004ca8833981519152908290a3506200007c6001600160e01b036200008616565b62000187565b3390565b620000996001600160e01b03620000fa16565b620000c15760405162461bcd60e51b8152600401620000b89062000166565b60405180910390fd5b6001546040516000916001600160a01b03169060008051602062004ca8833981519152908390a3600180546001600160a01b0319169055565b6001546000906001600160a01b03166200011c6001600160e01b036200008216565b6001600160a01b031614905090565b60006200013a6020836200017e565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b6020808252810162000178816200012b565b92915050565b90815260200190565b614b1180620001976000396000f3fe60806040526004361061031a5760003560e01c8063715018a6116101ab578063ac544a04116100f7578063dd62ed3e11610095578063f2fde38b1161006f578063f2fde38b146108c1578063f8ddf397146108e1578063f96b660a14610901578063ffa1ad74146109215761031a565b8063dd62ed3e14610861578063eebc508114610881578063ef4e1fe4146108a15761031a565b8063bf7d653b116100d1578063bf7d653b146107f9578063c5bf0e9d1461080e578063c674184f14610821578063d73dd623146108415761031a565b8063ac544a04146107a4578063b9fe1a8f146107c4578063baa7719c146107e45761031a565b80638fb807c5116101645780639dc29fac1161013e5780639dc29fac1461072f578063a75b87d21461074f578063a9059cbb14610764578063ab3d9ffa146107845761031a565b80638fb807c5146106f057806395d89b4114610705578063995363d31461071a5761031a565b8063715018a614610672578063797bf385146106875780637ff9b5961461069c5780638325a1c0146106b15780638da5cb5b146106c65780638f32d59b146106db5761031a565b8063284e2f561161026a57806340c10f1911610223578063631a3ef8116101fd578063631a3ef8146105f257806366188463146106125780636a8cb4c61461063257806370a08231146106525761031a565b806340c10f19146105905780634b57b0be146105b057806354198ce9146105d25761031a565b8063284e2f56146104db5780632ea295fa146104fb5780632fcb4f041461050e578063313ce5671461052e578063323e35b1146105505780633291c11a146105705761031a565b80630ae1dc65116102d757806318160ddd116102b157806318160ddd1461047c5780631d0806ae1461049157806320f6d07c146104a657806323b872dd146104bb5761031a565b80630ae1dc65146104275780630d198dd71461043c57806314dfe7921461045c5761031a565b8063047979301461035857806306b3efd61461038e57806306fdde03146103ae578063095ea7b3146103d057806309ec6b6b146103fd5780630a24cdce14610412575b3373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146103565760405162461bcd60e51b815260040161034d906148a8565b60405180910390fd5b005b34801561036457600080fd5b50610378610373366004613ccc565b610936565b604051610385919061467c565b60405180910390f35b34801561039a57600080fd5b506103786103a936600461385f565b610a4b565b3480156103ba57600080fd5b506103c3610a8d565b6040516103859190614717565b3480156103dc57600080fd5b506103f06103eb36600461396a565b610b18565b604051610385919061466e565b34801561040957600080fd5b50610378610b83565b34801561041e57600080fd5b50610378610bb1565b34801561043357600080fd5b50610378610bb7565b34801561044857600080fd5b50610356610457366004613b94565b610c40565b61046f61046a366004613ac2565b610c69565b6040516103859190614938565b34801561048857600080fd5b50610378610ced565b34801561049d57600080fd5b50610378610cf3565b3480156104b257600080fd5b50610378610cf9565b3480156104c757600080fd5b506103f06104d63660046138d5565b610d2f565b3480156104e757600080fd5b506103566104f6366004613922565b610d6a565b61046f6105093660046139fa565b610eb0565b34801561051a57600080fd5b5061035661052936600461385f565b610f45565b34801561053a57600080fd5b50610543610fc4565b6040516103859190614946565b34801561055c57600080fd5b5061035661056b366004613b76565b610fcd565b34801561057c57600080fd5b5061037861058b366004613b94565b61107e565b34801561059c57600080fd5b506103786105ab36600461396a565b611090565b3480156105bc57600080fd5b506105c5611106565b6040516103859190614569565b3480156105de57600080fd5b506103786105ed36600461385f565b61111e565b3480156105fe57600080fd5b5061037861060d366004613ccc565b6111bf565b34801561061e57600080fd5b506103f061062d36600461396a565b6112de565b34801561063e57600080fd5b506103f061064d366004613b76565b611381565b34801561065e57600080fd5b5061037861066d36600461385f565b6113da565b34801561067e57600080fd5b506103566113f5565b34801561069357600080fd5b506105c5611463565b3480156106a857600080fd5b50610378611479565b3480156106bd57600080fd5b50610378611493565b3480156106d257600080fd5b506105c56114aa565b3480156106e757600080fd5b506103f06114b9565b3480156106fc57600080fd5b506103786114df565b34801561071157600080fd5b506103c36114ec565b34801561072657600080fd5b506105c5611547565b34801561073b57600080fd5b5061037861074a36600461396a565b611559565b34801561075b57600080fd5b506105c5611602565b34801561077057600080fd5b506103f061077f36600461396a565b611627565b34801561079057600080fd5b5061035661079f366004613b76565b611637565b3480156107b057600080fd5b506103566107bf36600461399a565b6116e8565b3480156107d057600080fd5b506103786107df366004613b94565b61177f565b3480156107f057600080fd5b50610378611795565b34801561080557600080fd5b506103786117c9565b6103c361081c366004613bee565b6117e8565b34801561082d57600080fd5b5061037861083c366004613b94565b611b49565b34801561084d57600080fd5b506103f061085c36600461396a565b611bb1565b34801561086d57600080fd5b5061037861087c36600461389b565b611c42565b34801561088d57600080fd5b5061037861089c36600461385f565b611c6d565b3480156108ad57600080fd5b506103786108bc366004613d0f565b611c88565b3480156108cd57600080fd5b506103566108dc36600461385f565b611d5b565b3480156108ed57600080fd5b506103566108fc36600461399a565b611d8b565b34801561090d57600080fd5b5061037861091c366004613d0f565b611e1d565b34801561092d57600080fd5b50610378611ec8565b60008315610a44576001600160a01b0382166109645773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291505b600080516020614aaf8339815191526001600160a01b03166365df83f6600f60008560016040516020016109999291906144cb565b6040516020818303038152906040528051906020012060001c815260200190815260200160002054866040518363ffffffff1660e01b81526004016109df9291906146fb565b60206040518083038186803b1580156109f757600080fd5b505afa158015610a0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a2f9190810190613bd0565b9050610a39611ecd565b811115610a44575060005b9392505050565b6000610a85670de0b6b3a7640000610a79610a64611479565b610a6d866113da565b9063ffffffff611f0516565b9063ffffffff611f3f16565b90505b919050565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610b105780601f10610ae557610100808354040283529160200191610b10565b820191906000526020600020905b815481529060010190602001808311610af357829003601f168201915b505050505081565b3360008181526012602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610b7190869061467c565b60405180910390a35060015b92915050565b600080610b8e611f81565b9050610bab610ba182600061091c610bb7565b826108bc84611fb5565b91505090565b60155481565b6040516359418b1560e11b8152600090600080516020614aaf8339815191529063b283162a90610beb903090600401614577565b60206040518083038186803b158015610c0357600080fd5b505afa158015610c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c3b9190810190613bd0565b905090565b610c486114b9565b610c645760405162461bcd60e51b815260040161034d90614868565b601555565b610c71613683565b600160005414610c935760405162461bcd60e51b815260040161034d906148c8565b6002600081905550610cb06000356001600160e01b031916611381565b15610ccd5760405162461bcd60e51b815260040161034d90614928565b610cdc88888888888888611fc9565b600160005598975050505050505050565b60135490565b600e5481565b60405163250f447f60e11b8152600090600080516020614aaf83398151915290634a1e88fe90610beb9030908590600401614585565b6001600160a01b0383166000908152601260209081526040808320338452909152812054610d62908590859085906121e8565b949350505050565b610d726114aa565b6001600160a01b0316336001600160a01b031614610e03577f7ad06df6a0af6bd602d90db766e0d5f253b45187c3717a0f9026ea8b10ff0d4b547f34b31cff1dbd8374124bd4505521fc29cab0f9554a5386ba7d784a4e611c7e3154336001600160a01b038316148015610df75750806001600160a01b0316846001600160a01b0316145b610e0057600080fd5b50505b601480546001600160a01b038481166001600160a01b03198316179092556040519116906000903090610e3790859061455d565b6000604051808303816000865af19150503d8060008114610e74576040519150601f19603f3d011682016040523d82523d6000602084013e610e79565b606091505b50506040519091503d90816000823e82610e91578181fd5b601480546001600160a01b0319166001600160a01b0386161790558181f35b610eb8613683565b600160005414610eda5760405162461bcd60e51b815260040161034d906148c8565b6002600081905550610ef76000356001600160e01b031916611381565b15610f145760405162461bcd60e51b815260040161034d90614928565b610f338989898989898960405180602001604052806000815250612389565b60016000559998505050505050505050565b610f4d611602565b6001600160a01b0316336001600160a01b03161480610f845750610f6f6114aa565b6001600160a01b0316336001600160a01b0316145b610fa05760405162461bcd60e51b815260040161034d90614848565b7f80e6706973d0c59541550537fd6a33b971efad732635e6c3b99fb01006803cdf55565b60045460ff1681565b610fd5611602565b6001600160a01b0316336001600160a01b0316148061100c5750610ff76114aa565b6001600160a01b0316336001600160a01b0316145b6110285760405162461bcd60e51b815260040161034d90614848565b60405160009061105e9083907fa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e9104790602001614517565b604051602081830303815290604052805190602001209050600081555050565b600f6020526000908152604090205481565b60006001600054146110b45760405162461bcd60e51b815260040161034d906148c8565b60026000819055506110d16000356001600160e01b031916611381565b156110ee5760405162461bcd60e51b815260040161034d90614928565b6110f883836125ae565b90505b600160005592915050565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b600080827f37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb660001b6040516020016111579291906144f1565b604051602081830303815290604052805190602001209050610a448160116000866001600160a01b03166001600160a01b03168152602001908152602001600020546111a1611479565b6001600160a01b03871660009081526010602052604090205461273f565b60008315610a44576111cf611ecd565b8411610a44576001600160a01b0382166111fb5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291505b6112d7600a600080516020614aaf8339815191526001600160a01b03166313814ca4600f60008760016040516020016112359291906144cb565b6040516020818303038152906040528051906020012060001c815260200190815260200160002054886040518363ffffffff1660e01b815260040161127b9291906146fb565b60206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112cb9190810190613bd0565b9063ffffffff61279916565b9050610a44565b3360009081526012602090815260408083206001600160a01b038616845290915281205480831061131157506000611315565b8290035b3360008181526012602090815260408083206001600160a01b03891680855292529182902084905590519091907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061136f90859061467c565b60405180910390a35060019392505050565b600080827fa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e9104760001b6040516020016113ba929190614517565b60408051601f198184030181529190528051602090910120549392505050565b6001600160a01b031660009081526011602052604090205490565b6113fd6114b9565b6114195760405162461bcd60e51b815260040161034d90614868565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b600454600160601b90046001600160a01b031681565b6000610c3b61148e611489610cf9565b611fb5565b6127be565b6000610c3b6114a0611f81565b600061091c610bb7565b6001546001600160a01b031690565b6001546000906001600160a01b03166114d06127ed565b6001600160a01b031614905090565b6000610c3b611489610cf9565b6003805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610b105780601f10610ae557610100808354040283529160200191610b10565b600080516020614aaf83398151915281565b600060016000541461157d5760405162461bcd60e51b815260040161034d906148c8565b600260008190555061159a6000356001600160e01b031916611381565b156115b75760405162461bcd60e51b815260040161034d90614928565b6115c0826127f1565b905080156110fb576110fb6004600c9054906101000a90046001600160a01b03168483604051806040016040528060018152602001603560f81b815250612919565b7f80e6706973d0c59541550537fd6a33b971efad732635e6c3b99fb01006803cdf5490565b6000610a443384846000196121e8565b61163f611602565b6001600160a01b0316336001600160a01b0316148061167657506116616114aa565b6001600160a01b0316336001600160a01b0316145b6116925760405162461bcd60e51b815260040161034d90614848565b6040516000906116c89083907fa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e9104790602001614517565b604051602081830303815290604052805190602001209050600181555050565b6116f0611602565b6001600160a01b0316336001600160a01b0316148061172757506117126114aa565b6001600160a01b0316336001600160a01b0316145b6117435760405162461bcd60e51b815260040161034d90614848565b60005b8181101561177a5761177283838381811061175d57fe5b905060200201602061056b9190810190613b76565b600101611746565b505050565b6000610a8561178c610cf9565b8361091c610bb7565b604051635c3ef8ad60e11b8152600090600080516020614aaf8339815191529063b87df15a90610beb903090600401614577565b6000806117d4610cf9565b9050610bab816117e383611fb5565b612979565b606060016000541461180c5760405162461bcd60e51b815260040161034d906148c8565b60026000819055506118296000356001600160e01b031916611381565b156118465760405162461bcd60e51b815260040161034d90614928565b876118635760405162461bcd60e51b815260040161034d906148d8565b61186d60006129a5565b600061187f473463ffffffff612a0b16565b9050600061189661188e611f81565b6112cb611ecd565b905080600c819055506118da6004600c9054906101000a90046001600160a01b03168a8c60405180604001604052806002815260200161333960f01b815250612919565b7fc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e89896004600c9054906101000a90046001600160a01b03168d60405161192494939291906145bb565b60405180910390a16060866119725785858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293506119ad92505050565b8787604051611982929190614550565b60405190819003812061199b9188908890602001614533565b60405160208183030381529060405290505b60006060720f400e6818158d541c3ebe45fe3aa0d47372ff6001600160a01b03163463de064e0d8d866040516024016119e7929190614618565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611a20919061455d565b60006040518083038185875af1925050503d8060008114611a5d576040519150601f19603f3d011682016040523d82523d6000602084013e611a62565b606091505b509150915081611a845760405162461bcd60e51b815260040161034d90614888565b6000600c81905550600080516020614aaf8339815191526001600160a01b031663392544838d8f6015546040518463ffffffff1660e01b8152600401611acc93929190614653565b600060405180830381600087803b158015611ae657600080fd5b505af1158015611afa573d6000803e3d6000fd5b50505050844710158015611b18575083611b1561188e611f81565b10155b611b345760405162461bcd60e51b815260040161034d906147f8565b60016000559c9b505050505050505050505050565b600080611b54610cf9565b90506000611b6182611fb5565b905060008412611b8257611b7b818563ffffffff61279916565b9050611b99565b611b9681600086900363ffffffff612a0b16565b90505b610d62611baa83600061091c610bb7565b8383611c88565b3360009081526012602090815260408083206001600160a01b03861684529091528120548190611be7908463ffffffff61279916565b3360008181526012602090815260408083206001600160a01b038a168085529252918290208490559051929350917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061136f90859061467c565b6001600160a01b03918216600090815260126020908152604080832093909416825291909152205490565b6001600160a01b031660009081526010602052604090205490565b60008215801590611c995750828210155b15610a44576112d768056bc75e2d631000008002610a79611d4168056bc75e2d63100000600080516020614aaf8339815191526001600160a01b0316634699f8466040518163ffffffff1660e01b815260040160206040518083038186803b158015611d0457600080fd5b505afa158015611d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d3c9190810190613bd0565b612a0b565b610a6d611d4e8888612979565b899063ffffffff611f0516565b611d636114b9565b611d7f5760405162461bcd60e51b815260040161034d90614868565b611d8881612a4d565b50565b611d93611602565b6001600160a01b0316336001600160a01b03161480611dca5750611db56114aa565b6001600160a01b0316336001600160a01b0316145b611de65760405162461bcd60e51b815260040161034d90614848565b60005b8181101561177a57611e15838383818110611e0057fe5b905060200201602061079f9190810190613b76565b600101611de9565b600080611e3c611e33868663ffffffff61279916565b6117e387611fb5565b601654604051635e36559360e01b81529192506001600160a01b031690635e36559390611e6f90849087906004016146fb565b60206040518083038186803b158015611e8757600080fd5b505afa158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ebf9190810190613bd0565b95945050505050565b600781565b600480546040516370a0823160e01b8152600092600160601b9092046001600160a01b0316916370a0823191610beb91309101614577565b600082611f1457506000610b7d565b82820282848281611f2157fe5b0414610a445760405162461bcd60e51b815260040161034d90614838565b6000610a4483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612acf565b60405163157b9bb560e11b8152600090600080516020614aaf83398151915290632af7376a90610beb903090600401614577565b600c5480610a8857610a85826112cb611ecd565b611fd1613683565b611fe66000356001600160e01b031916611381565b156120035760405162461bcd60e51b815260040161034d90614928565b8715806120185750336001600160a01b038416145b6120345760405162461bcd60e51b815260040161034d906147c8565b61203d886129a5565b8761207457833033854260405160200161205b959493929190614472565b6040516020818303038152906040528051906020012097505b6001600160a01b03841661209a5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc293505b6004546001600160a01b03858116600160601b9092041614156120cf5760405162461bcd60e51b815260040161034d906147b8565b6120d76136a7565b6120df6136c5565b3082526001600160a01b0385166020830181905260408301526060810188905260808101879052600080612115888a8c8e612b06565b602087019390935293509091508290506121415760405162461bcd60e51b815260040161034d906147e8565b6121518c60008d8b88888c612b65565b8051909550600080516020614aaf8339815191529063b1bb8225908461218985610a7983670de0b6b3a764000063ffffffff611f0516565b6040518463ffffffff1660e01b81526004016121a793929190614709565b600060405180830381600087803b1580156121c157600080fd5b505af11580156121d5573d6000803e3d6000fd5b5050505050505050979650505050505050565b60006000198214612244576040805180820190915260028152610c4d60f21b602082015261221f908390859063ffffffff612d2f16565b6001600160a01b03861660009081526012602090815260408083203384529091529020555b6001600160a01b03841661226a5760405162461bcd60e51b815260040161034d90614738565b6001600160a01b03851660009081526011602090815260408083205481518083019092526002825261189b60f11b928201929092529091906122b5908390879063ffffffff612d2f16565b6001600160a01b038089166000908152601160205260408082208490559189168152908120549192506122ee828863ffffffff61279916565b6001600160a01b0389166000908152601160205260408120829055909150612314611479565b90506123228a868684612d5b565b61232e89848484612d5b565b886001600160a01b03168a6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8a604051612371919061467c565b60405180910390a35060019998505050505050505050565b612391613683565b6123a66000356001600160e01b031916611381565b156123c35760405162461bcd60e51b815260040161034d90614928565b876123e05760405162461bcd60e51b815260040161034d906148f8565b3415806123ec57508534145b6124085760405162461bcd60e51b815260040161034d90614778565b8515158061241557508815155b6124315760405162461bcd60e51b815260040161034d90614908565b6001600160a01b03851615158061244757503415155b8061245157508815155b61246d5760405162461bcd60e51b815260040161034d906148b8565b8815806124825750336001600160a01b038516145b61249e5760405162461bcd60e51b815260040161034d906147c8565b6124a7896129a5565b886124de5784303386426040516020016124c5959493929190614472565b6040516020818303038152906040528051906020012098505b6001600160a01b0385166125045773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc294505b6004546001600160a01b03868116600160601b9092041614156125395760405162461bcd60e51b815260040161034d90614728565b6125416136a7565b6125496136c5565b3082526001600160a01b03868116602080850191909152908616604080850191909152608083018a90528282018c90526000838201819052815192830190915280825261259f918d918d918b9087908790612b65565b9b9a5050505050505050505050565b60006125c56000356001600160e01b031916611381565b156125e25760405162461bcd60e51b815260040161034d90614928565b816125ff5760405162461bcd60e51b815260040161034d90614818565b61260960006129a5565b600061261961148e611489611f81565b905061263781610a7985670de0b6b3a764000063ffffffff611f0516565b91503461267f5761267a6004600c9054906101000a90046001600160a01b031633308660405180604001604052806002815260200161062760f31b815250612e11565b612707565b82341461269e5760405162461bcd60e51b815260040161034d90614828565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156126ed57600080fd5b505af1158015612701573d6000803e3d6000fd5b50505050505b6001600160a01b03841660009081526011602052604090205461273890859061273282868887612e35565b84612d5b565b5092915050565b60008161274e57506000610d62565b508354611ebf8161278d670de0b6b3a764000061278188612775898963ffffffff612f5616565b9063ffffffff612f9c16565b9063ffffffff61300716565b9063ffffffff61306b16565b600082820183811015610a445760405162461bcd60e51b815260040161034d90614758565b601354600090806127d157600e54610a44565b610a4481610a7985670de0b6b3a764000063ffffffff611f0516565b3390565b60006128086000356001600160e01b031916611381565b156128255760405162461bcd60e51b815260040161034d90614928565b816128425760405162461bcd60e51b815260040161034d90614858565b61284c60006129a5565b612855336113da565b82111561288957600019821461287d5760405162461bcd60e51b815260040161034d90614808565b612886336113da565b91505b600061289961148e611489611f81565b905060006128b9670de0b6b3a7640000610a79868563ffffffff611f0516565b905060006128c5611ecd565b9050819350808411156128ea5760405162461bcd60e51b815260040161034d90614788565b33600081815260116020526040902054612911919061290b828989896130b1565b86612d5b565b505050919050565b60405161297390859063a9059cbb60e01b9061293b9087908790602401614638565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152836131d6565b50505050565b60008115610b7d5761299e82610a798568056bc75e2d6310000063ffffffff611f0516565b9050610b7d565b60405163789b79bf60e11b8152600080516020614aaf8339815191529063f136f37e906129d690849060040161467c565b600060405180830381600087803b1580156129f057600080fd5b505af1158015612a04573d6000803e3d6000fd5b5050505050565b6000610a4483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612d2f565b6001600160a01b038116612a735760405162461bcd60e51b815260040161034d90614748565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b60008183612af05760405162461bcd60e51b815260040161034d9190614717565b506000838581612afc57fe5b0495945050505050565b600080600080612b1788888861329c565b90925090506000612b386f4b3b4ca85a86c47a098a22400000000087611f3f565b9050612b5781610a798568056bc75e2d6310000063ffffffff611f0516565b945050945094509450949050565b612b6d613683565b612b75611ecd565b602084015111801590612b94575060208401516001600160a01b031615155b612bb05760405162461bcd60e51b815260040161034d90614798565b60408401516001600160a01b0316612bd65760208401516001600160a01b031660408501525b6000612be48686868b61342c565b60208501516060860151919250612bfb9190612799565b60608501528715612c1b576060840151612c159089612a0b565b60608501525b600088612c29576000612c2c565b60015b90506000600f60008984604051602001612c479291906144cb565b6040516020818303038152906040528051906020012060001c815260200190815260200160002054905088600014612c9657612c936f4b3b4ca85a86c47a098a2240000000008a611f3f565b98505b600080516020614aaf8339815191526001600160a01b031663585314cf84838e868e8d8d8d6040518963ffffffff1660e01b8152600401612cdd979695949392919061468a565b6060604051808303818588803b158015612cf657600080fd5b505af1158015612d0a573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525061259f9190810190613bb2565b60008184841115612d535760405162461bcd60e51b815260040161034d9190614717565b505050900390565b604051600090612d919086907f37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6906020016144f1565b60405160208183030381529060405280519060200120905060008360001415612dbd5760009250612dee565b8415612dee576001600160a01b038616600090815260106020526040902054612deb9083908790869061273f565b90505b90556001600160a01b039093166000908152601060205260409020929092555050565b604051612a049086906323b872dd60e01b9061293b908890889088906024016145f0565b60006001600160a01b038516612e5d5760405162461bcd60e51b815260040161034d90614738565b6001600160a01b038516600090815260116020526040812054612e86908663ffffffff61279916565b6001600160a01b0387166000908152601160205260409020819055601354909150612eb7908663ffffffff61279916565b6013556040516001600160a01b038716907fb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb90612ef990889088908890614709565b60405180910390a2856001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef87604051612f45919061467c565b60405180910390a395945050505050565b6000818303818312801590612f6b5750838113155b80612f805750600083128015612f8057508381135b610a445760405162461bcd60e51b815260040161034d906148e8565b600082612fab57506000610b7d565b82600019148015612fbf5750600160ff1b82145b15612fdc5760405162461bcd60e51b815260040161034d90614898565b82820282848281612fe957fe5b0514610a445760405162461bcd60e51b815260040161034d90614898565b6000816130265760405162461bcd60e51b815260040161034d90614918565b8160001914801561303a5750600160ff1b83145b156130575760405162461bcd60e51b815260040161034d906147d8565b600082848161306257fe5b05949350505050565b60008282018183128015906130805750838112155b80613095575060008312801561309557508381125b610a445760405162461bcd60e51b815260040161034d90614768565b6040805180820182526002815261189b60f11b6020808301919091526001600160a01b038716600090815260119091529182205482916130f99190879063ffffffff612d2f16565b9050600a811161311a57613113858263ffffffff61279916565b9450600090505b6001600160a01b0386166000908152601160205260409020819055601354613148908663ffffffff612a0b16565b6013556040516001600160a01b038716907f743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b46449061318a90889088908890614709565b60405180910390a260006001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef87604051612f45919061467c565b60006060846001600160a01b0316846040516131f2919061455d565b6000604051808303816000865af19150503d806000811461322f576040519150601f19603f3d011682016040523d82523d6000602084013e613234565b606091505b50915091508183906132595760405162461bcd60e51b815260040161034d9190614717565b50805115612a04578080602001905161327591908101906139dc565b83906132945760405162461bcd60e51b815260040161034d9190614717565b505050505050565b6000806000600080516020614aaf8339815191526001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156132e857600080fd5b505afa1580156132fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613320919081019061387d565b60048054604051630a7549df60e21b81526001600160a01b03938416936329d5277c9361335b938c93600160601b90910490921691016145a0565b604080518083038186803b15801561337257600080fd5b505afa158015613386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506133aa9190810190613c9c565b909250905081158015906133bd57508015155b6133d95760405162461bcd60e51b815260040161034d906147a8565b6133f581610a7984670de0b6b3a764000063ffffffff611f0516565b8493509150841561342357613420836112cb670de0b6b3a7640000610a79898763ffffffff611f0516565b92505b50935093915050565b600454604084015160208401516060850151608086015160009473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2946001600160a01b03600160601b9092048216949093909290918b168514156134965760405162461bcd60e51b815260040161034d90614878565b3496508715613508576134c585858a60405180604001604052806002815260200161323760f01b815250612919565b878311156135035761350385600080516020614aaf8339815191528a860360405180604001604052806002815260200161323760f01b815250612919565b61353c565b61353c85600080516020614aaf8339815191528560405180604001604052806002815260200161323760f01b815250612919565b801561363a57856001600160a01b03168b6001600160a01b031614801561356257508615155b801561356e5750808710155b1561360557856001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156135ae57600080fd5b505af11580156135c2573d6000803e3d6000fd5b50505050506135fb8b600080516020614aaf8339815191528360405180604001604052806002815260200161064760f31b815250612919565b808703965061363a565b61363a8b33600080516020614aaf8339815191528460405180604001604052806002815260200161064760f31b815250612e11565b8115613675576136758533600080516020614aaf8339815191528560405180604001604052806002815260200161323960f01b815250612e11565b505050505050949350505050565b60405180606001604052806000801916815260200160008152602001600081525090565b60405180608001604052806004906020820280388339509192915050565b6040518060a001604052806005906020820280388339509192915050565b8035610b7d81614a7f565b8051610b7d81614a7f565b60008083601f84011261370b57600080fd5b50813567ffffffffffffffff81111561372357600080fd5b60208301915083602082028301111561373b57600080fd5b9250929050565b8051610b7d81614a93565b8035610b7d81614a9c565b8051610b7d81614a9c565b8035610b7d81614aa5565b60008083601f84011261378057600080fd5b50813567ffffffffffffffff81111561379857600080fd5b60208301915083600182028301111561373b57600080fd5b600082601f8301126137c157600080fd5b81356137d46137cf8261497b565b614954565b915080825260208301602083018583830111156137f057600080fd5b6137fb838284614a05565b50505092915050565b60006060828403121561381657600080fd5b6138206060614954565b9050600061382e8484613758565b825250602061383f84848301613758565b602083015250604061385384828501613758565b60408301525092915050565b60006020828403121561387157600080fd5b6000610d6284846136e3565b60006020828403121561388f57600080fd5b6000610d6284846136ee565b600080604083850312156138ae57600080fd5b60006138ba85856136e3565b92505060206138cb858286016136e3565b9150509250929050565b6000806000606084860312156138ea57600080fd5b60006138f686866136e3565b9350506020613907868287016136e3565b92505060406139188682870161374d565b9150509250925092565b6000806040838503121561393557600080fd5b600061394185856136e3565b925050602083013567ffffffffffffffff81111561395e57600080fd5b6138cb858286016137b0565b6000806040838503121561397d57600080fd5b600061398985856136e3565b92505060206138cb8582860161374d565b600080602083850312156139ad57600080fd5b823567ffffffffffffffff8111156139c457600080fd5b6139d0858286016136f9565b92509250509250929050565b6000602082840312156139ee57600080fd5b6000610d628484613742565b600080600080600080600080610100898b031215613a1757600080fd5b6000613a238b8b61374d565b9850506020613a348b828c0161374d565b9750506040613a458b828c0161374d565b9650506060613a568b828c0161374d565b9550506080613a678b828c016136e3565b94505060a0613a788b828c016136e3565b93505060c0613a898b828c016136e3565b92505060e089013567ffffffffffffffff811115613aa657600080fd5b613ab28b828c016137b0565b9150509295985092959890939650565b600080600080600080600060e0888a031215613add57600080fd5b6000613ae98a8a61374d565b9750506020613afa8a828b0161374d565b9650506040613b0b8a828b0161374d565b9550506060613b1c8a828b0161374d565b9450506080613b2d8a828b016136e3565b93505060a0613b3e8a828b016136e3565b92505060c088013567ffffffffffffffff811115613b5b57600080fd5b613b678a828b016137b0565b91505092959891949750929550565b600060208284031215613b8857600080fd5b6000610d628484613763565b600060208284031215613ba657600080fd5b6000610d62848461374d565b600060608284031215613bc457600080fd5b6000610d628484613804565b600060208284031215613be257600080fd5b6000610d628484613758565b600080600080600080600060a0888a031215613c0957600080fd5b6000613c158a8a61374d565b9750506020613c268a828b016136e3565b9650506040613c378a828b016136e3565b955050606088013567ffffffffffffffff811115613c5457600080fd5b613c608a828b0161376e565b9450945050608088013567ffffffffffffffff811115613c7f57600080fd5b613c8b8a828b0161376e565b925092505092959891949750929550565b60008060408385031215613caf57600080fd5b6000613cbb8585613758565b92505060206138cb85828601613758565b600080600060608486031215613ce157600080fd5b6000613ced868661374d565b9350506020613cfe8682870161374d565b9250506040613918868287016136e3565b600080600060608486031215613d2457600080fd5b6000613d30868661374d565b93505060206139078682870161374d565b6000613d4d8383613d81565b505060200190565b6000613d4d8383613e3c565b613d6a816149f4565b82525050565b613d6a613d7c826149c5565b614a3d565b613d6a816149c5565b613d93816149a6565b613d9d8184610a88565b9250613da8826149a3565b8060005b83811015613294578151613dc08782613d41565b9650613dcb836149b6565b925050600101613dac565b613ddf816149ac565b613de98184610a88565b9250613df4826149a3565b8060005b83811015613294578151613e0c8782613d55565b9650613e17836149b6565b925050600101613df8565b613d6a816149d0565b613d6a613e37826149d0565b614a48565b613d6a816149a3565b613d6a613e51826149a3565b6149a3565b613d6a613e51826149d5565b6000613e6e8385610a88565b9350613e7b838584614a05565b50500190565b6000613e8c826149b2565b613e9681856149bc565b9350613ea6818560208601614a11565b613eaf81614a69565b9093019392505050565b6000613ec4826149b2565b613ece8185610a88565b9350613ede818560208601614a11565b9290920192915050565b6000613ef56002836149bc565b61031360f41b815260200192915050565b6000613f136002836149bc565b61313560f01b815260200192915050565b6000613f316026836149bc565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000613f79601b836149bc565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613fb26021836149bc565b7f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613ff56001836149bc565b603760f81b815260200192915050565b60006140126002836149bc565b61333760f01b815260200192915050565b60006140306002836149bc565b610c8d60f21b815260200192915050565b600061404e6002836149bc565b61032360f41b815260200192915050565b600061406c6002836149bc565b61313160f01b815260200192915050565b600061408a6002836149bc565b61313360f01b815260200192915050565b60006140a86021836149bc565b7f5369676e6564536166654d6174683a206469766973696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006140eb6002836149bc565b61189960f11b815260200192915050565b60006141096002836149bc565b61034360f41b815260200192915050565b60006141276002836149bc565b61199960f11b815260200192915050565b60006141456002836149bc565b61313760f01b815260200192915050565b60006141636002836149bc565b61062760f31b815260200192915050565b60006141816021836149bc565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006141c4600c836149bc565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006141ec6002836149bc565b61313960f01b815260200192915050565b600061420a6020836149bc565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b60006142436002836149bc565b61191b60f11b815260200192915050565b6000614261600b836149bc565b6a18d85b1b0819985a5b195960aa1b815260200192915050565b60006142886027836149bc565b7f5369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f815266766572666c6f7760c81b602082015260400192915050565b60006142d16014836149bc565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b60006143016001836149bc565b603960f81b815260200192915050565b600061431e600c836149bc565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b60006143466002836149bc565b61066760f31b815260200192915050565b60006143646024836149bc565b7f5369676e6564536166654d6174683a207375627472616374696f6e206f766572815263666c6f7760e01b602082015260400192915050565b60006143aa6001836149bc565b601b60f91b815260200192915050565b60006143c76001836149bc565b600760fb1b815260200192915050565b60006143e46020836149bc565b7f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f815260200192915050565b600061441d6006836149bc565b651c185d5cd95960d21b815260200192915050565b805160608301906144438482613e3c565b5060208201516144566020850182613e3c565b5060408201516129736040850182613e3c565b613d6a816149ee565b600061447e8288613d70565b60148201915061448e8287613d70565b60148201915061449e8286613d70565b6014820191506144ae8285613d70565b6014820191506144be8284613e45565b5060200195945050505050565b60006144d78285613d70565b6014820191506144e78284613e2b565b5060010192915050565b60006144fd8285613d70565b60148201915061450d8284613e45565b5060200192915050565b60006145238285613e56565b60048201915061450d8284613e45565b600061453f8286613e56565b600482019150611ebf828486613e62565b6000610d62828486613e62565b6000610a448284613eb9565b60208101610b7d8284613d81565b60208101610b7d8284613d61565b604081016145938285613d61565b610a446020830184613d61565b604081016145ae8285613d81565b610a446020830184613d81565b608081016145c98287613d81565b6145d66020830186613d81565b6145e36040830185613d81565b611ebf6060830184613e3c565b606081016145fe8286613d81565b61460b6020830185613d81565b610d626040830184613e3c565b604081016146268285613d81565b8181036020830152610d628184613e81565b604081016146468285613d81565b610a446020830184613e3c565b606081016146618286613d81565b61460b6020830185613e3c565b60208101610b7d8284613e22565b60208101610b7d8284613e3c565b6101c08101614699828a613e3c565b6146a66020830189613e3c565b6146b36040830188613e22565b6146c06060830187613e3c565b6146cd6080830186613d8a565b6146db610100830185613dd6565b8181036101a08301526146ee8184613e81565b9998505050505050505050565b604081016146468285613e3c565b606081016146618286613e3c565b60208082528101610a448184613e81565b60208082528101610a8581613ee8565b60208082528101610a8581613f06565b60208082528101610a8581613f24565b60208082528101610a8581613f6c565b60208082528101610a8581613fa5565b60208082528101610a8581613fe8565b60208082528101610a8581614005565b60208082528101610a8581614023565b60208082528101610a8581614041565b60208082528101610a858161405f565b60208082528101610a858161407d565b60208082528101610a858161409b565b60208082528101610a85816140de565b60208082528101610a85816140fc565b60208082528101610a858161411a565b60208082528101610a8581614138565b60208082528101610a8581614156565b60208082528101610a8581614174565b60208082528101610a85816141b7565b60208082528101610a85816141df565b60208082528101610a85816141fd565b60208082528101610a8581614236565b60208082528101610a8581614254565b60208082528101610a858161427b565b60208082528101610a85816142c4565b60208082528101610a85816142f4565b60208082528101610a8581614311565b60208082528101610a8581614339565b60208082528101610a8581614357565b60208082528101610a858161439d565b60208082528101610a85816143ba565b60208082528101610a85816143d7565b60208082528101610a8581614410565b60608101610b7d8284614432565b60208101610b7d8284614469565b60405181810167ffffffffffffffff8111828210171561497357600080fd5b604052919050565b600067ffffffffffffffff82111561499257600080fd5b506020601f91909101601f19160190565b90565b50600490565b50600590565b5190565b60200190565b90815260200190565b6000610a85826149e2565b151590565b6001600160e01b03191690565b6001600160a01b031690565b60ff1690565b6000610a85826000610a85826149c5565b82818337506000910152565b60005b83811015614a2c578181015183820152602001614a14565b838111156129735750506000910152565b6000610a8582614a53565b6000610a8582614a5e565b6000610a8582614a79565b6000610a8582614a73565b601f01601f191690565b60f81b90565b60601b90565b614a88816149c5565b8114611d8857600080fd5b614a88816149d0565b614a88816149a3565b614a88816149d556fe000000000000000000000000d8ee69652e4e4838f2531732a46d1f7f584f0b7fa365627a7a72315820f08d69608993c54a231668dbabc76de551d2bd4ec715ee1d77cc28b70bcb63a06c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0

Deployed Bytecode

0x60806040526004361061031a5760003560e01c8063715018a6116101ab578063ac544a04116100f7578063dd62ed3e11610095578063f2fde38b1161006f578063f2fde38b146108c1578063f8ddf397146108e1578063f96b660a14610901578063ffa1ad74146109215761031a565b8063dd62ed3e14610861578063eebc508114610881578063ef4e1fe4146108a15761031a565b8063bf7d653b116100d1578063bf7d653b146107f9578063c5bf0e9d1461080e578063c674184f14610821578063d73dd623146108415761031a565b8063ac544a04146107a4578063b9fe1a8f146107c4578063baa7719c146107e45761031a565b80638fb807c5116101645780639dc29fac1161013e5780639dc29fac1461072f578063a75b87d21461074f578063a9059cbb14610764578063ab3d9ffa146107845761031a565b80638fb807c5146106f057806395d89b4114610705578063995363d31461071a5761031a565b8063715018a614610672578063797bf385146106875780637ff9b5961461069c5780638325a1c0146106b15780638da5cb5b146106c65780638f32d59b146106db5761031a565b8063284e2f561161026a57806340c10f1911610223578063631a3ef8116101fd578063631a3ef8146105f257806366188463146106125780636a8cb4c61461063257806370a08231146106525761031a565b806340c10f19146105905780634b57b0be146105b057806354198ce9146105d25761031a565b8063284e2f56146104db5780632ea295fa146104fb5780632fcb4f041461050e578063313ce5671461052e578063323e35b1146105505780633291c11a146105705761031a565b80630ae1dc65116102d757806318160ddd116102b157806318160ddd1461047c5780631d0806ae1461049157806320f6d07c146104a657806323b872dd146104bb5761031a565b80630ae1dc65146104275780630d198dd71461043c57806314dfe7921461045c5761031a565b8063047979301461035857806306b3efd61461038e57806306fdde03146103ae578063095ea7b3146103d057806309ec6b6b146103fd5780630a24cdce14610412575b3373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146103565760405162461bcd60e51b815260040161034d906148a8565b60405180910390fd5b005b34801561036457600080fd5b50610378610373366004613ccc565b610936565b604051610385919061467c565b60405180910390f35b34801561039a57600080fd5b506103786103a936600461385f565b610a4b565b3480156103ba57600080fd5b506103c3610a8d565b6040516103859190614717565b3480156103dc57600080fd5b506103f06103eb36600461396a565b610b18565b604051610385919061466e565b34801561040957600080fd5b50610378610b83565b34801561041e57600080fd5b50610378610bb1565b34801561043357600080fd5b50610378610bb7565b34801561044857600080fd5b50610356610457366004613b94565b610c40565b61046f61046a366004613ac2565b610c69565b6040516103859190614938565b34801561048857600080fd5b50610378610ced565b34801561049d57600080fd5b50610378610cf3565b3480156104b257600080fd5b50610378610cf9565b3480156104c757600080fd5b506103f06104d63660046138d5565b610d2f565b3480156104e757600080fd5b506103566104f6366004613922565b610d6a565b61046f6105093660046139fa565b610eb0565b34801561051a57600080fd5b5061035661052936600461385f565b610f45565b34801561053a57600080fd5b50610543610fc4565b6040516103859190614946565b34801561055c57600080fd5b5061035661056b366004613b76565b610fcd565b34801561057c57600080fd5b5061037861058b366004613b94565b61107e565b34801561059c57600080fd5b506103786105ab36600461396a565b611090565b3480156105bc57600080fd5b506105c5611106565b6040516103859190614569565b3480156105de57600080fd5b506103786105ed36600461385f565b61111e565b3480156105fe57600080fd5b5061037861060d366004613ccc565b6111bf565b34801561061e57600080fd5b506103f061062d36600461396a565b6112de565b34801561063e57600080fd5b506103f061064d366004613b76565b611381565b34801561065e57600080fd5b5061037861066d36600461385f565b6113da565b34801561067e57600080fd5b506103566113f5565b34801561069357600080fd5b506105c5611463565b3480156106a857600080fd5b50610378611479565b3480156106bd57600080fd5b50610378611493565b3480156106d257600080fd5b506105c56114aa565b3480156106e757600080fd5b506103f06114b9565b3480156106fc57600080fd5b506103786114df565b34801561071157600080fd5b506103c36114ec565b34801561072657600080fd5b506105c5611547565b34801561073b57600080fd5b5061037861074a36600461396a565b611559565b34801561075b57600080fd5b506105c5611602565b34801561077057600080fd5b506103f061077f36600461396a565b611627565b34801561079057600080fd5b5061035661079f366004613b76565b611637565b3480156107b057600080fd5b506103566107bf36600461399a565b6116e8565b3480156107d057600080fd5b506103786107df366004613b94565b61177f565b3480156107f057600080fd5b50610378611795565b34801561080557600080fd5b506103786117c9565b6103c361081c366004613bee565b6117e8565b34801561082d57600080fd5b5061037861083c366004613b94565b611b49565b34801561084d57600080fd5b506103f061085c36600461396a565b611bb1565b34801561086d57600080fd5b5061037861087c36600461389b565b611c42565b34801561088d57600080fd5b5061037861089c36600461385f565b611c6d565b3480156108ad57600080fd5b506103786108bc366004613d0f565b611c88565b3480156108cd57600080fd5b506103566108dc36600461385f565b611d5b565b3480156108ed57600080fd5b506103566108fc36600461399a565b611d8b565b34801561090d57600080fd5b5061037861091c366004613d0f565b611e1d565b34801561092d57600080fd5b50610378611ec8565b60008315610a44576001600160a01b0382166109645773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291505b600080516020614aaf8339815191526001600160a01b03166365df83f6600f60008560016040516020016109999291906144cb565b6040516020818303038152906040528051906020012060001c815260200190815260200160002054866040518363ffffffff1660e01b81526004016109df9291906146fb565b60206040518083038186803b1580156109f757600080fd5b505afa158015610a0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a2f9190810190613bd0565b9050610a39611ecd565b811115610a44575060005b9392505050565b6000610a85670de0b6b3a7640000610a79610a64611479565b610a6d866113da565b9063ffffffff611f0516565b9063ffffffff611f3f16565b90505b919050565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610b105780601f10610ae557610100808354040283529160200191610b10565b820191906000526020600020905b815481529060010190602001808311610af357829003601f168201915b505050505081565b3360008181526012602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610b7190869061467c565b60405180910390a35060015b92915050565b600080610b8e611f81565b9050610bab610ba182600061091c610bb7565b826108bc84611fb5565b91505090565b60155481565b6040516359418b1560e11b8152600090600080516020614aaf8339815191529063b283162a90610beb903090600401614577565b60206040518083038186803b158015610c0357600080fd5b505afa158015610c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c3b9190810190613bd0565b905090565b610c486114b9565b610c645760405162461bcd60e51b815260040161034d90614868565b601555565b610c71613683565b600160005414610c935760405162461bcd60e51b815260040161034d906148c8565b6002600081905550610cb06000356001600160e01b031916611381565b15610ccd5760405162461bcd60e51b815260040161034d90614928565b610cdc88888888888888611fc9565b600160005598975050505050505050565b60135490565b600e5481565b60405163250f447f60e11b8152600090600080516020614aaf83398151915290634a1e88fe90610beb9030908590600401614585565b6001600160a01b0383166000908152601260209081526040808320338452909152812054610d62908590859085906121e8565b949350505050565b610d726114aa565b6001600160a01b0316336001600160a01b031614610e03577f7ad06df6a0af6bd602d90db766e0d5f253b45187c3717a0f9026ea8b10ff0d4b547f34b31cff1dbd8374124bd4505521fc29cab0f9554a5386ba7d784a4e611c7e3154336001600160a01b038316148015610df75750806001600160a01b0316846001600160a01b0316145b610e0057600080fd5b50505b601480546001600160a01b038481166001600160a01b03198316179092556040519116906000903090610e3790859061455d565b6000604051808303816000865af19150503d8060008114610e74576040519150601f19603f3d011682016040523d82523d6000602084013e610e79565b606091505b50506040519091503d90816000823e82610e91578181fd5b601480546001600160a01b0319166001600160a01b0386161790558181f35b610eb8613683565b600160005414610eda5760405162461bcd60e51b815260040161034d906148c8565b6002600081905550610ef76000356001600160e01b031916611381565b15610f145760405162461bcd60e51b815260040161034d90614928565b610f338989898989898960405180602001604052806000815250612389565b60016000559998505050505050505050565b610f4d611602565b6001600160a01b0316336001600160a01b03161480610f845750610f6f6114aa565b6001600160a01b0316336001600160a01b0316145b610fa05760405162461bcd60e51b815260040161034d90614848565b7f80e6706973d0c59541550537fd6a33b971efad732635e6c3b99fb01006803cdf55565b60045460ff1681565b610fd5611602565b6001600160a01b0316336001600160a01b0316148061100c5750610ff76114aa565b6001600160a01b0316336001600160a01b0316145b6110285760405162461bcd60e51b815260040161034d90614848565b60405160009061105e9083907fa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e9104790602001614517565b604051602081830303815290604052805190602001209050600081555050565b600f6020526000908152604090205481565b60006001600054146110b45760405162461bcd60e51b815260040161034d906148c8565b60026000819055506110d16000356001600160e01b031916611381565b156110ee5760405162461bcd60e51b815260040161034d90614928565b6110f883836125ae565b90505b600160005592915050565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b600080827f37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb660001b6040516020016111579291906144f1565b604051602081830303815290604052805190602001209050610a448160116000866001600160a01b03166001600160a01b03168152602001908152602001600020546111a1611479565b6001600160a01b03871660009081526010602052604090205461273f565b60008315610a44576111cf611ecd565b8411610a44576001600160a01b0382166111fb5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291505b6112d7600a600080516020614aaf8339815191526001600160a01b03166313814ca4600f60008760016040516020016112359291906144cb565b6040516020818303038152906040528051906020012060001c815260200190815260200160002054886040518363ffffffff1660e01b815260040161127b9291906146fb565b60206040518083038186803b15801561129357600080fd5b505afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112cb9190810190613bd0565b9063ffffffff61279916565b9050610a44565b3360009081526012602090815260408083206001600160a01b038616845290915281205480831061131157506000611315565b8290035b3360008181526012602090815260408083206001600160a01b03891680855292529182902084905590519091907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061136f90859061467c565b60405180910390a35060019392505050565b600080827fa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e9104760001b6040516020016113ba929190614517565b60408051601f198184030181529190528051602090910120549392505050565b6001600160a01b031660009081526011602052604090205490565b6113fd6114b9565b6114195760405162461bcd60e51b815260040161034d90614868565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b600454600160601b90046001600160a01b031681565b6000610c3b61148e611489610cf9565b611fb5565b6127be565b6000610c3b6114a0611f81565b600061091c610bb7565b6001546001600160a01b031690565b6001546000906001600160a01b03166114d06127ed565b6001600160a01b031614905090565b6000610c3b611489610cf9565b6003805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610b105780601f10610ae557610100808354040283529160200191610b10565b600080516020614aaf83398151915281565b600060016000541461157d5760405162461bcd60e51b815260040161034d906148c8565b600260008190555061159a6000356001600160e01b031916611381565b156115b75760405162461bcd60e51b815260040161034d90614928565b6115c0826127f1565b905080156110fb576110fb6004600c9054906101000a90046001600160a01b03168483604051806040016040528060018152602001603560f81b815250612919565b7f80e6706973d0c59541550537fd6a33b971efad732635e6c3b99fb01006803cdf5490565b6000610a443384846000196121e8565b61163f611602565b6001600160a01b0316336001600160a01b0316148061167657506116616114aa565b6001600160a01b0316336001600160a01b0316145b6116925760405162461bcd60e51b815260040161034d90614848565b6040516000906116c89083907fa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e9104790602001614517565b604051602081830303815290604052805190602001209050600181555050565b6116f0611602565b6001600160a01b0316336001600160a01b0316148061172757506117126114aa565b6001600160a01b0316336001600160a01b0316145b6117435760405162461bcd60e51b815260040161034d90614848565b60005b8181101561177a5761177283838381811061175d57fe5b905060200201602061056b9190810190613b76565b600101611746565b505050565b6000610a8561178c610cf9565b8361091c610bb7565b604051635c3ef8ad60e11b8152600090600080516020614aaf8339815191529063b87df15a90610beb903090600401614577565b6000806117d4610cf9565b9050610bab816117e383611fb5565b612979565b606060016000541461180c5760405162461bcd60e51b815260040161034d906148c8565b60026000819055506118296000356001600160e01b031916611381565b156118465760405162461bcd60e51b815260040161034d90614928565b876118635760405162461bcd60e51b815260040161034d906148d8565b61186d60006129a5565b600061187f473463ffffffff612a0b16565b9050600061189661188e611f81565b6112cb611ecd565b905080600c819055506118da6004600c9054906101000a90046001600160a01b03168a8c60405180604001604052806002815260200161333960f01b815250612919565b7fc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e89896004600c9054906101000a90046001600160a01b03168d60405161192494939291906145bb565b60405180910390a16060866119725785858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293506119ad92505050565b8787604051611982929190614550565b60405190819003812061199b9188908890602001614533565b60405160208183030381529060405290505b60006060720f400e6818158d541c3ebe45fe3aa0d47372ff6001600160a01b03163463de064e0d8d866040516024016119e7929190614618565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611a20919061455d565b60006040518083038185875af1925050503d8060008114611a5d576040519150601f19603f3d011682016040523d82523d6000602084013e611a62565b606091505b509150915081611a845760405162461bcd60e51b815260040161034d90614888565b6000600c81905550600080516020614aaf8339815191526001600160a01b031663392544838d8f6015546040518463ffffffff1660e01b8152600401611acc93929190614653565b600060405180830381600087803b158015611ae657600080fd5b505af1158015611afa573d6000803e3d6000fd5b50505050844710158015611b18575083611b1561188e611f81565b10155b611b345760405162461bcd60e51b815260040161034d906147f8565b60016000559c9b505050505050505050505050565b600080611b54610cf9565b90506000611b6182611fb5565b905060008412611b8257611b7b818563ffffffff61279916565b9050611b99565b611b9681600086900363ffffffff612a0b16565b90505b610d62611baa83600061091c610bb7565b8383611c88565b3360009081526012602090815260408083206001600160a01b03861684529091528120548190611be7908463ffffffff61279916565b3360008181526012602090815260408083206001600160a01b038a168085529252918290208490559051929350917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061136f90859061467c565b6001600160a01b03918216600090815260126020908152604080832093909416825291909152205490565b6001600160a01b031660009081526010602052604090205490565b60008215801590611c995750828210155b15610a44576112d768056bc75e2d631000008002610a79611d4168056bc75e2d63100000600080516020614aaf8339815191526001600160a01b0316634699f8466040518163ffffffff1660e01b815260040160206040518083038186803b158015611d0457600080fd5b505afa158015611d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d3c9190810190613bd0565b612a0b565b610a6d611d4e8888612979565b899063ffffffff611f0516565b611d636114b9565b611d7f5760405162461bcd60e51b815260040161034d90614868565b611d8881612a4d565b50565b611d93611602565b6001600160a01b0316336001600160a01b03161480611dca5750611db56114aa565b6001600160a01b0316336001600160a01b0316145b611de65760405162461bcd60e51b815260040161034d90614848565b60005b8181101561177a57611e15838383818110611e0057fe5b905060200201602061079f9190810190613b76565b600101611de9565b600080611e3c611e33868663ffffffff61279916565b6117e387611fb5565b601654604051635e36559360e01b81529192506001600160a01b031690635e36559390611e6f90849087906004016146fb565b60206040518083038186803b158015611e8757600080fd5b505afa158015611e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ebf9190810190613bd0565b95945050505050565b600781565b600480546040516370a0823160e01b8152600092600160601b9092046001600160a01b0316916370a0823191610beb91309101614577565b600082611f1457506000610b7d565b82820282848281611f2157fe5b0414610a445760405162461bcd60e51b815260040161034d90614838565b6000610a4483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612acf565b60405163157b9bb560e11b8152600090600080516020614aaf83398151915290632af7376a90610beb903090600401614577565b600c5480610a8857610a85826112cb611ecd565b611fd1613683565b611fe66000356001600160e01b031916611381565b156120035760405162461bcd60e51b815260040161034d90614928565b8715806120185750336001600160a01b038416145b6120345760405162461bcd60e51b815260040161034d906147c8565b61203d886129a5565b8761207457833033854260405160200161205b959493929190614472565b6040516020818303038152906040528051906020012097505b6001600160a01b03841661209a5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc293505b6004546001600160a01b03858116600160601b9092041614156120cf5760405162461bcd60e51b815260040161034d906147b8565b6120d76136a7565b6120df6136c5565b3082526001600160a01b0385166020830181905260408301526060810188905260808101879052600080612115888a8c8e612b06565b602087019390935293509091508290506121415760405162461bcd60e51b815260040161034d906147e8565b6121518c60008d8b88888c612b65565b8051909550600080516020614aaf8339815191529063b1bb8225908461218985610a7983670de0b6b3a764000063ffffffff611f0516565b6040518463ffffffff1660e01b81526004016121a793929190614709565b600060405180830381600087803b1580156121c157600080fd5b505af11580156121d5573d6000803e3d6000fd5b5050505050505050979650505050505050565b60006000198214612244576040805180820190915260028152610c4d60f21b602082015261221f908390859063ffffffff612d2f16565b6001600160a01b03861660009081526012602090815260408083203384529091529020555b6001600160a01b03841661226a5760405162461bcd60e51b815260040161034d90614738565b6001600160a01b03851660009081526011602090815260408083205481518083019092526002825261189b60f11b928201929092529091906122b5908390879063ffffffff612d2f16565b6001600160a01b038089166000908152601160205260408082208490559189168152908120549192506122ee828863ffffffff61279916565b6001600160a01b0389166000908152601160205260408120829055909150612314611479565b90506123228a868684612d5b565b61232e89848484612d5b565b886001600160a01b03168a6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8a604051612371919061467c565b60405180910390a35060019998505050505050505050565b612391613683565b6123a66000356001600160e01b031916611381565b156123c35760405162461bcd60e51b815260040161034d90614928565b876123e05760405162461bcd60e51b815260040161034d906148f8565b3415806123ec57508534145b6124085760405162461bcd60e51b815260040161034d90614778565b8515158061241557508815155b6124315760405162461bcd60e51b815260040161034d90614908565b6001600160a01b03851615158061244757503415155b8061245157508815155b61246d5760405162461bcd60e51b815260040161034d906148b8565b8815806124825750336001600160a01b038516145b61249e5760405162461bcd60e51b815260040161034d906147c8565b6124a7896129a5565b886124de5784303386426040516020016124c5959493929190614472565b6040516020818303038152906040528051906020012098505b6001600160a01b0385166125045773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc294505b6004546001600160a01b03868116600160601b9092041614156125395760405162461bcd60e51b815260040161034d90614728565b6125416136a7565b6125496136c5565b3082526001600160a01b03868116602080850191909152908616604080850191909152608083018a90528282018c90526000838201819052815192830190915280825261259f918d918d918b9087908790612b65565b9b9a5050505050505050505050565b60006125c56000356001600160e01b031916611381565b156125e25760405162461bcd60e51b815260040161034d90614928565b816125ff5760405162461bcd60e51b815260040161034d90614818565b61260960006129a5565b600061261961148e611489611f81565b905061263781610a7985670de0b6b3a764000063ffffffff611f0516565b91503461267f5761267a6004600c9054906101000a90046001600160a01b031633308660405180604001604052806002815260200161062760f31b815250612e11565b612707565b82341461269e5760405162461bcd60e51b815260040161034d90614828565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156126ed57600080fd5b505af1158015612701573d6000803e3d6000fd5b50505050505b6001600160a01b03841660009081526011602052604090205461273890859061273282868887612e35565b84612d5b565b5092915050565b60008161274e57506000610d62565b508354611ebf8161278d670de0b6b3a764000061278188612775898963ffffffff612f5616565b9063ffffffff612f9c16565b9063ffffffff61300716565b9063ffffffff61306b16565b600082820183811015610a445760405162461bcd60e51b815260040161034d90614758565b601354600090806127d157600e54610a44565b610a4481610a7985670de0b6b3a764000063ffffffff611f0516565b3390565b60006128086000356001600160e01b031916611381565b156128255760405162461bcd60e51b815260040161034d90614928565b816128425760405162461bcd60e51b815260040161034d90614858565b61284c60006129a5565b612855336113da565b82111561288957600019821461287d5760405162461bcd60e51b815260040161034d90614808565b612886336113da565b91505b600061289961148e611489611f81565b905060006128b9670de0b6b3a7640000610a79868563ffffffff611f0516565b905060006128c5611ecd565b9050819350808411156128ea5760405162461bcd60e51b815260040161034d90614788565b33600081815260116020526040902054612911919061290b828989896130b1565b86612d5b565b505050919050565b60405161297390859063a9059cbb60e01b9061293b9087908790602401614638565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152836131d6565b50505050565b60008115610b7d5761299e82610a798568056bc75e2d6310000063ffffffff611f0516565b9050610b7d565b60405163789b79bf60e11b8152600080516020614aaf8339815191529063f136f37e906129d690849060040161467c565b600060405180830381600087803b1580156129f057600080fd5b505af1158015612a04573d6000803e3d6000fd5b5050505050565b6000610a4483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612d2f565b6001600160a01b038116612a735760405162461bcd60e51b815260040161034d90614748565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b60008183612af05760405162461bcd60e51b815260040161034d9190614717565b506000838581612afc57fe5b0495945050505050565b600080600080612b1788888861329c565b90925090506000612b386f4b3b4ca85a86c47a098a22400000000087611f3f565b9050612b5781610a798568056bc75e2d6310000063ffffffff611f0516565b945050945094509450949050565b612b6d613683565b612b75611ecd565b602084015111801590612b94575060208401516001600160a01b031615155b612bb05760405162461bcd60e51b815260040161034d90614798565b60408401516001600160a01b0316612bd65760208401516001600160a01b031660408501525b6000612be48686868b61342c565b60208501516060860151919250612bfb9190612799565b60608501528715612c1b576060840151612c159089612a0b565b60608501525b600088612c29576000612c2c565b60015b90506000600f60008984604051602001612c479291906144cb565b6040516020818303038152906040528051906020012060001c815260200190815260200160002054905088600014612c9657612c936f4b3b4ca85a86c47a098a2240000000008a611f3f565b98505b600080516020614aaf8339815191526001600160a01b031663585314cf84838e868e8d8d8d6040518963ffffffff1660e01b8152600401612cdd979695949392919061468a565b6060604051808303818588803b158015612cf657600080fd5b505af1158015612d0a573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525061259f9190810190613bb2565b60008184841115612d535760405162461bcd60e51b815260040161034d9190614717565b505050900390565b604051600090612d919086907f37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6906020016144f1565b60405160208183030381529060405280519060200120905060008360001415612dbd5760009250612dee565b8415612dee576001600160a01b038616600090815260106020526040902054612deb9083908790869061273f565b90505b90556001600160a01b039093166000908152601060205260409020929092555050565b604051612a049086906323b872dd60e01b9061293b908890889088906024016145f0565b60006001600160a01b038516612e5d5760405162461bcd60e51b815260040161034d90614738565b6001600160a01b038516600090815260116020526040812054612e86908663ffffffff61279916565b6001600160a01b0387166000908152601160205260409020819055601354909150612eb7908663ffffffff61279916565b6013556040516001600160a01b038716907fb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb90612ef990889088908890614709565b60405180910390a2856001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef87604051612f45919061467c565b60405180910390a395945050505050565b6000818303818312801590612f6b5750838113155b80612f805750600083128015612f8057508381135b610a445760405162461bcd60e51b815260040161034d906148e8565b600082612fab57506000610b7d565b82600019148015612fbf5750600160ff1b82145b15612fdc5760405162461bcd60e51b815260040161034d90614898565b82820282848281612fe957fe5b0514610a445760405162461bcd60e51b815260040161034d90614898565b6000816130265760405162461bcd60e51b815260040161034d90614918565b8160001914801561303a5750600160ff1b83145b156130575760405162461bcd60e51b815260040161034d906147d8565b600082848161306257fe5b05949350505050565b60008282018183128015906130805750838112155b80613095575060008312801561309557508381125b610a445760405162461bcd60e51b815260040161034d90614768565b6040805180820182526002815261189b60f11b6020808301919091526001600160a01b038716600090815260119091529182205482916130f99190879063ffffffff612d2f16565b9050600a811161311a57613113858263ffffffff61279916565b9450600090505b6001600160a01b0386166000908152601160205260409020819055601354613148908663ffffffff612a0b16565b6013556040516001600160a01b038716907f743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b46449061318a90889088908890614709565b60405180910390a260006001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef87604051612f45919061467c565b60006060846001600160a01b0316846040516131f2919061455d565b6000604051808303816000865af19150503d806000811461322f576040519150601f19603f3d011682016040523d82523d6000602084013e613234565b606091505b50915091508183906132595760405162461bcd60e51b815260040161034d9190614717565b50805115612a04578080602001905161327591908101906139dc565b83906132945760405162461bcd60e51b815260040161034d9190614717565b505050505050565b6000806000600080516020614aaf8339815191526001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156132e857600080fd5b505afa1580156132fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613320919081019061387d565b60048054604051630a7549df60e21b81526001600160a01b03938416936329d5277c9361335b938c93600160601b90910490921691016145a0565b604080518083038186803b15801561337257600080fd5b505afa158015613386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506133aa9190810190613c9c565b909250905081158015906133bd57508015155b6133d95760405162461bcd60e51b815260040161034d906147a8565b6133f581610a7984670de0b6b3a764000063ffffffff611f0516565b8493509150841561342357613420836112cb670de0b6b3a7640000610a79898763ffffffff611f0516565b92505b50935093915050565b600454604084015160208401516060850151608086015160009473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2946001600160a01b03600160601b9092048216949093909290918b168514156134965760405162461bcd60e51b815260040161034d90614878565b3496508715613508576134c585858a60405180604001604052806002815260200161323760f01b815250612919565b878311156135035761350385600080516020614aaf8339815191528a860360405180604001604052806002815260200161323760f01b815250612919565b61353c565b61353c85600080516020614aaf8339815191528560405180604001604052806002815260200161323760f01b815250612919565b801561363a57856001600160a01b03168b6001600160a01b031614801561356257508615155b801561356e5750808710155b1561360557856001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156135ae57600080fd5b505af11580156135c2573d6000803e3d6000fd5b50505050506135fb8b600080516020614aaf8339815191528360405180604001604052806002815260200161064760f31b815250612919565b808703965061363a565b61363a8b33600080516020614aaf8339815191528460405180604001604052806002815260200161064760f31b815250612e11565b8115613675576136758533600080516020614aaf8339815191528560405180604001604052806002815260200161323960f01b815250612e11565b505050505050949350505050565b60405180606001604052806000801916815260200160008152602001600081525090565b60405180608001604052806004906020820280388339509192915050565b6040518060a001604052806005906020820280388339509192915050565b8035610b7d81614a7f565b8051610b7d81614a7f565b60008083601f84011261370b57600080fd5b50813567ffffffffffffffff81111561372357600080fd5b60208301915083602082028301111561373b57600080fd5b9250929050565b8051610b7d81614a93565b8035610b7d81614a9c565b8051610b7d81614a9c565b8035610b7d81614aa5565b60008083601f84011261378057600080fd5b50813567ffffffffffffffff81111561379857600080fd5b60208301915083600182028301111561373b57600080fd5b600082601f8301126137c157600080fd5b81356137d46137cf8261497b565b614954565b915080825260208301602083018583830111156137f057600080fd5b6137fb838284614a05565b50505092915050565b60006060828403121561381657600080fd5b6138206060614954565b9050600061382e8484613758565b825250602061383f84848301613758565b602083015250604061385384828501613758565b60408301525092915050565b60006020828403121561387157600080fd5b6000610d6284846136e3565b60006020828403121561388f57600080fd5b6000610d6284846136ee565b600080604083850312156138ae57600080fd5b60006138ba85856136e3565b92505060206138cb858286016136e3565b9150509250929050565b6000806000606084860312156138ea57600080fd5b60006138f686866136e3565b9350506020613907868287016136e3565b92505060406139188682870161374d565b9150509250925092565b6000806040838503121561393557600080fd5b600061394185856136e3565b925050602083013567ffffffffffffffff81111561395e57600080fd5b6138cb858286016137b0565b6000806040838503121561397d57600080fd5b600061398985856136e3565b92505060206138cb8582860161374d565b600080602083850312156139ad57600080fd5b823567ffffffffffffffff8111156139c457600080fd5b6139d0858286016136f9565b92509250509250929050565b6000602082840312156139ee57600080fd5b6000610d628484613742565b600080600080600080600080610100898b031215613a1757600080fd5b6000613a238b8b61374d565b9850506020613a348b828c0161374d565b9750506040613a458b828c0161374d565b9650506060613a568b828c0161374d565b9550506080613a678b828c016136e3565b94505060a0613a788b828c016136e3565b93505060c0613a898b828c016136e3565b92505060e089013567ffffffffffffffff811115613aa657600080fd5b613ab28b828c016137b0565b9150509295985092959890939650565b600080600080600080600060e0888a031215613add57600080fd5b6000613ae98a8a61374d565b9750506020613afa8a828b0161374d565b9650506040613b0b8a828b0161374d565b9550506060613b1c8a828b0161374d565b9450506080613b2d8a828b016136e3565b93505060a0613b3e8a828b016136e3565b92505060c088013567ffffffffffffffff811115613b5b57600080fd5b613b678a828b016137b0565b91505092959891949750929550565b600060208284031215613b8857600080fd5b6000610d628484613763565b600060208284031215613ba657600080fd5b6000610d62848461374d565b600060608284031215613bc457600080fd5b6000610d628484613804565b600060208284031215613be257600080fd5b6000610d628484613758565b600080600080600080600060a0888a031215613c0957600080fd5b6000613c158a8a61374d565b9750506020613c268a828b016136e3565b9650506040613c378a828b016136e3565b955050606088013567ffffffffffffffff811115613c5457600080fd5b613c608a828b0161376e565b9450945050608088013567ffffffffffffffff811115613c7f57600080fd5b613c8b8a828b0161376e565b925092505092959891949750929550565b60008060408385031215613caf57600080fd5b6000613cbb8585613758565b92505060206138cb85828601613758565b600080600060608486031215613ce157600080fd5b6000613ced868661374d565b9350506020613cfe8682870161374d565b9250506040613918868287016136e3565b600080600060608486031215613d2457600080fd5b6000613d30868661374d565b93505060206139078682870161374d565b6000613d4d8383613d81565b505060200190565b6000613d4d8383613e3c565b613d6a816149f4565b82525050565b613d6a613d7c826149c5565b614a3d565b613d6a816149c5565b613d93816149a6565b613d9d8184610a88565b9250613da8826149a3565b8060005b83811015613294578151613dc08782613d41565b9650613dcb836149b6565b925050600101613dac565b613ddf816149ac565b613de98184610a88565b9250613df4826149a3565b8060005b83811015613294578151613e0c8782613d55565b9650613e17836149b6565b925050600101613df8565b613d6a816149d0565b613d6a613e37826149d0565b614a48565b613d6a816149a3565b613d6a613e51826149a3565b6149a3565b613d6a613e51826149d5565b6000613e6e8385610a88565b9350613e7b838584614a05565b50500190565b6000613e8c826149b2565b613e9681856149bc565b9350613ea6818560208601614a11565b613eaf81614a69565b9093019392505050565b6000613ec4826149b2565b613ece8185610a88565b9350613ede818560208601614a11565b9290920192915050565b6000613ef56002836149bc565b61031360f41b815260200192915050565b6000613f136002836149bc565b61313560f01b815260200192915050565b6000613f316026836149bc565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000613f79601b836149bc565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613fb26021836149bc565b7f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000613ff56001836149bc565b603760f81b815260200192915050565b60006140126002836149bc565b61333760f01b815260200192915050565b60006140306002836149bc565b610c8d60f21b815260200192915050565b600061404e6002836149bc565b61032360f41b815260200192915050565b600061406c6002836149bc565b61313160f01b815260200192915050565b600061408a6002836149bc565b61313360f01b815260200192915050565b60006140a86021836149bc565b7f5369676e6564536166654d6174683a206469766973696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006140eb6002836149bc565b61189960f11b815260200192915050565b60006141096002836149bc565b61034360f41b815260200192915050565b60006141276002836149bc565b61199960f11b815260200192915050565b60006141456002836149bc565b61313760f01b815260200192915050565b60006141636002836149bc565b61062760f31b815260200192915050565b60006141816021836149bc565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006141c4600c836149bc565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006141ec6002836149bc565b61313960f01b815260200192915050565b600061420a6020836149bc565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b60006142436002836149bc565b61191b60f11b815260200192915050565b6000614261600b836149bc565b6a18d85b1b0819985a5b195960aa1b815260200192915050565b60006142886027836149bc565b7f5369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f815266766572666c6f7760c81b602082015260400192915050565b60006142d16014836149bc565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b60006143016001836149bc565b603960f81b815260200192915050565b600061431e600c836149bc565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b60006143466002836149bc565b61066760f31b815260200192915050565b60006143646024836149bc565b7f5369676e6564536166654d6174683a207375627472616374696f6e206f766572815263666c6f7760e01b602082015260400192915050565b60006143aa6001836149bc565b601b60f91b815260200192915050565b60006143c76001836149bc565b600760fb1b815260200192915050565b60006143e46020836149bc565b7f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f815260200192915050565b600061441d6006836149bc565b651c185d5cd95960d21b815260200192915050565b805160608301906144438482613e3c565b5060208201516144566020850182613e3c565b5060408201516129736040850182613e3c565b613d6a816149ee565b600061447e8288613d70565b60148201915061448e8287613d70565b60148201915061449e8286613d70565b6014820191506144ae8285613d70565b6014820191506144be8284613e45565b5060200195945050505050565b60006144d78285613d70565b6014820191506144e78284613e2b565b5060010192915050565b60006144fd8285613d70565b60148201915061450d8284613e45565b5060200192915050565b60006145238285613e56565b60048201915061450d8284613e45565b600061453f8286613e56565b600482019150611ebf828486613e62565b6000610d62828486613e62565b6000610a448284613eb9565b60208101610b7d8284613d81565b60208101610b7d8284613d61565b604081016145938285613d61565b610a446020830184613d61565b604081016145ae8285613d81565b610a446020830184613d81565b608081016145c98287613d81565b6145d66020830186613d81565b6145e36040830185613d81565b611ebf6060830184613e3c565b606081016145fe8286613d81565b61460b6020830185613d81565b610d626040830184613e3c565b604081016146268285613d81565b8181036020830152610d628184613e81565b604081016146468285613d81565b610a446020830184613e3c565b606081016146618286613d81565b61460b6020830185613e3c565b60208101610b7d8284613e22565b60208101610b7d8284613e3c565b6101c08101614699828a613e3c565b6146a66020830189613e3c565b6146b36040830188613e22565b6146c06060830187613e3c565b6146cd6080830186613d8a565b6146db610100830185613dd6565b8181036101a08301526146ee8184613e81565b9998505050505050505050565b604081016146468285613e3c565b606081016146618286613e3c565b60208082528101610a448184613e81565b60208082528101610a8581613ee8565b60208082528101610a8581613f06565b60208082528101610a8581613f24565b60208082528101610a8581613f6c565b60208082528101610a8581613fa5565b60208082528101610a8581613fe8565b60208082528101610a8581614005565b60208082528101610a8581614023565b60208082528101610a8581614041565b60208082528101610a858161405f565b60208082528101610a858161407d565b60208082528101610a858161409b565b60208082528101610a85816140de565b60208082528101610a85816140fc565b60208082528101610a858161411a565b60208082528101610a8581614138565b60208082528101610a8581614156565b60208082528101610a8581614174565b60208082528101610a85816141b7565b60208082528101610a85816141df565b60208082528101610a85816141fd565b60208082528101610a8581614236565b60208082528101610a8581614254565b60208082528101610a858161427b565b60208082528101610a85816142c4565b60208082528101610a85816142f4565b60208082528101610a8581614311565b60208082528101610a8581614339565b60208082528101610a8581614357565b60208082528101610a858161439d565b60208082528101610a85816143ba565b60208082528101610a85816143d7565b60208082528101610a8581614410565b60608101610b7d8284614432565b60208101610b7d8284614469565b60405181810167ffffffffffffffff8111828210171561497357600080fd5b604052919050565b600067ffffffffffffffff82111561499257600080fd5b506020601f91909101601f19160190565b90565b50600490565b50600590565b5190565b60200190565b90815260200190565b6000610a85826149e2565b151590565b6001600160e01b03191690565b6001600160a01b031690565b60ff1690565b6000610a85826000610a85826149c5565b82818337506000910152565b60005b83811015614a2c578181015183820152602001614a14565b838111156129735750506000910152565b6000610a8582614a53565b6000610a8582614a5e565b6000610a8582614a79565b6000610a8582614a73565b601f01601f191690565b60f81b90565b60601b90565b614a88816149c5565b8114611d8857600080fd5b614a88816149d0565b614a88816149a3565b614a88816149d556fe000000000000000000000000d8ee69652e4e4838f2531732a46d1f7f584f0b7fa365627a7a72315820f08d69608993c54a231668dbabc76de551d2bd4ec715ee1d77cc28b70bcb63a06c6578706572696d656e74616cf564736f6c63430005110040

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.