Credit Manager
The CreditManagerV3 is the core accounting engine of the Gearbox Protocol. It manages Credit Account lifecycle, tracks debt and collateral, calculates health factors, and enforces risk parameters. All Credit Account state is stored and managed through this contract.
Core State: CreditAccountInfo
Every Credit Account's state is tracked in a CreditAccountInfo struct:
| Field | Type | Description |
|---|---|---|
debt | uint256 | Principal amount borrowed from the pool |
cumulativeIndexLastUpdate | uint256 | Pool's interest index at last debt update |
cumulativeQuotaInterest | uint128 | Accrued quota interest not yet added to debt |
quotaFees | uint128 | Quota fees owed |
enabledTokensMask | uint256 | Bitmask of currently enabled collateral tokens |
flags | uint16 | Account state flags (e.g., BOT_PERMISSIONS_SET_FLAG) |
lastDebtUpdate | uint64 | Timestamp of last debt change (flash-loan protection) |
borrower | address | Current account owner |
Debt Tracking Architecture
Indexed Interest Accrual
The Credit Manager uses an indexed interest model rather than storing accrued interest directly. This approach is gas-efficient because it doesn't require per-block updates.
Formula:
accruedInterest = debt * (currentIndex - lastIndex) / lastIndex
totalDebt = principal + accruedInterest + quotaInterest + fees
The cumulativeIndexLastUpdate is snapshotted whenever debt changes, allowing the contract to calculate exact interest at any time by comparing against the Pool's current baseInterestIndex().
Flash-Loan Protection
The lastDebtUpdate timestamp prevents multiple debt changes in the same block. This protects against flash-loan attacks where an attacker could:
- Borrow heavily
- Manipulate prices
- Close position profitably
Any second debt change in the same block will revert.
Collateral Management
Token Masking System
Every collateral token has a unique uint256 mask (power of 2). An account's enabledTokensMask is the bitwise OR of all enabled token masks.
Benefits:
- O(enabled_tokens) iteration: Health checks only iterate over enabled tokens, not all possible collateral
- Gas efficiency: Single storage slot tracks all enabled/disabled states
- Atomic updates: Enable/disable multiple tokens in one operation
// TypeScript: Checking enabled tokens const enabledMask = await creditManager.read.enabledTokensMaskOf([creditAccount]); // Get all enabled token addresses const collateralTokens = []; for (let i = 0; i < 256; i++) { if (enabledMask & (1n << BigInt(i))) { const tokenData = await creditManager.read.getTokenByMask([1n << BigInt(i)]); collateralTokens.push(tokenData); } }
Liquidation Thresholds (LT)
Each collateral token has a Liquidation Threshold determining how much of its value counts toward collateralization:
| Parameter | Description |
|---|---|
ltInitial | Starting LT value (e.g., 8500 = 85%) |
ltFinal | Final LT after ramping |
timestampRampStart | When LT ramping begins |
rampDuration | Duration of linear interpolation |
LT Ramping allows gradual changes to risk parameters without sudden liquidation cascades. The current LT is linearly interpolated between ltInitial and ltFinal over the ramp period.
Phantom Tokens
Phantom tokens are virtual representations of staked/LP positions (e.g., staked Curve LP tokens). They implement IPhantomToken.getPhantomTokenInfo() which returns the underlying deposited token.
During health factor calculations, phantom tokens are resolved to their underlying value, ensuring proper collateral accounting for wrapped positions.
Health Factor Calculation
TWV Formula
The Health Factor determines whether an account is solvent:
TWV (Threshold Weighted Value) = Sum(Balance_i * Price_i * LT_i)
TotalDebt = principal + baseInterest + quotaInterest + fees
HealthFactor = TWV / TotalDebt
An account is:
- Healthy: HF >= 1.0 (10000 in basis points)
- Liquidatable: HF < 1.0
Collateral Calculation Modes
The Credit Manager supports different calculation modes for gas optimization:
| Mode | Use Case |
|---|---|
DEBT_ONLY | Calculate debt + interest without collateral |
DEBT_COLLATERAL | Full TWV + HF calculation |
FULL_COLLATERAL_CHECK_LAZY | Optimized: stops early when HF exceeds threshold |
The lazy mode is used during multicalls where we only need to verify HF > 1, not calculate the exact value.
// TypeScript: Reading account health import { getContract } from 'viem'; const creditManager = getContract({ address: creditManagerAddress, abi: creditManagerV3Abi, client: publicClient, }); // Get full debt breakdown const debtData = await creditManager.read.calcDebtAndCollateral([ creditAccount, 2 // CollateralCalcTask.DEBT_COLLATERAL ]); // debtData returns: { debt, accruedInterest, accruedFees, totalDebtUSD, // totalValue, twvUSD, enabledTokensMask, ... } const healthFactor = debtData.twvUSD * 10000n / debtData.totalDebtUSD; console.log(`Health Factor: ${Number(healthFactor) / 100}%`);
Pool and Oracle Coordination
Pool Interaction
The Credit Manager coordinates with PoolV3 for all debt operations:
| Operation | Pool Function |
|---|---|
| Borrow | pool.lendCreditAccount(debt, creditAccount) |
| Repay | pool.repayCreditAccount(debt, profit, loss) |
| Interest tracking | pool.baseInterestIndex() |
On liquidation with loss, the Credit Manager reports the loss to the Pool, which may burn Treasury shares or incur "uncovered loss" that's socialized across LPs.
Oracle Interaction
Price data comes from PriceOracleV3:
| Function | Description |
|---|---|
convertToUSD(amount, token) | Convert token amount to USD value |
getPrice(token) | Get token price (respects USE_SAFE_PRICES_FLAG) |
Dual Price Safety: When USE_SAFE_PRICES_FLAG is set (for forbidden tokens), the oracle returns min(primaryPrice, reservePrice) to protect against price manipulation.
Access Control
The Credit Manager restricts sensitive operations:
| Caller | Allowed Operations |
|---|---|
CreditFacadeV3 | All account operations (open, close, multicall) |
CreditConfiguratorV3 | Parameter updates (tokens, adapters, fees) |
| Credit Account (via execute) | Adapter calls during multicall |
External contracts cannot directly manipulate Credit Account state - all operations must flow through the Facade.