Moonbase Alpha Testnet

Contract

0x9561238867930787E2D0045B4DFCcaAD94d52CeF

Overview

DEV Balance

Moonbase Alpha LogoMoonbase Alpha LogoMoonbase Alpha Logo0 DEV

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 11 internal transactions

Parent Transaction Hash Block From To
23601962022-06-25 1:35:24959 days ago1656120924
0x95612388...D94d52CeF
0 DEV
23601962022-06-25 1:35:24959 days ago1656120924
0x95612388...D94d52CeF
0 DEV
23601952022-06-25 1:35:12959 days ago1656120912
0x95612388...D94d52CeF
0 DEV
23601952022-06-25 1:35:12959 days ago1656120912
0x95612388...D94d52CeF
0 DEV
23601812022-06-25 1:32:00959 days ago1656120720
0x95612388...D94d52CeF
0 DEV
23601812022-06-25 1:32:00959 days ago1656120720
0x95612388...D94d52CeF
0 DEV
23601792022-06-25 1:31:36959 days ago1656120696
0x95612388...D94d52CeF
0 DEV
23601792022-06-25 1:31:36959 days ago1656120696
0x95612388...D94d52CeF
0 DEV
23600982022-06-25 1:14:18959 days ago1656119658
0x95612388...D94d52CeF
0 DEV
23600782022-06-25 1:09:48959 days ago1656119388
0x95612388...D94d52CeF
0 DEV
23600652022-06-25 1:07:06959 days ago1656119226
0x95612388...D94d52CeF
0 DEV
Loading...
Loading

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

Contract Name:
MasterState

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 21 : MasterState.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./interfaces/IMaster.sol";
import "./interfaces/IMasterState.sol";
import "./MasterEvents.sol";
import "./MasterAdmin.sol";
import "./MasterMessageHandler.sol";
import "./MasterInternals.sol";

contract MasterState is
    IMaster,
    IMasterState,
    MasterEvents,
    MasterAdmin,
    MasterMessageHandler,
    MasterInternals
{

    function initialize(address middleLayerAddress, address eccAddress) external onlyOwner() {
        middleLayer = IMiddleLayer(middleLayerAddress);
        ecc = IECC(eccAddress);
        borrowIndex = 1e18;
        accrualBlockNumber = block.number;
    }

    function borrowBalanceStored(
        address account
    ) external override view returns (uint256, uint256) {
        return _borrowBalanceStored(account);
    }

    function accrueInterest() external override {
        _accrueInterest();
    }

    function enterMarkets(address[] calldata tokens, uint256[] calldata chainIds)
        external
        override
        returns (bool[] memory r)
    {
        uint256 tokensLen = tokens.length;
        uint256 chainIdLen = chainIds.length;

        require(tokensLen == chainIdLen, "ARRAY_LENGTH");

        r = new bool[](tokensLen);
        for (uint256 i = 0; i < tokensLen; i++) {
            address token = tokens[i];
            uint256 chainId = chainIds[i];

            r[i] = _addToMarket(token, chainId, msg.sender);
        }
    }

    function getAccountAssets(address accountAddress)
        external
        view
        override
        returns (CollateralMarket[] memory)
    {
        return accountAssets[accountAddress];
    }

    function exchangeRateStored() external view override returns (uint256) {
        return _exchangeRateStored();
    }

    function getAccountLiquidity(address account)
        external
        override
        returns (uint256, uint256)
    {

        return _getHypotheticalAccountLiquidityRedeem(account, address(0), 0);
    }

    function liquidateCalculateSeizeTokens(
        address pTokenCollateral,
        uint256 chainId,
        uint256 actualRepayAmount
    ) external override returns (uint256) {
        return
            _liquidateCalculateSeizeTokens(
                pTokenCollateral,
                chainId,
                actualRepayAmount
            );
    }

    function liquidateBorrowAllowed(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) external override returns (bool) {
        return
            _liquidateBorrowAllowed(
                pTokenCollateral,
                borrower,
                chainId,
                repayAmount
            );
    }

    function liquidateBorrow(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) external override payable returns (bool) {
        _accrueInterest();

        return _liquidateBorrow(pTokenCollateral, borrower, chainId, repayAmount);
    }
}

File 2 of 21 : IMaster.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;

import "../MasterStorage.sol";

abstract contract IMaster is MasterStorage {
    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return (error code, the calculated balance or 0 if error code is non-zero)
     */
    function _borrowBalanceStored(address account)
        internal
        view
        virtual
        returns (uint256, uint256);

    function _accrueInterest() internal virtual;

    /**
     * @notice Add the market to the borrower's "assets in" for liquidity calculations
     * @param token The market to enter
     * @param chainId The chainId
     * @param borrower The address of the account to modify
     */
    function _addToMarket(
        address token,
        uint256 chainId,
        address borrower
    ) internal virtual returns (bool);

    /**
     * @notice Get a snapshot of the account's balance, and the cached exchange rate
     * @dev This is used by risk engine to more efficiently perform liquidity checks.
     * @param user Address of the account to snapshot
     * @param chainId metadata of the ptoken
     * @param token metadata of the ptoken
     * @return (possible error, token balance, exchange rate)
     */
    function _getAccountSnapshot(
        address user,
        uint256 chainId,
        address token
    ) internal view virtual returns (uint256, uint256);

    /**
     * @notice Calculates the exchange rate from the underlying to the PToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return (calculated exchange rate scaled by 1e18)
     */
    function _exchangeRateStored() internal view virtual returns (uint256);

    function _getHypotheticalAccountLiquidity(
        address account,
        address pTokenModify,
        uint256 redeemTokens,
        uint256 borrowAmount
    ) internal virtual returns (uint256, uint256);

    /**
     * @notice The liquidator liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this pToken to be liquidated
     * @param pTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function _liquidateBorrow(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) internal virtual returns (bool);

    function _liquidateCalculateSeizeTokens(
        address pTokenCollateral,
        uint256 chainId,
        uint256 actualRepayAmount
    ) internal view virtual returns (uint256);

    function _liquidateBorrowAllowed(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) internal virtual returns (bool);

    function satelliteLiquidateBorrow(
        uint256 chainId,
        address borrower,
        address liquidator,
        uint256 seizeTokens,
        address pTokenCollateral
    ) internal virtual;
}

File 3 of 21 : IMasterState.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;

import "../MasterStorage.sol";

abstract contract IMasterState is MasterStorage {

    function borrowBalanceStored(
        address account
    ) external virtual returns (uint256, uint256);

    function accrueInterest() external virtual;

    function enterMarkets(
        address[] calldata tokens,
        uint256[] calldata chainIds
    ) external virtual returns (bool[] memory r);

    function getAccountAssets(
        address accountAddress
    ) external virtual returns (CollateralMarket[] memory);

    function exchangeRateStored() external virtual returns (uint256);

    function getAccountLiquidity(
        address account
    ) external virtual returns (uint256, uint256);

    function liquidateCalculateSeizeTokens(
        address pTokenCollateral,
        uint256 chainId,
        uint256 actualRepayAmount
    ) external virtual returns (uint256);

    function liquidateBorrowAllowed(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) external virtual returns (bool);

    function liquidateBorrow(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) external virtual payable returns (bool);

    function addChain(uint256 chainId) external virtual;

    function changeOwner(address newOwner) external virtual;

    function changeMiddleLayer(
        IMiddleLayer oldMid,
        IMiddleLayer newMid
    ) external virtual;

    /**
     * @notice Add the market to the markets mapping and set it as listed
     * @dev Admin function to set isListed and add support for the market
     * @param token The address of the market (token) to list
     * @param chainId corresponding chain of the market
     */
    function supportMarket(
        address token,
        uint256 chainId,
        uint256 initialExchangeRate_,
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        address underlying_
    ) external virtual;

    function changeLiqIncentive(uint256 newLiqIncentive) external virtual;

    function changeCloseFactor(uint256 newCloseFactor) external virtual;

    function changeCollateralFactor(uint256 newCollateralFactor) external virtual;

    function changeProtocolSeizeShare(uint256 newProtocolSeizeShare) external virtual;

    function setPUSD(address newPUSD) external virtual;
}

File 4 of 21 : MasterEvents.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

abstract contract MasterEvents {
    event CollateralBalanceAdded(
        address indexed user,
        uint256 chainId,
        uint256 prevAmount,
        uint256 newAmount
    );

    event CollateralChanged(
        address indexed user,
        uint256 indexed chainId,
        uint256 prevAmount,
        uint256 newAmount
    );

    event LoanAdded(
        address indexed user,
        uint256 indexed chainId,
        uint256 prevAmount,
        uint256 newAmount
    );

    event LoanChanged(
        address indexed user,
        uint256 indexed chainId,
        uint256 prevAmount,
        uint256 newAmount
    );

    event LoanRepaid(
        address indexed user,
        uint256 indexed chainId,
        uint256 prevAmount,
        uint256 newAmount
    );

    /// @notice Emitted when an account enters a deposit market
    event MarketEntered(uint256 chainId, address token, address borrower);

    event ReceiveFromChain(uint256 _srcChainId, address _fromAddress);

    /// @notice Event emitted when a borrow is liquidated
    event LiquidateBorrow(
        address liquidator,
        address borrower,
        uint256 repayAmount,
        address cTokenCollateral,
        uint256 seizeTokens
    );

    // Master Admin Events

    event AddChain(uint256 chainId);

    event ChangeOwner(address newOwner);

    event ChangeMiddleLayer(address oldMid, address newMid);

    event MarketListed(address token);

    event ChangeLiqIncentive(uint256 newLiqIncentive);

    event ChangeCloseFactor(uint256 newCloseFactor);

    event ChangeCollateralFactor(uint256 newCollateralFactor);

    event ChangeProtocolSeizeShare(uint256 newProtocolSeizeShare);

    event SetPUSD(address newPUSD);

    event LoanApproved(uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);

    event LoanRejection(uint256 shortfall);

    event AccountLiquidity(uint256 collateral, uint256 borrowPlusEffects);

    event RepayBorrowMaster(uint256 loanOutstanding, uint256 totalBorrows, uint256 accountBorrows);

    event RedeemAllowed(uint256 collateralBalanceNew, uint256 totalSupply);

    event RedeemRejection(uint256 shortfall);
}

File 5 of 21 : MasterAdmin.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./MasterModifiers.sol";
import "./MasterEvents.sol";
import "./interfaces/IMaster.sol";
import "./interfaces/IMasterState.sol";

