Morpho Borrow Integration Guide - Solidity
This guide explains how to integrate the borrowing functionality of Morpho into your application. It covers four core functions: supplying collateral, borrowing assets, repaying debt, and withdrawing collateral.
Market Parameters
Every interaction with Morpho requires specifying a market using the MarketParams
structure:
struct MarketParams {
address loanToken; // Token that can be borrowed and supplied
address collateralToken; // Token that can be used as collateral
address oracle; // Oracle that can be used to price loan and collateral token
address irm; // Interest rate model
uint256 lltv; // Liquidation loan-to-value ratio
}
Each market is uniquely identified by these parameters, which must be passed to every function call.
Understanding Assets vs. Shares
Morpho offers two approaches for most operations:
- Asset-First Approach: Specify the exact token amount (e.g., "1000 USDC")
- Shares-First Approach: Specify the exact shares amount (internal accounting units)
This dual approach enables both intuitive user experiences and precision accounting.
Concept | Description |
---|---|
Assets | The actual tokens (USDC, DAI, etc.) with their respective decimals |
Shares | Internal accounting units that represent proportional ownership |
Supplying Collateral
Before borrowing, supply collateral to secure the loan position.
Function Signature
function supplyCollateral(
MarketParams memory marketParams,
uint256 assets,
address onBehalf,
bytes memory data
) external;
Required Steps
-
Approve token transfer:
IERC20(collateralToken).approve(morphoAddress, collateralAmount);
-
Supply collateral:
IMorpho(morphoAddress).supplyCollateral( marketParams, collateralAmount, address(this), // Supply on behalf of this contract "" // No callback data needed );
Important Notes
- This function only accepts assets (no shares parameter)
- Collateral does not earn yield in Morpho's base implementation
- Ensure sufficient token approval before calling
Borrowing Assets
After supplying collateral, borrow assets against it.
Function Signature
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
Required Steps
// Specify exact amount of assets to borrow
(uint256 assetsBorrowed, uint256 sharesBorrowed) = IMorpho(morphoAddress).borrow(
marketParams,
borrowAmount, // Amount of assets to borrow
0, // Use 0 for shares when specifying assets
address(this), // Borrow on behalf of this contract
address(this) // Send borrowed assets to this contract
);
Asset-First vs. Shares-First Approach
- Use assets (assets > 0, shares = 0): For borrowing a specific token amount ✓
- Use shares (assets = 0, shares > 0): For advanced use cases requiring share precision
Borrow Limits
Borrowing is limited by:
- Collateral value
- Market's LLTV (Liquidation Loan-To-Value)
- Position health requirement (debt ≤ collateral × LLTV)
Repaying Debt
Repay borrowed assets to reduce or eliminate debt.
Function Signature
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
Required Steps
-
Approve token transfer:
IERC20(loanToken).approve(morphoAddress, repayAmount);
-
Partial repayment (asset-based):
(uint256 assetsRepaid, uint256 sharesRepaid) = IMorpho(morphoAddress).repay( marketParams, repayAmount, // Amount of assets to repay 0, // Use 0 for shares when specifying assets address(this), // Repay on behalf of this contract "" // No callback data needed );
-
Full repayment (share-based - recommended):
// Fetch current borrow shares from position uint256 borrowShares = position[id][address(this)].borrowShares; (uint256 assetsRepaid, uint256 sharesRepaid) = IMorpho(morphoAddress).repay( marketParams, 0, // Use 0 for assets when specifying shares borrowShares, // Repay exact shares amount (full repayment) address(this), // Repay on behalf of this contract "" // No callback data needed );
When to Use Each Approach
- For partial repayments: Use assets parameter (assets > 0, shares = 0)
- For full repayments: Use shares parameter (assets = 0, shares > 0) to avoid dust
Security Considerations
- Always check for sufficient approvals before calling
- Always check for the health factor of the future loan position. Consider always adding buffer for users for protection.
Withdrawing Collateral
Retrieve collateral after repaying debt.
Function Signature
function withdrawCollateral(
MarketParams memory marketParams,
uint256 assets,
address onBehalf,
address receiver
) external;
Required Steps
IMorpho(morphoAddress).withdrawCollateral(
marketParams,
withdrawAmount, // Amount of collateral to withdraw
address(this), // Withdraw on behalf of this contract
address(this) // Send withdrawn collateral to this contract
);
Important Notes
- Can only withdraw if position remains healthy afterward
- Full withdrawal is possible when no outstanding debt exists
- Position health check prevents excessive withdrawal when debt exists
Complete Borrowing Workflow
Here's the complete borrowing and repayment workflow:
// 1. Approve collateral tokens
IERC20(collateralToken).approve(morphoAddress, collateralAmount);
// 2. Supply collateral
IMorpho(morphoAddress).supplyCollateral(
marketParams,
collateralAmount,
address(this),
""
);
// 3. Borrow assets against collateral
(uint256 assetsBorrowed, uint256 sharesBorrowed) = IMorpho(morphoAddress).borrow(
marketParams,
borrowAmount,
0,
address(this),
address(this)
);
// ... Use borrowed assets ...
// 4. Approve loan tokens for repayment
IERC20(loanToken).approve(morphoAddress, repayAmount);
// 5. Repay debt (using shares for full repayment)
(uint256 assetsRepaid, uint256 sharesRepaid) = IMorpho(morphoAddress).repay(
marketParams,
0,
sharesBorrowed, // Repay full amount of shares
address(this),
""
);
// 6. Withdraw collateral
IMorpho(morphoAddress).withdrawCollateral(
marketParams,
collateralAmount,
address(this),
address(this)
);
Best Practices for Borrowing Integration
For Collateral Management
- Apply a safety margin when calculating collateral requirements
- Monitor price fluctuations that could affect position health
- Consider over-collateralizing to reduce liquidation risk
For Borrowing
- Use asset-based approach (assets > 0, shares = 0) for most use cases
- Verify market liquidity before attempting large borrows
- Calculate maximum borrow amount based on collateral and LLTV, and be sure users are protected with a buffer.
For Repayment
- Use share-based approach for full repayments to avoid dust
- Use asset-based approach for partial repayments
For Withdrawing Collateral
- Check position health before attempting withdrawals
- Batch repayments and withdrawals when possible for gas efficiency
Function Selection Guide
Operation | Function | Approach | When to Use |
---|---|---|---|
Add Collateral | supplyCollateral | Assets only | Before borrowing to secure position |
Borrow | borrow with assets | Asset-First | When exact token amount is needed |
Borrow | borrow with shares | Share-First | Advanced integration with share accounting |
Partial Repay | repay with assets | Asset-First | When repaying specific token amount |
Full Repay | repay with shares | Share-First | When repaying entire debt to avoid dust |
Remove Collateral | withdrawCollateral | Assets only | After repaying to retrieve collateral |
By following these patterns, you can build robust integrations with Morpho's borrowing functionality.