Untitled diff

建立於 差異永不過期
524 刪除
830
583 新增
889
// Sources flattened with hardhat v2.20.1 https://hardhat.org

// SPDX-License-Identifier: BSD-3-Clause

// File src/CarefulMath.sol

pragma solidity 0.5.17;
pragma solidity 0.5.17;


Text moved to lines 792-888
contract ComptrollerErrorReporter {
enum Error {
NO_ERROR,
UNAUTHORIZED,
COMPTROLLER_MISMATCH,
INSUFFICIENT_SHORTFALL,
INSUFFICIENT_LIQUIDITY,
INVALID_CLOSE_FACTOR,
INVALID_COLLATERAL_FACTOR,
INVALID_LIQUIDATION_INCENTIVE,
MARKET_NOT_ENTERED, // no longer possible
MARKET_NOT_LISTED,
MARKET_ALREADY_LISTED,
MATH_ERROR,
NONZERO_BORROW_BALANCE,
PRICE_ERROR,
REJECTION,
SNAPSHOT_ERROR,
TOO_MANY_ASSETS,
TOO_MUCH_REPAY
}

enum FailureInfo {
ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
EXIT_MARKET_BALANCE_OWED,
EXIT_MARKET_REJECTION,
SET_CLOSE_FACTOR_OWNER_CHECK,
SET_CLOSE_FACTOR_VALIDATION,
SET_COLLATERAL_FACTOR_OWNER_CHECK,
SET_COLLATERAL_FACTOR_NO_EXISTS,
SET_COLLATERAL_FACTOR_VALIDATION,
SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
SET_IMPLEMENTATION_OWNER_CHECK,
SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
SET_LIQUIDATION_INCENTIVE_VALIDATION,
SET_MAX_ASSETS_OWNER_CHECK,
SET_PENDING_ADMIN_OWNER_CHECK,
SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
SET_PRICE_ORACLE_OWNER_CHECK,
SUPPORT_MARKET_EXISTS,
SUPPORT_MARKET_OWNER_CHECK,
SET_PAUSE_GUARDIAN_OWNER_CHECK,
SET_GAS_AMOUNT_OWNER_CHECK
}

/**
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
**/
event Failure(uint error, uint info, uint detail);

/**
* @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
*/
function fail(Error err, FailureInfo info) internal returns (uint) {
emit Failure(uint(err), uint(info), 0);

return uint(err);
}

/**
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
*/
function failOpaque(
Error err,
FailureInfo info,
uint opaqueError
) internal returns (uint) {
emit Failure(uint(err), uint(info), opaqueError);

return uint(err);
}
}

