# Contract Interactions

## Core Functions

### Mint

Supply underlying ERC-20 tokens to the protocol and receive mTokens in return. The amount of mTokens minted is determined by the current exchange rate. Before calling `mint`, the caller must have approved the mToken contract to transfer the underlying token via `ERC20.approve()`.

To skip the separate `approve` step, use `mintWithPermit` if the underlying token supports EIP-2612 permits.

```solidity
function mint(uint mintAmount) external returns (uint)
```

| Parameter    | Type   | Description                                           |
| ------------ | ------ | ----------------------------------------------------- |
| `mintAmount` | `uint` | The amount of underlying tokens to supply             |
| **returns**  | `uint` | 0 on success, otherwise an [Error code](#error-codes) |

```solidity
function mintWithPermit(
    uint mintAmount,
    uint deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external returns (uint)
```

| Parameter    | Type      | Description                                           |
| ------------ | --------- | ----------------------------------------------------- |
| `mintAmount` | `uint`    | The amount of underlying tokens to supply             |
| `deadline`   | `uint`    | The permit signature deadline                         |
| `v`          | `uint8`   | The recovery byte of the permit signature             |
| `r`          | `bytes32` | Half of the ECDSA permit signature pair               |
| `s`          | `bytes32` | Half of the ECDSA permit signature pair               |
| **returns**  | `uint`    | 0 on success, otherwise an [Error code](#error-codes) |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...);
EIP20Interface underlying = EIP20Interface(mToken.underlying());

// Approve the mToken contract to spend underlying
uint mintAmount = 100e18;
underlying.approve(address(mToken), mintAmount);

// Mint mTokens
uint err = mToken.mint(mintAmount);
require(err == 0, "mint failed");
```

***

### Redeem

Redeem mTokens in exchange for the underlying asset. The amount of underlying returned is determined by the current exchange rate. Pass `type(uint).max` to redeem your entire mToken balance.

```solidity
function redeem(uint redeemTokens) external returns (uint)
```

| Parameter      | Type   | Description                                                               |
| -------------- | ------ | ------------------------------------------------------------------------- |
| `redeemTokens` | `uint` | The number of mTokens to redeem, or `type(uint).max` for the full balance |
| **returns**    | `uint` | 0 on success, otherwise an [Error code](#error-codes)                     |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...);
uint err = mToken.redeem(50e8);
require(err == 0, "redeem failed");
```

***

### Redeem Underlying

Redeem mTokens in exchange for a specified amount of the underlying asset. The protocol calculates how many mTokens to burn based on the current exchange rate. Pass `type(uint).max` to redeem all underlying.

```solidity
function redeemUnderlying(uint redeemAmount) external returns (uint)
```

| Parameter      | Type   | Description                                                                          |
| -------------- | ------ | ------------------------------------------------------------------------------------ |
| `redeemAmount` | `uint` | The amount of underlying tokens to receive, or `type(uint).max` for the full balance |
| **returns**    | `uint` | 0 on success, otherwise an [Error code](#error-codes)                                |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...);
uint err = mToken.redeemUnderlying(100e18);
require(err == 0, "redeemUnderlying failed");
```

***

### Borrow

Borrow underlying tokens from the protocol. The caller must have entered a market with sufficient collateral via the Comptroller's `enterMarkets` function before borrowing.

```solidity
function borrow(uint borrowAmount) external returns (uint)
```

| Parameter      | Type   | Description                                           |
| -------------- | ------ | ----------------------------------------------------- |
| `borrowAmount` | `uint` | The amount of underlying tokens to borrow             |
| **returns**    | `uint` | 0 on success, otherwise an [Error code](#error-codes) |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...);
uint err = mToken.borrow(50e18);
require(err == 0, "borrow failed");
```

***

### Repay Borrow

Repay a borrow position. The caller must approve the mToken contract to transfer the underlying token before calling. Pass `type(uint).max` as `repayAmount` to repay the entire outstanding balance.

```solidity
function repayBorrow(uint repayAmount) external returns (uint)
```

| Parameter     | Type   | Description                                                                 |
| ------------- | ------ | --------------------------------------------------------------------------- |
| `repayAmount` | `uint` | The amount of underlying to repay, or `type(uint).max` for the full balance |
| **returns**   | `uint` | 0 on success, otherwise an [Error code](#error-codes)                       |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...);
EIP20Interface underlying = EIP20Interface(mToken.underlying());
uint repayAmount = 50e18;

underlying.approve(address(mToken), repayAmount);
uint err = mToken.repayBorrow(repayAmount);
require(err == 0, "repayBorrow failed");
```

***

### Repay Borrow Behalf

Repay a borrow position on behalf of another account.

```solidity
function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint)
```

| Parameter     | Type      | Description                                                                 |
| ------------- | --------- | --------------------------------------------------------------------------- |
| `borrower`    | `address` | The account whose borrow to repay                                           |
| `repayAmount` | `uint`    | The amount of underlying to repay, or `type(uint).max` for the full balance |
| **returns**   | `uint`    | 0 on success, otherwise an [Error code](#error-codes)                       |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...);
EIP20Interface underlying = EIP20Interface(mToken.underlying());
uint repayAmount = 50e18;
address borrower = 0x...; // The account whose borrow to repay

underlying.approve(address(mToken), repayAmount);
uint err = mToken.repayBorrowBehalf(borrower, repayAmount);
require(err == 0, "repayBorrowBehalf failed");
```

***

### Liquidate Borrow

Liquidate an underwater borrower's position. The caller repays a portion of the borrower's debt and receives their collateral mTokens at a discount. The maximum repayable amount is determined by the Comptroller's `closeFactorMantissa`.

```solidity
function liquidateBorrow(
    address borrower,
    uint repayAmount,
    MTokenInterface mTokenCollateral
) external returns (uint)
```

| Parameter          | Type              | Description                                                                                                                                                                        |
| ------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `borrower`         | `address`         | The account to liquidate                                                                                                                                                           |
| `repayAmount`      | `uint`            | The amount of underlying to repay on behalf of the borrower. Unlike `repayBorrow`, `type(uint).max` is **not** supported - it returns error code `INVALID_CLOSE_AMOUNT_REQUESTED`. |
| `mTokenCollateral` | `MTokenInterface` | The mToken collateral to seize from the borrower                                                                                                                                   |
| **returns**        | `uint`            | 0 on success, otherwise an [Error code](#error-codes)                                                                                                                              |

**Solidity**

```solidity
MErc20 mToken = MErc20(0x...); // The borrowed market
MErc20 collateral = MErc20(0x...); // The collateral market
EIP20Interface underlying = EIP20Interface(mToken.underlying());
address borrower = 0x...; // The underwater account
uint repayAmount = 100e18;

underlying.approve(address(mToken), repayAmount);
uint err = mToken.liquidateBorrow(borrower, repayAmount, collateral);
require(err == 0, "liquidateBorrow failed");
```

***

### Seize

Transfer collateral mTokens from a borrower to a liquidator. This function is called internally by the **borrowed** mToken's `liquidateBorrow` to seize collateral from the **collateral** mToken. It should not be called directly by end users.

```solidity
function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint)
```

| Parameter     | Type      | Description                                           |
| ------------- | --------- | ----------------------------------------------------- |
| `liquidator`  | `address` | The account receiving seized mTokens                  |
| `borrower`    | `address` | The account being liquidated                          |
| `seizeTokens` | `uint`    | The number of mTokens to seize                        |
| **returns**   | `uint`    | 0 on success, otherwise an [Error code](#error-codes) |

***

### Add Reserves

Add underlying tokens to the protocol's reserves for a market.

```solidity
function _addReserves(uint addAmount) external returns (uint)
```

| Parameter   | Type   | Description                                           |
| ----------- | ------ | ----------------------------------------------------- |
| `addAmount` | `uint` | The amount of underlying to add to reserves           |
| **returns** | `uint` | 0 on success, otherwise an [Error code](#error-codes) |

***

## ERC-20 Functions

mTokens implement the standard ERC-20 interface. Transfers of mTokens are checked by the Comptroller - a transfer will fail if it would cause the sender's position to become undercollateralized.

```solidity
function transfer(address dst, uint256 amount) external returns (bool)
function transferFrom(address src, address dst, uint256 amount) external returns (bool)
function approve(address spender, uint256 amount) external returns (bool)
function allowance(address owner, address spender) external view returns (uint256)
function balanceOf(address owner) external view returns (uint256)
```

***

## Query Functions

### Underlying

Returns the address of the underlying ERC-20 token for this mToken market.

```solidity
function underlying() external view returns (address)
```

***

### Exchange Rate

The exchange rate determines how many underlying tokens each mToken is worth. As interest accrues, the exchange rate increases, meaning each mToken is redeemable for a growing amount of underlying.

The exchange rate is scaled by `1e(18 - 8 + underlyingDecimals)`. mTokens always have **8 decimals**. For example, an exchange rate of `2e26` for an underlying with 18 decimals means 1 mToken (1e8 units) = 2 underlying tokens (2e18 units).

Formula: `exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply`

```solidity
function exchangeRateCurrent() public returns (uint)
```

Accrues interest and returns the up-to-date exchange rate.

```solidity
function exchangeRateStored() public view returns (uint)
```

Returns the exchange rate as of the last accrual (no state change, gas-efficient for reads).

***

### Balance Of Underlying

Returns the mToken holder's balance denominated in the underlying asset, by applying the current exchange rate. This call accrues interest.

```solidity
function balanceOfUnderlying(address owner) external returns (uint)
```

| Parameter   | Type      | Description                  |
| ----------- | --------- | ---------------------------- |
| `owner`     | `address` | The account to query         |
| **returns** | `uint`    | The underlying token balance |

***

### Get Account Snapshot

Returns a snapshot of the account's current state without modifying storage.

```solidity
function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint)
```

| Parameter   | Type                       | Description                                                   |
| ----------- | -------------------------- | ------------------------------------------------------------- |
| `account`   | `address`                  | The account to query                                          |
| **returns** | `(uint, uint, uint, uint)` | `(error, mTokenBalance, borrowBalance, exchangeRateMantissa)` |

***

### Borrow Balance

```solidity
function borrowBalanceCurrent(address account) external returns (uint)
```

Accrues interest and returns the account's current borrow balance (including interest).

```solidity
function borrowBalanceStored(address account) public view returns (uint)
```

Returns the stored borrow balance without accruing interest (gas-efficient for reads).

| Parameter   | Type      | Description          |
| ----------- | --------- | -------------------- |
| `account`   | `address` | The account to query |
| **returns** | `uint`    | The borrow balance   |

***

### Interest Rates

```solidity
function borrowRatePerTimestamp() external view returns (uint)
```

Returns the current borrow interest rate per second, scaled by `1e18`.

```solidity
function supplyRatePerTimestamp() external view returns (uint)
```

Returns the current supply interest rate per second, scaled by `1e18`.

***

### Total Borrows

```solidity
function totalBorrowsCurrent() external returns (uint)
```

Accrues interest and returns the total outstanding borrows for the market.

***

### Get Cash

```solidity
function getCash() external view returns (uint)
```

Returns the amount of underlying tokens held by the mToken contract (available liquidity).

***

### Total Supply

```solidity
function totalSupply() public view returns (uint)
```

Returns the total number of mTokens in existence.

***

### Total Reserves

```solidity
function totalReserves() public view returns (uint)
```

Returns the total reserves held by the market.

***

### Reserve Factor

```solidity
function reserveFactorMantissa() public view returns (uint)
```

Returns the current reserve factor, scaled by `1e18`. This is the fraction of interest that goes to reserves.

***

### Accrue Interest

```solidity
function accrueInterest() public returns (uint)
```

Applies accrued interest to total borrows and reserves. Called automatically by most state-changing functions, but can be called manually to bring the market up to date.

\| **returns** | `uint` | 0 on success, otherwise an [Error code](#error-codes) |

***

## Events

| Event                        | Parameters                                                                                           |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- |
| `Mint`                       | `address minter, uint mintAmount, uint mintTokens`                                                   |
| `Redeem`                     | `address redeemer, uint redeemAmount, uint redeemTokens`                                             |
| `Borrow`                     | `address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows`                        |
| `RepayBorrow`                | `address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows`          |
| `LiquidateBorrow`            | `address liquidator, address borrower, uint repayAmount, address mTokenCollateral, uint seizeTokens` |
| `AccrueInterest`             | `uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows`                      |
| `Transfer`                   | `address indexed from, address indexed to, uint amount`                                              |
| `Approval`                   | `address indexed owner, address indexed spender, uint amount`                                        |
| `NewReserveFactor`           | `uint oldReserveFactorMantissa, uint newReserveFactorMantissa`                                       |
| `ReservesAdded`              | `address benefactor, uint addAmount, uint newTotalReserves`                                          |
| `ReservesReduced`            | `address admin, uint reduceAmount, uint newTotalReserves`                                            |
| `NewPendingAdmin`            | `address oldPendingAdmin, address newPendingAdmin`                                                   |
| `NewAdmin`                   | `address oldAdmin, address newAdmin`                                                                 |
| `NewComptroller`             | `ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller`                           |
| `NewMarketInterestRateModel` | `InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel`                     |
| `NewProtocolSeizeShare`      | `uint oldProtocolSeizeShareMantissa, uint newProtocolSeizeShareMantissa`                             |
| `Failure`                    | `uint error, uint info, uint detail`                                                                 |

***

## Error Codes

All mToken functions that return a `uint` use `0` to indicate success. Non-zero values correspond to the following errors:

| Code | Name                             | Description                                                       |
| ---- | -------------------------------- | ----------------------------------------------------------------- |
| 0    | `NO_ERROR`                       | Operation succeeded                                               |
| 1    | `UNAUTHORIZED`                   | Caller is not authorized                                          |
| 2    | `BAD_INPUT`                      | Invalid parameter provided                                        |
| 3    | `COMPTROLLER_REJECTION`          | Comptroller rejected the operation (e.g. insufficient collateral) |
| 4    | `COMPTROLLER_CALCULATION_ERROR`  | Internal comptroller calculation error                            |
| 5    | `INTEREST_RATE_MODEL_ERROR`      | Interest rate model returned an error                             |
| 6    | `INVALID_ACCOUNT_PAIR`           | Invalid liquidation - liquidator and borrower are the same        |
| 7    | `INVALID_CLOSE_AMOUNT_REQUESTED` | Liquidation close amount is invalid                               |
| 8    | `INVALID_COLLATERAL_FACTOR`      | Invalid collateral factor                                         |
| 9    | `MATH_ERROR`                     | Internal math error                                               |
| 10   | `MARKET_NOT_FRESH`               | Market interest has not been accrued to the current block         |
| 11   | `MARKET_NOT_LISTED`              | Market is not listed in the Comptroller                           |
| 12   | `TOKEN_INSUFFICIENT_ALLOWANCE`   | Caller has not approved enough underlying tokens                  |
| 13   | `TOKEN_INSUFFICIENT_BALANCE`     | Caller does not have enough underlying tokens                     |
| 14   | `TOKEN_INSUFFICIENT_CASH`        | Market does not have enough liquidity                             |
| 15   | `TOKEN_TRANSFER_IN_FAILED`       | Underlying token transfer into the market failed                  |
| 16   | `TOKEN_TRANSFER_OUT_FAILED`      | Underlying token transfer out of the market failed                |

Errors are also emitted via the `Failure(uint error, uint info, uint detail)` event, where `info` provides more specific context about what failed. See the [Failure Info](#failure-info) section below.

***

## Failure Info

The `info` field in the `Failure` event provides granular context. These correspond to the `FailureInfo` enum:

| 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_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED`  |
| 7    | `BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED`              |
| 8    | `BORROW_ACCRUE_INTEREST_FAILED`                              |
| 9    | `BORROW_CASH_NOT_AVAILABLE`                                  |
| 10   | `BORROW_FRESHNESS_CHECK`                                     |
| 11   | `BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED`                |
| 12   | `BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED`       |
| 13   | `BORROW_MARKET_NOT_LISTED`                                   |
| 14   | `BORROW_COMPTROLLER_REJECTION`                               |
| 15   | `LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED`                    |
| 16   | `LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED`                |
| 17   | `LIQUIDATE_COLLATERAL_FRESHNESS_CHECK`                       |
| 18   | `LIQUIDATE_COMPTROLLER_REJECTION`                            |
| 19   | `LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED`        |
| 20   | `LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX`                         |
| 21   | `LIQUIDATE_CLOSE_AMOUNT_IS_ZERO`                             |
| 22   | `LIQUIDATE_FRESHNESS_CHECK`                                  |
| 23   | `LIQUIDATE_LIQUIDATOR_IS_BORROWER`                           |
| 24   | `LIQUIDATE_REPAY_BORROW_FRESH_FAILED`                        |
| 25   | `LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED`                   |
| 26   | `LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED`                   |
| 27   | `LIQUIDATE_SEIZE_COMPTROLLER_REJECTION`                      |
| 28   | `LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER`                     |
| 29   | `LIQUIDATE_SEIZE_TOO_MUCH`                                   |
| 30   | `MINT_ACCRUE_INTEREST_FAILED`                                |
| 31   | `MINT_COMPTROLLER_REJECTION`                                 |
| 32   | `MINT_EXCHANGE_CALCULATION_FAILED`                           |
| 33   | `MINT_EXCHANGE_RATE_READ_FAILED`                             |
| 34   | `MINT_FRESHNESS_CHECK`                                       |
| 35   | `MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED`                |
| 36   | `MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED`                   |
| 37   | `MINT_TRANSFER_IN_FAILED`                                    |
| 38   | `MINT_TRANSFER_IN_NOT_POSSIBLE`                              |
| 39   | `REDEEM_ACCRUE_INTEREST_FAILED`                              |
| 40   | `REDEEM_COMPTROLLER_REJECTION`                               |
| 41   | `REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED`                  |
| 42   | `REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED`                  |
| 43   | `REDEEM_EXCHANGE_RATE_READ_FAILED`                           |
| 44   | `REDEEM_FRESHNESS_CHECK`                                     |
| 45   | `REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED`              |
| 46   | `REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED`                 |
| 47   | `REDEEM_TRANSFER_OUT_NOT_POSSIBLE`                           |
| 48   | `REDUCE_RESERVES_ACCRUE_INTEREST_FAILED`                     |
| 49   | `REDUCE_RESERVES_ADMIN_CHECK`                                |
| 50   | `REDUCE_RESERVES_CASH_NOT_AVAILABLE`                         |
| 51   | `REDUCE_RESERVES_FRESH_CHECK`                                |
| 52   | `REDUCE_RESERVES_VALIDATION`                                 |
| 53   | `REPAY_BEHALF_ACCRUE_INTEREST_FAILED`                        |
| 54   | `REPAY_BORROW_ACCRUE_INTEREST_FAILED`                        |
| 55   | `REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED`        |
| 56   | `REPAY_BORROW_COMPTROLLER_REJECTION`                         |
| 57   | `REPAY_BORROW_FRESHNESS_CHECK`                               |
| 58   | `REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED` |
| 59   | `REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED`          |
| 60   | `REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE`                      |
| 61   | `SET_COLLATERAL_FACTOR_OWNER_CHECK`                          |
| 62   | `SET_COLLATERAL_FACTOR_VALIDATION`                           |
| 63   | `SET_COMPTROLLER_OWNER_CHECK`                                |
| 64   | `SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED`             |
| 65   | `SET_INTEREST_RATE_MODEL_FRESH_CHECK`                        |
| 66   | `SET_INTEREST_RATE_MODEL_OWNER_CHECK`                        |
| 67   | `SET_MAX_ASSETS_OWNER_CHECK`                                 |
| 68   | `SET_ORACLE_MARKET_NOT_LISTED`                               |
| 69   | `SET_PENDING_ADMIN_OWNER_CHECK`                              |
| 70   | `SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED`                  |
| 71   | `SET_RESERVE_FACTOR_ADMIN_CHECK`                             |
| 72   | `SET_RESERVE_FACTOR_FRESH_CHECK`                             |
| 73   | `SET_RESERVE_FACTOR_BOUNDS_CHECK`                            |
| 74   | `TRANSFER_COMPTROLLER_REJECTION`                             |
| 75   | `TRANSFER_NOT_ALLOWED`                                       |
| 76   | `TRANSFER_NOT_ENOUGH`                                        |
| 77   | `TRANSFER_TOO_MUCH`                                          |
| 78   | `ADD_RESERVES_ACCRUE_INTEREST_FAILED`                        |
| 79   | `ADD_RESERVES_FRESH_CHECK`                                   |
| 80   | `ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE`                      |
| 81   | `SET_PROTOCOL_SEIZE_SHARE_ACCRUE_INTEREST_FAILED`            |
| 82   | `SET_PROTOCOL_SEIZE_SHARE_OWNER_CHECK`                       |
| 83   | `SET_PROTOCOL_SEIZE_SHARE_FRESH_CHECK`                       |
