Morpho Earn Integration Guide - Solidity
Smart Contract Functions
When integrating Morpho Vaults into your application, you'll primarily work with the ERC4626 standard interface functions. This guide focuses on the core deposit and withdrawal functions that your users will need.
Approval
Before any deposit can occur, users must approve the Morpho Vault to use their tokens. A basic allowance or permit function is required.
Basic approval
// First approve the vault to spend your tokens
IERC20(underlyingToken).approve(vaultAddress, amount);
permit approval
All Morpho Vaults implement EIP-2612 permit, allowing for gasless approvals:
// Gasless approval using permit
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
Deposit & Mint
Morpho Vaults offer two methods for depositing assets:
Deposit
Use deposit()
when you know exactly how many tokens you want to deposit. This can be considered as an "Asset-First Approach"
// Deposit exactly 1000 USDC into the vault
uint256 amountToDeposit = 1000 * 10**6; // 1000 USDC with 6 decimals
uint256 sharesReceived = IMetaMorpho(vaultAddress).deposit(amountToDeposit, receiverAddress);
When to use: Most common scenario - user knows how much they want to deposit.
Mint
Use mint()
when you want to receive a specific number of vault shares. This can be considered as a "Shares-First Approach"
// Mint exactly 500 vault shares
uint256 sharesToMint = 500 * 10**18; // 500 shares with 18 decimals
uint256 assetsDeposited = IMetaMorpho(vaultAddress).mint(sharesToMint, receiverAddress);
When to use: User wants to receive a specific number of vault shares.
Withdraw & Redeem
Morpho Vaults also offer two methods for withdrawing assets:
Withdraw
Use withdraw()
when you want to receive a specific amount of underlying tokens. This can be considered as an "Asset-First Approach"
// Withdraw exactly 500 USDC from the vault
uint256 amountToWithdraw = 500 * 10**6; // 500 USDC with 6 decimals
uint256 sharesBurned = IMetaMorpho(vaultAddress).withdraw(
amountToWithdraw,
receiverAddress, // Where to send the tokens
ownerAddress // Who owns the shares being burned
);
When to use: When users need a specific amount of tokens.
Redeem
Use redeem()
when you want to withdraw with a specific amount of vault shares. This can be considered as a "Shares-First Approach"
// Redeem exactly 300 vault shares
uint256 sharesToRedeem = 300 * 10**18; // 300 shares with 18 decimals
uint256 assetsReceived = IMetaMorpho(vaultAddress).redeem(
sharesToRedeem,
receiverAddress, // Where to send the tokens
ownerAddress // Who owns the shares being burned
);
When to use: For full withdrawals, this is typically better as it avoids dust.
Key Differences
Understanding the differences is crucial for proper integration:
Function | Input | Output | Use Case |
---|---|---|---|
deposit | Asset amount | Shares received | Most common: "I want to deposit X tokens" |
mint | Shares amount | Assets required | Advanced: "I want exactly Y shares" |
withdraw | Asset amount | Shares burned | Specific: "I need X tokens back" |
redeem | Shares amount | Assets received | Best for full exit: "Redeem all my shares" |
Practical Implementation Tips
For Deposits:
- Always use
deposit()
unless you have a specific reason to usemint()
- Remember to handle approvals before calling deposit functions
For Withdrawals:
- Use
redeem()
for full withdrawals to avoid dust - Use
withdraw()
when users need specific token amounts - Check
maxRedeem()
andmaxWithdraw()
before executing to avoid reverts
Gas Optimization:
- For large vaults with many markets, withdrawals may be gas-intensive
Edge Case:
- During high utilization, withdrawals may be limited by available liquidity in the resp. market where the vault allocated its liquidity into