contract TokenErrorReporter {
enum Error {
NO_ERROR,
UNAUTHORIZED,
BAD_INPUT,
COMPTROLLER_REJECTION,
COMPTROLLER_CALCULATION_ERROR,
INTEREST_RATE_MODEL_ERROR,
INVALID_ACCOUNT_PAIR,
INVALID_CLOSE_AMOUNT_REQUESTED,
INVALID_COLLATERAL_FACTOR,
MATH_ERROR,
MARKET_NOT_FRESH,
MARKET_NOT_LISTED,
TOKEN_INSUFFICIENT_ALLOWANCE,
TOKEN_INSUFFICIENT_BALANCE,
TOKEN_INSUFFICIENT_CASH,
TOKEN_TRANSFER_IN_FAILED,
TOKEN_TRANSFER_OUT_FAILED
}

/*
* Note: FailureInfo (but not Error) is kept in alphabetical order
* This is because FailureInfo grows significantly faster, and
* the order of Error has some meaning, while the order of FailureInfo
* is entirely arbitrary.
*/
enum FailureInfo {
ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,
ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,
ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,
ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,
ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,
ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,
BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
BORROW_ACCRUE_INTEREST_FAILED,
BORROW_CASH_NOT_AVAILABLE,
BORROW_FRESHNESS_CHECK,
BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
BORROW_MARKET_NOT_LISTED,
BORROW_COMPTROLLER_REJECTION,
LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,
LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,
LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,
LIQUIDATE_COMPTROLLER_REJECTION,
LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,
LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,
LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,
LIQUIDATE_FRESHNESS_CHECK,
LIQUIDATE_LIQUIDATOR_IS_BORROWER,
LIQUIDATE_REPAY_BORROW_FRESH_FAILED,
LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,
LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,
LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,
LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,
LIQUIDATE_SEIZE_TOO_MUCH,
MINT_ACCRUE_INTEREST_FAILED,
MINT_COMPTROLLER_REJECTION,
MINT_EXCHANGE_CALCULATION_FAILED,
MINT_EXCHANGE_RATE_READ_FAILED,
MINT_FRESHNESS_CHECK,
MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
MINT_TRANSFER_IN_FAILED,
MINT_TRANSFER_IN_NOT_POSSIBLE,
REDEEM_ACCRUE_INTEREST_FAILED,
REDEEM_COMPTROLLER_REJECTION,
REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,
REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,
REDEEM_EXCHANGE_RATE_READ_FAILED,
REDEEM_FRESHNESS_CHECK,
REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
REDEEM_TRANSFER_OUT_NOT_POSSIBLE,
REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,
REDUCE_RESERVES_ADMIN_CHECK,
REDUCE_RESERVES_CASH_NOT_AVAILABLE,
REDUCE_RESERVES_FRESH_CHECK,
REDUCE_RESERVES_VALIDATION,
REPAY_BEHALF_ACCRUE_INTEREST_FAILED,
REPAY_BORROW_ACCRUE_INTEREST_FAILED,
REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_COMPTROLLER_REJECTION,
REPAY_BORROW_FRESHNESS_CHECK,
REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
SET_COLLATERAL_FACTOR_OWNER_CHECK,
SET_COLLATERAL_FACTOR_VALIDATION,
SET_COMPTROLLER_OWNER_CHECK,
SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,
SET_INTEREST_RATE_MODEL_FRESH_CHECK,
SET_INTEREST_RATE_MODEL_OWNER_CHECK,
SET_MAX_ASSETS_OWNER_CHECK,
SET_ORACLE_MARKET_NOT_LISTED,
SET_PENDING_ADMIN_OWNER_CHECK,
SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,
SET_RESERVE_FACTOR_ADMIN_CHECK,
SET_RESERVE_FACTOR_FRESH_CHECK,
SET_RESERVE_FACTOR_BOUNDS_CHECK,
TRANSFER_COMPTROLLER_REJECTION,
TRANSFER_NOT_ALLOWED,
TRANSFER_NOT_ENOUGH,
TRANSFER_TOO_MUCH,
ADD_RESERVES_ACCRUE_INTEREST_FAILED,
ADD_RESERVES_FRESH_CHECK,
ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE,
SET_PROTOCOL_SEIZE_SHARE_ACCRUE_INTEREST_FAILED,
SET_PROTOCOL_SEIZE_SHARE_OWNER_CHECK,
SET_PROTOCOL_SEIZE_SHARE_FRESH_CHECK
Text moved with changes to lines 375-378 (91.7% similarity)
}

/**
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
**/
event Failure(uint error, uint info, uint detail);

/**
* @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
*/
Text moved to lines 383-395
function fail(Error err, FailureInfo info) internal returns (uint) {
emit Failure(uint(err), uint(info), 0);

return uint(err);
}

/**
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
*/
function failOpaque(
Error err,
FailureInfo info,
uint opaqueError
) internal returns (uint) {
emit Failure(uint(err), uint(info), opaqueError);

return uint(err);
Text moved to lines 339-341
}
}

/**
* @title EIP20NonStandardInterface
* @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
* See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
interface EIP20NonStandardInterface {
Text moved with changes to lines 719-732 (98.0% similarity)
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);

/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);

///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///

/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transfer(address dst, uint256 amount) external;

///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
Text moved to lines 742-747

/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
Text moved to lines 754-787
function transferFrom(address src, address dst, uint256 amount) external;

/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved
* @return Whether or not the approval succeeded
*/
function approve(
address spender,
uint256 amount
) external returns (bool success);

/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent
*/
function allowance(
address owner,
address spender
) external view returns (uint256 remaining);

event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(
address indexed owner,
address indexed spender,
uint256 amount
);
}

/**
* @title ERC 20 Token Standard Interface
* https://eips.ethereum.org/EIPS/eip-20
*/
interface EIP20Interface {
function name() external view returns (string memory);

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

function decimals() external view returns (uint8);

/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);

/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);

/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(
address dst,
uint256 amount
) external returns (bool success);

/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(
address src,
address dst,
uint256 amount
) external returns (bool success);

/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(
address spender,
uint256 amount
) external returns (bool success);

/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(
address owner,
address spender
) external view returns (uint256 remaining);

event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(
address indexed owner,
address indexed spender,
uint256 amount
);
}
Text moved to lines 577-703