abstract contract MasterAdmin is IMaster, IMasterState, MasterModifiers, MasterEvents {
    function addChain(uint256 chainId) external override onlyOwner {
        chains.push(chainId);

        emit AddChain(chainId);
    }

    function changeOwner(address newOwner) external override onlyOwner {
        require(newOwner != address(0), "NON_ZEROADDRESS");
        admin = newOwner;

        emit ChangeOwner(newOwner);
    }

    function changeMiddleLayer(
        IMiddleLayer oldMid,
        IMiddleLayer newMid
    ) external override onlyOwner {
        require(middleLayer == oldMid, "INVALID_MIDDLE_LAYER");
        middleLayer = newMid;

        emit ChangeMiddleLayer(address(oldMid), address(newMid));
    }

    /**
     * @notice Add the market to the markets mapping and set it as listed
     * @dev Admin function to set isListed and add support for the market
     * @param token The address of the market (token) to list
     * @param chainId corresponding chain of the market
     */
    function supportMarket(
        address token,
        uint256 chainId,
        uint256 initialExchangeRate_,
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        address underlying_
    ) external override onlyOwner {
        require(!markets[chainId][token].isListed, "SUPPORT_MARKET_EXISTS");

        markets[chainId][token].isListed = true;
        markets[chainId][token].collateralFactor = 80e6;
        markets[chainId][token].initialExchangeRate = initialExchangeRate_;
        markets[chainId][token].name = name_;
        markets[chainId][token].symbol = symbol_;
        markets[chainId][token].decimals = decimals_;
        markets[chainId][token].underlying = underlying_;

        // slither-disable-next-line uninitialized-local
        for (uint256 i; i < allMarkets.length; i++) {
            require(
                allMarkets[i].token != token &&
                    allMarkets[i].chainId != chainId,
                "MARKET_EXISTS"
            );
        }
        CollateralMarket memory market = CollateralMarket({
            token: token,
            chainId: chainId,
            decimals: decimals_
        });

        allMarkets.push(market);

        emit MarketListed(token);
    }

    function changeLiqIncentive(uint256 newLiqIncentive) external override onlyOwner {
        liquidityIncentive = newLiqIncentive;

        emit ChangeLiqIncentive(newLiqIncentive);
    }

    function changeCloseFactor(uint256 newCloseFactor) external override onlyOwner {
        closeFactor = newCloseFactor;

        emit ChangeCloseFactor(newCloseFactor);
    }

    function changeCollateralFactor(uint256 newCollateralFactor)
        external
        override
        onlyOwner
    {
        collateralFactor = newCollateralFactor;

        emit ChangeCollateralFactor(newCollateralFactor);
    }

    function changeProtocolSeizeShare(uint256 newProtocolSeizeShare)
        external
        override
        onlyOwner
    {
        protocolSeizeShare = newProtocolSeizeShare;

        emit ChangeProtocolSeizeShare(newProtocolSeizeShare);
    }

    function setPUSD(address newPUSD) external override onlyOwner() {
        require(newPUSD != address(0), "NON_ZEROADDRESS");
        pusd = newPUSD;

        emit SetPUSD(newPUSD);
    }

    function setReserveFactor(uint256 newFactor) external onlyOwner() {
        reserveFactor = newFactor;
    }
}

File 6 of 21 : MasterMessageHandler.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../interfaces/IHelper.sol";

import "./interfaces/IMaster.sol";
import "./MasterModifiers.sol";
import "./MasterEvents.sol";

abstract contract MasterMessageHandler is IMaster, MasterModifiers, MasterEvents {
    // slither-disable-next-line assembly
    function satelliteLiquidateBorrow(
        uint256 chainId,
        address borrower,
        address liquidator,
        uint256 seizeTokens,
        address pTokenCollateral
    ) internal virtual override {
        bytes memory payload = abi.encode(
            uint256(0),
            IHelper.SLiquidateBorrow(
                IHelper.Selector.SATELLITE_LIQUIDATE_BORROW,
                borrower,
                liquidator,
                seizeTokens,
                pTokenCollateral
            )
        );

        bytes32 metadata = ecc.preRegMsg(payload, msg.sender);
        assembly {
            mstore(add(payload, 0x20), metadata)
        }

        middleLayer.msend{value: msg.value}(
            chainId,
            payload, // bytes payload
            payable(msg.sender), // refund address
            address(0)
        );
    }

    // pass in the erc20 prevBalance, newBalance
    /// @dev Update the collateral balance for the given arguments
    /// @notice This will come from the satellite chain- the approve models
    function masterDeposit(
        IHelper.MDeposit memory params,
        bytes32 metadata,
        uint256 chainId
    ) external payable onlyMid() {
        if (!ecc.preProcessingValidation(abi.encode(params), metadata)) return;

        if (collateralBalances[chainId][params.user][params.pToken] != params.previousAmount) {
            // fallback to satellite to report failure
        }

        if (collateralBalances[chainId][params.user][params.pToken] == 0) {
            _addToMarket(params.pToken, chainId, params.user);
        }

        collateralBalances[chainId][params.user][params.pToken] += params.amountIncreased;
        markets[chainId][params.pToken].totalSupply += params.amountIncreased;

        emit CollateralBalanceAdded(
            params.user,
            chainId,
            collateralBalances[chainId][params.user][params.pToken],
            collateralBalances[chainId][params.user][params.pToken]
        );

        require(ecc.flagMsgValidated(abi.encode(params), metadata), "FMV");

        // fallback to satellite to report receipt
    }

    // slither-disable-next-line assembly
    function borrowAllowed(
        IHelper.MBorrowAllowed memory params,
        bytes32 metadata,
        uint256 chainId,
        address fallbackAddress
    ) external payable onlyMid() {
        if (!ecc.preProcessingValidation(abi.encode(params), metadata)) return;

        // TODO: liquidity calculation
        _accrueInterest();

        (, uint256 shortfall) = _getHypotheticalAccountLiquidity(
            params.user,
            address(0),
            0,
            params.borrowAmount
        );

        //if approved, update the balance and fire off a return message
        // slither-disable-next-line incorrect-equality
        if (shortfall == 0) {
            (uint256 _accountBorrows, ) = _borrowBalanceStored(params.user);

            /////////////////////////
            // EFFECTS & INTERACTIONS
            // (No safe failures beyond this point)

            accountBorrows[params.user].principal = _accountBorrows + params.borrowAmount;
            accountBorrows[params.user].interestIndex = borrowIndex;

            loansOutstanding[params.user][chainId] += params.borrowAmount;
            totalBorrows += params.borrowAmount;

            bytes memory payload = abi.encode(
                uint256(0),
                IHelper.FBBorrow(
                    IHelper.Selector.FB_BORROW,
                    params.user,
                    params.borrowAmount
                )
            );

            bytes32 _metadata = ecc.preRegMsg(payload, params.user);
            assembly {
                mstore(add(payload, 0x20), _metadata)
            }

            middleLayer.msend{ value: msg.value }(
                chainId,
                payload, // bytes payload
                payable(msg.sender), // refund address
                fallbackAddress
            );

            require(ecc.flagMsgValidated(abi.encode(params), metadata), "FMV");

            emit LoanApproved(params.borrowAmount, accountBorrows[params.user].principal, totalBorrows);
        } else {
            emit LoanRejection(shortfall);
            // middleLayer.msend{ value: msg.value }(
            //   chainId,
            //   dstContractLookup[chainId], // send to this address on the destination
            //   payload, // bytes payload
            //   payable(msg.sender), // refund address
            //   address(0x0), // future parameter
            //   bytes("") // adapterParams (see "Advanced Features")
            // );
        }
    }

    function masterRepay(
        IHelper.MRepay memory params,
        bytes32 metadata,
        uint256 chainId
    ) external payable onlyMid() {
        if (!ecc.preProcessingValidation(abi.encode(params), metadata)) return;

        if (loansOutstanding[params.borrower][chainId] < params.amountRepaid
        ) {
            // TODO: fallback to satellite to report failure
        }
        (uint256 _accountBorrows,) = _borrowBalanceStored(params.borrower);

        loansOutstanding[params.borrower][chainId] -= params.amountRepaid;
        totalBorrows -= params.amountRepaid;
        accountBorrows[params.borrower].principal = _accountBorrows - params.amountRepaid;

        _accrueInterest();

        require(ecc.flagMsgValidated(abi.encode(params), metadata), "FMV");

        emit RepayBorrowMaster(loansOutstanding[params.borrower][chainId], totalBorrows, accountBorrows[params.borrower].principal);

        // TODO: fallback to satellite to report receipt
    }

    // slither-disable-next-line assembly
    function redeemAllowed(
        IHelper.MRedeemAllowed memory params,
        bytes32 metadata,
        uint256 chainId,
        address fallbackAddress
    ) external payable onlyMid() {
        if (!ecc.preProcessingValidation(abi.encode(params), metadata)) return;

        _accrueInterest();

        //calculate hypothetical liquidity for the user
        //make sure we also check that the redeem isn't more than what's deposited
        // bool approved = true;

        (, uint256 shortfall) = _getHypotheticalAccountLiquidity(
            params.user,
            params.pToken,
            params.amount,
            0
        );

        bytes memory payload = abi.encode(
            uint256(0),
            IHelper.FBRedeem(
                IHelper.Selector.FB_REDEEM,
                params.pToken,
                params.user,
                params.amount
            )
        );

        bytes32 _metadata = ecc.preRegMsg(payload, params.user);
        assembly {
            mstore(add(payload, 0x20), _metadata)
        }

        //if approved, update the balance and fire off a return message
        // slither-disable-next-line incorrect-equality
        if (shortfall == 0) {
            collateralBalances[chainId][params.user][params.pToken] -= params.amount;
            markets[chainId][params.pToken].totalSupply -= params.amount;

            require(ecc.flagMsgValidated(abi.encode(params), metadata), "FMV");

            middleLayer.msend{value: msg.value}(
                chainId,
                payload, // bytes payload
                payable(msg.sender), // refund address
                fallbackAddress
            );
            
            emit RedeemAllowed(collateralBalances[chainId][params.user][params.pToken], markets[chainId][params.pToken].totalSupply);

        } else {
            middleLayer.msend{value: msg.value}(
                chainId,
                payload, // bytes payload
                payable(msg.sender), // refund address
                fallbackAddress
            );

            emit RedeemRejection(shortfall);
        }
    }

    // slither-disable-next-line assembly
    function transferAllowed(
        IHelper.MTransferAllowed memory params,
        bytes32 metadata,
        uint256 chainId,
        address fallbackAddress
    ) public payable onlyMid() {
        if (!ecc.preProcessingValidation(abi.encode(params), metadata)) return;

        _accrueInterest();

        (, uint256 shortfall) = _getHypotheticalAccountLiquidity(
            params.user,
            params.pToken,
            0,
            0
        );

        bytes memory payload = abi.encode(
            uint256(0),
            IHelper.FBCompleteTransfer(
                uint8(IHelper.Selector.FB_COMPLETE_TRANSFER),
                params.pToken,
                params.spender,
                params.user, // src
                params.dst,
                params.amount // tokens
            )
        );

        bytes32 _metadata = ecc.preRegMsg(payload, params.user);
        assembly {
            mstore(add(payload, 0x20), _metadata)
        }

        // slither-disable-next-line incorrect-equality
        if (shortfall == 0) {
            collateralBalances[chainId][params.user][params.pToken] -= params.amount;
            collateralBalances[chainId][params.dst][params.pToken] += params.amount;

            require(ecc.flagMsgValidated(abi.encode(params), metadata), "FMV");

            middleLayer.msend{value: msg.value}(
                chainId,
                payload, // bytes payload
                payable(msg.sender), // refund address
                fallbackAddress
            );
        } else {
            // TODO: shortfall > 0
        }
    }
}

File 7 of 21 : MasterInternals.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./interfaces/IMaster.sol";
import "./MasterEvents.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

