Skip to content
Lattice

InterestRate

Git Source

Title: InterestRate

Author: Modified from Compound (https://github.com/compound-finance/compound-protocol/blob/master/contracts/JumpRateModelV2.sol)

Stateless utility library implementing the kinked (Aave/Compound-style) interest rate model.

No own ERC-7201 storage. The consumer module holds any storage that references this library. All rates are ray-scaled (1e27 = 100%).

Constants

RAY

Ray scaling factor (1e27 = 100%).

uint256 internal constant RAY = 1e27;

Functions

getBorrowRate

Computes the annualized borrow rate given current utilization.

Uses a two-slope (kinked) model:

  • Below kink: baseRate + utilization * slope1 / kink
  • At or above kink: baseRate + slope1 + (utilization - kink) * slope2 / (RAY - kink) Utilization is capped at RAY (100%) on entry; values above RAY are physically impossible and would cause division-by-zero when kink == RAY (remainingRange == 0). When kink == RAY, capping util to RAY means util <= kink is always true, so the second slope never applies and the denominator is never zero.
function getBorrowRate(Config memory config, uint256 util) internal pure returns (uint256 borrowRate);

Parameters

NameTypeDescription
configConfigRate model parameters.
utiluint256Borrow/supply ratio, ray-scaled (1e27 = 100%). Values above RAY are capped to RAY.

Returns

NameTypeDescription
borrowRateuint256Annualized borrow rate, ray-scaled.

getSupplyRate

Computes the annualized supply rate given utilization and reserve factor.

Formula: borrowRate * utilization * (RAY - reserveFactor) / RAY / RAY. Uses two sequential full-precision mulDiv steps to avoid intermediate overflow without requiring 512-bit arithmetic.

function getSupplyRate(Config memory config, uint256 util, uint256 reserveFactor)
        internal
        pure
        returns (uint256 supplyRate);

Parameters

NameTypeDescription
configConfigRate model parameters.
utiluint256Borrow/supply ratio, ray-scaled.
reserveFactoruint256Fraction of borrow interest kept as protocol reserves, ray-scaled.
Must be <= RAY (i.e., at most 100% of interest goes to reserves).

Returns

NameTypeDescription
supplyRateuint256Annualized supply rate, ray-scaled.

utilization

Computes borrow utilization as totalBorrows / totalSupply, ray-scaled.

Returns 0 if totalSupply is 0 to avoid division by zero.

Overflow note (L-4): totalBorrows * RAY overflows uint256 when totalBorrows > type(uint256).max / 1e27 ≈ 1.16e50. This is an astronomically large token amount (far beyond any real protocol's TVL), but callers should ensure totalBorrows is within this bound. If overflow-safe math is required, use mulDiv(totalBorrows, RAY, totalSupply).

function utilization(uint256 totalBorrows, uint256 totalSupply) internal pure returns (uint256 util);

Parameters

NameTypeDescription
totalBorrowsuint256Total outstanding borrows denominated in the asset.
totalSupplyuint256Total supplied assets (may include idle + allocated).

Returns

NameTypeDescription
utiluint256Utilization ratio, ray-scaled (1e27 = 100%).

validateConfig

Validates that a Config is well-formed; reverts with InvalidConfig otherwise.

Checks:

  • kink must be <= RAY (utilization is always in [0, RAY])
  • kink must be > 0 (otherwise the first-slope formula divides by zero)

Note on overflow (L-3): baseRate, slope1, and slope2 are not bounded here. The two-slope formula can produce a borrowRate larger than RAY for extreme configs (e.g. slope2 >> RAY). If borrowRate > type(uint256).max / RAY, the intermediate product in _rayMul silently overflows. Consumers MUST ensure that baseRate + slope1 + slope2 &lt;= type(uint256).max / RAY (~1.16e50) for safety. Practical lending protocols use rates well below this bound (e.g., all fields <= 10*RAY).

function validateConfig(Config memory config) internal pure;

Parameters

NameTypeDescription
configConfigThe Config to validate.

_rayMul

Multiplies two ray-scaled values and divides by RAY, truncating (floor). Intermediate product can reach up to (1e27)^2 = 1e54 < 2^256, so no overflow.

function _rayMul(uint256 a, uint256 b) private pure returns (uint256);

Parameters

NameTypeDescription
auint256
buint256

Returns

NameTypeDescription
<none>uint256

Errors

InvalidConfig

Reverts when a Config is structurally invalid (e.g., kink > RAY).

error InvalidConfig();

Structs

Config

Configuration for the kinked interest rate model.

struct Config {
        /// @dev Annualized borrow rate at 0% utilization, ray-scaled (1e27 = 100%).
        uint256 baseRate;
        /// @dev Slope of the rate curve below the kink, ray-scaled.
        uint256 slope1;
        /// @dev Slope of the rate curve above the kink, ray-scaled.
        uint256 slope2;
        /// @dev Utilization breakpoint where the slope changes, ray-scaled (e.g., 0.8e27 = 80%).
        uint256 kink;
    }

Properties

NameTypeDescription
baseRateuint256
slope1uint256
slope2uint256
kinkuint256