BorrowableCToken

Overview

BorrowableCTokens are Curvance's lending market tokens that enable users to earn interest on deposited assets while simultaneously creating borrowing liquidity for the protocol. These tokens extend the base cToken functionality with comprehensive lending market features, including borrowing, interest accrual, liquidations, and flash loans. Users who deposit underlying assets receive BorrowableCTokens representing their share of the lending pool, which increase in value as borrowers pay interest.

Core Architecture

BorrowableCTokens build upon the cToken foundation by extending BaseCTokenWithYield.

  • BaseCTokenWithYield: Provides the core vault functionality with yield distribution mechanisms.

  • BorrowableCToken: Adds lending market functionality including:

    • Borrow against collateral

    • Interest rate management

    • Debt tracking and liquidations

    • Flash loan capabilities

    • Protocol fee collection

Key Integrations

BorrowableCTokens operate within a sophisticated network of contracts:

  • MarketManager: Manages risk parameters, collateral requirements, borrowing authorization, and liquidation processes.

  • DynamicIRM (Interest Rate Model): Determines borrowing and lending rates based on market utilization and other factors.

  • CentralRegistry: Provides protocol-wide configuration, permissions, and fee settings.

  • Oracle System: Supplies accurate asset pricing for collateral valuation and liquidation triggers.

  • Position Managers: Enable complex leveraged positions and automated strategies.

State Management

BorrowableCTokens maintain sophisticated state tracking for lending operations:

IDynamicIRM public IRM;
uint240 public marketOutstandingDebt;
uint16 public interestFee;
/// @notice Active debt information associated with an account.
mapping(address => uint256) internal _debtOf;
uint256 internal _vestingData;

Interest Rate Mechanism

BorrowableCTokens employ a dynamic interest rate system that responds to market conditions:

  • Utilization-Based rates: Interest rates adjust based on the ratio of borrowed assets to total supplied assets.

  • Dynamic Adjustments: The DynamicIRM continuously monitors market conditions and adjusts rates at regular intervals.

  • Dual Rate System:

    • Borrow Rate:

    • Supply Rate:

Data Flow

Lending (Deposit) Flow

  1. User calls deposit() or mint() with underlying assets.

  2. Contract accrues any pending interest.

  3. Contract calculates shares based on current exchange rate.

  4. Underlying tokens are transferred from the user to the contract.

  5. User's share of the lending pool increases.

  6. Tokens begin earning interest from borrower payments.

Borrowing Flow

  1. User must first have collateral posted in compatible CTokens

  2. User calls borrow() specifying desired amounts.

  3. Contract accrues pending interest and updates rates.

  4. MarketManager validates borrowing capacity against collateral.

  5. Debt is recorded with current debt index for interest calculations.

  6. Underlying assets are transferred to the borrower.

  7. User's redemption ability is paused for 20 minutes (anti-flash loan protection).

Repayment Flow

  1. User calls repay() or repayFor() with repayment amount.

  2. Contract accrues pending interest to capture latest debt amount.

  3. Interest is calculated based on time elapsed and current rates.

  4. Underlying tokens are transferred from the user to the contract.

  5. Assets are transferred to repay debt.

  6. User's debt position is updated or closed.

  7. MarketManager is notified of debt reduction.

Interest Accrual Flow

  1. _accrueIfNeeded() is called before most operations.

  2. Time elapsed since last accrual is calculated.

  3. Interest rates are fetched from the DynamicIRM.

  4. Interest is applied to all outstanding debt.

  5. Interest increases the value of BorrowableCTokens.

  6. Debt indices are updated for accurate individual debt tracking.

Liquidation Flow

  1. Liquidator identifies underwater positions.

  2. Calls liquidateExact() or liquidate() functions

  3. Contract accrues pending interest to get current debt values.

  4. MarketManager calculates liquidation amounts and collateral seizure.

  5. Liquidator repays portion of debt.

  6. Collateral is seized from borrower and transferred to liquidator.

  7. Any bad debt is recognized and removed from total assets.

Debt Index System

BorrowableCTokens use a sophisticated debt index system for accurate interest calculations:

  • Market Debt Index: Global index that increases as interest accrues, stored in the upper bits of _vestingData.

  • Account Debt Index: Personal index recorded when debt is created or modified, stored with each user's debt amount.

  • Interest Calculation: User's accrued interest = (current market index / user's debt index - 1) * principal debt.

This system ensures accurate interest calculations regardless of when users borrow or repay.

Liquidation Mechanics

BorrowableCTokens support comprehensive liquidation capabilities:

  • Health Factor Monitoring: Continuous monitoring of borrower collateral ratios through oracle price feeds.

  • Liquidation Triggers: Positions become liquidatable when collateral value falls below required thresholds.

  • Partial Liquidations: Liquidators can repay specific amounts for bad debt when collateral is insufficient.

  • Incentive Structure: Liquidators receive collateral bonuses for maintaining market health.

Flash Loan Functionality

BorrowableCTokens provide flash loan capabilities for advanced users:

  • Uncollateralized Borrowing: Temporary loans without collateral requirements.

  • Atomic Transactions: Borrowed funds must be returned within the same transaction.

  • Fee Structure: 0.04% fee (4 basis points) on borrowed amounts.

  • Callback Integration: Implements IFlashLoan interface for custom logic execution.

  • Use Cases: Arbitrage, liquidations, collateral swapping, and other DeFi strategies.

Position Manager Integration