contract ComptrollerInterface {
/// @notice Indicator that this is a Comptroller contract (for inspection)
bool public constant isComptroller = true;

/// @notice The amount of gas to use when making a native asset transfer.
uint16 public gasAmount;

/*** Assets You Are In ***/

function enterMarkets(
address[] calldata mTokens
) external returns (uint[] memory);

function exitMarket(address mToken) external returns (uint);

/*** Policy Hooks ***/

function mintAllowed(
address mToken,
address minter,
uint mintAmount
) external returns (uint);

function mintVerify(
address mToken,
address minter,
uint mintAmount,
uint mintTokens
) external;

function redeemAllowed(
address mToken,
address redeemer,
uint redeemTokens
) external returns (uint);

function redeemVerify(
address mToken,
address redeemer,
uint redeemAmount,
uint redeemTokens
) external;

function borrowAllowed(
address mToken,
address borrower,
uint borrowAmount
) external returns (uint);

function borrowVerify(
address mToken,
address borrower,
uint borrowAmount
) external;

function repayBorrowAllowed(
address mToken,
address payer,
address borrower,
uint repayAmount
) external returns (uint);

function repayBorrowVerify(
address mToken,
address payer,
address borrower,
uint repayAmount,
uint borrowerIndex
) external;

function liquidateBorrowAllowed(
address mTokenBorrowed,
address mTokenCollateral,
address liquidator,
address borrower,
uint repayAmount
) external returns (uint);

function liquidateBorrowVerify(
address mTokenBorrowed,
address mTokenCollateral,
address liquidator,
address borrower,
uint repayAmount,
uint seizeTokens
) external;

function seizeAllowed(
address mTokenCollateral,
address mTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens
) external returns (uint);

function seizeVerify(
address mTokenCollateral,
address mTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens
) external;

function transferAllowed(
address mToken,
address src,
address dst,
uint transferTokens
) external returns (uint);

function transferVerify(
address mToken,
address src,
address dst,
uint transferTokens
) external;

/*** Liquidity/Liquidation Calculations ***/

function liquidateCalculateSeizeTokens(
address mTokenBorrowed,
address mTokenCollateral,
uint repayAmount
) external view returns (uint, uint);
}

/**
* @title Careful Math
* @author Moonwell
* @notice Derived from OpenZeppelin's SafeMath library
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
*/
contract CarefulMath {
contract CarefulMath {
/**
/**
* @dev Possible error codes that we can return
* @dev Possible error codes that we can return
*/
*/
enum MathError {
enum MathError {
NO_ERROR,
NO_ERROR,
DIVISION_BY_ZERO,
DIVISION_BY_ZERO,
INTEGER_OVERFLOW,
INTEGER_OVERFLOW,
INTEGER_UNDERFLOW
INTEGER_UNDERFLOW
}
}


/**
* @dev Multiplies two numbers, returns an error on overflow.
*/
function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (a == 0) {
if (a == 0) {
return (MathError.NO_ERROR, 0);
return (MathError.NO_ERROR, 0);
}
}


uint c = a * b;
uint c = a * b;


if (c / a != b) {
if (c / a != b) {
return (MathError.INTEGER_OVERFLOW, 0);
return (MathError.INTEGER_OVERFLOW, 0);
} else {
} else {
return (MathError.NO_ERROR, c);
return (MathError.NO_ERROR, c);
}
}
}
}


/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b == 0) {
if (b == 0) {
return (MathError.DIVISION_BY_ZERO, 0);
return (MathError.DIVISION_BY_ZERO, 0);
}
}


return (MathError.NO_ERROR, a / b);
return (MathError.NO_ERROR, a / b);
}
}


/**
* @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
*/
function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
if (b <= a) {
if (b <= a) {
return (MathError.NO_ERROR, a - b);
return (MathError.NO_ERROR, a - b);
} else {
} else {
return (MathError.INTEGER_UNDERFLOW, 0);
return (MathError.INTEGER_UNDERFLOW, 0);
}
}
}
}


/**
* @dev Adds two numbers, returns an error on overflow.
*/
function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
uint c = a + b;
uint c = a + b;


if (c >= a) {
if (c >= a) {
return (MathError.NO_ERROR, c);
return (MathError.NO_ERROR, c);
} else {
} else {
return (MathError.INTEGER_OVERFLOW, 0);
return (MathError.INTEGER_OVERFLOW, 0);
}
}
}
}


