Market Mechanics
Interacting with Morpho Markets involves a set of core functions and concepts that govern how assets are supplied, borrowed, and tracked. Unlike ERC4626 vaults, which have a standardized interface, Morpho's market interactions are defined by its unique internal accounting system.
This page explains the fundamental mechanics you need to understand to build a robust borrowing integration.
Core Data Structures
At the heart of Morpho are two key structs that define the state of every market and every user's position within it.
Market
Struct
This struct tracks the overall state of a single, isolated market.
struct Market {
uint128 totalSupplyAssets;
uint128 totalSupplyShares;
uint128 totalBorrowAssets;
uint128 totalBorrowShares;
uint128 lastUpdate;
uint128 fee;
}
totalSupply/BorrowAssets
: The total amount of the underlying token supplied or borrowed. This value changes as interest accrues.totalSupply/BorrowShares
: The total number of internal accounting units (shares) held by suppliers or borrowers. This value only changes with user interactions.
Position
Struct
This struct tracks an individual user's position within a specific market.
struct Position {
uint256 supplyShares;
uint128 borrowShares;
uint128 collateral;
}
collateral
: The amount of collateral the user has supplied to this specific market.
Assets vs. Shares: The Core Mechanic
The most critical concept to grasp is the relationship between Assets and Shares. This dual-accounting system is how Morpho manages positions and accrues interest.
Assets
- Definition: The actual, underlying tokens (e.g., USDC, WETH) that users interact with.
- Use Case: Ideal for user-facing interactions where a specific token amount is desired (e.g., "I want to borrow 1,000 USDC").
Shares
- Definition: Internal, non-transferable accounting units that represent a user's proportional stake in the market's total supply or debt.
- How it works: When you supply assets, you "buy" shares at the current exchange rate. As interest accrues in the market, the value of each share (its exchange rate back to assets) increases.
- Use Case: Ideal for protocol-level interactions and for ensuring full repayment or withdrawal, as it avoids rounding errors ("dust").
The Relationship: Share Price
The "price" of a share is its exchange rate to the underlying asset. This price is dynamic and increases as interest accrues.
// This is a conceptual calculation; the contract uses SharesMathLib for precision.
sharePrice = totalAssets / totalShares;
- For suppliers, the value of their shares grows over time, representing their earned yield.
- For borrowers, the asset value of their debt grows over time, representing the interest they owe.
Core Functions & Their Dual Nature
Most core functions in Morpho allow you to specify an amount in either assets
or shares
. You must provide a value for one and zero for the other.
supply
and borrow
function supply(uint256 assets, uint256 shares, ...);
function borrow(uint256 assets, uint256 shares, ...);
- Use
assets
> 0,shares
= 0: When a user wants to supply or borrow a precise amount of tokens. This is the most common use case for dApps. - Use
assets
= 0,shares
> 0: For advanced use cases where you need to mint a precise number of shares.
repay
and withdraw
function repay(uint256 assets, uint256 shares, ...);
function withdraw(uint256 assets, uint256 shares, ...);
- Use
assets
> 0,shares
= 0: For partial repayments or withdrawals where a specific token amount is needed. - Use
assets
= 0,shares
> 0: Recommended for full repayments/withdrawals. By specifying the user's exact share balance, you ensure their position is completely closed without leaving dust.
Collateral and Health
supplyCollateral
&withdrawCollateral
: These functions are straightforward and only operate onassets
. Collateral in Morpho does not earn yield and thus does not use a share-based system.- Position Health: A user's ability to borrow or withdraw collateral is determined by their Health Factor, which is a function of their collateral value, debt value, and the market's
lltv
.
Practical Implementation Snippets
Supplying Collateral & Borrowing (Asset-First)
// Conceptual TypeScript using a web3 library like Viem
// 1. Approve collateral tokens
await client.writeContract({ functionName: 'approve', args: [morphoAddress, collateralAmount] });
// 2. Supply collateral
await client.writeContract({ functionName: 'supplyCollateral', args: [marketParams, collateralAmount, userAddress] });
// 3. Borrow assets
const { result } = await client.simulateContract({
functionName: 'borrow',
args: [marketParams, borrowAmount, 0, userAddress, userAddress] // assets > 0, shares = 0
});
await client.writeContract(result.request);
Full Repayment (Shares-First)
// 1. Fetch the user's current borrow shares
const { borrowShares } = await client.readContract({
functionName: 'position',
args: [marketId, userAddress]
});
// 2. Approve the loan token for repayment
// The amount to approve should be slightly more than the expected asset value of the shares
// to account for interest accrued since the last block.
const repayAmountAssets = await client.readContract({
functionName: 'toAssetsUp', // using a helper or SDK function
args: [borrowShares, market.totalBorrowAssets, market.totalBorrowShares]
});
await client.writeContract({ functionName: 'approve', args: [morphoAddress, repayAmountAssets] });
// 3. Repay the full debt by specifying the exact shares
await client.writeContract({
functionName: 'repay',
args: [marketParams, 0, borrowShares, userAddress] // assets = 0, shares > 0
});
Best Practices
- For User-Facing Actions: Use the
assets
parameter forsupply
,borrow
, and partialrepay
/withdraw
as it's more intuitive for users. - For Closing Positions: Use the
shares
parameter for fullrepay
andwithdraw
operations to ensure the position is fully closed. - Slippage: When converting between assets and shares, be aware of potential slippage due to interest accrual between transaction simulation and execution. The Morpho SDKs and Bundlers handle this automatically.
- Interest Accrual: Remember that
totalBorrowAssets
andtotalSupplyAssets
are only updated when an interaction triggers_accrueInterest
. For the most up-to-date values, use a library likeMorphoBalancesLib
or the Morpho SDK.
By understanding these core mechanics, you can build safe, efficient, and user-friendly applications on top of Morpho Markets.