abstract contract MasterInternals is IMaster, MasterEvents {
    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return (error code, the calculated balance or 0 if error code is non-zero)
     */
    function _borrowBalanceStored(
        address account
    ) internal view virtual override returns (uint256, uint256) {
        /* Note: we do not assert that the market is up to date */

        BorrowSnapshot storage borrowSnapshot = accountBorrows[account];

        /* If borrowBalance = 0 then borrowIndex is likely also 0.
        * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
        */
        if (borrowSnapshot.principal == 0) {
            return (0, 0);
        }

        /* Calculate new borrow balance using the interest index:
        *  recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
        */
        uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;
        uint256 result = principalTimesIndex / borrowSnapshot.interestIndex;

        return (result, borrowSnapshot.principal);
    }

    function _accrueInterest() internal virtual override {
        if (accrualBlockNumber != block.number) {
            uint256 accrualBlockNumberPrior = accrualBlockNumber;

            // uint cashPrior = getCashPrior();
            uint256 borrowsPrior = totalBorrows;
            // TODO Deal with Reserves
            uint256 reservesPrior = totalReserves;
            uint256 borrowIndexPrior = borrowIndex;

            // TODO interest rate model - set to 0.0002% per block for now
            uint256 borrowRate = 2e6; // TODO: interestRateModel.setBorrowRate();
            require(borrowRate <= BORROW_RATE_MAX, "borrow rate is absurdly high");

            require(block.number >= accrualBlockNumberPrior, "Cannot calculate data");
            uint256 blockDelta = block.number - accrualBlockNumberPrior;

            uint256 simpleInterestFactor = borrowRate * blockDelta;

            uint256 multiplier = 10**8; // TODO: PUSDAddress.decimals();

            uint256 interestAccumulated = (simpleInterestFactor * borrowsPrior) /
                multiplier;

            uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;

            uint256 totalReservesNew = (reserveFactor * interestAccumulated) /
                multiplier + reservesPrior;

            uint256 borrowIndexNew = (simpleInterestFactor * borrowIndexPrior) /
                multiplier + borrowIndexPrior;

            /////////////////////////
            // EFFECTS & INTERACTIONS
            // (No safe failures beyond this point)

            accrualBlockNumber = block.number;
            borrowIndex = borrowIndexNew;
            totalBorrows = totalBorrowsNew;
            totalReserves = totalReservesNew;

            // emit AccrueInterest(interestAccumulated, borrowIndexNew, totalBorrowsNew);
        }
    }

    /**
     * @notice Add the market to the borrower's "assets in" for liquidity calculations
     * @param token The market to enter
     * @param chainId The chainId
     * @param borrower The address of the account to modify
     */
    // slither-disable-next-line low-level-calls
    function _addToMarket(
        address token,
        uint256 chainId,
        address borrower
    ) internal virtual override returns (bool) {
        Market storage marketToJoin = markets[chainId][token];

        if (!marketToJoin.isListed) {
            return false;
        }

        if (marketToJoin.accountMembership[borrower]) {
            return true;
        }

        // survived the gauntlet, add to list
        // NOTE: we store these somewhat redundantly as a significant optimization
        //  this avoids having to iterate through the list for the most common use cases
        //  that is, only when we need to perform liquidity checks
        //  and not whenever we want to check if an account is in a particular market
        marketToJoin.accountMembership[borrower] = true;

        CollateralMarket memory market = CollateralMarket({
            token: token,
            chainId: chainId,
            decimals: marketToJoin.decimals
        });

        accountAssets[borrower].push(market);

        emit MarketEntered(market.chainId, market.token, borrower);

        return true;
    }

    /**
     * @notice Get a snapshot of the account's balance, and the cached exchange rate
     * @dev This is used by risk engine to more efficiently perform liquidity checks.
     * @param user Address of the account to snapshot
     * @param chainId metadata of the ptoken
     * @param token metadata of the ptoken
     * @return (possible error, token balance, exchange rate)
     */
    function _getAccountSnapshot(
        address user,
        uint256 chainId,
        address token
    ) internal view virtual override returns (uint256, uint256) {
        uint256 pTokenBalance = collateralBalances[chainId][user][token];
        uint256 exchangeRate = _exchangeRateStored();

        return (pTokenBalance, exchangeRate);
    }

    /**
     * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.
     *  Note that `pTokenBalance` is the number of pTokens the account owns in the market,
     *  whereas `borrowBalance` is the amount of underlying that the account has borrowed.
     */
    struct AccountLiquidityLocalVars {
        uint256 sumCollateral;
        uint256 sumBorrowPlusEffects;
        uint256 pTokenBalance;
        uint256 borrowBalance;
        uint256 collateralFactor;
        uint256 exchangeRate;
        uint256 oraclePrice;
        uint256 tokensToDenom;
    }

    function _getHypotheticalAccountLiquidity(
        address account,
        address pTokenModify,
        uint256 redeemTokens,
        uint256 borrowAmount
    ) internal virtual override returns (uint256, uint256) {
        AccountLiquidityLocalVars memory vars; // Holds all our calculation results

        //add in the existing borrow
        (vars.sumBorrowPlusEffects, ) = _borrowBalanceStored(account);

        // For each asset the account is in
        CollateralMarket[] memory assets = accountAssets[account];
        // slither-disable-next-line uninitialized-local
        for (uint256 i; i < assets.length; i++) {
            CollateralMarket memory asset = assets[i];

            // Read the balances and exchange rate from the pToken
            (vars.pTokenBalance, vars.exchangeRate) = _getAccountSnapshot(
                account,
                asset.chainId,
                asset.token
            );

            // Unlike prime protocol, getUnderlyingPrice is relatively expensive because we use ChainLink as our primary price feed.
            // If user has no supply / borrow balance on this asset, and user is not redeeming / borrowing this asset, skip it.
            // slither-disable-next-line incorrect-equality
            if (vars.pTokenBalance == 0) {
                continue;
            }

            uint256 precision = markets[asset.chainId][asset.token].decimals;
            uint256 multiplier = 10**precision;

            // hardcoded for test
            vars.collateralFactor = markets[asset.chainId][asset.token]
                .collateralFactor;

            // TODO: using hard coded price of 1, FIX THIS
            vars.oraclePrice = multiplier; //oracle.getUnderlyingPrice(asset);

            require(vars.oraclePrice != 0, "PRICE_ERROR");

            // Pre-compute a conversion factor from tokens -> ether (normalized price value)
            vars.tokensToDenom = ((((vars.collateralFactor *
                vars.exchangeRate) / multiplier) * vars.oraclePrice) /
                multiplier);

            // sumCollateral += tokensToDenom * pTokenBalance
            vars.sumCollateral =
                (vars.tokensToDenom * vars.pTokenBalance) /
                multiplier +
                vars.sumCollateral;

            if (asset.token == pTokenModify) {
                // redeem effect
                // sumBorrowPlusEffects += tokensToDenom * redeemTokens
                vars.sumBorrowPlusEffects += (vars.tokensToDenom * redeemTokens) /
                    multiplier; /* normalize */
            }
        }

        // //get the multiplier and the oracle price from the loanAgent
        // // Read the balances and exchange rate from the pToken
        // (vars.pTokenBalance, vars.exchangeRate) = asset.getAccountSnapshot(
        //   account
        // );
        // // sumBorrowPlusEffects += oraclePrice * borrowBalance

        // borrow effect
        // sumBorrowPlusEffects += oraclePrice * borrowAmount
        vars.sumBorrowPlusEffects += borrowAmount;

        emit AccountLiquidity(vars.sumCollateral, vars.sumBorrowPlusEffects);

        // These are safe, as the underflow condition is checked first
        if (vars.sumCollateral > vars.sumBorrowPlusEffects) {
            return (vars.sumCollateral - vars.sumBorrowPlusEffects, 0);
        } else {
            return (0, vars.sumBorrowPlusEffects - vars.sumCollateral);
        }
    }

    /**
        * FIXME: Refactor this method: https://primeprotocol.atlassian.net/browse/PC-211
        *
        * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed
        * @param pTokenModify The market to hypothetically redeem/borrow in
        * @param account The account to determine liquidity for
        * @param redeemTokens The number of tokens to hypothetically redeem
        * @dev Note that we calculate the exchangeRateStored for each collateral pToken using stored data,
        *  without calculating accumulated interest.
        * @return (possible error code,
                    hypothetical account liquidity in excess of collateral requirements,
        *          hypothetical account shortfall below collateral requirements)
        */
    function _getHypotheticalAccountLiquidityRedeem(
        address account,
        address pTokenModify,
        uint256 redeemTokens
    ) internal returns (uint256, uint256) {
        // For each asset the account is in
        CollateralMarket[] memory assets = accountAssets[account];

        require(assets.length > 0, "no account assets");

        /// @notice if we exit the loop early for one  PToken, we need to reset these values.
        ///   i could see an exploit where they use an old multiplier value for a specific PToken
        uint256 precision;
        uint256 multiplier;

        AccountLiquidityLocalVars memory vars;

        // slither-disable-next-line uninitialized-local
        for (uint256 i; i < assets.length; i++) {
            CollateralMarket memory asset = assets[i];

            // Read the balances and exchange rate from the pToken
            vars.pTokenBalance = collateralBalances[asset.chainId][account][
                asset.token
            ];

            // Unlike prime protocol, getUnderlyingPrice is relatively expensive because we use ChainLink as our primary price feed.
            // If user has no supply / borrow balance on this asset, and user is not redeeming / borrowing this asset, skip it.
            if (vars.pTokenBalance == 0 && asset.token != pTokenModify) {
                continue;
            }

            precision = asset.decimals;
            multiplier = 10**precision;

            // Get the normalized price of the asset
            // TODO: using hard coded price of 1, FIX THIS
            vars.oraclePrice = multiplier; //oracle.getUnderlyingPrice(asset);

            require(vars.oraclePrice != 0, "PRICE_ERROR");

            // 1e8
            // vars.collateralFactor = markets[asset.chainId][asset.token].collateralFactor;
            vars.collateralFactor = collateralFactor;
            vars.exchangeRate = _exchangeRateStored();

            // Pre-compute a conversion factor from tokens -> ether (normalized price value)
            // exchangeRate is getAccountSnapshot (pToken => underlying); if we deposited ETH, how much pETH are you getting
            // if someone deposited 10 ETH a month ago, they could get like 1k pTokens. if someone does the same this month, they would get the new exchangeRate, which would theoretically be lower. like 200 pTokens
            // should be 1, actual is (1 * 100000000 * 100000000)
            vars.tokensToDenom =
                (vars.collateralFactor * vars.exchangeRate * vars.oraclePrice) /
                multiplier /
                multiplier; /* normalize */

            // sumCollateral += tokensToDenom * pTokenBalance
            vars.sumCollateral +=
                (vars.tokensToDenom * vars.pTokenBalance) /
                multiplier; /* normalize */

            // Calculate effects of interacting with pTokenModify
            if (asset.token == pTokenModify) {
                // redeem effect
                // sumBorrowPlusEffects += tokensToDenom * redeemTokens
                vars.sumBorrowPlusEffects +=
                    (vars.tokensToDenom * redeemTokens) /
                    multiplier; /* normalize */
            }
        }

        // //get the multiplier and the oracle price from the loanAgent
        // // Read the balances and exchange rate from the pToken
        // (vars.pTokenBalance, vars.exchangeRate) = asset.getAccountSnapshot(
        //   account
        // );
        // // sumBorrowPlusEffects += oraclePrice * borrowBalance

        // FIXME: using hard coded price of 1
        uint256 borrowOraclePrice = multiplier; //oracle.getUnderlyingPriceBorrow(borrowMarket);
        (uint256 borrowBalance, ) = _borrowBalanceStored(account);

        vars.sumBorrowPlusEffects +=
            (borrowOraclePrice * borrowBalance) /
            multiplier; /* normalize */

        emit AccountLiquidity(vars.sumCollateral, vars.sumBorrowPlusEffects);

        // These are safe, as the underflow condition is checked first
        if (vars.sumCollateral > vars.sumBorrowPlusEffects) {
            return (vars.sumCollateral - vars.sumBorrowPlusEffects, 0);
        } else {
            return (0, vars.sumBorrowPlusEffects - vars.sumCollateral);
        }
    }

    function _liquidateCalculateSeizeTokens(
        address pTokenCollateral,
        uint256 chainId,
        uint256 actualRepayAmount
    ) internal view virtual override returns (uint256) {
        /* TODO: Read oracle prices for borrowed and collateral markets */
        // PUSD Price
        uint256 priceBorrowed = 1e8; //oracle.getUnderlyingPriceBorrow(pTokenCollateral);
        uint256 priceCollateral = 1e8; //oracle.getUnderlyingPrice(pTokenCollateral);
        require(priceCollateral > 0 && priceBorrowed > 0, "PRICE_FETCH");

        uint256 multiplier = 10**markets[chainId][pTokenCollateral].decimals;

        /*
         * Get the exchange rate and calculate the number of collateral tokens to seize:
         *  seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral
         *  seizeTokens = seizeAmount / exchangeRate
         *   = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)
         */
        uint256 numerator = (actualRepayAmount *
            (multiplier + liquidityIncentive) *
            priceBorrowed) / multiplier;
        uint256 denominator = (priceCollateral * _exchangeRateStored()) /
            multiplier;
        uint256 seizeTokens = numerator / denominator;

        return seizeTokens;
    }

    function _liquidateBorrowAllowed(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) internal virtual override returns (bool) {
        if (!markets[chainId][pTokenCollateral].isListed) {
            return false;
        }

        /* The borrower must have shortfall in order to be liquidatable */
        (, uint256 shortfall) = _getHypotheticalAccountLiquidityRedeem(
            borrower,
            address(0),
            0
        );

        // slither-disable-next-line incorrect-equality
        if (shortfall == 0) {
            return false;
        }

        uint256 multiplier = 10**markets[chainId][pTokenCollateral].decimals;

        /* The liquidator may not repay more than what is allowed by the closeFactor */
        (uint256 borrowBalance, ) = _borrowBalanceStored(borrower);

        uint256 maxClose = (closeFactor * borrowBalance) / multiplier;

        if (repayAmount > maxClose) {
            return false;
        }

        return true;
    }

    struct RepayBorrowLocalVars {
        uint256 repayAmount;
        uint256 borrowerIndex;
        uint256 accountBorrows;
        uint256 accountBorrowsNew;
        uint256 totalBorrowsNew;
        uint256 actualRepayAmount;
    }

    function _repayBorrowFresh(
        address borrower,
        uint256 repayAmount /*override*/
    ) internal virtual returns (uint256) {
        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != block.number) revert("REPAY_BORROW_FRESHNESS_CHECK");

        // slither-disable-next-line uninitialized-local
        RepayBorrowLocalVars memory vars;

        /* We remember the original borrowerIndex for verification purposes */
        vars.borrowerIndex = accountBorrows[borrower].interestIndex;

        /* We fetch the amount the borrower owes, with accumulated interest */
        (vars.accountBorrows, ) = _borrowBalanceStored(borrower);

        /* If repayAmount == -1, repayAmount = accountBorrows */
        // As of Solidity v0.8 Explicit conversions between literals and an integer type T are only allowed if the literal lies between type(T).min and type(T).max. In particular, replace usages of uint(-1) with type(uint).max.
        // type(uint).max
        vars.actualRepayAmount = repayAmount == type(uint256).max
            ? vars.accountBorrows
            : repayAmount;

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We call doTransferIn for the payer and the repayAmount
         *  Note: The pToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the pToken holds an additional repayAmount of cash.
         *  doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
         *   it returns the amount actually transferred, in case of a fee.
         */
        // vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);
        // TODO: Handle this in lz call
        // PUSDAddress.burnFrom(/*msg.sender*/ -> payer, vars.repayAmount); // burn the pusd

        // vars.actualRepayAmount = vars.repayAmount;

        /*
         * We calculate the new borrower and total borrow balances, failing on underflow:
         *  accountBorrowsNew = accountBorrows - actualRepayAmount
         *  totalBorrowsNew = totalBorrows - actualRepayAmount
         */
        require(
            vars.accountBorrows >= vars.actualRepayAmount,
            "REPAY_GT_BORROWS"
        );
        // ! This case should be impossible if the above check passes
        require(totalBorrows >= vars.actualRepayAmount, "REPAY_GT_TBORROWS");

        vars.accountBorrowsNew = vars.accountBorrows - vars.actualRepayAmount;
        vars.totalBorrowsNew = totalBorrows - vars.actualRepayAmount;

        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a RepayBorrow event */
        // emit RepayBorrow(
        //     payer,
        //     borrower,
        //     vars.actualRepayAmount,
        //     vars.accountBorrowsNew,
        //     vars.totalBorrowsNew
        // );

        return vars.actualRepayAmount;
    }

    function _seizeAllowed() internal virtual returns (bool) {
        // return seizeGuardianPaused;
    }

    function _liquidateBorrow(
        address pTokenCollateral,
        address borrower,
        uint256 chainId,
        uint256 repayAmount
    ) internal virtual override returns (bool) {
        /* Fail if liquidate not allowed */
        require(
            _liquidateBorrowAllowed(
                pTokenCollateral,
                borrower,
                chainId,
                repayAmount
            ),
            "LIQUIDATE_RISKENGINE_REJECTION"
        );

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != block.number) revert("LIQUIDATE_FRESHNESS_CHECK");

        /* Fail if borrower = liquidator */
        // ? Using msg.sender here is more optimal than using a local var
        // ? that is in every case assigned to msg.sender
        require(borrower != msg.sender, "LIQUIDATE_LIQUIDATOR_IS_BORROWER");

        /* Fail if repayAmount = 0 */
        require(repayAmount > 0, "LIQUIDATE_CLOSE_AMOUNT_IS_ZERO");

        /* Fail if repayAmount = -1 */
        // NOTE: What case is this check covering?
        // require(repayAmount != type(uint128).max, "INVALID_CLOSE_AMOUNT_REQUESTED | LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX");

        // Fail if repayBorrow fails
        uint256 actualRepayAmount = _repayBorrowFresh(
            // msg.sender, // ! payer value unused in function call
            borrower,
            repayAmount
        );

        uint256 protocolSeizeShareAmount = (actualRepayAmount * protocolSeizeShare)/1e8;

        // We calculate the number of collateral tokens that will be seized
        uint256 seizeTokens = _liquidateCalculateSeizeTokens(
            pTokenCollateral,
            chainId,
            actualRepayAmount - protocolSeizeShareAmount
        );

        uint256 collateralBalance = collateralBalances[chainId][borrower][pTokenCollateral];

        // Revert if borrower collateral token balance < seizeTokens
        require(
            collateralBalance >= seizeTokens,
            "LIQUIDATE_SEIZE_TOO_MUCH"
        );

        accountBorrows[borrower].principal += protocolSeizeShareAmount;
        collateralBalances[chainId][borrower][pTokenCollateral] = collateralBalance - seizeTokens;
        collateralBalances[chainId][msg.sender][pTokenCollateral] += seizeTokens;
        totalReserves += protocolSeizeShareAmount;

        ERC20Burnable(pusd).burnFrom(msg.sender, actualRepayAmount);

        // ! If this call fails on satellite we accept a fallback call
        // ! to revert above state changes
        satelliteLiquidateBorrow(
            chainId,
            borrower,
            msg.sender,
            seizeTokens,
            pTokenCollateral
        );

        /* We emit a LiquidateBorrow event */
        // emit LiquidateBorrow(
        //     msg.sender,
        //     borrower,
        //     actualRepayAmount,
        //     address(pTokenCollateral),
        //     seizeTokens
        // );

        return true;
    }

    function _exchangeRateStored()
        internal
        view
        virtual
        override
        returns (uint256)
    {
        // this is where the tests are failing
        // uint256 _totalSupply = totalSupply;
        // if (_totalSupply == 0) {
        //   /*
        //    * If there are no tokens minted:
        //    *  exchangeRate = initialExchangeRate
        //    */
        //   return initialExchangeRate;
        // } else {
        //   /*
        //    * Otherwise:
        //    *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
        //    */
        //   uint256 totalCash = getCashPrior();
        //   uint256 cashPlusBorrowsMinusReserves;
        //   uint256 exchangeRate;

        //   cashPlusBorrowsMinusReserves = totalCash - totalReserves;

        //   exchangeRate = (totalCash * 10**decimals) / _totalSupply;
        //   return exchangeRate;
        // }
        return 1e8;
    }
}

