mToken

In the Market Protocol, each mToken contract can be thought of as an individual vault that stores an underlying asset for a pool. Each underlying asset has its own mToken and they are unique to each pool, thanks to the isolation provided by the protocol. Also in our docs, we use CToken and MToken interchangeably.

Implementation

The mToken contract is implemented as an upgradable proxy, where the CTokenDelegator contract proxies all interactions/logic to CTokenDelegate while using the storage of CTokenDelegator. To learn more about upgradable proxies, read Proxy Upgradable Pattern by OpenZeppelin.

Some Important Terms

Exchange Rate

Each mToken is convertible into an ever increasing quantity of the underlying asset, as interest accrues in the market.

Interest Calculation

The APY for supplying or borrowing into a mToken in any given pool, can be calculated very easily, here's a sample snippet:

uint256 supplyRate = mToken.supplyRatePerBlock();
uint256 blocksPerDay = (60 * 60 * 24)/2 // for polygon that has 1 block per 2s
uint256 year = 365; // 1yr = 365d
uint256 mantissa = 1e18;

uint256 APY = ((((supplyRate * blocksPerDay)/mantissa)+1)**year - 1) * 100;

Reserves

Reserves are an accounting entry in each mToken contract that represents a portion of historical interest set aside as cash which can be withdrawn or transferred through the protocol's governance. A small portion of borrower interest accrues into the protocol, determined by the reserve factor.

Reserve factor is the fraction of interest that is set-aside for reserves.

View Methods

exchangeRateCurrent -> uint

function exchangeRateCurrent() external returns (uint);
  • returns - The current exchange rate as an unsigned integer, scaled by 1e18.

getCash -> uint

function getCash() external view returns (uint);
  • returns - The total amount of underlying balance owned by the contract as an unsigned integer, scaled by 1e18.

totalBorrowsCurrent -> uint

function totalBorrowsCurrent() external returns (uint);
  • returns - The total amount of underlying that has been currently loaned out to users with interest included.

  • note - use eth_call on this function, otherwise it will create a transaction.

totalSupply -> uint

function totalSupply() external view returns(uint);
  • returns - The total number of tokens that are in circulation

totalReserves -> uint

function totalReserves() external view returns(uint);
  • returns - The total amount of reserves of the underlying held in this mToken

balanceOfUnderlying(address) -> uint

function balanceOfUnderlying(address account) external returns(uint);
  • returns - The total amount of underlying asset owned by a user that is held in this contract

  • note - use eth_call on this function, otherwise it will create a transaction.

  • This is calculated by multiplying the exchangeRate with the number of mTokens the user holds

borrowRatePerBlock -> uint

function borrowRatePerBlock() external view returns (uint);
  • returns - The current per-block borrow interest rate for this mToken scaled by 1e18.

supplyRatePerBlock -> uint

function supplyRatePerBlock() external view returns (uint);
  • returns - The current per-block supply interest rate for this mToken scaled by 1e18.

reserveFactorMantissa -> uint

function reserveFactorMantissa() external view returns(uint);
  • returns - Reserve Factor of the mToken which is fraction of interest currently set aside for reserves. It is scaled to 18 decimals.

adminFeeMantissa -> uint

function adminFeeMantissa() external view returns(uint);
  • returns - The admin fee charged by the pool administrator. It is scaled to 18 decimals.

Write Methods

mint(uint) -> uint

function mint(uint mintAmount) external returns (uint);

Allows a user to deposit underlying into this mToken. approve must be called on the underlying for this contract.

  • mintAmount - the amount of underlying to be deposited

  • returns - an error code. 0 is a success and anything else is a failure.

borrow(uint) -> uint

function borrow(uint borrowAmount) external returns (uint);

Allows a user who has collateral in the pool, to borrow from this mToken.

  • borrowAmount - the amount of underlying to be borrowed

  • returns - an error code. 0 is a success and anything else is a failure.

redeem(uint) -> uint

function redeem(uint redeemTokens) external returns (uint);

Allows a user who has supplied underlying in this mToken to redeem it back based on the number of mTokens they want. It uses exchangeRate internally to convert number of mTokens to underlying tokens.

  • redeemAmount - the number of mTokens against which the user wants to redeem underlying

  • returns - an error code. 0 is a success and anything else is a failure

redeemUnderlying(uint) -> uint

function redeemUnderlying(uint redeemAmount) external returns (uint);

Allows a user who has supplied underlying in this mToken to redeem it back based on the number of underlying tokens they want.

  • redeemAmount - the number of underlying tokens which they want to redeem

  • returns - an error code. 0 is a success and anything else is a failure

repayBorrow(uint) -> uint

function repayBorrow(uint repayAmount) external returns (uint);

