# Core Market Integration

This guide walks through integrating your smart contract with Moonwell Core lending markets. By the end, you'll know how to supply assets, borrow against collateral, query positions, claim rewards, and handle errors.

## Prerequisites

Your contract needs to interact with two contracts:

* **mToken** - The market contract for each asset (e.g. mUSDC, mWETH). Handles supply, borrow, repay, withdraw, liquidate.
* **Comptroller** - The policy layer. Manages collateral, health checks, and rewards.

See [mTokens](https://docs.moonwell.fi/moonwell/developers/protocol/mtokens) and [Comptroller](https://docs.moonwell.fi/moonwell/developers/protocol/comptroller) for the full function reference.

## Step 1: Supply Assets

Supplying means depositing underlying tokens and receiving mTokens in return. Your mToken balance grows in value over time as interest accrues.

```solidity
MErc20 mToken = MErc20(0x...); // e.g. Moonwell USDC
EIP20Interface underlying = EIP20Interface(mToken.underlying());
uint supplyAmount = 1000e6; // 1,000 USDC

// Approve the mToken to pull underlying
underlying.approve(address(mToken), supplyAmount);

// Mint mTokens - returns 0 on success
uint err = mToken.mint(supplyAmount);
require(err == 0, "mint failed");
```

After minting, your contract holds mTokens. These are standard ERC-20 tokens - transferrable and composable.

## Step 2: Enable as Collateral

Supplying alone does not enable borrowing. You must explicitly enter the market via the Comptroller to use your supply as collateral.

```solidity
Comptroller comptroller = Comptroller(0x...);

address[] memory markets = new address[](1);
markets[0] = address(mToken);

uint[] memory errors = comptroller.enterMarkets(markets);
require(errors[0] == 0, "enterMarkets failed");
```

You can enter multiple markets in a single call. Once entered, your supply counts toward your borrowing capacity.

## Step 3: Borrow

With collateral enabled, you can borrow from any market up to your account liquidity.

```solidity
MErc20 mWETH = MErc20(0x...);
uint borrowAmount = 0.5 ether;

uint err = mWETH.borrow(borrowAmount);
require(err == 0, "borrow failed");
```

{% hint style="info" %}
Check your borrowing capacity first with `comptroller.getAccountLiquidity(address(this))`. The second return value (`liquidity`) is the USD value you can still borrow. The third (`shortfall`) is non-zero if you're underwater.
{% endhint %}

## Step 4: Repay and Withdraw

```solidity
// Repay the borrow
EIP20Interface weth = EIP20Interface(mWETH.underlying());
uint repayAmount = 0.5 ether;

weth.approve(address(mWETH), repayAmount);
uint err = mWETH.repayBorrow(repayAmount);
require(err == 0, "repay failed");

// Withdraw your supply (specify underlying amount)
err = mToken.redeemUnderlying(1000e6);
require(err == 0, "redeem failed");
```

Pass `type(uint).max` to `repayBorrow` to repay the full outstanding balance without calculating it yourself.

## Step 5: Query Positions

```solidity
// Get a snapshot of an account's position in a single market
(uint err, uint mTokenBalance, uint borrowBalance, uint exchangeRate) =
    mToken.getAccountSnapshot(account);

// Get overall account health (USD values, 18 decimal mantissa)
(uint error, uint liquidity, uint shortfall) =
    comptroller.getAccountLiquidity(account);

// liquidity > 0 means the account can borrow more
// shortfall > 0 means the account is liquidatable
```

## Step 6: Claim Rewards

Moonwell distributes WELL token rewards to suppliers and borrowers. Claim them through the Comptroller.

```solidity
// Claim all rewards for your contract
comptroller.claimReward();

// Or claim for a specific account across specific markets
MToken[] memory markets = new MToken[](2);
markets[0] = MToken(address(mUSDC));
markets[1] = MToken(address(mWETH));
comptroller.claimReward(address(this), markets);
```

## Error Handling

mToken and Comptroller functions use two failure modes. Your integration must handle both.

**Error codes** - Business logic rejections (insufficient collateral, comptroller rejection) return a non-zero `uint` without reverting:

```solidity
uint err = mToken.mint(amount);
require(err == 0, "mint failed"); // Always check the return value
```

**Reverts** - Transfer failures, math overflows, and pause/cap enforcement revert the transaction. Use try/catch if you need to handle these gracefully:

```solidity
try mToken.borrow(amount) returns (uint err) {
    require(err == 0, "borrow rejected");
} catch {
    // Transfer failed, market paused, or cap reached
}
```

See [mToken Error Codes](https://docs.moonwell.fi/moonwell/protocol/mtokens/contract-interactions#error-codes) and [Comptroller Error Codes](https://docs.moonwell.fi/moonwell/protocol/mtokens/contract-interactions#error-codes) for the full tables.

## Full Example

A complete contract that accepts deposits from users, supplies to Moonwell, borrows against the collateral, and allows withdrawal:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {MErc20} from "@moonwell/MErc20.sol";
import {EIP20Interface} from "@moonwell/EIP20Interface.sol";
import {ComptrollerInterface} from "@moonwell/ComptrollerInterface.sol";

contract MoonwellVault {
    MErc20 public immutable mToken;
    EIP20Interface public immutable underlying;
    ComptrollerInterface public immutable comptroller;

    constructor(address _mToken, address _comptroller) {
        mToken = MErc20(_mToken);
        underlying = EIP20Interface(mToken.underlying());
        comptroller = ComptrollerInterface(_comptroller);

        // Enter market on deployment so deposits can be used as collateral
        address[] memory markets = new address[](1);
        markets[0] = _mToken;
        comptroller.enterMarkets(markets);

        // Max approve once
        underlying.approve(_mToken, type(uint).max);
    }

    function deposit(uint amount) external {
        underlying.transferFrom(msg.sender, address(this), amount);
        uint err = mToken.mint(amount);
        require(err == 0, "mint failed");
    }

    function withdraw(uint amount) external {
        uint err = mToken.redeemUnderlying(amount);
        require(err == 0, "redeem failed");
        underlying.transfer(msg.sender, amount);
    }

    function getPosition() external view returns (uint mTokenBalance, uint borrowBalance, uint exchangeRate) {
        (uint err, uint bal, uint borrows, uint rate) =
            mToken.getAccountSnapshot(address(this));
        require(err == 0, "snapshot failed");
        return (bal, borrows, rate);
    }
}
```

## Deployed Addresses

See [mTokens - Deployed Contracts](https://docs.moonwell.fi/moonwell/protocol/mtokens#deployed-contracts) for all mToken market addresses on Base and OP Mainnet.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.moonwell.fi/moonwell/developers/guides/core-market-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
