Introduction

This section provides a technical deep dive into the implementation details of isolated markets in HypurrFi.

For a conceptual overview of what isolated markets are and their benefits, please refer to the Isolated Lending Markets section. For additional details, see the Fraxlend documentation.

Isolated Markets are a fundamental primitive within the isolated markets protocol, implementing specialized lending and borrowing functionality between pairs of ERC-20 tokens.

The technical design follows a shares-based accounting model that enables gas-efficient interest accrual and position management.

Key Concepts

Pairs

Each pair is an isolated market to borrow a single ERC-20 token (known as the Asset Token) by depositing a different ERC-20 token (known as the Collateral Token).

When Lenders deposit Asset Tokens into the Pair, they receive hyTokens. hyTokens are ERC-20 tokens and are redeemable for Asset Tokens (sometimes referred to as the underlying asset).

As interest is accrued, hyTokens are redeemable for increasing amounts of the underlying asset.

Borrowers deposit Collateral Tokens into the Pair and in exchange receive the right to borrow Asset Tokens.

Loan-To-Value (LTV)

Each borrower’s position has a Loan-To-Value (LTV). This represents the ratio between the value of the assets borrowed and the value of the collateral deposited. The LTV changes when:

  • The exchange rate between Asset and Collateral Tokens moves
  • Interest is capitalized

If a borrower’s LTV rises above the Maximum LTV, their position is considered unhealthy. To remediate this, a borrower can:

  • Add collateral
  • Repay debt

The Maximum LTV value is immutable and configured at deployment.

Typically the value is set to 75%. Custom Term Sheet deployments can set this value manually, even creating under-collateralized loans by setting the value above 100%.

Maximum LTV configured above 100% must be accompanied by a borrower whitelist to protect against malicious actors.

Rate Calculator

Each pair is configured to use a specific Rate Calculator contract to determine interest rates. Fraxlend supports three types of Rate Calculators:

  1. Time-Weighted Variable Rate Calculator

    • Interest rate changes based on utilization
    • Below target utilization: rates adjust downward
    • Above target utilization: rates adjust upward
  2. Linear Rate Calculator

    • Calculates interest rate purely as a function of utilization
    • Lower utilization = lower borrowing rate
    • Higher utilization = higher borrowing rates
  3. Variable Rate V2

    • Calculates interest rate as a function of utilization
    • Immediate response to utilization changes
    • Rate curve shape changes based on utilization history
    • Slope increases when utilization is above target
    • Slope decreases when utilization is below target

Liquidations

When a borrower’s LTV rises above the Maximum LTV, any user can:

  1. Repay all or a portion of the debt on the borrower’s behalf
  2. Receive an equal value of collateral plus a liquidation fee

The liquidation fee is immutable and defined at deployment. By default, the value is set to 10%.

hyToken Share Price

When lenders deposit Asset Tokens, they receive hyTokens at the current hyToken Share Price. hyTokens represent:

  • A lender’s share of the total amount of underlying assets deposited
  • Capitalized interest from borrowers

As interest accrues, the Share Price increases. Upon redemption, hyTokens are redeemable for an ever-increasing amount of Asset Tokens which includes capitalized interest.

Vault Account

The Vault Account is a core concept to all accounting in the Pair. A Vault Account is a struct containing:

struct VaultAccount {
    // Represents the total amount of tokens in the vault
    uint128 amount; // Analogous to market capitalization
    
    // Represents the total number of shares or claims to the vault
    uint128 shares; // Analogous to shares outstanding
}

The Shares represent the total number of claims to the amount. Shares can be redeemed for Asset Tokens. The rate of redemption, known as the Share Price, is determined by:

Share Price = Amount / Shares

To convert between values:

  • Shares = Amount / Share Price
  • Amount = Shares × Share Price

Technical Implementation

Core Contract Interfaces

interface IFraxlendPair {
    // State-changing functions
    function addCollateral(uint256 _collateralAmount, address _borrower) external;
    function removeCollateral(uint256 _collateralAmount, address _receiver) external;
    function borrowAsset(
        uint256 _borrowAmount,
        uint256 _collateralAmount,
        address _receiver
    ) external returns (uint256 _shares);
    function repayAsset(uint256 _shares, address _borrower) external returns (uint256 _amountToRepay);
    function repayAssetWithCollateral(
        address _swapperAddress,
        uint256 _collateralToSwap,
        uint256 _amountAssetOutMin,
        address[] memory _path
    ) external returns (uint256 _amountAssetOut);
    function liquidate(
        uint128 _sharesToLiquidate,
        uint256 _deadline,
        address _borrower
    ) external returns (uint256 _collateralForLiquidator);
    
    // View functions
    function getUserSnapshot(
        address _address
    ) external view returns (
        uint256 _userAssetShares,
        uint256 _userBorrowShares,
        uint256 _userCollateralBalance
    );
    function getPairAccounting()
        external
        view
        returns (
            uint128 _totalAssetAmount,
            uint128 _totalAssetShares,
            uint128 _totalBorrowAmount,
            uint128 _totalBorrowShares,
            uint256 _totalCollateral
        );
}

interface IFraxlendPairRegistry {
    function addPair(address _pairAddress) external;
    function deployedPairsByName(string memory) external view returns (address);
    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);
}

Vault Accounting Library

Provides a library for use with the VaultAccount struct, offering convenient math implementations using uint128 to save on storage.

// Convert amount to shares
function toShares(struct VaultAccount total, uint256 amount, bool roundUp) 
    internal pure returns (uint256 shares)

// Convert shares to amount
function toAmount(struct VaultAccount total, uint256 shares, bool roundUp) 
    internal pure returns (uint256 amount)

Technical Constraints

The following implementation constraints apply to isolated markets:

  1. Maximum collateral value: 2^128 - 1 (to prevent overflow)
  2. Maximum borrow duration: Unlimited (interest compounds continuously)
  3. Minimum collateral-to-debt ratio: Varies by market pair (typically 110-200%)
  4. Price update frequency: Depends on oracle implementation (usually 5-30 minutes)
  5. Gas cost considerations: High gas operations like liquidation are optimized

Comparison to Pooled Lending

Unlike pooled lending models where all assets share the same risk, isolated markets:

  1. Contain risk to specific asset pairs
  2. Allow custom parameters per market
  3. Prevent cross-asset contagion
  4. Enable more precise risk management
  5. Support specialized asset pairs that might not fit in shared pools