Allows a user to repay their loan previously taken from this mToken

  • repayAmount - the number of underlying tokens the user wants to repay

  • returns - an error code. 0 is a success and anything else is a failure

repayBorrowBehalf(address, uint) -> uint

function repayBorrowBehalf(
    address borrower, 
    uint repayAmount
) external returns (uint);

Allows a user to repay a loan on someone else's behalf

  • borrower - address of the borrower's account for which the user wants to repay

  • repayAmount - the number of underlying tokens the user wants to repay

  • returns - an error code. 0 is a success and anything else is a failure

liquidateBorrow(address, uint, address) -> uint

function liquidateBorrow(
    address borrower, 
    uint repayAmount, 
    address mTokenCollateral
) external returns (uint);

Allows a user to liquidate an unhealthy borrower's debt and gain liquidation incentive for doing this.

  • borrower - the account which is being liquidated

  • repayAmount - the number of underlying tokens the user wants to repay

  • mTokenCollateral - the mToken to be received for liquidating this account's debt

  • returns - an error code. 0 is a success and anything else is a failure

_setAdminFee(uint) -> uint

function _setAdminFee(uint newAdminFeeMantissa) external returns (uint);

Allows pool administrators to set an admin fee for managing this asset.

  • newAdminFeeMantissa - the new admin fee to be set. scaled to 18 decimals.

  • returns - an error code. 0 is a success and anything else is a failure.

_setReserveFactor(uint) -> uint

function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint);

Allows pool administrators to set the reserve factor, which contributes a fraction of the interest into reserves.

  • newReserveFactorMantissa - the new reserve factor value to be set. scaled to 18 decimals.

  • returns - an error code. 0 is a success and anything else is a failure.

_setInterestRateModel(address) -> uint

function _setInterestRateModel(
    address newInterestRateModel
) external returns (uint);

Allows pool administrators to set a new interest rate model for this mToken.

  • newInterestRateModel - address of the new interest rate model contract

  • returns - an error code. 0 is a success and anything else is a failure.

_setNameAndSymbol(string, string) -> uint

function _setNameAndSymbol(
    string calldata _name, 
    string calldata _symbol
) external;

Allows pool administrators to change the name/symbol of this mToken to their desired name/symbol.

Error Codes

CodeNameDescription

0

NO_ERROR

Success. Not an error.

1

UNAUTHORIZED

The sender is not authorized to perform this action.

2

BAD_INPUT

An invalid argument was supplied by the caller.

3

COMPTROLLER_REJECTION

The comptroller rejects the action requested by the market/mToken.

4

COMPTROLLER_CALCULATION_ERROR

An internal calculation has failed in the comptroller.

5

INTEREST_RATE_MODEL_ERROR

The interest rate model returned an invalid value.

6

INVALID_ACCOUNT_PAIR

The specified combination of accounts is invalid.

7

INVALID_CLOSE_AMOUNT_REQUESTED

The amount to liquidate is invalid.

8

INVALID_COLLATERAL_FACTOR

The collateral factor is invalid.

9

MATH_ERROR

A math calculation error occurred.

10

MARKET_NOT_FRESH

Interest has not been properly accrued.

11

MARKET_NOT_LISTED

The mToken is not currently listed by its comptroller.

12

TOKEN_INSUFFICIENT_ALLOWANCE

ERC-20 contract must allow mToken contract to call transferFrom. The current allowance is either 0 or less than the requested supply, repayBorrow or liquidate amount.

13

TOKEN_INSUFFICIENT_BALANCE

Caller does not have sufficient balance in the ERC-20 contract to complete the desired action.

14

TOKEN_INSUFFICIENT_CASH

The mToken does not have a sufficient cash balance to complete the transaction. You may attempt this transaction again later.

15

TOKEN_TRANSFER_IN_FAILED

Failure in ERC-20 when transferring token into the mToken.

16

TOKEN_TRANSFER_OUT_FAILED

Failure in ERC-20 when transferring token out of the mToken.

17

UTILIZATION_ABOVE_MAX

No more of this token can be borrowed right now.

Failure Info

CodeName

0

ACCEPT_ADMIN_PENDING_ADMIN_CHECK

1

ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED

2

ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED

3

ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED

4

ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED

5

ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED

6

ACCRUE_INTEREST_NEW_TOTAL_FUSE_FEES_CALCULATION_FAILED

7

ACCRUE_INTEREST_NEW_TOTAL_ADMIN_FEES_CALCULATION_FAILED

8

ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED

9

BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED

10

BORROW_ACCRUE_INTEREST_FAILED

11

BORROW_CASH_NOT_AVAILABLE

12

BORROW_FRESHNESS_CHECK

13

BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED

14

BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED

15

BORROW_MARKET_NOT_LISTED

16

BORROW_COMPTROLLER_REJECTION

