Links

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

Code
Name
Description
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

Code
Name
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