Skip to content

← Back to contracts

Interest Rate Models

Code

Interest rate models are defined as a list of governance-approved contracts. Each contract implements the IRM interface exposed below.

Function

borrowRate

function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256);

Returns the borrow rate of the market marketParams.

Parameters:

NameTypeDescription
marketParamsMarketParamsThe MarketParams struct of the market.
marketMarketThe Market struct of the market.

Return values:

NameTypeDescription
borrowRateuint256The borrow rate of the market.

View Function

borrowRateView:

function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256);

Returns the borrow rate of the market marketParams without modifying any storage.

Parameters:

NameTypeDescription
marketParamsMarketParamsThe MarketParams struct of the market.
marketMarketThe Market struct of the market.

Return values:

NameTypeDescription
borrowRateuint256The borrow rate of the market.

Calculations

The Annual Percentage Yields (APY) for both borrowing and supplying are key indicators of the returns for lenders and the cost for borrowers. The APY takes into account the compounding interest to provide a standardized measure of yields over a one-year period.

Borrow APY

The Borrow APY is calculated using the following formula:

borrowAPY=(e(borrowRate×secondsPerYear)1)\text{borrowAPY} = \left(e^{\left(\text{borrowRate} \times \text{secondsPerYear}\right)} - 1\right)

Where:

  • borrowRate is the borrow rate per second, as determined by the Interest Rate Model (IRM),
  • secondsPerYear represents the total number of seconds in a year (31,536,000).

To obtain the borrowRate value, a simple call can be made to the borrowRateView or borrowRate functions defined in the upper sections.

Supply APY

The Supply APY is calculated considering the utilization and the fee. The formula is:

supplyAPY=borrowAPY×utilization×(1fee)\text{supplyAPY} = \text{borrowAPY} \times \text{utilization} \times (1 - \text{fee})

Where:

  • fee is the fee of the market, to be activated by the DAO, on a per-market basis,
  • utilization is calculated as:
utilization=totalBorrowAssetstotalSupplyAssets\text{utilization} = \frac{\text{totalBorrowAssets}}{\text{totalSupplyAssets}}

AdaptiveCurveIRM

Here is a video that shows how the Adaptive Curve IRM works:

Overview

In Morpho, the interest borrowers pay is defined by an external interest rate model (IRM) that can be chosen at market creation among a governance-defined collection.

The AdaptiveCurveIRM is the first IRM that will be available for Morpho markets. It fundamentally differs from the ones used in traditional lending pools for two main reasons:

  • Unlike current lending pools' IRMs which can be updated, the AdaptiveCurveIRM is immutable. It must therefore adapt autonomously to market conditions, such as changes in interest rates on other venues.
  • In Morpho, the supply is not used as collateral. There is no need to keep markets very liquid to allow liquidations at any time. Removing this systemic risk enables more aggressive target utilization of the capital and lower penalties for illiquidity, enabling more efficient markets.

The AdaptiveCurveIRM is designed to adjust utilization to the target utilization, which is set at 90%. There are two time horizons at play: In the short term, we don't want utilization to get too low, or too high and cause liquidity problems. In the medium and long term, we want the rate level to adapt to changing market dynamics.

To achieve this, the AdaptiveCurveIRM adjusts user incentives through the action of two different mechanisms:

  • The Curve Mechanism
  • The Adaptive Mechanism

The Curve Mechanism

This mechanism is similar to the interest rate curve used in traditional lending pools.

The curve is characterized by two parameters:

r90% r_{90\%}

which is the target rate at utilization target

u_target=0.9u\_{target}=0.9

and

c=4c=4

a fixed parameter that determines the steepness of the curve above and below the utilization target.

Curve Mechanism 1

At each interaction, utilization will change, resulting in a discontinuous change in the rate determined by the curve.

For example:

  • if utilization is 90%, the rate is
r_90% r\_{90\%}
  • if utilization is 100%, the rate is
4r_90%4*r\_{90\%}

(APR)

The aim of the Curve Mechanism is to manage short-term utilization changes.

The Adaptive Mechanism

This mechanism continuously shifts the curve to adjust to market conditions over time.

Note that the rate follows the shift of the curve. This means that the rate is continuously evolving over time, even when there is no interaction.

The shifting of the curve is done by continuously changing the value of

r_90%r\_{90\%}

over time:

  • When the utilization is above the target utilization,
r_90% r\_{90\%}