BorrowableCTokens integrate with Position Managers for sophisticated strategies:

  • Leveraged Positions: Automated borrowing and collateral posting for leverage.

  • Cross-Market Operations: Coordinated actions across multiple markets.

  • Slippage Protection: Built-in protection for complex multi-step operations.

  • Callback Mechanisms: Position Managers can execute custom logic during borrow operations.

Security Features

BorrowableCTokens implement multiple security layers:

  1. Debt-Collateral Separation: Users cannot post BorrowableCTokens as collateral if they have outstanding debt in the same market.

  2. Pause Mechanisms: Independent pausing of borrowing, lending, and liquidation functions.

  3. Reentrancy Protection: Comprehensive guards against reentrancy attacks.

  4. Interest Rate Limits: Maximum bounds on interest rates to prevent exploitation.

  5. Oracle Integration: Multiple price feed validation for liquidation accuracy.

  6. Flash Loan Protection: 20-minute withdrawal delays after borrowing to prevent flash loan attacks.

Protocol Revenue

BorrowableCTokens generate protocol revenue through multiple mechanisms:

  • Interest Fees: Configurable percentage of borrower interest payments.

  • Flash Loan Fees: 0.04% fee on all flash loan amounts.

  • Liquidation Fees: Portion of liquidation bonuses directed to protocol reserves.

  • Fee Distribution: Protocol fees are accumulate and can be withdrawn by governance.

Risk Management

Debt Caps: Maximum borrowing limits per market to control protocol exposure.

Collateral Factors: Loan-to-value ratios based on asset risk profiles.

Liquidation Thresholds: Dynamic thresholds that trigger liquidations before insolvency.

Oracle Safeguards: Multiple price feeds and staleness protection.

Interest Rate Bounds: Maximum and minimum rate limits to prevent extreme scenarios.

Integration Considerations

State Updates: Always call functions that update interest before relying on debt or balance information.

Market Conditions: Interest rates and liquidation thresholds can change based on market utilization.

User Interaction Functions

Borrow Functions

borrow()

Contract: BorrowableCToken.sol

Description: Borrows underlying tokens from lenders, based on collateral posted inside this market.

Function signature:

function borrow(uint256 amount) external
Type
Name
Description

uint256

amount

The amount of the underlying asset to borrow

Event:

// From cToken
event Borrow(address account, uint256 amount);
// Emitted from cToken and underlying ERC20 asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Potentially emitted multiple times, if this is the first time borrowing this cToken,
// and for any positions that need to be closed after borrowing.
event PositionUpdated(address cToken, address account, bool open);

borrowFor()

Contract: BorrowableCToken.sol

Description: Used by a delegated user to borrow underlying tokens from lenders, based on collateral posted inside this market by account

Function signature:

function borrowFor(
        address account,
        address recipient,
        uint256 amount
    ) external nonReentrant
Type
Name
Description

address

account

The account who will have their assets borrowed against

address

recipient

The account who will receive the borrowed assets

uint256

amount

The amount of the underlying asset to borrow

Event:

// From BorrowableCToken.sol
event Borrow(address account, uint256 amount);
// Emitted from cToken and underlying ERC20 asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Potentially emitted multiple times, if this is the first time borrowing this eToken,
// and for any positions that need to be closed after borrowing.
event PositionUpdated(address cToken, address account, bool open);

Repay Functions

repay()

Contract: BorrowableCToken.sol

Description: Repays underlying tokens to lenders, freeing up their collateral posted inside this market and updates interest before executing the repayment.

Function signature:

function repay(uint256 amount) external nonReentrant
Type
Name
Description

uint256

amount

The amount of the underlying asset to repay, or 0 for the full outstanding amount

Event:

// From BorrowableCToken.sol
event Repay(address payer, address account, uint256 amount);
// Emitted from underlying ERC20 asset transfer.
event Transfer(address indexed from, address indexed to, uint256 value);
// From MarketManager
// Potentially emitted if a position is fully closed.
event PositionUpdated(address cToken, address account, bool open);

repayFor()

Contract: BorrowableCToken.sol

Description: Repays underlying tokens to lenders, on behalf of account, freeing up their collateral posted inside this market.

Function signature:

function repayFor(address account, uint256 amount) external nonReentrant
Type
Name
Description

address

account

The account address to repay on behalf of.

uint256

amount

The amount to repay, or 0 for the full outstanding amount.

Event:

// From BorrowableCToken.sol
event Repay(address payer, address account, uint256 amount);
// Only emitted if interest needs to be accrued.
// Emitted from underlying ERC20 asset transfer.
event Transfer(address indexed from, address indexed to, uint256 value);
// From MarketManager
// Potentially emitted if a position is fully closed.
event PositionUpdated(address cToken, address account, bool open);

Debt Tracking

debtBalance()

Contract: BorrowableCToken.sol

Description: Returns the current debt balance for a given account without accruing interest. This is a view function that uses the cached exchange rate.

Function signature:

    function debtBalance(
        address account
    ) external nonReentrant returns (uint256 result)
Type
Name
Description

address

account

The address whose debt balance should be calculated

Return data:

Type
Description

uint256

The current balance of debt for the account


debtBalanceUpdated()

Contract: BorrowableCToken.sol

Description: Returns the current outstanding debt balance of an account with pending interest applied via _accrueIfNeeded().

Function signature:

    function debtBalanceUpdated(
        address account
    ) external nonReentrant returns (uint256 result)
Type
Name
Description

address

account

The address whose debt balance should be calculated

Return data:

Type
Description

uint256

The estimated debt balance at the specified timestamp

Last updated