# Vault Integration

This guide walks through integrating with Moonwell's Morpho Vaults. These vaults accept single-asset deposits and allocate funds across multiple Morpho Blue markets, optimizing yield automatically. They implement the standard ERC-4626 interface.

## Deployed Vaults

### Base

| Vault   | Address                                                                                                                 |
| ------- | ----------------------------------------------------------------------------------------------------------------------- |
| mwUSDC  | [`0xc1256Ae5FF1cf2719D4937adb3bbCCab2E00A2Ca`](https://basescan.org/address/0xc1256Ae5FF1cf2719D4937adb3bbCCab2E00A2Ca) |
| mwETH   | [`0xa0E430870c4604CcfC7B38Ca7845B1FF653D0ff1`](https://basescan.org/address/0xa0E430870c4604CcfC7B38Ca7845B1FF653D0ff1) |
| mwEURC  | [`0xf24608E0CCb972b0b0f4A6446a0BBf58c701a026`](https://basescan.org/address/0xf24608E0CCb972b0b0f4A6446a0BBf58c701a026) |
| mwcbBTC | [`0x543257ef2161176d7c8cd90ba65c2d4caef5a796`](https://basescan.org/address/0x543257ef2161176d7c8cd90ba65c2d4caef5a796) |

### OP Mainnet

| Vault  | Address                                                                                                                            |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| mwUSDC | [`0x3520E1a10038131A3C00Bf2158835A75e929642d`](https://optimistic.etherscan.io/address/0x3520E1a10038131A3C00Bf2158835A75e929642d) |

## Step 1: Deposit

Deposit underlying tokens into the vault and receive vault shares.

```solidity
IERC4626 vault = IERC4626(0xc1256Ae5FF1cf2719D4937adb3bbCCab2E00A2Ca); // mwUSDC on Base
IERC20 underlying = IERC20(vault.asset());
uint depositAmount = 1000e6; // 1,000 USDC

// Approve the vault to pull underlying
underlying.approve(address(vault), depositAmount);

// Deposit and receive shares
uint shares = vault.deposit(depositAmount, address(this));
```

You can also specify exactly how many shares you want with `mint()`:

```solidity
// Mint a specific number of vault shares
uint sharesToMint = 1000e18;

// previewMint tells you how many assets are needed for that many shares
uint assetsRequired = vault.previewMint(sharesToMint);

underlying.approve(address(vault), assetsRequired);
uint assets = vault.mint(sharesToMint, address(this));
```

## Step 2: Query Balances

```solidity
// Shares held by your contract
uint shares = vault.balanceOf(address(this));

// Convert shares to underlying value
uint underlyingValue = vault.convertToAssets(shares);

// Max you can deposit / withdraw right now
uint maxDeposit = vault.maxDeposit(address(this));
uint maxWithdraw = vault.maxWithdraw(address(this));
```

{% hint style="info" %}
`maxWithdraw` reflects available liquidity. If all deposited funds are currently lent out in Morpho markets, withdrawals may be limited until borrowers repay or new deposits come in.
{% endhint %}

## Step 3: Withdraw

Withdraw underlying tokens by specifying either an asset amount or a share amount.

```solidity
// Withdraw a specific amount of underlying
uint shares = vault.withdraw(500e6, msg.sender, address(this));

// Or redeem a specific number of shares
uint assets = vault.redeem(shares, msg.sender, address(this));
```

The `receiver` parameter lets you send withdrawn assets directly to another address. The `owner` parameter specifies whose shares to burn - if it's not `msg.sender`, the caller needs an ERC-20 allowance on the vault shares.

## Building on Top

Your contract can accept user deposits, route them into a Moonwell vault, and issue its own token on top. Since Morpho vaults are ERC-4626, this works with any standard vault integration.

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

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";

/// @notice Example: a wrapper that deposits into a Moonwell Morpho vault
///         and issues its own token backed by vault shares
contract YieldProduct is ERC20 {
    IERC4626 public immutable vault;
    IERC20 public immutable asset;

    constructor(address _vault) ERC20("Yield Token", "yTKN") {
        vault = IERC4626(_vault);
        asset = IERC20(vault.asset());
        asset.approve(_vault, type(uint).max);
    }

    function deposit(uint amount) external {
        asset.transferFrom(msg.sender, address(this), amount);

        // Deposit into Moonwell Morpho vault
        uint shares = vault.deposit(amount, address(this));

        // Mint product tokens proportional to vault shares received
        _mint(msg.sender, shares);
    }

    function withdraw(uint shareAmount) external {
        _burn(msg.sender, shareAmount);

        // Redeem vault shares directly to the user
        vault.redeem(shareAmount, msg.sender, address(this));
    }

    /// @notice Total underlying held in the vault
    function totalUnderlying() external view returns (uint) {
        return vault.convertToAssets(vault.balanceOf(address(this)));
    }
}
```

Product tokens map 1:1 to vault shares. As the vault accrues yield, each share becomes redeemable for more underlying over time.