continuously shifts upwards.

  • When the utilization is below the target utilization,
r90%r_{90\%}

continuously shifts downwards.

Morpho Banner

The speed at which math r_{90\%} moves is updated at each interaction: the farther we are from the target, the faster

r_90%r\_{90\%}

hence the curve, shifts.

For example, if the utilization remains at 100% for 5 days,

r_90%r\_{90\%}

will progressively double. This is the maximum speed at which

r_90%r\_{90\%}

can move.

Formal description

We define:

  • Utilzation ( uu

)

u(t)u(t)

is the ratio of total borrow over total supply at time

tt

The utilization target is constant:

u_target=0.9u\_{target}=0.9
  • Error ( ee

):

t,\forall t, e(u)={u(t)utarget1utargetif u(t)>utargetu(t)utargetutargetif u(t)utargete(u)=\begin{cases} \frac{u(t)-u_{target}}{1-u_{target}}&\text{if } u(t)>u_{target} \\ \frac{u(t)-u_{target}}{u_{target}}&\text{if } u(t)\le u_{target} \end{cases}

It can be seen as the difference between the utilization and the target, divided by a normalization factor. The normalization is here to make the distance between math u_{target} and math u=1 equals to the distance between math u_{target} and

u=0u=0
Morpho Banner
  • Curve:
curve(u)={(11kd)e(u)+1if uutarget(kd1)e(u)+1if u>utarget\text{curve}(u)= \begin{cases} (1-\frac{1}{k_d})*e(u)+1&\text{if } u\le u_{target} \\ (k_d-1)*e(u)+1&\text{if } u>u_{target} \end{cases}

with

kd=4k_d=4
  • History of interactions (

    H\mathcal{H}

):

Noting

tit_i

the time at which the

ithi^{th}

interaction occurred,

t,\forall t, H(t)={0}+{ti}ti<t\mathcal{H}(t)=\{0\}+\{t_i\}_{t_i< t}
  • Last interaction (
last \text{last} t,\forall t, last(t)=max(H(t))\text{last}(t) = \max(\mathcal{H}(t))
  • Speed factor (
speed \text{speed}

):

t, speed(t)=exp(kPe(u(last(t)))(tlast(t))), with kp=50\forall t, \text{ speed}(t) = \exp \big({k_P*e(\text{u}(\text{last}(t)))*(t-\text{last}(t))\big)}, \text{ with } k_p = 50
  • Rate at target (
rT r_T rT(0)r_T(0)

is set to an arbitrary value

Then,

t>0,rT(t)=rT(last(t))speed(t)\forall t >0, r_T(t)=r_{T}(\text{last}(t))*\text{speed}(t)

At any time math t , the borrow rate

rr

is given by the formula:

r(t)=rT(t)curve(u(t))r(t) = r_{T}(t)* \text{curve}(u(t))

Implementation

Adaptive Curve IRM Github repository

The contract implements the Interest Rate Model interface to fit Morpho's specifications.

Moreover, the implementation stores configuration variables and a market parameter updated at each borrowRate call for this market.

Variables

Constants

The values of the following constants are hardcoded into the code deployed on Ethereum

  • CURVE_STEEPNESS: Curve steepness (scaled by WAD), value = 4.
  • ADJUSTMENT_SPEED: Adjustment speed per second (scaled by WAD), value = 50/nb of seconds per year.
  • TARGET_UTILIZATION: Target utilization (scaled by WAD), value = 90%.
  • INITIAL_RATE_AT_TARGET: Initial rate at target per second (scaled by WAD), value = 4%/nb of seconds per year.
  • MIN_RATE_AT_TARGET: Minimum rate at target per second (scaled by WAD), value = 0.1%/nb of seconds per year.
  • MAX_RATE_AT_TARGET: Maximum rate at target per second (scaled by WAD), value = 200%/nb of seconds per year.

Immutables

  • MORPHO: Address of Morpho.

Mappings

Rate at target

mapping(Id => uint256) public rateAtTarget;

Rate at target utilization for each market. Tells the height of the curve.

Events

BorrowRateUpdate

event BorrowRateUpdate(Id indexed id, uint256 avgBorrowRate, uint256 rateAtTarget);

Emitted when the borrow rate is updated (called by Morpho).

Parameters:

NameTypeDescription
idIdThe id of the market.
avgBorrowRateuint256The average borrow rate of the market.
rateAtTargetuint256The stored rate at target of the market.