/**
* @dev add a and b and then subtract c
*/
function addThenSubUInt(
function addThenSubUInt(
uint a,
uint a,
uint b,
uint b,
uint c
uint c
) internal pure returns (MathError, uint) {
) internal pure returns (MathError, uint) {
(MathError err0, uint sum) = addUInt(a, b);
(MathError err0, uint sum) = addUInt(a, b);


if (err0 != MathError.NO_ERROR) {
if (err0 != MathError.NO_ERROR) {
return (err0, 0);
return (err0, 0);
}
}


return subUInt(sum, c);
return subUInt(sum, c);
}
}
}
}


// File src/ExponentialNoError.sol

pragma solidity 0.5.17;

/**
/**
* @title Exponential module for storing fixed-precision decimals
* @title Exponential module for storing fixed-precision decimals
* @author Moonwell
* @author Moonwell
* @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
* @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
* Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
* Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
* `Exp({mantissa: 5100000000000000000})`.
* `Exp({mantissa: 5100000000000000000})`.
*/
*/
contract ExponentialNoError {
contract ExponentialNoError {
uint constant expScale = 1e18;
uint constant expScale = 1e18;
uint constant doubleScale = 1e36;
uint constant doubleScale = 1e36;
uint constant halfExpScale = expScale / 2;
uint constant halfExpScale = expScale / 2;
uint constant mantissaOne = expScale;
uint constant mantissaOne = expScale;


struct Exp {
struct Exp {
uint mantissa;
uint mantissa;
}
}


struct Double {
struct Double {
uint mantissa;
uint mantissa;
}
}


/**
/**
* @dev Truncates the given exp to a whole number value.
* @dev Truncates the given exp to a whole number value.
* For example, truncate(Exp{mantissa: 15 * expScale}) = 15
* For example, truncate(Exp{mantissa: 15 * expScale}) = 15
*/
*/
function truncate(Exp memory exp) internal pure returns (uint) {
function truncate(Exp memory exp) internal pure returns (uint) {
// Note: We are not using careful math here as we're performing a division that cannot fail
// Note: We are not using careful math here as we're performing a division that cannot fail
return exp.mantissa / expScale;
return exp.mantissa / expScale;
}
}


/**
/**
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
*/
*/
function mul_ScalarTruncate(
function mul_ScalarTruncate(
Exp memory a,
Exp memory a,
uint scalar
uint scalar
) internal pure returns (uint) {
) internal pure returns (uint) {
Exp memory product = mul_(a, scalar);
Exp memory product = mul_(a, scalar);
return truncate(product);
return truncate(product);
}
}


/**
/**
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
*/
*/
function mul_ScalarTruncateAddUInt(
function mul_ScalarTruncateAddUInt(
Exp memory a,
Exp memory a,
uint scalar,
uint scalar,
uint addend
uint addend
) internal pure returns (uint) {
) internal pure returns (uint) {
Exp memory product = mul_(a, scalar);
Exp memory product = mul_(a, scalar);
return add_(truncate(product), addend);
return add_(truncate(product), addend);
}
}


/**
/**
* @dev Checks if first Exp is less than second Exp.
* @dev Checks if first Exp is less than second Exp.
*/
*/
function lessThanExp(
function lessThanExp(
Exp memory left,
Exp memory left,
Exp memory right
Exp memory right
) internal pure returns (bool) {
) internal pure returns (bool) {
return left.mantissa < right.mantissa;
return left.mantissa < right.mantissa;
}
}


/**
/**
* @dev Checks if left Exp <= right Exp.
* @dev Checks if left Exp <= right Exp.
*/
*/
function lessThanOrEqualExp(
function lessThanOrEqualExp(
Exp memory left,
Exp memory left,
Exp memory right
Exp memory right
) internal pure returns (bool) {
) internal pure returns (bool) {
return left.mantissa <= right.mantissa;
return left.mantissa <= right.mantissa;
}
}


/**
/**
* @dev Checks if left Exp > right Exp.
* @dev Checks if left Exp > right Exp.
*/
*/
function greaterThanExp(
function greaterThanExp(
Exp memory left,
Exp memory left,
Exp memory right
Exp memory right
) internal pure returns (bool) {
) internal pure returns (bool) {
return left.mantissa > right.mantissa;
return left.mantissa > right.mantissa;
}
}


/**
/**
* @dev returns true if Exp is exactly zero
* @dev returns true if Exp is exactly zero
*/
*/
function isZeroExp(Exp memory value) internal pure returns (bool) {
function isZeroExp(Exp memory value) internal pure returns (bool) {
return value.mantissa == 0;
return value.mantissa == 0;
}
}


function safe224(
function safe224(
uint n,
uint n,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint224) {
) internal pure returns (uint224) {
require(n < 2 ** 224, errorMessage);
require(n < 2 ** 224, errorMessage);
return uint224(n);
return uint224(n);
}
}


function safe32(
function safe32(
uint n,
uint n,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint32) {
) internal pure returns (uint32) {
require(n < 2 ** 32, errorMessage);
require(n < 2 ** 32, errorMessage);
return uint32(n);
return uint32(n);
}
}


function add_(
function add_(
Exp memory a,
Exp memory a,
Exp memory b
Exp memory b
) internal pure returns (Exp memory) {
) internal pure returns (Exp memory) {
return Exp({mantissa: add_(a.mantissa, b.mantissa)});
return Exp({mantissa: add_(a.mantissa, b.mantissa)});
}
}


function add_(
function add_(
Double memory a,
Double memory a,
Double memory b
Double memory b
) internal pure returns (Double memory) {
) internal pure returns (Double memory) {
return Double({mantissa: add_(a.mantissa, b.mantissa)});
return Double({mantissa: add_(a.mantissa, b.mantissa)});
}
}


function add_(uint a, uint b) internal pure returns (uint) {
function add_(uint a, uint b) internal pure returns (uint) {
return add_(a, b, "addition overflow");
return add_(a, b, "addition overflow");
}
}


function add_(
function add_(
uint a,
uint a,
uint b,
uint b,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint) {
) internal pure returns (uint) {
uint c = a + b;
uint c = a + b;
require(c >= a, errorMessage);
require(c >= a, errorMessage);
return c;
return c;
}
}


function sub_(
function sub_(
Exp memory a,
Exp memory a,
Exp memory b
Exp memory b
) internal pure returns (Exp memory) {
) internal pure returns (Exp memory) {
return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
}
}


function sub_(
function sub_(
Double memory a,
Double memory a,
Double memory b
Double memory b
) internal pure returns (Double memory) {
) internal pure returns (Double memory) {
return Double({mantissa: sub_(a.mantissa, b.mantissa)});
return Double({mantissa: sub_(a.mantissa, b.mantissa)});
}
}


function sub_(uint a, uint b) internal pure returns (uint) {
function sub_(uint a, uint b) internal pure returns (uint) {
return sub_(a, b, "subtraction underflow");
return sub_(a, b, "subtraction underflow");
}
}


function sub_(
function sub_(
uint a,
uint a,
uint b,
uint b,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint) {
) internal pure returns (uint) {
require(b <= a, errorMessage);
require(b <= a, errorMessage);
return a - b;
return a - b;
}
}


function mul_(
function mul_(
Exp memory a,
Exp memory a,
Exp memory b
Exp memory b
) internal pure returns (Exp memory) {
) internal pure returns (Exp memory) {
return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
}
}


function mul_(Exp memory a, uint b) internal pure returns (Exp memory) {
function mul_(Exp memory a, uint b) internal pure returns (Exp memory) {
return Exp({mantissa: mul_(a.mantissa, b)});
return Exp({mantissa: mul_(a.mantissa, b)});
}
}


function mul_(uint a, Exp memory b) internal pure returns (uint) {
function mul_(uint a, Exp memory b) internal pure returns (uint) {
return mul_(a, b.mantissa) / expScale;
return mul_(a, b.mantissa) / expScale;
}
}


function mul_(
function mul_(
Double memory a,
Double memory a,
Double memory b
Double memory b
) internal pure returns (Double memory) {
) internal pure returns (Double memory) {
return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
}
}


function mul_(
function mul_(
Double memory a,
Double memory a,
uint b
uint b
) internal pure returns (Double memory) {
) internal pure returns (Double memory) {
return Double({mantissa: mul_(a.mantissa, b)});
return Double({mantissa: mul_(a.mantissa, b)});
}
}


function mul_(uint a, Double memory b) internal pure returns (uint) {
function mul_(uint a, Double memory b) internal pure returns (uint) {
return mul_(a, b.mantissa) / doubleScale;
return mul_(a, b.mantissa) / doubleScale;
}
}


function mul_(uint a, uint b) internal pure returns (uint) {
function mul_(uint a, uint b) internal pure returns (uint) {
return mul_(a, b, "multiplication overflow");
return mul_(a, b, "multiplication overflow");
}
}


function mul_(
function mul_(
uint a,
uint a,
uint b,
uint b,
string memory errorMessage
string memory errorMessage
) internal pure returns (uint) {
) internal pure returns (uint) {
if (a == 0 || b == 0) {
if (a == 0 || b == 0) {
return 0;
return 0;
}
}
uint c = a * b;
uint c = a * b;
require(c / a == b, errorMessage);
require(c / a == b, errorMessage);
return c;
return c;
}
}


function div_(
function div_(
Exp memory a,
Exp memory a,
Exp memory b
Exp memory b
) internal pure returns (Exp memory) {
) internal pure returns (Exp memory) {
return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
}
}


function div_(Exp memory a, uint b) internal pure returns (Exp memory) {
function div_(Exp memory a, uint b) internal pure returns (Exp memory) {
return Exp({mantissa: div_(a.mantissa, b)});
return Exp({mantissa: div_(a.mantissa, b)});
}
}


function div_(uint a, Exp memory b) internal pure returns (uint) {
function div_(uint a, Exp memory b) internal pure returns (uint) {
return div_(mul_(a, expScale), b.mantissa);
return div_(mul_(a, expScale), b.mantissa);
}
}


function div_(
function div_(
Double memory a,
Double memory a,
Double memory b
Double memory b
) internal pure returns (Double memory) {
) internal pure returns (Double memory) {
return
return
Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
}
}


function div_(
function div_(
Double memory a,
Double memory a,
uint b
uint b
) internal pure returns (Double memory) {
) internal pure returns (Double memory) {
return D
return Double({mantissa: div_(a.mantissa, b)});
}

function div_(uint a, Double memory b) internal pure returns (uint) {
return div_(mul_(a, doubleScale), b.mantissa);
}

function div_(uint a, uint b) internal pure returns (uint) {
return div_(a, b, "divide by zero");
}

function div_(
uint a,
uint b,
string memory errorMessage
) internal pure returns (uint) {
require(b > 0, errorMessage);
return a / b;
}

function fraction(uint a, uint b) internal pure returns (Double memory) {
return Double({mantissa: div_(mul_(a, doubleScale), b)});
Text moved from lines 218-220
}
}

// File src/Exponential.sol

pragma solidity 0.5.17;

/**
* @title Exponential module for storing fixed-precision decimals
* @author Moonwell
* @dev Legacy contract for compatibility reasons with existing contracts that still use MathError
* @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
* Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
* `Exp({mantissa: 5100000000000000000})`.
*/
contract Exponential is CarefulMath, ExponentialNoError {
/**
* @dev Creates an exponential from numerator and denominator values.
* Note: Returns an error if (`num` * 10e18) > MAX_INT,
* or if `denom` is zero.
*/
function getExp(
uint num,
uint denom
) internal pure returns (MathError, Exp memory) {
(MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}

(MathError err1, uint rational) = divUInt(scaledNumerator, denom);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}

return (MathError.NO_ERROR, Exp({mantissa: rational}));
Text moved with changes from lines 190-193 (91.7% similarity)
}

/**
* @dev Adds two exponentials, returning a new exponential.
*/
function addExp(
Exp memory a,
Exp memory b
Text moved from lines 201-213
) internal pure returns (MathError, Exp memory) {
(MathError error, uint result) = addUInt(a.mantissa, b.mantissa);

return (error, Exp({mantissa: result}));
}

/**
* @dev Subtracts two exponentials, returning a new exponential.
*/
function subExp(
Exp memory a,
Exp memory b
) internal pure returns (MathError, Exp memory) {
(MathError error, uint result) = subUInt(a.mantissa, b.mantissa);

return (error, Exp({mantissa: result}));
}

/**
* @dev Multiply an Exp by a scalar, returning a new Exp.
*/
function mulScalar(
Exp memory a,
uint scalar
) internal pure returns (MathError, Exp memory) {
(MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}

return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
}

/**
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
*/
function mulScalarTruncate(
Exp memory a,
uint scalar
) internal pure returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}

return (MathError.NO_ERROR, truncate(product));
}

