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
User calls
deposit()
ormint()
with underlying assets.Contract accrues any pending interest.
Contract calculates shares based on current exchange rate.
Underlying tokens are transferred from the user to the contract.
User's share of the lending pool increases.
Tokens begin earning interest from borrower payments.
Borrowing Flow
User must first have collateral posted in compatible CTokens
User calls
borrow()
specifying desired amounts.Contract accrues pending interest and updates rates.
MarketManager validates borrowing capacity against collateral.
Debt is recorded with current debt index for interest calculations.
Underlying assets are transferred to the borrower.
User's redemption ability is paused for 20 minutes (anti-flash loan protection).
Repayment Flow
User calls
repay()
orrepayFor()
with repayment amount.Contract accrues pending interest to capture latest debt amount.
Interest is calculated based on time elapsed and current rates.
Underlying tokens are transferred from the user to the contract.
Assets are transferred to repay debt.
User's debt position is updated or closed.
MarketManager is notified of debt reduction.
Interest Accrual Flow
_accrueIfNeeded() is called before most operations.
Time elapsed since last accrual is calculated.
Interest rates are fetched from the DynamicIRM.
Interest is applied to all outstanding debt.
Interest increases the value of BorrowableCTokens.
Debt indices are updated for accurate individual debt tracking.
Liquidation Flow
Liquidator identifies underwater positions.
Calls liquidateExact() or liquidate() functions
Contract accrues pending interest to get current debt values.
MarketManager calculates liquidation amounts and collateral seizure.
Liquidator repays portion of debt.
Collateral is seized from borrower and transferred to liquidator.
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:
Debt-Collateral Separation: Users cannot post BorrowableCTokens as collateral if they have outstanding debt in the same market.
Pause Mechanisms: Independent pausing of borrowing, lending, and liquidation functions.
Reentrancy Protection: Comprehensive guards against reentrancy attacks.
Interest Rate Limits: Maximum bounds on interest rates to prevent exploitation.
Oracle Integration: Multiple price feed validation for liquidation accuracy.
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
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
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
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
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)
address
account
The address whose debt balance should be calculated
Return data:
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)
address
account
The address whose debt balance should be calculated
Return data:
uint256
The estimated debt balance at the specified timestamp
Last updated