File 8 of 21 : MasterStorage.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

// TODO: Change this import to somewhere else probably
import "../master/oracle/interfaces/IPTokenOracle.sol";
import "../middleLayer/interfaces/IMiddleLayer.sol";
import "../ecc/interfaces/IECC.sol";

abstract contract MasterStorage {
    /**
    * @notice Administrator for this contract
    */
    address public admin;

    // slither-disable-next-line unused-state
    IMiddleLayer internal middleLayer;

    // slither-disable-next-line unused-state
    IECC internal ecc;

    // slither-disable-next-line unused-state
    address internal pusd;

    /**
     * @notice Block number that interest was last accrued at
     */
    uint256 public accrualBlockNumber;

    /**
     * @notice Total amount of outstanding borrows of the underlying in this market
     */
    uint256 public totalBorrows;

    /**
    * @notice Total amount of reserves of the underlying held in this market
    */
    uint256 public totalReserves;

    /**
     * @notice Accumulator of the total earned interest rate since the opening of the market
     */
    uint256 public borrowIndex; // TODO - needs initialized

    uint256 public liquidityIncentive = 5e6; // 5%
    uint256 public closeFactor = 50e6; // 50%
    uint256 public collateralFactor = 80e6; // 80%
    uint256 public protocolSeizeShare = 5e6; // 5%
    uint256 public reserveFactor = 80e6; // 80%

    /**
     * @notice Maximum borrow rate that can ever be applied (.0005% / block)
     */
    // slither-disable-next-line unused-state
    uint256 internal constant BORROW_RATE_MAX = 0.0005e16;

    // chainid => user => token => token balance
    mapping(uint256 => mapping(address => mapping(address => uint256)))
        public collateralBalances;

    // user => chainId => token balance
    mapping(address => mapping(uint256 => uint256)) public loansOutstanding;

    struct Market {
        uint256 collateralFactor;
        uint256 initialExchangeRate;
        uint256 totalSupply;
        string name; // 256
        string symbol; // 256
        address underlying; // 20
        bool isListed; // 8
        uint8 decimals;
        mapping(address => bool) accountMembership;
    }

    /**
     * @notice Official mapping of pTokens -> Market metadata
     * @dev Used e.g. to determine if a market is supported
     */
    // chain => ptoken address => market
    mapping(uint256 => mapping(address => Market)) public markets;

    struct InterestSnapshot {
        uint256 interestAccrued;
        uint256 interestIndex;
    }

    /**
     * @notice Container for borrow balance information
     * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
     * @member interestIndex Global borrowIndex as of the most recent balance-changing action
     */
    struct BorrowSnapshot {
        uint256 principal;
        uint256 interestIndex;
    }

    /**
     * @notice Mapping of account addresses to outstanding borrow balances
     */
    mapping(address => BorrowSnapshot) public accountBorrows;

    /// @notice A list of all deposit markets
    CollateralMarket[] public allMarkets;

    struct CollateralMarket {
        address token;
        uint256 chainId;
        uint8 decimals;
    }
    // user => interest index
    mapping(address => CollateralMarket[]) public accountAssets;

    uint256[] public chains;
}

File 9 of 21 : IPTokenOracle.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import "../../../satellite/pToken/interfaces/IPToken.sol";
import "../../../satellite/loanAgent/interfaces/ILoanAgent.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