/**
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
*/
function mulScalarTruncateAddUInt(
Exp memory a,
uint scalar,
uint addend
) internal pure returns (MathError, uint) {
(MathError err, Exp memory product) = mulScalar(a, scalar);
if (err != MathError.NO_ERROR) {
return (err, 0);
}

return addUInt(truncate(product), addend);
}

/**
* @dev Divide an Exp by a scalar, returning a new Exp.
*/
function divScalar(
Exp memory a,
uint scalar
) internal pure returns (MathError, Exp memory) {
(MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}

return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
}

/**
* @dev Divide a scalar by an Exp, returning a new Exp.
*/
function divScalarByExp(
uint scalar,
Exp memory divisor
) internal pure returns (MathError, Exp memory) {
/*
We are doing this as:
getExp(mulUInt(expScale, scalar), divisor.mantissa)

How it works:
Exp = a / b;
Scalar = s;
`s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
*/
(MathError err0, uint numerator) = mulUInt(expScale, scalar);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}
return getExp(numerator, divisor.mantissa);
}

/**
* @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
*/
function divScalarByExpTruncate(
uint scalar,
Exp memory divisor
) internal pure returns (MathError, uint) {
(MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
if (err != MathError.NO_ERROR) {
return (err, 0);
}

return (MathError.NO_ERROR, truncate(fraction));
}

/**
* @dev Multiplies two exponentials, returning a new exponential.
*/
function mulExp(
Exp memory a,
Exp memory b
) internal pure returns (MathError, Exp memory) {
(MathError err0, uint doubleScaledProduct) = mulUInt(
a.mantissa,
b.mantissa
);
if (err0 != MathError.NO_ERROR) {
return (err0, Exp({mantissa: 0}));
}

// We add half the scale before dividing so that we get rounding instead of truncation.
// See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
// Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
(MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(
halfExpScale,
doubleScaledProduct
);
if (err1 != MathError.NO_ERROR) {
return (err1, Exp({mantissa: 0}));
}

(MathError err2, uint product) = divUInt(
doubleScaledProductWithHalfScale,
expScale
);
// The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
assert(err2 == MathError.NO_ERROR);

return (MathError.NO_ERROR, Exp({mantissa: product}));
}

/**
* @dev Multiplies two exponentials given their mantissas, returning a new exponential.
*/
function mulExp(
uint a,
uint b
) internal pure returns (MathError, Exp memory) {
return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
}

/**
* @dev Multiplies three exponentials, returning a new exponential.
*/
function mulExp3(
Exp memory a,
Exp memory b,
Exp memory c
) internal pure returns (MathError, Exp memory) {
(MathError err, Exp memory ab) = mulExp(a, b);
if (err != MathError.NO_ERROR) {
return (err, ab);
}
return mulExp(ab, c);
}

/**
* @dev Divides two exponentials, returning a new exponential.
* (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
* which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
*/
function divExp(
Exp memory a,
Exp memory b
) internal pure returns (MathError, Exp memory) {
return getExp(a.mantissa, b.mantissa);
}
}

// File src/ComptrollerInterface.sol

pragma solidity 0.5.17;
Text moved from lines 378-504

contract ComptrollerInterface {
/// @notice Indicator that this is a Comptroller contract (for inspection)
bool public constant isComptroller = true;

/// @notice The amount of gas to use when making a native asset transfer.
uint16 public gasAmount;

/*** Assets You Are In ***/

function enterMarkets(
address[] calldata mTokens
) external returns (uint[] memory);

function exitMarket(address mToken) external returns (uint);

/*** Policy Hooks ***/

function mintAllowed(
address mToken,
address minter,
uint mintAmount
) external returns (uint);

function mintVerify(
address mToken,
address minter,
uint mintAmount,
uint mintTokens
) external;

function redeemAllowed(
address mToken,
address redeemer,
uint redeemTokens
) external returns (uint);

function redeemVerify(
address mToken,
address redeemer,
uint redeemAmount,
uint redeemTokens
) external;

function borrowAllowed(
address mToken,
address borrower,
uint borrowAmount
) external returns (uint);

function borrowVerify(
address mToken,
address borrower,
uint borrowAmount
) external;

function repayBorrowAllowed(
address mToken,
address payer,
address borrower,
uint repayAmount
) external returns (uint);

function repayBorrowVerify(
address mToken,
address payer,
address borrower,
uint repayAmount,
uint borrowerIndex
) external;

function liquidateBorrowAllowed(
address mTokenBorrowed,
address mTokenCollateral,
address liquidator,
address borrower,
uint repayAmount
) external returns (uint);

function liquidateBorrowVerify(
address mTokenBorrowed,
address mTokenCollateral,
address liquidator,
address borrower,
uint repayAmount,
uint seizeTokens
) external;

function seizeAllowed(
address mTokenCollateral,
address mTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens
) external returns (uint);

function seizeVerify(
address mTokenCollateral,
address mTokenBorrowed,
address liquidator,
address borrower,
uint seizeTokens
) external;

function transferAllowed(
address mToken,
address src,
address dst,
uint transferTokens
) external returns (uint);

function transferVerify(
address mToken,
address src,
address dst,
uint transferTokens
) external;

/*** Liquidity/Liquidation Calculations ***/

function liquidateCalculateSeizeTokens(
address mTokenBorrowed,
address mTokenCollateral,
uint repayAmount
) external view returns (uint, uint);
}

// File src/EIP20Interface.sol

pragma solidity 0.5.17;

/**
* @title ERC 20 Token Standard Interface
* https://eips.ethereum.org/EIPS/eip-20
*/
interface EIP20Interface {
function name() external view returns (string memory);

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

function decimals() external view returns (uint8);

Text moved with changes from lines 227-240 (98.0% similarity)
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);

/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);