17

LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED

18

LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED

19

LIQUIDATE_COLLATERAL_FRESHNESS_CHECK

20

LIQUIDATE_COMPTROLLER_REJECTION

21

LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED

22

LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX

23

LIQUIDATE_CLOSE_AMOUNT_IS_ZERO

24

LIQUIDATE_FRESHNESS_CHECK

25

LIQUIDATE_LIQUIDATOR_IS_BORROWER

26

LIQUIDATE_REPAY_BORROW_FRESH_FAILED

27

LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED

28

LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED

29

LIQUIDATE_SEIZE_COMPTROLLER_REJECTION

30

LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER

31

LIQUIDATE_SEIZE_TOO_MUCH

32

MINT_ACCRUE_INTEREST_FAILED

33

MINT_COMPTROLLER_REJECTION

34

MINT_EXCHANGE_CALCULATION_FAILED

35

MINT_EXCHANGE_RATE_READ_FAILED

36

MINT_FRESHNESS_CHECK

37

MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED

38

MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED

39

MINT_TRANSFER_IN_FAILED

40

MINT_TRANSFER_IN_NOT_POSSIBLE

41

NEW_UTILIZATION_RATE_ABOVE_MAX

42

REDEEM_ACCRUE_INTEREST_FAILED

43

REDEEM_COMPTROLLER_REJECTION

44

REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED

45

REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED

46

REDEEM_EXCHANGE_RATE_READ_FAILED

47

REDEEM_FRESHNESS_CHECK

48

REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED

49

REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED

50

REDEEM_TRANSFER_OUT_NOT_POSSIBLE

51

WITHDRAW_PROTOCOL_FEES_ACCRUE_INTEREST_FAILED

52

WITHDRAW_PROTOCOL_FEES_CASH_NOT_AVAILABLE

53

WITHDRAW_PROTOCOL_FEES_FRESH_CHECK

54

WITHDRAW_PROTOCOL_FEES_VALIDATION

55

WITHDRAW_ADMIN_FEES_ACCRUE_INTEREST_FAILED

56

WITHDRAW_ADMIN_FEES_CASH_NOT_AVAILABLE

57

WITHDRAW_ADMIN_FEES_FRESH_CHECK

58

WITHDRAW_ADMIN_FEES_VALIDATION

59

REDUCE_RESERVES_ACCRUE_INTEREST_FAILED

60

REDUCE_RESERVES_ADMIN_CHECK

61

REDUCE_RESERVES_CASH_NOT_AVAILABLE

62

REDUCE_RESERVES_FRESH_CHECK

63

REDUCE_RESERVES_VALIDATION

64

REPAY_BEHALF_ACCRUE_INTEREST_FAILED

65

REPAY_BORROW_ACCRUE_INTEREST_FAILED

66

REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED

67

REPAY_BORROW_COMPTROLLER_REJECTION

68

REPAY_BORROW_FRESHNESS_CHECK

69

REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED

70

REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED

71

REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE

72

SET_COLLATERAL_FACTOR_OWNER_CHECK

73

SET_COLLATERAL_FACTOR_VALIDATION

74

SET_COMPTROLLER_OWNER_CHECK

75

SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED

76

SET_INTEREST_RATE_MODEL_FRESH_CHECK

77

SET_INTEREST_RATE_MODEL_OWNER_CHECK

78

SET_MAX_ASSETS_OWNER_CHECK

79

SET_ORACLE_MARKET_NOT_LISTED

80

SET_ORACLE_MARKET_NOT_LISTED

81

SET_PENDING_ADMIN_OWNER_CHECK

82

SET_ADMIN_FEE_ACCRUE_INTEREST_FAILED

83

SET_ADMIN_FEE_ADMIN_CHECK

84

SET_ADMIN_FEE_FRESH_CHECK

85

SET_ADMIN_FEE_BOUNDS_CHECK

86

SET_PROTOCOL_FEE_ACCRUE_INTEREST_FAILED

87

SET_PROTOCOL_FEE_FRESH_CHECK

88

SET_PROTOCOL_FEE_BOUNDS_CHECK

89

SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED

90

SET_RESERVE_FACTOR_ADMIN_CHECK

91

SET_RESERVE_FACTOR_FRESH_CHECK

92

SET_RESERVE_FACTOR_BOUNDS_CHECK

93

TRANSFER_COMPTROLLER_REJECTION

94

TRANSFER_NOT_ALLOWED

95

TRANSFER_NOT_ENOUGH

96

TRANSFER_TOO_MUCH

97

ADD_RESERVES_ACCRUE_INTEREST_FAILED

98

ADD_RESERVES_FRESH_CHECK

99

ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE

Last updated