interface IPTokenOracle {
    /**
     * @notice Get the underlying price of a cToken asset
     * @param pToken The pToken to get the underlying price of
     * @return The underlying asset price.
     *  Zero means the price is unavailable.
     */
    function getUnderlyingPrice(IERC20 pToken) external view returns (uint256);

    /**
     * @notice Get the underlying borrow price of a pToken asset
     * @param loanAgent The loanAgent associated with the pToken
     * @return The underlying borrow price
     *  Zero means the price is unavailable.
     */
    function getUnderlyingPriceBorrow(ILoanAgent loanAgent) external view returns (uint256);
}

File 10 of 21 : IMiddleLayer.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

abstract contract IMiddleLayer {
    /**
     * @notice routes and encodes messages for you
     * @param params - abi.encode() of the struct related to the selector, used to generate _payload
     * all params starting with '_' are directly sent to the lz 'send()' function
     */
    function msend(
        uint256 _dstChainId,
        bytes memory params,
        address payable _refundAddress,
        address fallbackAddress
    ) external payable virtual;

    function mreceive(
        uint256 _srcChainId,
        bytes memory payload
    ) external virtual;
}

File 11 of 21 : IECC.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface IECC {
    struct Metadata {
        bytes5 soph; // start of payload hash
        uint40 creation;
        uint16 nonce; // in case the same exact message is sent multiple times the same block, we increase the nonce in metadata
        address sender;
    }

    function preRegMsg(
        bytes memory payload,
        address instigator
    ) external returns (bytes32 metadata);

    function preProcessingValidation(
        bytes memory payload,
        bytes32 metadata
    ) external view returns (bool allowed);

    function flagMsgValidated(
        bytes memory payload,
        bytes32 metadata
    ) external returns (bool);

    // function rsm(uint256 messagePtr) external returns (bool);
}

File 12 of 21 : IPToken.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;

abstract contract IPToken {

    function mint(uint256 amount) external virtual payable;

    function redeemUnderlying(uint256 redeemAmount) external virtual payable;


    function setMidLayer(address newMiddleLayer) external virtual;

    function setMasterCID(uint256 newChainId) external virtual;

    function changeOwner(address payable _newOwner) external virtual;
}

File 13 of 21 : ILoanAgent.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;

import "../LoanAgentStorage.sol";
import "../../../interfaces/IHelper.sol";

abstract contract ILoanAgent is LoanAgentStorage {
    function initialize(address eccAddress) external virtual;

    function borrow(uint256 borrowAmount) external payable virtual;

    // function completeBorrow(
    //     address borrower,
    //     uint borrowAmount
    // ) external virtual;

    function repayBorrow(uint256 repayAmount) external payable virtual returns (bool);

    function repayBorrowBehalf(
        address borrower,
        uint256 repayAmount
    ) external payable virtual returns (bool);

    function borrowApproved(
        IHelper.FBBorrow memory params,
        bytes32 metadata
    ) external payable virtual;

    function setPUSD(address newPUSD) external virtual;

    function setMidLayer(address newMiddleLayer) external virtual;

    function setMasterCID(uint256 newChainId) external virtual;
}

File 14 of 21 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

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

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

File 15 of 21 : LoanAgentStorage.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;

import "../../middleLayer/interfaces/IMiddleLayer.sol";
import "../../ecc/interfaces/IECC.sol";

abstract contract LoanAgentStorage {
    /**
    * @notice Administrator for this contract
    */
    address payable public admin;

    // slither-disable-next-line unused-state
    address internal PUSD;

    // slither-disable-next-line unused-state
    IMiddleLayer internal middleLayer;

    // slither-disable-next-line unused-state
    IECC internal ecc;

    // slither-disable-next-line unused-state
    uint256 internal masterCID;

    uint256 public borrowIndex;
}

File 16 of 21 : IHelper.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

interface IHelper {
    enum Selector {
        MASTER_DEPOSIT,
        MASTER_REDEEM_ALLOWED,
        FB_REDEEM,
        MASTER_REPAY,
        MASTER_BORROW_ALLOWED,
        FB_BORROW,
        SATELLITE_LIQUIDATE_BORROW,
        MASTER_TRANSFER_ALLOWED,
        FB_COMPLETE_TRANSFER,
        PUSD_BRIDGE
    }

    // !!!!
    // @dev
    // an artificial uint256 param for metadata should be added
    // after packing the payload
    // metadata can be generated via call to ecc.preRegMsg()

    struct MDeposit {
        Selector selector; // = Selector.MASTER_DEPOSIT
        address user;
        address pToken;
        uint256 previousAmount;
        uint256 amountIncreased;
    }

    struct MRedeemAllowed {
        Selector selector; // = Selector.MASTER_REDEEM_ALLOWED
        address pToken;
        address user;
        uint256 amount;
    }

    struct FBRedeem {
        Selector selector; // = Selector.FB_REDEEM
        address pToken;
        address user;
        uint256 redeemAmount;
    }

    struct MRepay {
        Selector selector; // = Selector.MASTER_REPAY
        address borrower;
        uint256 amountRepaid;
    }

    struct MBorrowAllowed {
        Selector selector; // = Selector.MASTER_BORROW_ALLOWED
        address user;
        uint256 borrowAmount;
    }

    struct FBBorrow {
        Selector selector; // = Selector.FB_BORROW
        address user;
        uint256 borrowAmount;
    }

    struct SLiquidateBorrow {
        Selector selector; // = Selector.SATELLITE_LIQUIDATE_BORROW
        address borrower;
        address liquidator;
        uint256 seizeTokens;
        address pTokenCollateral;
    }

    struct MTransferAllowed {
        uint8 selector; // = Selector.MASTER_TRANSFER_ALLOWED
        address pToken;
        address spender;
        address user;
        address dst;
        uint256 amount;
    }

    struct FBCompleteTransfer {
        uint8 selector; // = Selector.FB_COMPLETE_TRANSFER
        address pToken;
        address spender;
        address src;
        address dst;
        uint256 tokens;
    }

    struct PUSDBridge {
        uint8 selector; // = Selector.PUSD_BRIDGE
        address minter;
        uint256 amount;
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

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

pragma solidity ^0.8.0;

import "../IERC20.sol";

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

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

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

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

pragma solidity ^0.8.0;

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

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

File 20 of 21 : MasterModifiers.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./MasterStorage.sol";

abstract contract MasterModifiers is MasterStorage {
    modifier onlyOwner() {
        require(msg.sender == admin, "ONLY_OWNER");
        _;
    }

    modifier onlyMid() {
        require(
            IMiddleLayer(msg.sender) == middleLayer,
            "ONLY_MIDDLE_LAYER"
        );
        _;
    }
}

File 21 of 21 : ERC20Burnable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        _spendAllowance(account, _msgSender(), amount);
        _burn(account, amount);
    }
}

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

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowPlusEffects","type":"uint256"}],"name":"AccountLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"AddChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCloseFactor","type":"uint256"}],"name":"ChangeCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCollateralFactor","type":"uint256"}],"name":"ChangeCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLiqIncentive","type":"uint256"}],"name":"ChangeLiqIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldMid","type":"address"},{"indexed":false,"internalType":"address","name":"newMid","type":"address"}],"name":"ChangeMiddleLayer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"ChangeOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newProtocolSeizeShare","type":"uint256"}],"name":"ChangeProtocolSeizeShare","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prevAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"CollateralBalanceAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prevAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"CollateralChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prevAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"LoanAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"LoanApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prevAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"LoanChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shortfall","type":"uint256"}],"name":"LoanRejection","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prevAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"LoanRepaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_srcChainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_fromAddress","type":"address"}],"name":"ReceiveFromChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateralBalanceNew","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"RedeemAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"shortfall","type":"uint256"}],"name":"RedeemRejection","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"loanOutstanding","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"}],"name":"RepayBorrowMaster","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPUSD","type":"address"}],"name":"SetPUSD","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountBorrows","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"interestIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"addChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum IHelper.Selector","name":"selector","type":"uint8"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"internalType":"struct IHelper.MBorrowAllowed","name":"params","type":"tuple"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"fallbackAddress","type":"address"}],"name":"borrowAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"chains","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCloseFactor","type":"uint256"}],"name":"changeCloseFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCollateralFactor","type":"uint256"}],"name":"changeCollateralFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLiqIncentive","type":"uint256"}],"name":"changeLiqIncentive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMiddleLayer","name":"oldMid","type":"address"},{"internalType":"contract IMiddleLayer","name":"newMid","type":"address"}],"name":"changeMiddleLayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newProtocolSeizeShare","type":"uint256"}],"name":"changeProtocolSeizeShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"collateralBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"enterMarkets","outputs":[{"internalType":"bool[]","name":"r","type":"bool[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"}],"name":"getAccountAssets","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"internalType":"struct MasterStorage.CollateralMarket[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"middleLayerAddress","type":"address"},{"internalType":"address","name":"eccAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pTokenCollateral","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pTokenCollateral","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pTokenCollateral","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidityIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"loansOutstanding","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"internalType":"uint256","name":"collateralFactor","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum IHelper.Selector","name":"selector","type":"uint8"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"pToken","type":"address"},{"internalType":"uint256","name":"previousAmount","type":"uint256"},{"internalType":"uint256","name":"amountIncreased","type":"uint256"}],"internalType":"struct IHelper.MDeposit","name":"params","type":"tuple"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"masterDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IHelper.Selector","name":"selector","type":"uint8"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"amountRepaid","type":"uint256"}],"internalType":"struct IHelper.MRepay","name":"params","type":"tuple"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"masterRepay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"protocolSeizeShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum IHelper.Selector","name":"selector","type":"uint8"},{"internalType":"address","name":"pToken","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IHelper.MRedeemAllowed","name":"params","type":"tuple"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"fallbackAddress","type":"address"}],"name":"redeemAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"reserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newPUSD","type":"address"}],"name":"setPUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFactor","type":"uint256"}],"name":"setReserveFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"initialExchangeRate_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address","name":"underlying_","type":"address"}],"name":"supportMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"selector","type":"uint8"},{"internalType":"address","name":"pToken","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IHelper.MTransferAllowed","name":"params","type":"tuple"},{"internalType":"bytes32","name":"metadata","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"fallbackAddress","type":"address"}],"name":"transferAllowed","outputs":[],"stateMutability":"payable","type":"function"}]

Deployed Bytecode

