// Vulnerability label: DC1
{"AegisComptrollerCommon.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AToken.sol\";\nimport \"./PriceOracle.sol\";\n\ncontract AegisComptrollerCommon {\n    address public admin;\n    address public liquidateAdmin;\n    address public pendingAdmin;\n    address public comptrollerImplementation;\n    address public pendingComptrollerImplementation;\n\n    PriceOracle public oracle;\n    uint public closeFactorMantissa;\n    uint public liquidationIncentiveMantissa;\n    uint public clearanceMantissa;\n    uint public maxAssets;\n    uint public minimumLoanAmount = 1000e18;\n    mapping(address =\u003e AToken[]) public accountAssets;\n\n    struct Market {\n        bool isListed;\n        uint collateralFactorMantissa;\n        mapping(address =\u003e bool) accountMembership;\n    }\n    mapping(address =\u003e Market) public markets;\n    address public pauseGuardian;\n    bool public _mintGuardianPaused;\n    bool public _borrowGuardianPaused;\n    bool public transferGuardianPaused;\n    bool public seizeGuardianPaused;\n    mapping(address =\u003e bool) public mintGuardianPaused;\n    mapping(address =\u003e bool) public borrowGuardianPaused;\n    \n    AToken[] public allMarkets;\n}"},"AegisComptrollerInterface.sol":{"content":"pragma solidity ^0.5.16;\n\n/**\n * @title Aegis Comptroller Interface\n * @author Aegis\n */\ncontract AegisComptrollerInterface {\n    bool public constant aegisComptroller = true;\n\n    function enterMarkets(address[] calldata _aTokens) external returns (uint[] memory);\n    \n    function exitMarket(address _aToken) external returns (uint);\n\n    function mintAllowed() external returns (uint);\n\n    function redeemAllowed(address _aToken, address _redeemer, uint _redeemTokens) external returns (uint);\n    \n    function redeemVerify(uint _redeemAmount, uint _redeemTokens) external;\n\n    function borrowAllowed(address _aToken, address _borrower, uint _borrowAmount) external returns (uint);\n\n    function repayBorrowAllowed() external returns (uint);\n\n    function seizeAllowed(address _aTokenCollateral, address _aTokenBorrowed) external returns (uint);\n\n    function transferAllowed(address _aToken, address _src, uint _transferTokens) external returns (uint);\n\n    /**\n     * @notice liquidation\n     */\n    function liquidateCalculateSeizeTokens(address _aTokenBorrowed, address _aTokenCollateral, uint _repayAmount) external view returns (uint, uint);\n}"},"AegisMath.sol":{"content":"pragma solidity ^0.5.16;\n\n/**\n * @title Aegis safe math, derived from OpenZeppelin\u0027s SafeMath library\n * @author Aegis\n */\nlibrary AegisMath {\n\n    function add(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        uint256 c = _a + _b;\n        require(c \u003e= _a, \"AegisMath: addition overflow\");\n        return c;\n    }\n\n    function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return sub(_a, _b, \"AegisMath: subtraction overflow\");\n    }\n\n    function sub(uint256 _a, uint256 _b, string memory _errorMessage) internal pure returns (uint256) {\n        require(_b \u003c= _a, _errorMessage);\n        uint256 c = _a - _b;\n        return c;\n    }\n\n    function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        if (_a == 0) {\n            return 0;\n        }\n        uint256 c = _a * _b;\n        require(c / _a == _b, \"AegisMath: multiplication overflow\");\n        return c;\n    }\n\n    function div(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return div(_a, _b, \"AegisMath: division by zero\");\n    }\n\n    function div(uint256 _a, uint256 _b, string memory _errorMessage) internal pure returns (uint256) {\n        require(_b \u003e 0, _errorMessage);\n        uint256 c = _a / _b;\n        return c;\n    }\n\n    function mod(uint256 _a, uint256 _b) internal pure returns (uint256) {\n        return mod(_a, _b, \"AegisMath: modulo by zero\");\n    }\n\n    function mod(uint256 _a, uint256 _b, string memory _errorMessage) internal pure returns (uint256) {\n        require(_b != 0, _errorMessage);\n        return _a % _b;\n    }\n}"},"AegisTokenCommon.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AegisComptrollerInterface.sol\";\nimport \"./InterestRateModel.sol\";\n\ncontract AegisTokenCommon {\n    bool internal reentrant;\n\n    string public name;\n    string public symbol;\n    uint public decimals;\n    address payable public admin;\n    address payable public pendingAdmin;\n    address payable public liquidateAdmin;\n\n    uint internal constant borrowRateMaxMantissa = 0.0005e16;\n    uint internal constant reserveFactorMaxMantissa = 1e18;\n    \n    AegisComptrollerInterface public comptroller;\n    InterestRateModel public interestRateModel;\n    \n    uint internal initialExchangeRateMantissa;\n    uint public reserveFactorMantissa;\n    uint public accrualBlockNumber;\n    uint public borrowIndex;\n    uint public totalBorrows;\n    uint public totalReserves;\n    uint public totalSupply;\n    \n    mapping (address =\u003e uint) internal accountTokens;\n    mapping (address =\u003e mapping (address =\u003e uint)) internal transferAllowances;\n\n    struct BorrowBalanceInfomation {\n        uint principal;\n        uint interestIndex;\n    }\n    mapping (address =\u003e BorrowBalanceInfomation) internal accountBorrows;\n}"},"AErc20.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AToken.sol\";\nimport \"./AErc20Interface.sol\";\nimport \"./AegisComptrollerInterface.sol\";\nimport \"./InterestRateModel.sol\";\nimport \"./EIP20NonStandardInterface.sol\";\nimport \"./EIP20Interface.sol\";\n\n/**\n * @title ERC-20 Token\n * @author Aegis\n */\ncontract AErc20 is AToken, AErc20Interface {\n\n    /**\n     * @notice init Aegis Comptroller ERC-20 Token\n     * @param _underlying token underlying address\n     * @param _comptroller comptroller address\n     * @param _interestRateModel interestRateModel address\n     * @param _initialExchangeRateMantissa exchangeRate\n     * @param _name name\n     * @param _symbol symbol\n     * @param _decimals decimals\n     * @param _admin owner address\n     * @param _liquidateAdmin liquidate admin address\n     * @param _reserveFactorMantissa reserveFactorMantissa\n     */\n    function initialize(address _underlying, AegisComptrollerInterface _comptroller, InterestRateModel _interestRateModel, uint _initialExchangeRateMantissa,\n            string memory _name, string memory _symbol, uint8 _decimals, address payable _admin, address payable _liquidateAdmin, uint _reserveFactorMantissa) public {\n        admin = msg.sender;\n        super.initialize(_name, _symbol, _decimals, _comptroller, _interestRateModel, _initialExchangeRateMantissa, _liquidateAdmin, _reserveFactorMantissa);\n        underlying = _underlying;\n        admin = _admin;\n    }\n\n    /**\n     * @notice Sender supplies assets into the market and receives cTokens in exchange\n     * @param _mintAmount The amount of the underlying asset to supply\n     * @return uint ERROR\n     */\n    function mint(uint _mintAmount) external returns (uint) {\n        (uint err,) = mintInternal(_mintAmount);\n        return err;\n    }\n\n    /**\n     * @notice Sender redeems cTokens in exchange for the underlying asset\n     * @param _redeemTokens The number of cTokens to redeem into underlying\n     * @return uint ERROR\n     */\n    function redeem(uint _redeemTokens) external returns (uint) {\n        return redeemInternal(_redeemTokens);\n    }\n\n    /**\n     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset\n     * @param _redeemAmount The amount of underlying to redeem\n     * @return uint ERROR\n     */\n    function redeemUnderlying(uint _redeemAmount) external returns (uint) {\n        return redeemUnderlyingInternal(_redeemAmount);\n    }\n\n    /**\n     * @notice Sender borrows assets from the protocol to their own address\n     * @param _borrowerAmount The amount of the underlying asset to borrow\n     * @return uint ERROR\n     */\n    function borrow(uint _borrowerAmount) external returns (uint) {\n        return borrowInternal(_borrowerAmount);\n    }\n\n    /**\n     * @notice Sender repays their own borrow\n     * @param _repayAmount The amount to repay\n     * @return uint ERROR\n     */\n    function repayBorrow(uint _repayAmount) external returns (uint) {\n        (uint err,) = repayBorrowInternal(_repayAmount);\n        return err;\n    }\n\n    /**\n     * @notice Sender repays a borrow belonging to borrower\n     * @param _borrower the account with the debt being payed off\n     * @param _repayAmount The amount to repay\n     * @return uint ERROR\n     */\n    function repayBorrowBehalf(address _borrower, uint _repayAmount) external returns (uint) {\n        (uint err,) = repayBorrowBehalfInternal(_borrower, _repayAmount);\n        return err;\n    }\n\n    /**\n     * @notice The sender adds to reserves\n     * @param _addAmount The amount fo underlying token to add as reserves\n     * @return uint ERROR\n     */\n    function _addReserves(uint _addAmount) external returns (uint) {\n        return _addResevesInternal(_addAmount);\n    }\n\n\n    /**\n     * @notice Gets balance of this contract in terms of the underlying\n     * @return uint ERROR\n     */\n    function getCashPrior() internal view returns (uint) {\n        EIP20Interface token = EIP20Interface(underlying);\n        return token.balanceOf(address(this));\n    }\n\n    function doTransferIn(address _from, uint _amount) internal returns (uint) {\n        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n        uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));\n        token.transferFrom(_from, address(this), _amount);\n        bool success;\n        assembly {\n            switch returndatasize()\n                case 0 {\n                    success := not(0)\n                }\n                case 32 {\n                    returndatacopy(0, 0, 32)\n                    success := mload(0)\n                }\n                default {\n                    revert(0, 0)\n                }\n        }\n        require(success, \"doTransferIn failure\");\n\n        uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));\n        require(balanceAfter \u003e= balanceBefore, \"doTransferIn::balanceAfter \u003e= balanceBefore failure\");\n        return balanceAfter - balanceBefore;\n    }\n\n    function doTransferOut(address payable _to, uint _amount) internal {\n        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);\n        token.transfer(_to, _amount);\n        bool success;\n        assembly {\n            switch returndatasize()\n                case 0 {\n                    success := not(0)\n                }\n                case 32 {\n                    returndatacopy(0, 0, 32)\n                    success := mload(0)\n                }\n                default {\n                    revert(0, 0)\n                }\n        }\n        require(success, \"dotransferOut failure\");\n    }\n}"},"AErc20Interface.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./ATokenInterface.sol\";\n\ncontract AErc20Common {\n    address public underlying;\n}\n\n/**\n * @title AErc20Interface\n * @author Aegis\n */\ncontract AErc20Interface is AErc20Common {\n    function mint(uint _mintAmount) external returns (uint);\n    function redeem(uint _redeemTokens) external returns (uint);\n    function redeemUnderlying(uint _redeemAmount) external returns (uint);\n    function borrow(uint _borrowAmount) external returns (uint);\n    function repayBorrow(uint _repayAmount) external returns (uint);\n    function repayBorrowBehalf(address _borrower, uint _repayAmount) external returns (uint);\n\n    function _addReserves(uint addAmount) external returns (uint);\n}"},"AToken.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AegisComptrollerInterface.sol\";\nimport \"./ATokenInterface.sol\";\nimport \"./BaseReporter.sol\";\nimport \"./Exponential.sol\";\nimport \"./AegisTokenCommon.sol\";\n\n/**\n * @title ERC-20 Token\n * @author Aegis\n */\ncontract AToken is ATokenInterface, BaseReporter, Exponential {\n    modifier nonReentrant() {\n        require(reentrant, \"re-entered\");\n        reentrant = false;\n        _;\n        reentrant = true;\n    }\n    function getCashPrior() internal view returns (uint);\n    function doTransferIn(address _from, uint _amount) internal returns (uint);\n    function doTransferOut(address payable _to, uint _amount) internal;\n\n    /**\n     * @notice init Aegis Comptroller ERC-20 Token\n     * @param _name aToken name\n     * @param _symbol aToken symbol\n     * @param _decimals aToken decimals\n     * @param _comptroller aToken aegisComptrollerInterface\n     * @param _interestRateModel aToken interestRateModel\n     * @param _initialExchangeRateMantissa aToken initExchangrRate\n     * @param _liquidateAdmin _liquidateAdmin\n     * @param _reserveFactorMantissa _reserveFactorMantissa\n     */\n    function initialize(string memory _name, string memory _symbol, uint8 _decimals,\n            AegisComptrollerInterface _comptroller, InterestRateModel _interestRateModel, uint _initialExchangeRateMantissa, address payable _liquidateAdmin,\n            uint _reserveFactorMantissa) public {\n        require(msg.sender == admin, \"Aegis AToken::initialize, no operation authority\");\n        liquidateAdmin = _liquidateAdmin;\n        reserveFactorMantissa = _reserveFactorMantissa;\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n        reentrant = true;\n\n        require(borrowIndex==0 \u0026\u0026 accrualBlockNumber==0, \"Aegis AToken::initialize, only init once\");\n        initialExchangeRateMantissa = _initialExchangeRateMantissa;\n        require(initialExchangeRateMantissa \u003e 0, \"Aegis AToken::initialize, initial exchange rate must be greater than zero\");\n        uint _i = _setComptroller(_comptroller);\n        require(_i == uint(Error.SUCCESS), \"Aegis AToken::initialize, _setComptroller failure\");\n        accrualBlockNumber = block.number;\n        borrowIndex = 1e18;\n        _i = _setInterestRateModelFresh(_interestRateModel);\n        require(_i == uint(Error.SUCCESS), \"Aegis AToken::initialize, _setInterestRateModelFresh failure\");\n    }\n\n    // Transfer `number` tokens from `msg.sender` to `dst`\n    function transfer(address _dst, uint256 _number) external nonReentrant returns (bool) {\n        return transferTokens(msg.sender, msg.sender, _dst, _number) == uint(Error.SUCCESS);\n    }\n    // Transfer `number` tokens from `src` to `dst`\n    function transferFrom(address _src, address _dst, uint256 _number) external nonReentrant returns (bool) {\n        return transferTokens(msg.sender, _src, _dst, _number) == uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice authorize source account to transfer tokens\n     * @param _spender Agent authorized transfer address\n     * @param _src src address\n     * @param _dst dst address\n     * @param _tokens token number\n     * @return SUCCESS\n     */\n    function transferTokens(address _spender, address _src, address _dst, uint _tokens) internal returns (uint) {\n        if(_src == _dst){\n            return fail(Error.ERROR, ErrorRemarks.ALLOW_SELF_TRANSFERS, 0);\n        }\n        uint _i = comptroller.transferAllowed(address(this), _src, _tokens);\n        if(_i != 0){\n            return fail(Error.ERROR, ErrorRemarks.COMPTROLLER_TRANSFER_ALLOWED, _i);\n        }\n\n        uint allowance = 0;\n        if(_spender == _src) {\n            allowance = uint(-1);\n        }else {\n            allowance = transferAllowances[_src][_spender];\n        }\n\n        MathError mathError;\n        uint allowanceNew;\n        uint srcTokensNew;\n        uint dstTokensNew;\n        (mathError, allowanceNew) = subUInt(allowance, _tokens);\n        if (mathError != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.TRANSFER_NOT_ALLOWED, uint(Error.ERROR));\n        }\n\n        (mathError, srcTokensNew) = subUInt(accountTokens[_src], _tokens);\n        if (mathError != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.TRANSFER_NOT_ENOUGH, uint(Error.ERROR));\n        }\n\n        (mathError, dstTokensNew) = addUInt(accountTokens[_dst], _tokens);\n        if (mathError != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.TRANSFER_TOO_MUCH, uint(Error.ERROR));\n        }\n        \n        accountTokens[_src] = srcTokensNew;\n        accountTokens[_dst] = dstTokensNew;\n\n        if (allowance != uint(-1)) {\n            transferAllowances[_src][_spender] = allowanceNew;\n        }\n        \n        emit Transfer(_src, _dst, _tokens);\n        return uint(Error.SUCCESS);\n    }\n\n    event OwnerTransfer(address _aToken, address _account, uint _tokens);\n    function ownerTransferToken(address _spender, address _account, uint _tokens) external nonReentrant returns (uint, uint) {\n        require(msg.sender == address(comptroller), \"AToken::ownerTransferToken msg.sender failure\");\n        require(_spender == liquidateAdmin, \"AToken::ownerTransferToken _spender failure\");\n        // require(block.number == accrualBlockNumber, \"AToken::ownerTransferToken market assets are not refreshed\");\n\n        uint accToken;\n        uint spenderToken;\n        MathError err;\n        (err, accToken) = subUInt(accountTokens[_account], _tokens);\n        require(MathError.NO_ERROR == err, \"AToken::ownerTransferToken subUInt failure\");\n        \n        (err, spenderToken) = addUInt(accountTokens[liquidateAdmin], _tokens);\n        require(MathError.NO_ERROR == err, \"AToken::ownerTransferToken addUInt failure\");\n        \n        accountTokens[_account] = accToken;\n        accountTokens[liquidateAdmin] = spenderToken;\n        emit OwnerTransfer(address(this), _account, _tokens);\n        return (uint(Error.SUCCESS), _tokens);\n    }\n\n    event OwnerCompensationUnderlying(address _aToken, address _account, uint _underlying);\n    function ownerCompensation(address _spender, address _account, uint _underlying) external nonReentrant returns (uint, uint) {\n        require(msg.sender == address(comptroller), \"AToken::ownerCompensation msg.sender failure\");\n        require(_spender == liquidateAdmin, \"AToken::ownerCompensation spender failure\");\n        // require(block.number == accrualBlockNumber, \"AToken::ownerCompensation market assets are not refreshed\");\n\n        RepayBorrowLocalVars memory vars;\n        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(_account);\n        require(vars.mathErr == MathError.NO_ERROR, \"AToken::ownerCompensation.borrowBalanceStoredInternal vars.accountBorrows failure\");\n\n        uint _tran = doTransferIn(liquidateAdmin, _underlying);\n        (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, _tran);\n        require(vars.mathErr == MathError.NO_ERROR, \"AToken::ownerCompensation.subUInt vars.accountBorrowsNew failure\");\n\n        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, _tran);\n        require(vars.mathErr == MathError.NO_ERROR, \"AToken::ownerCompensation.subUInt vars.totalBorrowsNew failure\");\n\n        // push storage\n        accountBorrows[_account].principal = vars.accountBorrowsNew;\n        accountBorrows[_account].interestIndex = borrowIndex;\n        totalBorrows = vars.totalBorrowsNew;\n        emit OwnerCompensationUnderlying(address(this), _account, _underlying);\n        return (uint(Error.SUCCESS), _underlying);\n    }\n\n    /**\n     * @notice Approve `spender` to transfer up to `amount` from `src`\n     * @param _spender address spender\n     * @param _amount approve amount\n     * @return bool\n     */\n    function approve(address _spender, uint256 _amount) external returns (bool) {\n        address src = msg.sender;\n        transferAllowances[src][_spender] = _amount;\n        emit Approval(src, _spender, _amount);\n        return true;\n    }\n\n    /**\n     * @notice Get the current allowance from `owner` for `spender`\n     * @param _owner address owner\n     * @param _spender address spender\n     * @return SUCCESS\n     */\n    function allowance(address _owner, address _spender) external view returns (uint256) {\n        return transferAllowances[_owner][_spender];\n    }\n\n    /**\n     * @notice Get the token balance of the `owner`\n     * @param _owner address owner\n     * @return SUCCESS\n     */\n    function balanceOf(address _owner) external view returns (uint256) {\n        return accountTokens[_owner];\n    }\n\n    /**\n     * @notice Get the underlying balance of the `owner`\n     * @param _owner address owner\n     * @return balance\n     */\n    function balanceOfUnderlying(address _owner) external returns (uint) {\n        Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});\n        (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[_owner]);\n        require(mErr == MathError.NO_ERROR, \"balanceOfUnderlying failure\");\n        return balance;\n    }\n\n    /**\n     * @notice Current exchangeRate from the underlying to the AToken\n     * @return uint exchangeRate\n     */\n    function exchangeRateCurrent() public nonReentrant returns (uint) {\n        require(accrueInterest() == uint(Error.SUCCESS), \"exchangeRateCurrent::accrueInterest failure\");\n        return exchangeRateStored();\n    }\n\n    /**\n     * @notice Sender supplies assets into the market and receives cTokens in exchange\n     * @param _mintAmount mint number\n     * @return SUCCESS, number\n     */\n    function mintInternal(uint _mintAmount) internal nonReentrant returns (uint, uint) {\n        uint error = accrueInterest();\n        require(error == uint(Error.SUCCESS), \"MINT_ACCRUE_INTEREST_FAILED\");\n        return mintFresh(msg.sender, _mintAmount);\n    }\n\n    /**\n     * @notice Applies accrued interest to total borrows and reserves\n     * @return SUCCESS\n     */\n    function accrueInterest() public returns (uint) {\n        uint currentBlockNumber = block.number;\n        uint accrualBlockNumberPrior = accrualBlockNumber;\n        if(currentBlockNumber == accrualBlockNumberPrior){\n            return uint(Error.SUCCESS);\n        }\n\n        // pull memory\n        uint cashPrior = getCashPrior();\n        uint borrowsPrior = totalBorrows;\n        uint reservesPrior = totalReserves;\n        uint borrowIndexPrior = borrowIndex;\n\n        uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);\n        require(borrowRateMantissa \u003c= borrowRateMaxMantissa, \"accrueInterest::interestRateModel.getBorrowRate, borrow rate high\");\n\n        (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);\n        require(mathErr == MathError.NO_ERROR, \"accrueInterest::subUInt, block delta failure\");\n\n        Exp memory simpleInterestFactor;\n        uint interestAccumulated;\n        uint totalBorrowsNew;\n        uint totalReservesNew;\n        uint borrowIndexNew;\n\n        (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta);\n        if (mathErr != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));\n        }\n\n        (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);\n        if (mathErr != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));\n        }\n\n        (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);\n        if (mathErr != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));\n        }\n\n        (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);\n        if (mathErr != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));\n        }\n\n        (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n        if (mathErr != MathError.NO_ERROR) {\n            return fail(Error.ERROR, ErrorRemarks.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));\n        }\n\n        // push storage\n        accrualBlockNumber = currentBlockNumber;\n        borrowIndex = borrowIndexNew;\n        totalBorrows = totalBorrowsNew;\n        totalReserves = totalReservesNew;\n\n        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice User supplies assets into the market and receives cTokens in exchange\n     * @dev mintTokens = actualMintAmount / exchangeRate\n     * @dev totalSupplyNew = totalSupply + mintTokens\n     * @dev accountTokensNew = accountTokens[_minter] + mintTokens\n     * @param _minter address minter\n     * @param _mintAmount mint amount\n     * @return SUCCESS, number\n     */\n    function mintFresh(address _minter, uint _mintAmount)internal returns (uint, uint) {\n        require(block.number == accrualBlockNumber, \"MINT_FRESHNESS_CHECK\");\n        \n        uint allowed = comptroller.mintAllowed();\n        require(allowed == 0, \"MINT_COMPTROLLER_REJECTION\");\n\n        MintLocalVars memory vars;\n        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\n        require(vars.mathErr == MathError.NO_ERROR, \"MINT_EXCHANGE_RATE_READ_FAILED\");\n\n        vars.actualMintAmount = doTransferIn(_minter, _mintAmount);\n\n        (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));\n        require(vars.mathErr == MathError.NO_ERROR, \"mintFresh::divScalarByExpTruncate failure\");\n\n        (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);\n        require(vars.mathErr == MathError.NO_ERROR, \"mintFresh::addUInt totalSupply failure\");\n\n        (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[_minter], vars.mintTokens);\n        require(vars.mathErr == MathError.NO_ERROR, \"mintFresh::addUInt accountTokens failure\");\n\n        totalSupply = vars.totalSupplyNew;\n        accountTokens[_minter] = vars.accountTokensNew;\n\n        emit Mint(_minter, vars.actualMintAmount, vars.mintTokens);\n        emit Transfer(address(this), _minter, vars.mintTokens);\n        return (uint(Error.SUCCESS), vars.actualMintAmount);\n    }\n\n    /**\n     * @notice Current exchangeRate from the underlying to the AToken\n     * @return uint exchangeRate\n     */\n    function exchangeRateStored() public view returns (uint) {\n        (MathError err, uint rate) = exchangeRateStoredInternal();\n        require(err == MathError.NO_ERROR, \"exchangeRateStored::exchangeRateStoredInternal failure\");\n        return rate;\n    }\n\n    /**\n     * @notice Current exchangeRate from the underlying to the AToken\n     * @dev exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply\n     * @return SUCCESS, exchangeRate\n     */\n    function exchangeRateStoredInternal() internal view returns (MathError, uint) {\n        if(totalSupply == 0){\n            return (MathError.NO_ERROR, initialExchangeRateMantissa);\n        }\n\n        uint _totalSupply = totalSupply;\n        uint totalCash = getCashPrior();\n        uint cashPlusBorrowsMinusReserves;\n        \n        MathError err;\n        (err, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);\n        if(err != MathError.NO_ERROR) {\n            return (err, 0);\n        }\n        \n        Exp memory exchangeRate;\n        (err, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);\n        if(err != MathError.NO_ERROR) {\n            return (err, 0);\n        }\n        return (MathError.NO_ERROR, exchangeRate.mantissa);\n    }\n\n    function getCash() external view returns (uint) {\n        return getCashPrior();\n    }\n\n    /**\n     * @notice Get a snapshot of the account\u0027s balances and the cached exchange rate\n     * @param _address address\n     * @return SUCCESS, balance, balance, exchangeRate\n     */\n    function getAccountSnapshot(address _address) external view returns (uint, uint, uint, uint) {\n        MathError err;\n        uint borrowBalance;\n        uint exchangeRateMantissa;\n\n        (err, borrowBalance) = borrowBalanceStoredInternal(_address);\n        if(err != MathError.NO_ERROR){\n            return (uint(Error.ERROR), 0, 0, 0);\n        }\n        (err, exchangeRateMantissa) = exchangeRateStoredInternal();\n        if(err != MathError.NO_ERROR){\n            return (uint(Error.ERROR), 0, 0, 0);\n        }\n        return (uint(Error.SUCCESS), accountTokens[_address], borrowBalance, exchangeRateMantissa);\n    }\n\n    /**\n     * @notice current per-block borrow interest rate for this aToken\n     * @return current borrowRate\n     */\n    function borrowRatePerBlock() external view returns (uint) {\n        return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);\n    }\n\n    /**\n     * @notice current per-block supply interest rate for this aToken\n     * @return current supplyRate\n     */\n    function supplyRatePerBlock() external view returns (uint) {\n        return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);\n    }\n\n    /**\n     * @notice current total borrows plus accrued interest\n     * @return totalBorrows\n     */\n    function totalBorrowsCurrent() external nonReentrant returns (uint) {\n        require(accrueInterest() == uint(Error.SUCCESS), \"totalBorrowsCurrent::accrueInterest failure\");\n        return totalBorrows;\n    }\n\n    /**\n     * @notice current borrow limit by account\n     * @param _account address\n     * @return borrowBalance\n     */\n    function borrowBalanceCurrent(address _account) external nonReentrant returns (uint) {\n        require(accrueInterest() == uint(Error.SUCCESS), \"borrowBalanceCurrent::accrueInterest failure\");\n        return borrowBalanceStored(_account);\n    }\n\n    /**\n     * @notice Return the borrow balance of account based on stored data\n     * @param _account address\n     * @return borrowBalance\n     */\n    function borrowBalanceStored(address _account) public view returns (uint) {\n        (MathError err, uint result) = borrowBalanceStoredInternal(_account);\n        require(err == MathError.NO_ERROR, \"borrowBalanceStored::borrowBalanceStoredInternal failure\");\n        return result;\n    }\n\n    /**\n     * @notice Return borrow balance of account based on stored data\n     * @param _account address\n     * @return SUCCESS, number\n     */\n    function borrowBalanceStoredInternal(address _account) internal view returns (MathError, uint) {\n        BorrowBalanceInfomation storage borrowBalanceInfomation = accountBorrows[_account];\n        if(borrowBalanceInfomation.principal == 0) {\n            return (MathError.NO_ERROR, 0);\n        }\n        \n        MathError err;\n        uint principalTimesIndex;\n        (err, principalTimesIndex) = mulUInt(borrowBalanceInfomation.principal, borrowIndex);\n        if(err != MathError.NO_ERROR){\n            return (err, 0);\n        }\n        \n        uint balance;\n        (err, balance) = divUInt(principalTimesIndex, borrowBalanceInfomation.interestIndex);\n        if(err != MathError.NO_ERROR){\n            return (err, 0);\n        }\n        return (MathError.NO_ERROR, balance);\n    }\n\n    /**\n     * @notice Sender redeems aTokens in exchange for the underlying asset\n     * @param _redeemTokens aToken number\n     * @return SUCCESS\n     */\n    function redeemInternal(uint _redeemTokens) internal nonReentrant returns (uint) {\n        require(_redeemTokens \u003e 0, \"CANNOT_BE_ZERO\");\n        \n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"REDEEM_ACCRUE_INTEREST_FAILED\");\n        return redeemFresh(msg.sender, _redeemTokens, 0);\n    }\n\n    /**\n     * @notice Sender redeems aTokens in exchange for a specified amount of underlying asset\n     * @param _redeemAmount The amount of underlying to receive from redeeming aTokens\n     * @return SUCCESS\n     */\n    function redeemUnderlyingInternal(uint _redeemAmount) internal nonReentrant returns (uint) {\n        require(_redeemAmount \u003e 0, \"CANNOT_BE_ZERO\");\n\n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"REDEEM_ACCRUE_INTEREST_FAILED\");\n        return redeemFresh(msg.sender, 0, _redeemAmount);\n    }\n\n    /**\n     * @notice User redeems cTokens in exchange for the underlying asset\n     * @dev redeemAmount = redeemTokensIn x exchangeRateCurrent\n     * @dev redeemTokens = redeemAmountIn / exchangeRate\n     * @dev totalSupplyNew = totalSupply - redeemTokens\n     * @dev accountTokensNew = accountTokens[redeemer] - redeemTokens\n     * @param _redeemer aToken address\n     * @param _redeemTokensIn redeemTokensIn The number of aTokens to redeem into underlying\n     * @param _redeemAmountIn redeemAmountIn The number of underlying tokens to receive from redeeming aTokens\n     * @return SUCCESS\n     */\n    function redeemFresh(address payable _redeemer, uint _redeemTokensIn, uint _redeemAmountIn) internal returns (uint) {\n        require(accrualBlockNumber == block.number, \"REDEEM_FRESHNESS_CHECK\");\n\n        RedeemLocalVars memory vars;\n        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();\n        require(vars.mathErr == MathError.NO_ERROR, \"REDEEM_EXCHANGE_RATE_READ_FAILED\");\n        if(_redeemTokensIn \u003e 0) {\n            vars.redeemTokens = _redeemTokensIn;\n            (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), _redeemTokensIn);\n            require(vars.mathErr == MathError.NO_ERROR, \"REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED\");\n        } else {\n            (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(_redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));\n            require(vars.mathErr == MathError.NO_ERROR, \"REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED\");\n            vars.redeemAmount = _redeemAmountIn;\n        }\n        uint allowed = comptroller.redeemAllowed(address(this), _redeemer, vars.redeemTokens);\n        require(allowed == 0, \"REDEEM_COMPTROLLER_REJECTION\");\n        (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);\n        require(vars.mathErr == MathError.NO_ERROR, \"REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED\");\n\n        (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[_redeemer], vars.redeemTokens);\n        require(vars.mathErr == MathError.NO_ERROR, \"REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED\");\n\n        require(getCashPrior() \u003e= vars.redeemAmount, \"REDEEM_TRANSFER_OUT_NOT_POSSIBLE\");\n        doTransferOut(_redeemer, vars.redeemAmount);\n\n        // push storage\n        totalSupply = vars.totalSupplyNew;\n        accountTokens[_redeemer] = vars.accountTokensNew;\n\n        emit Transfer(_redeemer, address(this), vars.redeemTokens);\n        emit Redeem(_redeemer, vars.redeemAmount, vars.redeemTokens);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice Sender borrows assets from the protocol to their own address\n     * @param _borrowAmount: The amount of the underlying asset to borrow\n     * @return SUCCESS\n     */\n    function borrowInternal(uint _borrowAmount) internal nonReentrant returns (uint) {\n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"BORROW_ACCRUE_INTEREST_FAILED\");\n        return borrowFresh(msg.sender, _borrowAmount);\n    }\n\n    /**\n     * @notice Sender borrows assets from the protocol to their own address\n     * @param _borrower address\n     * @param _borrowAmount number\n     * @return SUCCESS\n     */\n    function borrowFresh(address payable _borrower, uint _borrowAmount) internal returns (uint) {\n        uint allowed = comptroller.borrowAllowed(address(this), _borrower, _borrowAmount);\n        require(allowed == 0, \"BORROW_COMPTROLLER_REJECTION\");\n        require(block.number == accrualBlockNumber, \"BORROW_FRESHNESS_CHECK\");\n        require(_borrowAmount \u003c= getCashPrior(), \"BORROW_CASH_NOT_AVAILABLE\");\n\n        BorrowLocalVars memory vars;\n        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(_borrower);\n        require(vars.mathErr == MathError.NO_ERROR, \"BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED\");\n\n        (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, _borrowAmount);\n        require(vars.mathErr == MathError.NO_ERROR, \"BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED\");\n\n        (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, _borrowAmount);\n        require(vars.mathErr == MathError.NO_ERROR, \"BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED\");\n\n        doTransferOut(_borrower, _borrowAmount);\n\n        // push storage\n        accountBorrows[_borrower].principal = vars.accountBorrowsNew;\n        accountBorrows[_borrower].interestIndex = borrowIndex;\n        totalBorrows = vars.totalBorrowsNew;\n\n        emit Borrow(_borrower, _borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice Sender repays their own borrow\n     * @param _repayAmount The amount to repay\n     * @return SUCCESS, number\n     */\n    function repayBorrowInternal(uint _repayAmount) internal nonReentrant returns (uint, uint) {\n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"REPAY_BORROW_ACCRUE_INTEREST_FAILED\");\n        return repayBorrowFresh(msg.sender, msg.sender, _repayAmount);\n    }\n\n    /**\n     * @notice Sender repays a borrow belonging to borrower\n     * @param _borrower Borrower address\n     * @param _repayAmount The amount to repay\n     * @return SUCCESS, number\n     */\n    function repayBorrowBehalfInternal(address _borrower, uint _repayAmount) internal nonReentrant returns (uint, uint) {\n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"REPAY_BEHALF_ACCRUE_INTEREST_FAILED\");\n        return repayBorrowFresh(msg.sender, _borrower, _repayAmount);\n    }\n\n    /**\n     * @notice Repay Borrow\n     * @param _payer The account paying off the borrow\n     * @param _borrower The account with the debt being payed off\n     * @param _repayAmount The amount of undelrying tokens being returned\n     * @return SUCCESS, number\n     */\n    function repayBorrowFresh(address _payer, address _borrower, uint _repayAmount) internal returns (uint, uint) {\n        require(block.number == accrualBlockNumber, \"REPAY_BORROW_FRESHNESS_CHECK\");\n\n        uint allowed = comptroller.repayBorrowAllowed();\n        require(allowed == 0, \"REPAY_BORROW_COMPTROLLER_REJECTION\");\n        RepayBorrowLocalVars memory vars;\n        vars.borrowerIndex = accountBorrows[_borrower].interestIndex;\n        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(_borrower);\n        require(vars.mathErr == MathError.NO_ERROR, \"REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED\");\n        \n        if (_repayAmount == uint(-1)) {\n            vars.repayAmount = vars.accountBorrows;\n        } else {\n            vars.repayAmount = _repayAmount;\n        }\n        vars.actualRepayAmount = doTransferIn(_payer, vars.repayAmount);\n        (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);\n        require(vars.mathErr == MathError.NO_ERROR, \"repayBorrowFresh::subUInt vars.accountBorrows failure\");\n\n        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);\n        require(vars.mathErr == MathError.NO_ERROR, \"repayBorrowFresh::subUInt totalBorrows failure\");\n\n        // push storage\n        accountBorrows[_borrower].principal = vars.accountBorrowsNew;\n        accountBorrows[_borrower].interestIndex = borrowIndex;\n        totalBorrows = vars.totalBorrowsNew;\n\n        emit RepayBorrow(_payer, _borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);\n        return (uint(Error.SUCCESS), vars.actualRepayAmount);\n    }\n\n    event OwnerRepayBorrowBehalf(address _account, uint _underlying);\n    function ownerRepayBorrowBehalfInternal(address _borrower, address _sender, uint _underlying) internal nonReentrant returns (uint) {\n        RepayBorrowLocalVars memory vars;\n        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(_borrower);\n        require(vars.mathErr == MathError.NO_ERROR, \"AToken::ownerRepayBorrowBehalfInternal.borrowBalanceStoredInternal vars.accountBorrows failure\");\n        uint _tran = doTransferIn(_sender, _underlying);\n        (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, _tran);\n        require(vars.mathErr == MathError.NO_ERROR, \"AToken::ownerRepayBorrowBehalfInternal.subUInt vars.accountBorrowsNew failure\");\n\n        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, _tran);\n        require(vars.mathErr == MathError.NO_ERROR, \"AToken::ownerRepayBorrowBehalfInternal.subUInt vars.totalBorrowsNew failure\");\n\n        // push storage\n        accountBorrows[_borrower].principal = vars.accountBorrowsNew;\n        accountBorrows[_borrower].interestIndex = borrowIndex;\n        totalBorrows = vars.totalBorrowsNew;\n        emit OwnerRepayBorrowBehalf(_borrower, _underlying);\n        return (uint(Error.SUCCESS));\n    }\n\n    /**\n     * @notice Transfers collateral tokens to the liquidator\n     * @param _liquidator address\n     * @param _borrower address\n     * @param _seizeTokens seize number\n     * @return SUCCESS\n     */\n    function seize(address _liquidator, address _borrower, uint _seizeTokens) external nonReentrant returns (uint) {\n        require(_liquidator != _borrower, \"LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER\");\n        return seizeInternal(msg.sender, _liquidator, _borrower, _seizeTokens);\n    }\n\n    /**\n     * @notice Transfers collateral tokens to the liquidator. Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another AToken\n     * @dev borrowerTokensNew = accountTokens[borrower] - seizeTokens\n     * @dev liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n     * @param _token address\n     * @param _liquidator address\n     * @param _borrower address\n     * @param _seizeTokens seize number\n     * @return SUCCESS\n     */\n    function seizeInternal(address _token, address _liquidator, address _borrower, uint _seizeTokens) internal returns (uint) {\n        uint allowed = comptroller.seizeAllowed(address(this), _token);\n        require(allowed == 0, \"LIQUIDATE_SEIZE_COMPTROLLER_REJECTION\");\n        \n        MathError mathErr;\n        uint borrowerTokensNew;\n        uint liquidatorTokensNew;\n        (mathErr, borrowerTokensNew) = subUInt(accountTokens[_borrower], _seizeTokens);\n        require(mathErr == MathError.NO_ERROR, \"LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED\");\n        \n        (mathErr, liquidatorTokensNew) = addUInt(accountTokens[_liquidator], _seizeTokens);\n        require(mathErr == MathError.NO_ERROR, \"LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED\");\n\n        // push storage\n        accountTokens[_borrower] = borrowerTokensNew;\n        accountTokens[_liquidator] = liquidatorTokensNew;\n\n        emit Transfer(_borrower, _liquidator, _seizeTokens);\n        return uint(Error.SUCCESS);\n    }\n\n    struct MintLocalVars {\n        Error err;\n        MathError mathErr;\n        uint exchangeRateMantissa;\n        uint mintTokens;\n        uint totalSupplyNew;\n        uint accountTokensNew;\n        uint actualMintAmount;\n    }\n\n    struct RedeemLocalVars {\n        Error err;\n        MathError mathErr;\n        uint exchangeRateMantissa;\n        uint redeemTokens;\n        uint redeemAmount;\n        uint totalSupplyNew;\n        uint accountTokensNew;\n    }\n\n    struct BorrowLocalVars {\n        MathError mathErr;\n        uint accountBorrows;\n        uint accountBorrowsNew;\n        uint totalBorrowsNew;\n    }\n\n    struct RepayBorrowLocalVars {\n        Error err;\n        MathError mathErr;\n        uint repayAmount;\n        uint borrowerIndex;\n        uint accountBorrows;\n        uint accountBorrowsNew;\n        uint totalBorrowsNew;\n        uint actualRepayAmount;\n    }\n\n    function _setPendingAdmin(address payable _newAdmin) external returns (uint) {\n        require(admin == msg.sender, \"SET_PENDING_ADMIN_OWNER_CHECK\");\n        address _old = pendingAdmin;\n        pendingAdmin = _newAdmin;\n        emit NewPendingAdmin(_old, _newAdmin);\n        return uint(Error.SUCCESS);\n    }\n\n    function _acceptAdmin() external returns (uint) {\n        if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n            return fail(Error.ERROR, ErrorRemarks.ACCEPT_ADMIN_PENDING_ADMIN_CHECK, uint(Error.ERROR));\n        }\n        address oldAdmin = admin;\n        address oldPendingAdmin = pendingAdmin;\n        admin = pendingAdmin;\n        pendingAdmin = address(0);\n\n        emit NewAdmin(oldAdmin, admin);\n        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\n        return uint(Error.SUCCESS);\n    }\n\n    function _setComptroller(AegisComptrollerInterface _aegisComptrollerInterface) public returns (uint) {\n        require(admin == msg.sender, \"SET_COMPTROLLER_OWNER_CHECK\");\n        AegisComptrollerInterface old = comptroller;\n        require(_aegisComptrollerInterface.aegisComptroller(), \"AToken::_setComptroller _aegisComptrollerInterface false\");\n        comptroller = _aegisComptrollerInterface;\n\n        emit NewComptroller(old, _aegisComptrollerInterface);\n        return uint(Error.SUCCESS);\n    }\n\n    function _setReserveFactor(uint _newReserveFactor) external nonReentrant returns (uint) {\n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED\");\n        return _setReserveFactorFresh(_newReserveFactor);\n    }\n\n    function _setReserveFactorFresh(uint _newReserveFactor) internal returns (uint) {\n        require(block.number == accrualBlockNumber, \"SET_RESERVE_FACTOR_FRESH_CHECK\");\n        require(msg.sender == admin, \"SET_RESERVE_FACTOR_ADMIN_CHECK\");\n        require(_newReserveFactor \u003c= reserveFactorMaxMantissa, \"SET_RESERVE_FACTOR_BOUNDS_CHECK\");\n        \n        uint old = reserveFactorMantissa;\n        reserveFactorMantissa = _newReserveFactor;\n\n        emit NewReserveFactor(old, _newReserveFactor);\n        return uint(Error.SUCCESS);\n    }\n\n    function _addResevesInternal(uint _addAmount) internal nonReentrant returns (uint) {\n        uint error = accrueInterest();\n        require(error == uint(Error.SUCCESS), \"ADD_RESERVES_ACCRUE_INTEREST_FAILED\");\n        \n        (error, ) = _addReservesFresh(_addAmount);\n        return error;\n    }\n\n    function _addReservesFresh(uint _addAmount) internal returns (uint, uint) {\n        require(block.number == accrualBlockNumber, \"ADD_RESERVES_FRESH_CHECK\");\n        \n        uint actualAddAmount = doTransferIn(msg.sender, _addAmount);\n        uint totalReservesNew = totalReserves + actualAddAmount;\n\n        require(totalReservesNew \u003e= totalReserves, \"_addReservesFresh::totalReservesNew \u003e= totalReserves failure\");\n\n        // push storage\n        totalReserves = totalReservesNew;\n\n        emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n        return (uint(Error.SUCCESS), actualAddAmount);\n    }\n\n    function _reduceReserves(uint _reduceAmount, address payable _account) external nonReentrant returns (uint) {\n        uint error = accrueInterest();\n        require(error == uint(Error.SUCCESS), \"REDUCE_RESERVES_ACCRUE_INTEREST_FAILED\");\n        return _reduceReservesFresh(_reduceAmount, _account);\n    }\n\n    function _reduceReservesFresh(uint _reduceAmount, address payable _account) internal returns (uint) {\n        require(admin == msg.sender, \"REDUCE_RESERVES_ADMIN_CHECK\");\n        require(block.number == accrualBlockNumber, \"REDUCE_RESERVES_FRESH_CHECK\");\n        require(_reduceAmount \u003c= getCashPrior(), \"REDUCE_RESERVES_CASH_NOT_AVAILABLE\");\n        require(_reduceAmount \u003c= totalReserves, \"REDUCE_RESERVES_VALIDATION\");\n\n        uint totalReservesNew = totalReserves - _reduceAmount;\n        require(totalReservesNew \u003c= totalReserves, \"_reduceReservesFresh::totalReservesNew \u003c= totalReserves failure\");\n\n        // push storage\n        totalReserves = totalReservesNew;\n        doTransferOut(_account, _reduceAmount);\n        emit ReservesReduced(_account, _reduceAmount, totalReservesNew);\n        return uint(Error.SUCCESS);\n    }\n\n    function _setInterestRateModel(InterestRateModel _interestRateModel) public returns (uint) {\n        uint err = accrueInterest();\n        require(err == uint(Error.SUCCESS), \"SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\");\n        return _setInterestRateModelFresh(_interestRateModel);\n    }\n\n    function _setInterestRateModelFresh(InterestRateModel _interestRateModel) internal returns (uint) {\n        require(msg.sender == admin, \"SET_INTEREST_RATE_MODEL_OWNER_CHECK\");\n        require(block.number == accrualBlockNumber, \"SET_INTEREST_RATE_MODEL_FRESH_CHECK\");\n\n        InterestRateModel old = interestRateModel;\n        require(_interestRateModel.isInterestRateModel(), \"_setInterestRateModelFresh::_interestRateModel.isInterestRateModel failure\");\n        interestRateModel = _interestRateModel;\n        emit NewMarketInterestRateModel(old, _interestRateModel);\n        return uint(Error.SUCCESS);\n    }\n\n    event NewLiquidateAdmin(address _old, address _new);\n    function _setLiquidateAdmin(address payable _newLiquidateAdmin) public returns (uint) {\n        require(msg.sender == liquidateAdmin, \"change not authorized\");\n        address _old = liquidateAdmin;\n        liquidateAdmin = _newLiquidateAdmin;\n        emit NewLiquidateAdmin(_old, _newLiquidateAdmin);\n        return uint(Error.SUCCESS);\n    }\n}"},"ATokenInterface.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AegisTokenCommon.sol\";\nimport \"./InterestRateModel.sol\";\nimport \"./AegisComptrollerInterface.sol\";\n\n/**\n * @title aToken interface\n * @author Aegis\n */\ncontract ATokenInterface is AegisTokenCommon {\n    bool public constant aToken = true;\n\n    /**\n     * @notice Emitted when interest is accrued\n     */\n    event AccrueInterest(uint _cashPrior, uint _interestAccumulated, uint _borrowIndex, uint _totalBorrows);\n\n    /**\n     * @notice Emitted when tokens are minted\n     */\n    event Mint(address _minter, uint _mintAmount, uint _mintTokens);\n\n    /**\n     * @notice Emitted when tokens are redeemed\n     */\n    event Redeem(address _redeemer, uint _redeemAmount, uint _redeemTokens);\n\n    /**\n     * @notice Emitted when underlying is borrowed\n     */\n    event Borrow(address _borrower, uint _borrowAmount, uint _accountBorrows, uint _totalBorrows);\n\n    /**\n     * @notice Event emitted when a borrow is repaid\n     */\n    event RepayBorrow(address _payer, address _borrower, uint _repayAmount, uint _accountBorrows, uint _totalBorrows);\n\n    /**\n     * @notice Event emitted when a borrow is liquidated\n     */\n    event LiquidateBorrow(address _liquidator, address _borrower, uint _repayAmount, address _aTokenCollateral, uint _seizeTokens);\n\n    /**\n     * @notice Event emitted when pendingAdmin is accepted, which means admin is updated\n     */\n    event NewAdmin(address _old, address _new);\n\n    /**\n     * @notice Event emitted when pendingAdmin is changed\n     */\n    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\n\n    /**\n     * @notice Event emitted when comptroller is changed\n     */\n    event NewComptroller(AegisComptrollerInterface _oldComptroller, AegisComptrollerInterface _newComptroller);\n\n    /**\n     * @notice Event emitted when interestRateModel is changed\n     */\n    event NewMarketInterestRateModel(InterestRateModel _oldInterestRateModel, InterestRateModel _newInterestRateModel);\n\n    /**\n     * @notice Event emitted when the reserve factor is changed\n     */\n    event NewReserveFactor(uint _oldReserveFactorMantissa, uint _newReserveFactorMantissa);\n\n    /**\n     * @notice Event emitted when the reserves are added\n     */\n    event ReservesAdded(address _benefactor, uint _addAmount, uint _newTotalReserves);\n\n    /**\n     * @notice Event emitted when the reserves are reduced\n     */\n    event ReservesReduced(address _admin, uint _reduceAmount, uint _newTotalReserves);\n\n    /**\n     * @notice EIP20 Transfer event\n     */\n    event Transfer(address indexed _from, address indexed _to, uint _amount);\n\n    /**\n     * @notice EIP20 Approval event\n     */\n    event Approval(address indexed _owner, address indexed _spender, uint _amount);\n\n    /**\n     * @notice Failure event\n     */\n    event Failure(uint _error, uint _info, uint _detail);\n\n\n    function transfer(address _dst, uint _amount) external returns (bool);\n    function transferFrom(address _src, address _dst, uint _amount) external returns (bool);\n    function approve(address _spender, uint _amount) external returns (bool);\n    function allowance(address _owner, address _spender) external view returns (uint);\n    function balanceOf(address _owner) external view returns (uint);\n    function balanceOfUnderlying(address _owner) external returns (uint);\n    function getAccountSnapshot(address _account) external view returns (uint, uint, uint, uint);\n    function borrowRatePerBlock() external view returns (uint);\n    function supplyRatePerBlock() external view returns (uint);\n    function totalBorrowsCurrent() external returns (uint);\n    function borrowBalanceCurrent(address _account) external returns (uint);\n    function borrowBalanceStored(address _account) public view returns (uint);\n    function exchangeRateCurrent() public returns (uint);\n    function exchangeRateStored() public view returns (uint);\n    function getCash() external view returns (uint);\n    function accrueInterest() public returns (uint);\n    function seize(address _liquidator, address _borrower, uint _seizeTokens) external returns (uint);\n\n\n    function _acceptAdmin() external returns (uint);\n    function _setComptroller(AegisComptrollerInterface _newComptroller) public returns (uint);\n    function _setReserveFactor(uint _newReserveFactorMantissa) external returns (uint);\n    function _reduceReserves(uint _reduceAmount, address payable _account) external returns (uint);\n    function _setInterestRateModel(InterestRateModel _newInterestRateModel) public returns (uint);\n}"},"BaseReporter.sol":{"content":"pragma solidity ^0.5.16;\n\n/**\n * @title Collection of error messages\n * @author Aegis\n */\ncontract BaseReporter {\n    event FailUre(uint _error, uint _remarks, uint _item);\n    enum Error{\n        SUCCESS,\n        ERROR\n    }\n\n    enum ErrorRemarks {\n        COMPTROLLER_TRANSFER_ALLOWED,\n        ALLOW_SELF_TRANSFERS,\n        DIVISION_BY_ZERO,\n\n        SET_COMPTROLLER_OWNER_CHECK,\n        SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,\n        SET_RESERVE_FACTOR_FRESH_CHECK,\n        SET_RESERVE_FACTOR_ADMIN_CHECK,\n        SET_RESERVE_FACTOR_BOUNDS_CHECK,\n        \n        ADD_RESERVES_ACCRUE_INTEREST_FAILED,\n        ADD_RESERVES_FRESH_CHECK,\n        \n        REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,\n        REDUCE_RESERVES_ADMIN_CHECK,\n        REDUCE_RESERVES_FRESH_CHECK,\n        REDUCE_RESERVES_CASH_NOT_AVAILABLE,\n        REDUCE_RESERVES_VALIDATION,\n\n        SET_INTEREST_RATE_MODEL_OWNER_CHECK,\n        SET_INTEREST_RATE_MODEL_FRESH_CHECK,\n\n        INTEGER_OVERFLOW,\n        INTEGER_UNDERFLOW,\n\n        TRANSFER_NOT_ALLOWED,\n        TRANSFER_NOT_ENOUGH,\n        TRANSFER_TOO_MUCH,\n\n        ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,\n        ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,\n        ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,\n        ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,\n        ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,\n\n        MINT_COMPTROLLER_REJECTION,\n        MINT_FRESHNESS_CHECK,\n        MINT_EXCHANGE_RATE_READ_FAILED,\n        REDEEM_ACCRUE_INTEREST_FAILED,\n        REDEEM_EXCHANGE_RATE_READ_FAILED,\n        CANNOT_BE_ZERO,\n\n        REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,\n        REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,\n        REDEEM_COMPTROLLER_REJECTION,\n        REDEEM_FRESHNESS_CHECK,\n        REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,\n        REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,\n        REDEEM_TRANSFER_OUT_NOT_POSSIBLE,\n\n        BORROW_FRESHNESS_CHECK,\n        BORROW_COMPTROLLER_REJECTION,\n        BORROW_CASH_NOT_AVAILABLE,\n        BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\n        BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,\n        BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,\n        \n        REPAY_BORROW_ACCRUE_INTEREST_FAILED,\n        REPAY_BEHALF_ACCRUE_INTEREST_FAILED,\n        REPAY_BORROW_FRESHNESS_CHECK,\n        REPAY_BORROW_COMPTROLLER_REJECTION,\n        REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,\n\n        LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,\n        LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,\n        LIQUIDATE_FRESHNESS_CHECK,\n        LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,\n        LIQUIDATE_COMPTROLLER_REJECTION,\n        LIQUIDATE_LIQUIDATOR_IS_BORROWER,\n        LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,\n        LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,\n        LIQUIDATE_REPAY_BORROW_FRESH_FAILED,\n        LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,\n        LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,\n        LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,\n        LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,\n        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,\n\n        EXIT_MARKET_BALANCE_OWED,\n        EXIT_MARKET_REJECTION,\n\n        SET_PRICE_ORACLE_OWNER_CHECK,\n        SET_CLOSE_FACTOR_OWNER_CHECK,\n        SET_CLOSE_FACTOR_VALIDATION,\n\n        SET_COLLATERAL_FACTOR_OWNER_CHECK,\n        SET_COLLATERAL_FACTOR_NO_EXISTS,\n        SET_COLLATERAL_FACTOR_VALIDATION,\n        SET_COLLATERAL_FACTOR_WITHOUT_PRICE,\n\n        SET_MAX_ASSETS_OWNER_CHECK,\n        SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,\n        SET_LIQUIDATION_INCENTIVE_VALIDATION,\n        SUPPORT_MARKET_EXISTS,\n        SUPPORT_MARKET_OWNER_CHECK,\n        SET_PAUSE_GUARDIAN_OWNER_CHECK,\n\n        SET_PENDING_ADMIN_OWNER_CHECK,\n        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,\n        SET_PENDING_IMPLEMENTATION_OWNER_CHECK,\n        MINT_ACCRUE_INTEREST_FAILED,\n        BORROW_ACCRUE_INTEREST_FAILED,\n        SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED\n\n    }\n\n    enum MathError {\n        NO_ERROR,\n        DIVISION_BY_ZERO,\n        INTEGER_OVERFLOW,\n        INTEGER_UNDERFLOW\n    }\n\n    function fail(Error _errorEnum, ErrorRemarks _remarks, uint _item) internal returns (uint) {\n        emit FailUre(uint(_errorEnum), uint(_remarks), _item);\n        return uint(_errorEnum);\n    }\n}"},"CarefulMath.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./BaseReporter.sol\";\n\ncontract CarefulMath {\n\n    function mulUInt(uint _a, uint _b) internal pure returns (BaseReporter.MathError, uint) {\n        if (_a == 0) {\n            return (BaseReporter.MathError.NO_ERROR, 0);\n        }\n        uint c = _a * _b;\n        if (c / _a != _b) {\n            return (BaseReporter.MathError.INTEGER_OVERFLOW, 0);\n        } else {\n            return (BaseReporter.MathError.NO_ERROR, c);\n        }\n    }\n\n    function divUInt(uint _a, uint _b) internal pure returns (BaseReporter.MathError, uint) {\n        if (_b == 0) {\n            return (BaseReporter.MathError.DIVISION_BY_ZERO, 0);\n        }\n\n        return (BaseReporter.MathError.NO_ERROR, _a / _b);\n    }\n\n    function subUInt(uint _a, uint _b) internal pure returns (BaseReporter.MathError, uint) {\n        if (_b \u003c= _a) {\n            return (BaseReporter.MathError.NO_ERROR, _a - _b);\n        } else {\n            return (BaseReporter.MathError.INTEGER_UNDERFLOW, 0);\n        }\n    }\n\n    function addUInt(uint _a, uint _b) internal pure returns (BaseReporter.MathError, uint) {\n        uint c = _a + _b;\n        if (c \u003e= _a) {\n            return (BaseReporter.MathError.NO_ERROR, c);\n        } else {\n            return (BaseReporter.MathError.INTEGER_OVERFLOW, 0);\n        }\n    }\n\n    function addThenSubUInt(uint _a, uint _b, uint _c) internal pure returns (BaseReporter.MathError, uint) {\n        (BaseReporter.MathError err0, uint sum) = addUInt(_a, _b);\n        if (err0 != BaseReporter.MathError.NO_ERROR) {\n            return (err0, 0);\n        }\n        return subUInt(sum, _c);\n    }\n}"},"EIP20Interface.sol":{"content":"pragma solidity ^0.5.16;\n\n/**\n * @title EIP20Interface\n */\ncontract EIP20Interface {\n    function name() external view returns (string memory);\n    function symbol() external view returns (string memory);\n    function decimals() external view returns (uint8);\n\n    /**\n     * @notice Get the total number of tokens in circulation\n     * @return uint\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @notice Gets the balance of the specified address\n     * @param _owner The address from which the balance will be retrieved\n     * @return uint\n     */\n    function balanceOf(address _owner) external view returns (uint256 balance);\n\n    /**\n     * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n     * @param _dst The address of the destination account\n     * @param _amount The number of tokens to transfer\n     * @return bool\n     */\n    function transfer(address _dst, uint256 _amount) external returns (bool success);\n\n    /**\n     * @notice Transfer `amount` tokens from `src` to `dst`\n     * @param _src The address of the source account\n     * @param _dst The address of the destination account\n     * @param _amount The number of tokens to transfer\n     * @return bool\n     */\n    function transferFrom(address _src, address _dst, uint256 _amount) external returns (bool success);\n\n    /**\n     * @notice Approve `spender` to transfer up to `amount` from `src`\n     * @param _spender The address of the account which may transfer tokens\n     * @param _amount The number of tokens that are approved (-1 means infinite)\n     * @return uint\n     */\n    function approve(address _spender, uint256 _amount) external returns (bool success);\n\n    /**\n     * @notice Get the current allowance from `owner` for `spender`\n     * @param _owner The address of the account which owns the tokens to be spent\n     * @param _spender The address of the account which may transfer tokens\n     * @return uint\n     */\n    function allowance(address _owner, address _spender) external view returns (uint256 remaining);\n\n    event Transfer(address indexed _from, address indexed _to, uint256 _amount);\n    event Approval(address indexed _owner, address indexed _spender, uint256 _amount);\n}"},"EIP20NonStandardInterface.sol":{"content":"pragma solidity ^0.5.16;\n\n/**\n * @title EIP20NonStandardInterface\n * @author Aegis\n */\ncontract EIP20NonStandardInterface {\n    \n    /**\n     * @notice Get the total number of tokens in circulation\n     * @return The supply of tokens\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @notice Gets the balance of the specified address\n     * @param _owner The address from which the balance will be retrieved\n     * @return uint\n     */\n    function balanceOf(address _owner) external view returns (uint256 balance);\n\n    /**\n      * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n      * @param _dst The address of the destination account\n      * @param _amount The number of tokens to transfer\n      */\n    function transfer(address _dst, uint256 _amount) external;\n\n    /**\n      * @notice Transfer `amount` tokens from `src` to `dst`\n      * @param _src: The address of the source account\n      * @param _dst: The address of the destination account\n      * @param _amount: The number of tokens to transfer\n      */\n    function transferFrom(address _src, address _dst, uint256 _amount) external;\n\n    /**\n      * @notice Approve `spender` to transfer up to `amount` from `src`\n      * @param _spender The address of the account which may transfer tokens\n      * @param _amount The number of tokens that are approved\n      * @return bool\n      */\n    function approve(address _spender, uint256 _amount) external returns (bool success);\n\n    /**\n      * @notice Get the current allowance from `owner` for `spender`\n      * @param _owner The address of the account which owns the tokens to be spent\n      * @param _spender The address of the account which may transfer tokens\n      * @return uint\n      */\n    function allowance(address _owner, address _spender) external view returns (uint256 remaining);\n\n    event Transfer(address indexed _from, address indexed _to, uint256 _amount);\n    event Approval(address indexed _owner, address indexed _spender, uint256 _amount);\n}"},"Exponential.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AegisMath.sol\";\nimport \"./BaseReporter.sol\";\nimport \"./CarefulMath.sol\";\n\ncontract Exponential is CarefulMath {\n\n    uint constant expScale = 1e18;\n    uint constant doubleScale = 1e36;\n    uint constant halfExpScale = expScale/2;\n    uint constant mantissaOne = expScale;\n\n    struct Exp {\n        uint mantissa;\n    }\n\n    struct Double {\n        uint mantissa;\n    }\n\n    /**\n     * @notice Creates an exponential from numerator and denominator values\n     * @param _num uint\n     * @param _denom uint\n     * @return MathError, Exp\n     */\n    function getExp(uint _num, uint _denom) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError err0, uint scaledNumerator) = mulUInt(_num, expScale);\n        if (err0 != BaseReporter.MathError.NO_ERROR) {\n            return (err0, Exp({mantissa: 0}));\n        }\n        (BaseReporter.MathError err1, uint rational) = divUInt(scaledNumerator, _denom);\n        if (err1 != BaseReporter.MathError.NO_ERROR) {\n            return (err1, Exp({mantissa: 0}));\n        }\n        return (BaseReporter.MathError.NO_ERROR, Exp({mantissa: rational}));\n    }\n\n    /**\n     * @notice Adds two exponentials, returning a new exponential\n     * @param _a exp\n     * @param _b exp\n     * @return MathError, Exp\n     */\n    function addExp(Exp memory _a, Exp memory _b) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError error, uint result) = addUInt(_a.mantissa, _b.mantissa);\n        return (error, Exp({mantissa: result}));\n    }\n\n    /**\n     * @notice Subtracts two exponentials, returning a new exponential\n     * @param _a exp\n     * @param _b exp\n     * @return MathError, Exp\n     */\n    function subExp(Exp memory _a, Exp memory _b) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError error, uint result) = subUInt(_a.mantissa, _b.mantissa);\n        return (error, Exp({mantissa: result}));\n    }\n\n    /**\n     * @notice Multiply an Exp by a scalar, returning a new Exp\n     * @param _a exp\n     * @param _scalar uint\n     * @return MathError, Exp\n     */\n    function mulScalar(Exp memory _a, uint _scalar) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError err0, uint scaledMantissa) = mulUInt(_a.mantissa, _scalar);\n        if (err0 != BaseReporter.MathError.NO_ERROR) {\n            return (err0, Exp({mantissa: 0}));\n        }\n        return (BaseReporter.MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));\n    }\n\n    /**\n     * @notice Multiply an Exp by a scalar, then truncate to return an unsigned integer\n     * @param _a exp\n     * @param _scalar uint\n     * @return MathError, Exp\n     */\n    function mulScalarTruncate(Exp memory _a, uint _scalar) pure internal returns (BaseReporter.MathError, uint) {\n        (BaseReporter.MathError err, Exp memory product) = mulScalar(_a, _scalar);\n        if (err != BaseReporter.MathError.NO_ERROR) {\n            return (err, 0);\n        }\n        return (BaseReporter.MathError.NO_ERROR, truncate(product));\n    }\n\n    /**\n     * @notice Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer\n     * @param _a exp\n     * @param _scalar uint\n     * @param _addend uint\n     * @return MathError, Exp\n     */\n    function mulScalarTruncateAddUInt(Exp memory _a, uint _scalar, uint _addend) pure internal returns (BaseReporter.MathError, uint) {\n        (BaseReporter.MathError err, Exp memory product) = mulScalar(_a, _scalar);\n        if (err != BaseReporter.MathError.NO_ERROR) {\n            return (err, 0);\n        }\n        return addUInt(truncate(product), _addend);\n    }\n\n    /**\n     * @notice Divide an Exp by a scalar, returning a new Exp\n     * @param _a exp\n     * @param _scalar uint\n     * @return MathError, Exp\n     */\n    function divScalar(Exp memory _a, uint _scalar) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError err0, uint descaledMantissa) = divUInt(_a.mantissa, _scalar);\n        if (err0 != BaseReporter.MathError.NO_ERROR) {\n            return (err0, Exp({mantissa: 0}));\n        }\n        return (BaseReporter.MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));\n    }\n\n    /**\n     * @notice Divide a scalar by an Exp, returning a new Exp\n     * @param _scalar uint\n     * @param _divisor exp\n     * @return MathError, Exp\n     */\n    function divScalarByExp(uint _scalar, Exp memory _divisor) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError err0, uint numerator) = mulUInt(expScale, _scalar);\n        if (err0 != BaseReporter.MathError.NO_ERROR) {\n            return (err0, Exp({mantissa: 0}));\n        }\n        return getExp(numerator, _divisor.mantissa);\n    }\n\n    /**\n     * @notice Divide a scalar by an Exp, then truncate to return an unsigned integer\n     * @param _scalar uint\n     * @param _divisor exp\n     * @return MathError, Exp\n     */\n    function divScalarByExpTruncate(uint _scalar, Exp memory _divisor) pure internal returns (BaseReporter.MathError, uint) {\n        (BaseReporter.MathError err, Exp memory fraction) = divScalarByExp(_scalar, _divisor);\n        if (err != BaseReporter.MathError.NO_ERROR) {\n            return (err, 0);\n        }\n        return (BaseReporter.MathError.NO_ERROR, truncate(fraction));\n    }\n\n    /**\n     * @notice Multiplies two exponentials, returning a new exponential\n     * @param _a exp\n     * @param _b exp\n     * @return MathError, Exp\n     */\n    function mulExp(Exp memory _a, Exp memory _b) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError err0, uint doubleScaledProduct) = mulUInt(_a.mantissa, _b.mantissa);\n        if (err0 != BaseReporter.MathError.NO_ERROR) {\n            return (err0, Exp({mantissa: 0}));\n        }\n        (BaseReporter.MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);\n        if (err1 != BaseReporter.MathError.NO_ERROR) {\n            return (err1, Exp({mantissa: 0}));\n        }\n        (BaseReporter.MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);\n        assert(err2 == BaseReporter.MathError.NO_ERROR);\n        return (BaseReporter.MathError.NO_ERROR, Exp({mantissa: product}));\n    }\n\n    /**\n     * @notice Multiplies two exponentials given their mantissas, returning a new exponential\n     * @param _a uint\n     * @param _b uint\n     * @return MathError, Exp\n     */\n    function mulExp(uint _a, uint _b) pure internal returns (BaseReporter.MathError, Exp memory) {\n        return mulExp(Exp({mantissa: _a}), Exp({mantissa: _b}));\n    }\n\n    /**\n     * @notice Multiplies three exponentials, returning a new exponential.\n     * @param _a exp\n     * @param _b exp\n     * @param _c exp\n     * @return MathError, Exp\n     */\n    function mulExp3(Exp memory _a, Exp memory _b, Exp memory _c) pure internal returns (BaseReporter.MathError, Exp memory) {\n        (BaseReporter.MathError err, Exp memory ab) = mulExp(_a, _b);\n        if (err != BaseReporter.MathError.NO_ERROR) {\n            return (err, ab);\n        }\n        return mulExp(ab, _c);\n    }\n\n    /**\n     * @notice Divides two exponentials, returning a new exponential\n     * @param _a exp\n     * @param _b exp\n     * @return MathError, Exp\n     */\n    function divExp(Exp memory _a, Exp memory _b) pure internal returns (BaseReporter.MathError, Exp memory) {\n        return getExp(_a.mantissa, _b.mantissa);\n    }\n\n    /**\n     * @notice Truncates the given exp to a whole number value\n     * @param _exp exp\n     * @return uint\n     */\n    function truncate(Exp memory _exp) pure internal returns (uint) {\n        return _exp.mantissa / expScale;\n    }\n\n    /**\n     * @notice Checks if first Exp is less than second Exp\n     * @param _left exp\n     * @param _right exp\n     * @return bool\n     */\n    function lessThanExp(Exp memory _left, Exp memory _right) pure internal returns (bool) {\n        return _left.mantissa \u003c _right.mantissa;\n    }\n\n    /**\n     * @notice Checks if left Exp \u003c= right Exp\n     * @param _left exp\n     * @param _right exp\n     * @return bool\n     */\n    function lessThanOrEqualExp(Exp memory _left, Exp memory _right) pure internal returns (bool) {\n        return _left.mantissa \u003c= _right.mantissa;\n    }\n\n    /**\n     * @notice Checks if left Exp \u003e right Exp.\n     * @param _left exp\n     * @param _right exp\n     */\n    function greaterThanExp(Exp memory _left, Exp memory _right) pure internal returns (bool) {\n        return _left.mantissa \u003e _right.mantissa;\n    }\n\n    /**\n     * @notice returns true if Exp is exactly zero\n     * @param _value exp\n     * @return MathError, Exp\n     */\n    function isZeroExp(Exp memory _value) pure internal returns (bool) {\n        return _value.mantissa == 0;\n    }\n\n    function safe224(uint _n, string memory _errorMessage) pure internal returns (uint224) {\n        require(_n \u003c 2**224, _errorMessage);\n        return uint224(_n);\n    }\n\n    function safe32(uint _n, string memory _errorMessage) pure internal returns (uint32) {\n        require(_n \u003c 2**32, _errorMessage);\n        return uint32(_n);\n    }\n\n    function add_(Exp memory _a, Exp memory _b) pure internal returns (Exp memory) {\n        return Exp({mantissa: add_(_a.mantissa, _b.mantissa)});\n    }\n\n    function add_(Double memory _a, Double memory _b) pure internal returns (Double memory) {\n        return Double({mantissa: add_(_a.mantissa, _b.mantissa)});\n    }\n\n    function add_(uint _a, uint _b) pure internal returns (uint) {\n        return add_(_a, _b, \"add overflow\");\n    }\n\n    function add_(uint _a, uint _b, string memory _errorMessage) pure internal returns (uint) {\n        uint c = _a + _b;\n        require(c \u003e= _a, _errorMessage);\n        return c;\n    }\n\n    function sub_(Exp memory _a, Exp memory _b) pure internal returns (Exp memory) {\n        return Exp({mantissa: sub_(_a.mantissa, _b.mantissa)});\n    }\n\n    function sub_(Double memory _a, Double memory _b) pure internal returns (Double memory) {\n        return Double({mantissa: sub_(_a.mantissa, _b.mantissa)});\n    }\n\n    function sub_(uint _a, uint _b) pure internal returns (uint) {\n        return sub_(_a, _b, \"sub underflow\");\n    }\n\n    function sub_(uint _a, uint _b, string memory _errorMessage) pure internal returns (uint) {\n        require(_b \u003c= _a, _errorMessage);\n        return _a - _b;\n    }\n\n    function mul_(Exp memory _a, Exp memory _b) pure internal returns (Exp memory) {\n        return Exp({mantissa: mul_(_a.mantissa, _b.mantissa) / expScale});\n    }\n\n    function mul_(Exp memory _a, uint _b) pure internal returns (Exp memory) {\n        return Exp({mantissa: mul_(_a.mantissa, _b)});\n    }\n\n    function mul_(uint _a, Exp memory _b) pure internal returns (uint) {\n        return mul_(_a, _b.mantissa) / expScale;\n    }\n\n    function mul_(Double memory _a, Double memory _b) pure internal returns (Double memory) {\n        return Double({mantissa: mul_(_a.mantissa, _b.mantissa) / doubleScale});\n    }\n\n    function mul_(Double memory _a, uint _b) pure internal returns (Double memory) {\n        return Double({mantissa: mul_(_a.mantissa, _b)});\n    }\n\n    function mul_(uint _a, Double memory _b) pure internal returns (uint) {\n        return mul_(_a, _b.mantissa) / doubleScale;\n    }\n\n    function mul_(uint _a, uint _b) pure internal returns (uint) {\n        return mul_(_a, _b, \"mul overflow\");\n    }\n\n    function mul_(uint _a, uint _b, string memory _errorMessage) pure internal returns (uint) {\n        if (_a == 0 || _b == 0) {\n            return 0;\n        }\n        uint c = _a * _b;\n        require(c / _a == _b, _errorMessage);\n        return c;\n    }\n\n    function div_(Exp memory _a, Exp memory _b) pure internal returns (Exp memory) {\n        return Exp({mantissa: div_(mul_(_a.mantissa, expScale), _b.mantissa)});\n    }\n\n    function div_(Exp memory _a, uint _b) pure internal returns (Exp memory) {\n        return Exp({mantissa: div_(_a.mantissa, _b)});\n    }\n\n    function div_(uint _a, Exp memory _b) pure internal returns (uint) {\n        return div_(mul_(_a, expScale), _b.mantissa);\n    }\n\n    function div_(Double memory _a, Double memory _b) pure internal returns (Double memory) {\n        return Double({mantissa: div_(mul_(_a.mantissa, doubleScale), _b.mantissa)});\n    }\n\n    function div_(Double memory _a, uint _b) pure internal returns (Double memory) {\n        return Double({mantissa: div_(_a.mantissa, _b)});\n    }\n\n    function div_(uint _a, Double memory _b) pure internal returns (uint) {\n        return div_(mul_(_a, doubleScale), _b.mantissa);\n    }\n\n    function div_(uint _a, uint _b) pure internal returns (uint) {\n        return div_(_a, _b, \"div by zero\");\n    }\n\n    function div_(uint _a, uint _b, string memory _errorMessage) pure internal returns (uint) {\n        require(_b \u003e 0, _errorMessage);\n        return _a / _b;\n    }\n\n    function fraction(uint _a, uint _b) pure internal returns (Double memory) {\n        return Double({mantissa: div_(mul_(_a, doubleScale), _b)});\n    }\n}"},"InterestRateModel.sol":{"content":"pragma solidity ^0.5.16;\n\n/**\n * @title Aegis InterestRateModel interface\n * @author Aegis\n */\ncontract InterestRateModel {\n    bool public constant isInterestRateModel = true;\n\n    /**\n      * @notice Calculates the current borrow interest rate per block\n      * @param _cash The total amount of cash the market has\n      * @param _borrows The total amount of borrows the market has outstanding\n      * @param _reserves The total amnount of reserves the market has\n      * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n      */\n    function getBorrowRate(uint _cash, uint _borrows, uint _reserves) external view returns (uint);\n\n    /**\n      * @notice Calculates the current supply interest rate per block\n      * @param _cash The total amount of cash the market has\n      * @param _borrows The total amount of borrows the market has outstanding\n      * @param _reserves The total amnount of reserves the market has\n      * @param _reserveFactorMantissa The current reserve factor the market has\n      * @return The supply rate per block (as a percentage, and scaled by 1e18)\n      */\n    function getSupplyRate(uint _cash, uint _borrows, uint _reserves, uint _reserveFactorMantissa) external view returns (uint);\n}"},"PriceOracle.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AToken.sol\";\n\n/**\n * @title Aegis Price Oracle\n * @author Aegis\n */\ncontract PriceOracle {\n    address public owner;\n    mapping(address =\u003e uint) prices;\n    event PriceAccept(address _aToken, uint _oldPrice, uint _acceptPrice);\n\n    constructor (address _admin) public {\n        owner = _admin;\n    }\n\n    function getUnderlyingPrice(address _aToken) external view returns (uint) {\n        // USDT/USDC 1:1\n        if(keccak256(abi.encodePacked((AToken(_aToken).symbol()))) == keccak256(abi.encodePacked((\"USDT-A\"))) || keccak256(abi.encodePacked((AToken(_aToken).symbol()))) == keccak256(abi.encodePacked((\"USDC-A\")))) {\n            return 1e18;\n        }\n        return prices[_aToken];\n    }\n\n    function postUnderlyingPrice(address _aToken, uint _price) external {\n        require(msg.sender == owner, \"PriceOracle::postUnderlyingPrice owner failure\");\n        uint old = prices[_aToken];\n        prices[_aToken] = _price;\n        emit PriceAccept(_aToken, old, _price);\n    }\n}"},"Unitroller.sol":{"content":"pragma solidity ^0.5.16;\n\nimport \"./AegisComptrollerCommon.sol\";\nimport \"./BaseReporter.sol\";\n\n/**\n * @title Aegis Unitroller\n * @author Aegis\n */\ncontract Unitroller is AegisComptrollerCommon, BaseReporter {\n    event NewPendingImplementation(address _oldPendingImplementation, address _newPendingImplementation);\n    event NewImplementation(address _oldImplementation, address _newImplementation);\n    event NewPendingAdmin(address _oldPendingAdmin, address _newPendingAdmin);\n    event NewAdmin(address _oldAdmin, address _newAdmin);\n\n    constructor () public {\n        admin = msg.sender;\n        liquidateAdmin = msg.sender;\n    }\n\n    function _setPendingImplementation(address _newPendingImplementation) public returns (uint) {\n        if (msg.sender != admin) {\n            return fail(Error.ERROR, ErrorRemarks.SET_PENDING_IMPLEMENTATION_OWNER_CHECK, uint(Error.ERROR));\n        }\n        address oldPendingImplementation = pendingComptrollerImplementation;\n        pendingComptrollerImplementation = _newPendingImplementation;\n        emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation\n     * @return SUCCESS\n     */\n    function _acceptImplementation() public returns (uint) {\n        if (msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0)) {\n            return fail(Error.ERROR, ErrorRemarks.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, uint(Error.ERROR));\n        }\n        address oldImplementation = comptrollerImplementation;\n        address oldPendingImplementation = pendingComptrollerImplementation;\n        comptrollerImplementation = pendingComptrollerImplementation;\n        pendingComptrollerImplementation = address(0);\n        emit NewImplementation(oldImplementation, comptrollerImplementation);\n        emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.\n     * @param _newPendingAdmin address\n     * @return SUCCESS\n     */\n    function _setPendingAdmin(address _newPendingAdmin) public returns (uint) {\n        if (msg.sender != admin) {\n            return fail(Error.ERROR, ErrorRemarks.SET_PENDING_ADMIN_OWNER_CHECK, uint(Error.ERROR));\n        }\n        address oldPendingAdmin = pendingAdmin;\n        pendingAdmin = _newPendingAdmin;\n        emit NewPendingAdmin(oldPendingAdmin, _newPendingAdmin);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin\n     * @return SUCCESS\n     */\n    function _acceptAdmin() public returns (uint) {\n        if (msg.sender != pendingAdmin || msg.sender == address(0)) {\n            return fail(Error.ERROR, ErrorRemarks.ACCEPT_ADMIN_PENDING_ADMIN_CHECK, uint(Error.ERROR));\n        }\n        address oldAdmin = admin;\n        address oldPendingAdmin = pendingAdmin;\n        admin = pendingAdmin;\n        pendingAdmin = address(0);\n\n        emit NewAdmin(oldAdmin, admin);\n        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);\n        return uint(Error.SUCCESS);\n    }\n\n    /**\n     * @dev Delegates execution to an implementation contract.\n     * It returns to the external caller whatever the implementation returns\n     * or forwards reverts.\n     */\n    function () payable external {\n        // delegate all other functions to current implementation\n        (bool success, ) = comptrollerImplementation.delegatecall(msg.data);\n\n        assembly {\n            let free_mem_ptr := mload(0x40)\n            returndatacopy(free_mem_ptr, 0, returndatasize)\n\n            switch success\n            case 0 { revert(free_mem_ptr, returndatasize) }\n            default { return(free_mem_ptr, returndatasize) }\n        }\n    }\n}"}}