/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(
address dst,
uint256 amount
) external returns (bool success);
Text moved from lines 258-263

/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(
address src,
address dst,
uint256 amount
Text moved from lines 265-298
) external returns (bool success);

/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(
address spender,
uint256 amount
) external returns (bool success);

/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(
address owner,
address spender
) external view returns (uint256 remaining);

event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(
address indexed owner,
address indexed spender,
uint256 amount
);
}

// File src/ErrorReporter.sol

pragma solidity 0.5.17;

Text moved from lines 3-99
contract ComptrollerErrorReporter {
enum Error {
NO_ERROR,
UNAUTHORIZED,
COMPTROLLER_MISMATCH,
INSUFFICIENT_SHORTFALL,
INSUFFICIENT_LIQUIDITY,
INVALID_CLOSE_FACTOR,
INVALID_COLLATERAL_FACTOR,
INVALID_LIQUIDATION_INCENTIVE,
MARKET_NOT_ENTERED, // no longer possible
MARKET_NOT_LISTED,
MARKET_ALREADY_LISTED,
MATH_ERROR,
NONZERO_BORROW_BALANCE,
PRICE_ERROR,
REJECTION,
SNAPSHOT_ERROR,
TOO_MANY_ASSETS,
TOO_MUCH_REPAY
}

enum FailureInfo {
ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
EXIT_MARKET_BALANCE_OWED,
EXIT_MARKET_REJECTION,
SET_CLOSE_FACTOR_OWNER_CHECK,
SET_CLOSE_FACTOR_VALIDATION,
SET_COLLATERAL_FACTOR_OWNER_CHECK,
SET_COLLATERAL_FACTOR_NO_EXISTS,
SET_COLLATERAL_FACTOR_VALIDATION,
SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
SET_IMPLEMENTATION_OWNER_CHECK,
SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
SET_LIQUIDATION_INCENTIVE_VALIDATION,
SET_MAX_ASSETS_OWNER_CHECK,
SET_PENDING_ADMIN_OWNER_CHECK,
SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
SET_PRICE_ORACLE_OWNER_CHECK,
SUPPORT_MARKET_EXISTS,
SUPPORT_MARKET_OWNER_CHECK,
SET_PAUSE_GUARDIAN_OWNER_CHECK,
SET_GAS_AMOUNT_OWNER_CHECK
}

/**
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
**/
event Failure(uint error, uint info, uint detail);

/**
* @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
*/
function fail(Error err, FailureInfo info) internal returns (uint) {
emit Failure(uint(err), uint(info), 0);

return uint(err);
}

/**
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
*/
function failOpaque(
Error err,
FailureInfo info,
uint opaqueError
) internal returns (uint) {
emit Failure(uint(err), uint(info), opaqueError);

return uint(err);
}
}

contract TokenErrorReporter {
enum Error {
NO_ERROR,
UNAUTHORIZED,
BAD_INPUT,
COMPTROLLER_REJECTION,
COMPTROLLER_CALCULATION_ERROR,
INTEREST_RATE_MODEL_ERROR,
INVALID_ACCOUNT_PAIR,
INVALID_CLOSE_AMOUNT_REQUESTED,
INVALID_COLLATERAL_FACTOR,
MATH_ERROR,
MARKET_NOT_FRESH,
MARKET_NOT_LISTED,
TOKEN_INSUFFICIENT_ALLOWANCE,
TOKEN_INSUFFICIENT_BALANCE,
TOKEN_INSUFFICIENT_CASH,
TOKEN_TRANSFER_IN_FAILED,
TOKEN_TRANSFER_OUT_FAILED
}

/*
* Note