0x6080604052600436106102515760003560e01c80638856810911610139578063aa5af0fd116100b6578063dce154491161007a578063dce1544914610718578063df011c4114610738578063e313cdd31461074e578063f241638614610761578063f851a44014610774578063fd8c75d2146107ac57600080fd5b8063aa5af0fd1461066e578063aca0a95214610684578063c46afdf4146106a4578063d40e8f4a146106c4578063d566e2ff146106f857600080fd5b80639ad4e17c116100fd5780639ad4e17c146105f35780639d01be4814610606578063a053c32e14610626578063a6afed9514610639578063a6f9dae11461064e57600080fd5b806388568109146105675780638d777c74146105945780638f840ddd146105aa57806395dd9193146105c057806399f22f24146105e057600080fd5b806335f63266116101d257806352d84d1e1161019657806352d84d1e14610460578063550325b5146104a85780635ec88c79146104c85780636c540baf146104fd578063767818b514610513578063803bbac01461054757600080fd5b806335f63266146103d4578063361279c7146103f45780634322b7141461041457806347bd37181461042a578063485cc9551461044057600080fd5b8063182df0f511610219578063182df0f5146103375780631c4469831461034e5780631ec02f3a1461036e5780632ce5a0991461039b57806332cf078b146103be57600080fd5b80630287809d1461025657806304e59e5c146102a757806305308b9f146102c757806306788bc9146102dd57806307ffd044146102ff575b600080fd5b34801561026257600080fd5b506102946102713660046139f2565b600d60209081526000938452604080852082529284528284209052825290205481565b6040519081526020015b60405180910390f35b3480156102b357600080fd5b506102946102c2366004613a34565b6107cc565b3480156102d357600080fd5b5061029460095481565b3480156102e957600080fd5b506102fd6102f8366004613b46565b6107e3565b005b34801561030b57600080fd5b5061029461031a366004613bf5565b600e60209081526000928352604080842090915290825290205481565b34801561034357600080fd5b506305f5e100610294565b34801561035a57600080fd5b506102fd610369366004613c21565b610b42565b34801561037a57600080fd5b5061038e610389366004613c86565b610b71565b60405161029e9190613cf2565b6103ae6103a9366004613d38565b610c98565b604051901515815260200161029e565b3480156103ca57600080fd5b50610294600b5481565b3480156103e057600080fd5b506102fd6103ef366004613c21565b610cb9565b34801561040057600080fd5b506102fd61040f366004613d7e565b610d1f565b34801561042057600080fd5b50610294600c5481565b34801561043657600080fd5b5061029460055481565b34801561044c57600080fd5b506102fd61045b366004613d9b565b610ddf565b34801561046c57600080fd5b5061048061047b366004613c21565b610e47565b604080516001600160a01b039094168452602084019290925260ff169082015260600161029e565b3480156104b457600080fd5b506102946104c3366004613c21565b610e87565b3480156104d457600080fd5b506104e86104e3366004613d7e565b610ea8565b6040805192835260208301919091520161029e565b34801561050957600080fd5b5061029460045481565b34801561051f57600080fd5b5061053361052e366004613dd4565b610ec0565b60405161029e989796959493929190613e46565b34801561055357600080fd5b506102fd610562366004613c21565b611038565b34801561057357600080fd5b50610587610582366004613d7e565b611097565b60405161029e9190613ead565b3480156105a057600080fd5b5061029460085481565b3480156105b657600080fd5b5061029460065481565b3480156105cc57600080fd5b506104e86105db366004613d7e565b611132565b6102fd6105ee366004613f21565b61113e565b6102fd610601366004613fc6565b611436565b34801561061257600080fd5b506102fd610621366004613d9b565b61190b565b6102fd610634366004614076565b6119e8565b34801561064557600080fd5b506102fd611dba565b34801561065a57600080fd5b506102fd610669366004613d7e565b611dc4565b34801561067a57600080fd5b5061029460075481565b34801561069057600080fd5b506102fd61069f366004613c21565b611e84565b3480156106b057600080fd5b506103ae6106bf366004613d38565b611ee3565b3480156106d057600080fd5b506104e86106df366004613d7e565b6010602052600090815260409020805460019091015482565b34801561070457600080fd5b506102fd610713366004613c21565b611ef1565b34801561072457600080fd5b50610480610733366004613bf5565b611f50565b34801561074457600080fd5b50610294600a5481565b6102fd61075c366004614198565b611f9f565b6102fd61076f3660046141d6565b6123bb565b34801561078057600080fd5b50600054610794906001600160a01b031681565b6040516001600160a01b03909116815260200161029e565b3480156107b857600080fd5b506102fd6107c7366004613c21565b61267c565b60006107d984848461270b565b90505b9392505050565b6000546001600160a01b031633146108165760405162461bcd60e51b815260040161080d9061420a565b60405180910390fd5b6000868152600f602090815260408083206001600160a01b038b168452909152902060050154600160a01b900460ff161561088b5760405162461bcd60e51b8152602060048201526015602482015274535550504f52545f4d41524b45545f45584953545360581b604482015260640161080d565b6000868152600f602090815260408083206001600160a01b038b168452825290912060058101805460ff60a01b1916600160a01b1790556304c4b40081556001810187905585516108e4926003909201918701906138ec565b506000868152600f602090815260408083206001600160a01b038b1684528252909120845161091b926004909201918601906138ec565b506000868152600f602090815260408083206001600160a01b038b81168552925282206005018054600161ff0160a01b031916600160a81b60ff8716026001600160a01b031916179184169190911790555b601154811015610a2e57876001600160a01b0316601182815481106109945761099461422e565b60009182526020909120600390910201546001600160a01b0316148015906109e0575086601182815481106109cb576109cb61422e565b90600052602060002090600302016001015414155b610a1c5760405162461bcd60e51b815260206004820152600d60248201526c4d41524b45545f45584953545360981b604482015260640161080d565b80610a268161425a565b91505061096d565b50604080516060810182526001600160a01b0389811680835260208084018b815260ff8881168688019081526011805460018101825560009190915287517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68600390920291820180546001600160a01b031916919098161790965591517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6986015590517f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6a909401805460ff19169490911693909317909255925192835290917fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f910160405180910390a15050505050505050565b6000546001600160a01b03163314610b6c5760405162461bcd60e51b815260040161080d9061420a565b600c55565b60608382808214610bb35760405162461bcd60e51b815260206004820152600c60248201526b082a4a482b2be988a9c8ea8960a31b604482015260640161080d565b8167ffffffffffffffff811115610bcc57610bcc613a69565b604051908082528060200260200182016040528015610bf5578160200160208202803683370190505b50925060005b82811015610c8d576000888883818110610c1757610c1761422e565b9050602002016020810190610c2c9190613d7e565b90506000878784818110610c4257610c4261422e565b905060200201359050610c568282336127b9565b868481518110610c6857610c6861422e565b9115156020928302919091019091015250819050610c858161425a565b915050610bfb565b505050949350505050565b6000610ca261291a565b610cae85858585612a29565b90505b949350505050565b6000546001600160a01b03163314610ce35760405162461bcd60e51b815260040161080d9061420a565b600b8190556040518181527f5aeb52a1490541359c29ff085eb029648d4260c491b9dbbad79c71097f957604906020015b60405180910390a150565b6000546001600160a01b03163314610d495760405162461bcd60e51b815260040161080d9061420a565b6001600160a01b038116610d915760405162461bcd60e51b815260206004820152600f60248201526e4e4f4e5f5a45524f4144445245535360881b604482015260640161080d565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f600c4608dcb52870659a459fb978bc37ff74c3ccff43645322a64dd13103ed4a90602001610d14565b6000546001600160a01b03163314610e095760405162461bcd60e51b815260040161080d9061420a565b600180546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055670de0b6b3a764000060075543600455565b60118181548110610e5757600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116925060ff1683565b60138181548110610e9757600080fd5b600091825260209091200154905081565b600080610eb783600080612d6e565b91509150915091565b600f60205281600052604060002060205280600052604060002060009150915050806000015490806001015490806002015490806003018054610f0290614273565b80601f0160208091040260200160405190810160405280929190818152602001828054610f2e90614273565b8015610f7b5780601f10610f5057610100808354040283529160200191610f7b565b820191906000526020600020905b815481529060010190602001808311610f5e57829003601f168201915b505050505090806004018054610f9090614273565b80601f0160208091040260200160405190810160405280929190818152602001828054610fbc90614273565b80156110095780601f10610fde57610100808354040283529160200191611009565b820191906000526020600020905b815481529060010190602001808311610fec57829003601f168201915b505050600590930154919250506001600160a01b0381169060ff600160a01b8204811691600160a81b90041688565b6000546001600160a01b031633146110625760405162461bcd60e51b815260040161080d9061420a565b600a8190556040518181527ff6a9693473c54ec6f1a9eab67841062df77b38b8ec79180f0e93f1549b3b47ca90602001610d14565b6001600160a01b0381166000908152601260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015611127576000848152602090819020604080516060810182526003860290920180546001600160a01b031683526001808201548486015260029091015460ff169183019190915290835290920191016110cf565b505050509050919050565b600080610eb783613119565b6001546001600160a01b031633146111685760405162461bcd60e51b815260040161080d906142ad565b6002546040516001600160a01b0390911690637b1995639061118e908690602001614310565b604051602081830303815290604052846040518363ffffffff1660e01b81526004016111bb92919061435f565b602060405180830381865afa1580156111d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111fc9190614381565b15611431576000818152600d60209081526040808320868301516001600160a01b03908116855290835281842087830151909116845290915281205490036112535761125183604001518285602001516127b9565b505b60808301516000828152600d60209081526040808320828801516001600160a01b0390811685529083528184208289015190911684529091528120805490919061129e9084906143a3565b909155505060808301516000828152600f60209081526040808320818801516001600160a01b03168452909152812060020180549091906112e09084906143a3565b9091555050602083810180516000848152600d808552604080832085516001600160a01b039081168552818852828520838c01805183168752908952838620548a875294895296518116855290875281842095518116845294865291829020548251878152958601919091529084015216907f5fdd70297ba8cca754023b90db77a4feeba6b2ee9bcd93cbd2565d2daca0297a9060600160405180910390a26002546040516001600160a01b0390911690639495a3e3906113a5908690602001614310565b604051602081830303815290604052846040518363ffffffff1660e01b81526004016113d292919061435f565b6020604051808303816000875af11580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190614381565b6114315760405162461bcd60e51b815260040161080d906143bb565b505050565b6001546001600160a01b031633146114605760405162461bcd60e51b815260040161080d906142ad565b6002546040516001600160a01b0390911690637b19956390611486908790602001614413565b604051602081830303815290604052856040518363ffffffff1660e01b81526004016114b392919061435f565b602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614381565b156119055761150161291a565b600061151c856040015186602001518760600151600061317c565b915050600080604051806080016040528060026009811115611540576115406142d8565b815260200188602001516001600160a01b0316815260200188604001516001600160a01b031681526020018860600151815250604051602001611584929190614421565b60408051601f1981840301815282825260025491890151634ca2500560e01b84529093506000926001600160a01b0390921691634ca25005916115cc91869190600401614435565b6020604051808303816000875af11580156115eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160f919061445f565b90508060208301528260000361185d5760608701516000868152600d60209081526040808320818c01516001600160a01b039081168552908352818420838d015190911684529091528120805490919061166a908490614478565b909155505060608701516000868152600f60209081526040808320828c01516001600160a01b03168452909152812060020180549091906116ac908490614478565b90915550506002546040516001600160a01b0390911690639495a3e3906116d7908a90602001614413565b604051602081830303815290604052886040518363ffffffff1660e01b815260040161170492919061435f565b6020604051808303816000875af1158015611723573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117479190614381565b6117635760405162461bcd60e51b815260040161080d906143bb565b600154604051633483addf60e11b81526001600160a01b03909116906369075bbe90349061179b908990879033908b9060040161448f565b6000604051808303818588803b1580156117b457600080fd5b505af11580156117c8573d6000803e3d6000fd5b5050506000878152600d602090815260408083208c8201516001600160a01b0390811685529083528184208d8401805183168652908452828520548c8652600f855283862091519092168552835292819020600201548151938452918301919091527f1417fdb785cf8621d5c6baea867be2bfd98a3469b7a38abccce53729c947895c935001905060405180910390a1611901565b600154604051633483addf60e11b81526001600160a01b03909116906369075bbe903490611895908990879033908b9060040161448f565b6000604051808303818588803b1580156118ae57600080fd5b505af11580156118c2573d6000803e3d6000fd5b50505050507f77c52d00f10223cdd39d60fdfe20c9a30962ad1a7354f0f5572fb04109987e85836040516118f891815260200190565b60405180910390a15b5050505b50505050565b6000546001600160a01b031633146119355760405162461bcd60e51b815260040161080d9061420a565b6001546001600160a01b038381169116146119895760405162461bcd60e51b815260206004820152601460248201527324a72b20a624a22fa6a4a2222622afa620aca2a960611b604482015260640161080d565b600180546001600160a01b0319166001600160a01b0383811691821790925560408051928516835260208301919091527f08a0f36caa997f21421e775d6c65f15aff8e3297e01fb38cf1c2905a003e17f2910160405180910390a15050565b6001546001600160a01b03163314611a125760405162461bcd60e51b815260040161080d906142ad565b6002546040516001600160a01b0390911690637b19956390611a38908790602001614518565b604051602081830303815290604052856040518363ffffffff1660e01b8152600401611a6592919061435f565b602060405180830381865afa158015611a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa69190614381565b1561190557611ab361291a565b6000611aca8560600151866020015160008061317c565b9150506000806040518060c0016040528060086009811115611aee57611aee6142d8565b60ff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018860a00151815250604051602001611b5b929190614526565b60408051601f19818403018152908290526002546060890151634ca2500560e01b84529193506000926001600160a01b0390911691634ca2500591611ba4918691600401614435565b6020604051808303816000875af1158015611bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be7919061445f565b9050806020830152826000036119015760a08701516000868152600d6020908152604080832060608c01516001600160a01b039081168552908352818420838d0151909116845290915281208054909190611c43908490614478565b909155505060a08701516000868152600d6020908152604080832060808c01516001600160a01b039081168552908352818420838d0151909116845290915281208054909190611c949084906143a3565b90915550506002546040516001600160a01b0390911690639495a3e390611cbf908a90602001614518565b604051602081830303815290604052886040518363ffffffff1660e01b8152600401611cec92919061435f565b6020604051808303816000875af1158015611d0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2f9190614381565b611d4b5760405162461bcd60e51b815260040161080d906143bb565b600154604051633483addf60e11b81526001600160a01b03909116906369075bbe903490611d83908990879033908b9060040161448f565b6000604051808303818588803b158015611d9c57600080fd5b505af1158015611db0573d6000803e3d6000fd5b5050505050611901565b611dc261291a565b565b6000546001600160a01b03163314611dee5760405162461bcd60e51b815260040161080d9061420a565b6001600160a01b038116611e365760405162461bcd60e51b815260206004820152600f60248201526e4e4f4e5f5a45524f4144445245535360881b604482015260640161080d565b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527ff285329298fd841af46eb83bbe90d1ebe2951c975a65b19a02f965f842ee69c590602001610d14565b6000546001600160a01b03163314611eae5760405162461bcd60e51b815260040161080d9061420a565b60098190556040518181527f2c987140103a76894adcc1072529873e69700442b3b99f1496d8ef57bc17775a90602001610d14565b6000610cae858585856134cd565b6000546001600160a01b03163314611f1b5760405162461bcd60e51b815260040161080d9061420a565b60088190556040518181527f4ab84f96e9e108491c28141147c73407f5863bf296fe4857976131590868788b90602001610d14565b60126020528160005260406000208181548110611f6c57600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116935090915060ff1683565b6001546001600160a01b03163314611fc95760405162461bcd60e51b815260040161080d906142ad565b6002546040516001600160a01b0390911690637b19956390611fef908790602001614563565b604051602081830303815290604052856040518363ffffffff1660e01b815260040161201c92919061435f565b602060405180830381865afa158015612039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205d9190614381565b156119055761206a61291a565b60006120818560200151600080886040015161317c565b9150508060000361238057600061209b8660200151613119565b5090508560400151816120ae91906143a3565b602080880180516001600160a01b0390811660009081526010845260408082209590955560075483518316825285822060010155848b015192519091168152600e8352838120888252909252918120805490919061210d9084906143a3565b90915550506040860151600580546000906121299084906143a3565b909155505060408051606081018252600581526020888101516001600160a01b0316818301528883015182840152915160009261216a928492909101614571565b60408051601f198184030181529082905260025460208a0151634ca2500560e01b84529193506000926001600160a01b0390911691634ca25005916121b3918691600401614435565b6020604051808303816000875af11580156121d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f6919061445f565b60208301819052600154604051633483addf60e11b81529192506001600160a01b0316906369075bbe903490612236908a90879033908c9060040161448f565b6000604051808303818588803b15801561224f57600080fd5b505af1158015612263573d6000803e3d6000fd5b50506002546040516001600160a01b039091169350639495a3e3925061228e91508b90602001614563565b604051602081830303815290604052896040518363ffffffff1660e01b81526004016122bb92919061435f565b6020604051808303816000875af11580156122da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122fe9190614381565b61231a5760405162461bcd60e51b815260040161080d906143bb565b6040888101516020808b01516001600160a01b0316600090815260108252839020546005548451938452918301528183015290517f97e1a27395cd6cecae11b16fdb395385346475933c0b8fa76116bc547958c18b9181900360600190a15050506123b4565b6040518181527f97620848ab6c73c152db53135f3cb3210a212770039f9bedb09f30a00af998fd9060200160405180910390a15b5050505050565b6001546001600160a01b031633146123e55760405162461bcd60e51b815260040161080d906142ad565b6002546040516001600160a01b0390911690637b1995639061240b908690602001614563565b604051602081830303815290604052846040518363ffffffff1660e01b815260040161243892919061435f565b602060405180830381865afa158015612455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124799190614381565b1561143157602083810180516001600160a01b03166000908152600e835260408120848252909252516124ab90613119565b506040808601516020808801516001600160a01b03166000908152600e8252838120878252909152918220805493945090929091906124eb908490614478565b9091555050604084015160058054600090612507908490614478565b9091555050604084015161251b9082614478565b6020808601516001600160a01b031660009081526010909152604090205561254161291a565b6002546040516001600160a01b0390911690639495a3e390612567908790602001614563565b604051602081830303815290604052856040518363ffffffff1660e01b815260040161259492919061435f565b6020604051808303816000875af11580156125b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d79190614381565b6125f35760405162461bcd60e51b815260040161080d906143bb565b602080850180516001600160a01b039081166000908152600e845260408082208783528552808220546005549451909316825260109094528390205492517f3ab1940b2ef8e6817d358b8be143432ed1cdbead351951c3e56107a654db950c9361266e93919283526020830191909152604082015260600190565b60405180910390a150505050565b6000546001600160a01b031633146126a65760405162461bcd60e51b815260040161080d9061420a565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090018190556040518181527f770b999c06036d4bf437b86d5742fd51273a9fa040dfa11b993aaf02fe30e7ec90602001610d14565b60006305f5e100806000858152600f602090815260408083206001600160a01b038a16845290915281206005015461274e90600160a81b900460ff16600a614669565b9050600081846008548461276291906143a3565b61276c9089614678565b6127769190614678565b6127809190614697565b90506000826127936305f5e10086614678565b61279d9190614697565b905060006127ab8284614697565b9a9950505050505050505050565b6000828152600f602090815260408083206001600160a01b038716845290915281206005810154600160a01b900460ff166127f85760009150506107dc565b6001600160a01b038316600090815260068201602052604090205460ff16156128255760019150506107dc565b6001600160a01b03838116600081815260068401602090815260408083208054600160ff1991821681179092558251606080820185528d891682528186018d815260058b015460ff600160a81b90910481168488019081528a8a5260128952878a2080548089018255908b529989902085516003909b020180546001600160a01b0319169a909c16998a178c559151958b0186905590516002909a01805490941699169890981790915582519182529281019390935282019290925290917f871980568a218a897acedf2828882506c976caaff520ede7df4be53759904eca910160405180910390a150600195945050505050565b4360045414611dc257600454600554600654600754621e84808443101561297b5760405162461bcd60e51b815260206004820152601560248201527443616e6e6f742063616c63756c617465206461746160581b604482015260640161080d565b60006129878643614478565b905060006129958284614678565b90506305f5e1006000816129a98985614678565b6129b39190614697565b905060006129c189836143a3565b90506000888484600c546129d59190614678565b6129df9190614697565b6129e991906143a3565b9050600088856129f98289614678565b612a039190614697565b612a0d91906143a3565b4360045560075550600591909155600655505050505050505050565b6000612a37858585856134cd565b612a835760405162461bcd60e51b815260206004820152601e60248201527f4c49515549444154455f5249534b454e47494e455f52454a454354494f4e0000604482015260640161080d565b4360045414612ad45760405162461bcd60e51b815260206004820152601960248201527f4c49515549444154455f46524553484e4553535f434845434b00000000000000604482015260640161080d565b336001600160a01b03851603612b2c5760405162461bcd60e51b815260206004820181905260248201527f4c49515549444154455f4c495155494441544f525f49535f424f52524f574552604482015260640161080d565b60008211612b7c5760405162461bcd60e51b815260206004820152601e60248201527f4c49515549444154455f434c4f53455f414d4f554e545f49535f5a45524f0000604482015260640161080d565b6000612b8885846135a9565b905060006305f5e100600b5483612b9f9190614678565b612ba99190614697565b90506000612bc18887612bbc8587614478565b61270b565b6000878152600d602090815260408083206001600160a01b03808d168552908352818420908d16845290915290205490915081811015612c435760405162461bcd60e51b815260206004820152601860248201527f4c49515549444154455f5345495a455f544f4f5f4d5543480000000000000000604482015260640161080d565b6001600160a01b03881660009081526010602052604081208054859290612c6b9084906143a3565b90915550612c7b90508282614478565b6000888152600d602090815260408083206001600160a01b03808e168552818452828520908f168086529084528285209590955533845282528083209383529290529081208054849290612cd09084906143a3565b925050819055508260066000828254612ce991906143a3565b909155505060035460405163079cc67960e41b8152336004820152602481018690526001600160a01b03909116906379cc679090604401600060405180830381600087803b158015612d3a57600080fd5b505af1158015612d4e573d6000803e3d6000fd5b50505050612d5f878933858d61377f565b50600198975050505050505050565b6001600160a01b0383166000908152601260209081526040808320805482518185028101850190935280835284938493929190849084015b82821015612dfe576000848152602090819020604080516060810182526003860290920180546001600160a01b031683526001808201548486015260029091015460ff16918301919091529083529092019101612da6565b5050505090506000815111612e495760405162461bcd60e51b81526020600482015260116024820152706e6f206163636f756e742061737365747360781b604482015260640161080d565b600080612e54613970565b60005b845181101561304d576000858281518110612e7457612e7461422e565b60200260200101519050600d60008260200151815260200190815260200160002060008c6001600160a01b03166001600160a01b03168152602001908152602001600020600082600001516001600160a01b03166001600160a01b031681526020019081526020016000205483604001818152505082604001516000148015612f135750896001600160a01b031681600001516001600160a01b031614155b15612f1e575061303b565b604081015160ff169450612f3385600a6146b9565b60c0840181905293506000849003612f7b5760405162461bcd60e51b815260206004820152600b60248201526a282924a1a2afa2a92927a960a91b604482015260640161080d565b600a54608084018190526305f5e10060a0850181905260c085015186928392612fa391614678565b612fad9190614678565b612fb79190614697565b612fc19190614697565b60e0840181905260408401518591612fd99190614678565b612fe39190614697565b83518490612ff29083906143a3565b90525080516001600160a01b03808c169116036130395783898460e0015161301a9190614678565b6130249190614697565b8360200181815161303591906143a3565b9052505b505b806130458161425a565b915050612e57565b5081600061305a8b613119565b509050836130688284614678565b6130729190614697565b8360200181815161308391906143a3565b905250825160208085015160408051938452918301527fdfb1b6609eaf2fffcd759d809998cc1bfb7b30b69d8c5ab9dbbb9ab6a1675ae1910160405180910390a16020830151835111156130f357602083015183516130e29190614478565b600097509750505050505050613111565b8251602084015160009161310691614478565b975097505050505050505b935093915050565b6001600160a01b0381166000908152601060205260408120805482919082036131485750600093849350915050565b600754815460009161315991614678565b9050600082600101548261316d9190614697565b92549296929550919350505050565b600080613187613970565b61319087613119565b506020808301919091526001600160a01b03881660009081526012825260408082208054825181860281018601909352808352929391929091849084015b82821015613226576000848152602090819020604080516060810182526003860290920180546001600160a01b031683526001808201548486015260029091015460ff169183019190915290835290920191016131ce565b50505050905060005b815181101561342b57600082828151811061324c5761324c61422e565b602002602001015190506132998a826020015183600001516000918252600d602090815260408084206001600160a01b0395861685528252808420929094168352522054906305f5e10090565b60a0860152604085018190526000036132b25750613419565b6020818101516000908152600f8252604080822084516001600160a01b0316835290925290812060050154600160a81b900460ff16906132f382600a6146b9565b6020808501516000908152600f8252604080822087516001600160a01b0316835290925290812054608089015260c088018290529091508190036133675760405162461bcd60e51b815260206004820152600b60248201526a282924a1a2afa2a92927a960a91b604482015260640161080d565b808660c00151828860a0015189608001516133829190614678565b61338c9190614697565b6133969190614678565b6133a09190614697565b60e0870181905286516040880151909183916133bb91614678565b6133c59190614697565b6133cf91906143a3565b865282516001600160a01b03808d1691160361341557808a8760e001516133f69190614678565b6134009190614697565b8660200181815161341191906143a3565b9052505b5050505b806134238161425a565b91505061322f565b50848260200181815161343e91906143a3565b905250815160208084015160408051938452918301527fdfb1b6609eaf2fffcd759d809998cc1bfb7b30b69d8c5ab9dbbb9ab6a1675ae1910160405180910390a16020820151825111156134aa576020820151825161349d9190614478565b60009350935050506134c4565b815160208301516000916134bd91614478565b9350935050505b94509492505050565b6000828152600f602090815260408083206001600160a01b0388168452909152812060050154600160a01b900460ff1661350957506000610cb1565b600061351785600080612d6e565b9150508060000361352c576000915050610cb1565b6000848152600f602090815260408083206001600160a01b038a16845290915281206005015461356790600160a81b900460ff16600a614669565b9050600061357487613119565b509050600082826009546135889190614678565b6135929190614697565b905080861115612d5f576000945050505050610cb1565b600043600454146135fc5760405162461bcd60e51b815260206004820152601c60248201527f52455041595f424f52524f575f46524553484e4553535f434845434b00000000604482015260640161080d565b6136356040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160a01b0384166000908152601060209081526040909120600101549082015261366184613119565b5060408201526000198314613676578261367c565b80604001515b60a08201819052604082015110156136c95760405162461bcd60e51b815260206004820152601060248201526f52455041595f47545f424f52524f575360801b604482015260640161080d565b8060a0015160055410156137135760405162461bcd60e51b815260206004820152601160248201527052455041595f47545f54424f52524f575360781b604482015260640161080d565b8060a0015181604001516137279190614478565b606082015260a081015160055461373e9190614478565b6080820190815260608201516001600160a01b03861660009081526010602052604090209081556007546001909101555160055560a0015190505b92915050565b6000806040518060a00160405280600660098111156137a0576137a06142d8565b8152602001876001600160a01b03168152602001866001600160a01b03168152602001858152602001846001600160a01b03168152506040516020016137e79291906146c5565b60408051601f1981840301815290829052600254634ca2500560e01b83529092506000916001600160a01b0390911690634ca250059061382d9085903390600401614435565b6020604051808303816000875af115801561384c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613870919061445f565b60208301819052600154604051633483addf60e11b81529192506001600160a01b0316906369075bbe9034906138b1908b908790339060009060040161448f565b6000604051808303818588803b1580156138ca57600080fd5b505af11580156138de573d6000803e3d6000fd5b505050505050505050505050565b8280546138f890614273565b90600052602060002090601f01602090048101928261391a5760008555613960565b82601f1061393357805160ff1916838001178555613960565b82800160010185558215613960579182015b82811115613960578251825591602001919060010190613945565b5061396c9291506139b5565b5090565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b8082111561396c57600081556001016139b6565b6001600160a01b03811681146139df57600080fd5b50565b80356139ed816139ca565b919050565b600080600060608486031215613a0757600080fd5b833592506020840135613a19816139ca565b91506040840135613a29816139ca565b809150509250925092565b600080600060608486031215613a4957600080fd5b8335613a54816139ca565b95602085013595506040909401359392505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715613aa257613aa2613a69565b60405290565b600082601f830112613ab957600080fd5b813567ffffffffffffffff80821115613ad457613ad4613a69565b604051601f8301601f19908116603f01168101908282118183101715613afc57613afc613a69565b81604052838152866020858801011115613b1557600080fd5b836020870160208301376000602085830101528094505050505092915050565b803560ff811681146139ed57600080fd5b600080600080600080600060e0888a031215613b6157600080fd5b8735613b6c816139ca565b96506020880135955060408801359450606088013567ffffffffffffffff80821115613b9757600080fd5b613ba38b838c01613aa8565b955060808a0135915080821115613bb957600080fd5b50613bc68a828b01613aa8565b935050613bd560a08901613b35565b915060c0880135613be5816139ca565b8091505092959891949750929550565b60008060408385031215613c0857600080fd5b8235613c13816139ca565b946020939093013593505050565b600060208284031215613c3357600080fd5b5035919050565b60008083601f840112613c4c57600080fd5b50813567ffffffffffffffff811115613c6457600080fd5b6020830191508360208260051b8501011115613c7f57600080fd5b9250929050565b60008060008060408587031215613c9c57600080fd5b843567ffffffffffffffff80821115613cb457600080fd5b613cc088838901613c3a565b90965094506020870135915080821115613cd957600080fd5b50613ce687828801613c3a565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015613d2c578351151583529284019291840191600101613d0e565b50909695505050505050565b60008060008060808587031215613d4e57600080fd5b8435613d59816139ca565b93506020850135613d69816139ca565b93969395505050506040820135916060013590565b600060208284031215613d9057600080fd5b81356107dc816139ca565b60008060408385031215613dae57600080fd5b8235613db9816139ca565b91506020830135613dc9816139ca565b809150509250929050565b60008060408385031215613de757600080fd5b823591506020830135613dc9816139ca565b6000815180845260005b81811015613e1f57602081850181015186830182015201613e03565b81811115613e31576000602083870101525b50601f01601f19169290920160200192915050565b60006101008a8352896020840152886040840152806060840152613e6c81840189613df9565b90508281036080840152613e808188613df9565b6001600160a01b039690961660a0840152505091151560c083015260ff1660e09091015295945050505050565b602080825282518282018190526000919060409081850190868401855b82811015613f0557815180516001600160a01b03168552868101518786015285015160ff168585015260609093019290850190600101613eca565b5091979650505050505050565b8035600a81106139ed57600080fd5b600080600083850360e0811215613f3757600080fd5b60a0811215613f4557600080fd5b5060405160a0810181811067ffffffffffffffff82111715613f6957613f69613a69565b604052613f7585613f12565b81526020850135613f85816139ca565b60208201526040850135613f98816139ca565b604082015260608581013590820152608080860135908201529560a0850135955060c0909401359392505050565b60008060008084860360e0811215613fdd57600080fd5b6080811215613feb57600080fd5b506040516080810181811067ffffffffffffffff8211171561400f5761400f613a69565b60405261401b86613f12565b8152602086013561402b816139ca565b6020820152604086013561403e816139ca565b60408201526060868101359082015293506080850135925060a0850135915060c085013561406b816139ca565b939692955090935050565b60008060008084860361012081121561408e57600080fd5b60c081121561409c57600080fd5b506140a5613a7f565b6140ae86613b35565b815260208601356140be816139ca565b602082015260408601356140d1816139ca565b604082015260608601356140e4816139ca565b606082015260808601356140f7816139ca565b608082015260a08681013590820152935060c0850135925060e0850135915061412361010086016139e2565b905092959194509250565b60006060828403121561414057600080fd5b6040516060810181811067ffffffffffffffff8211171561416357614163613a69565b60405290508061417283613f12565b81526020830135614182816139ca565b6020820152604092830135920191909152919050565b60008060008060c085870312156141ae57600080fd5b6141b8868661412e565b9350606085013592506080850135915060a085013561406b816139ca565b600080600060a084860312156141eb57600080fd5b6141f5858561412e565b95606085013595506080909401359392505050565b6020808252600a908201526927a7262cafa7aba722a960b11b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161426c5761426c614244565b5060010190565b600181811c9082168061428757607f821691505b6020821081036142a757634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526011908201527027a7262cafa6a4a2222622afa620aca2a960791b604082015260600190565b634e487b7160e01b600052602160045260246000fd5b600a811061430c57634e487b7160e01b600052602160045260246000fd5b9052565b600060a0820190506143238284516142ee565b602083015160018060a01b0380821660208501528060408601511660408501525050606083015160608301526080830151608083015292915050565b6040815260006143726040830185613df9565b90508260208301529392505050565b60006020828403121561439357600080fd5b815180151581146107dc57600080fd5b600082198211156143b6576143b6614244565b500190565b6020808252600390820152622326ab60e91b604082015260600190565b6143e38282516142ee565b6020818101516001600160a01b039081169184019190915260408083015190911690830152606090810151910152565b6080810161377982846143d8565b82815260a081016107dc60208301846143d8565b6040815260006144486040830185613df9565b905060018060a01b03831660208301529392505050565b60006020828403121561447157600080fd5b5051919050565b60008282101561448a5761448a614244565b500390565b8481526080602082015260006144a86080830186613df9565b6001600160a01b039485166040840152929093166060909101529392505050565b60ff8151168252602081015160018060a01b038082166020850152806040840151166040850152806060840151166060850152806080840151166080850152505060a081015160a08301525050565b60c0810161377982846144c9565b82815260e081016107dc60208301846144c9565b6145458282516142ee565b6020818101516001600160a01b031690830152604090810151910152565b60608101613779828461453a565b828152608081016107dc602083018461453a565b600181815b808511156145c05781600019048211156145a6576145a6614244565b808516156145b357918102915b93841c939080029061458a565b509250929050565b6000826145d757506001613779565b816145e457506000613779565b81600181146145fa576002811461460457614620565b6001915050613779565b60ff84111561461557614615614244565b50506001821b613779565b5060208310610133831016604e8410600b8410161715614643575081810a613779565b61464d8383614585565b806000190482111561466157614661614244565b029392505050565b60006107dc60ff8416836145c8565b600081600019048311821515161561469257614692614244565b500290565b6000826146b457634e487b7160e01b600052601260045260246000fd5b500490565b60006107dc83836145c8565b600060c0820190508382526146de6020830184516142ee565b602083015160018060a01b038082166040850152806040860151166060850152606085015160808501528060808601511660a08501525050939250505056fea264697066735822122018a2fc7fde97fa2f31a3df2a150ede515c7f422670a3c43acd1ed7242bdcd60b64736f6c634300080d0033

Block Transaction Gas Used Reward
view all blocks collator

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
[ 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.