Section 14 of 18

Final Build
+50 Lynx

Core Lending Complete

Final Build

Submit your complete protocol and run the full test suite. Earn the "compound-v2-builder" badge on completion.

What You Built

You just wrote the core lending protocol. Every function that powers supply, withdraw, borrow, and repay is now implemented. This is the engine that held billions of dollars in Compound V2 and was forked by dozens of protocols. Here is everything you built across the core contracts:

ExponentialNoError (Fixed-Point Math)

FunctionPurpose
truncate()Convert Exp to integer (discard fractional part)
mul_ScalarTruncate()Multiply then truncate in one step
mul_() overloadsScale-aware multiplication (ExpExp, Expuint, uintExp, uintuint)
div_() overloadsScale-aware division (Exp/Exp, Exp/uint, uint/Exp)
add_(), sub_()Exp arithmetic

JumpRateModel (Interest Rates)

FunctionPurpose
utilizationRate()Calculate pool utilization: borrows / (cash + borrows - reserves)
getBorrowRate()Piecewise linear rate with kink at 80% utilization
getSupplyRate()Derived from borrow rate: borrowRate * utilization * (1 - reserveFactor)

CTokenStorage (State and Accounting)

State VariablePurpose
totalSupplyTotal cTokens in existence
totalBorrowsTotal underlying lent out (grows with interest)
totalReservesProtocol revenue from interest
borrowIndexCumulative interest multiplier for lazy per-user calculation
accountTokenscToken balances per user
accountBorrowsBorrowSnapshot per user (principal + interestIndex)

CTokenInterest (Interest Accrual)

FunctionPurpose
accrueInterest()Update borrowIndex, totalBorrows, totalReserves for elapsed blocks
exchangeRateStoredInternal()Calculate cToken-to-underlying rate
borrowBalanceStoredInternal()Calculate a borrower's current debt with accrued interest
getAccountSnapshot()Return a user's cToken balance, borrow balance, and exchange rate

CTokenMint and CTokenRedeem (Supply and Withdraw)

FunctionPurpose
mintInternal() / mintFresh()Deposit underlying, receive cTokens
redeemInternal() / redeemFresh()Burn cTokens, receive underlying
redeemUnderlyingInternal()Redeem by specifying underlying amount

Comptroller (Risk Engine)

FunctionPurpose
_supportMarket()Register a new cToken market
enterMarkets()Opt into using markets as collateral
getAccountLiquidity()Calculate a user's total collateral vs total borrows
mintAllowed() / redeemAllowed() / borrowAllowed()Policy hooks enforcing solvency
repayBorrowAllowed()Minimal check (repaying is always safe)

CTokenBorrow and CTokenRepay (Debt Management)

FunctionPurpose
borrowInternal() / borrowFresh()Take out a loan against collateral
repayBorrowInternal()Repay your own debt
repayBorrowBehalfInternal()Repay someone else's debt
repayBorrowFresh()Core repay logic with type(uint256).max support

Key Concepts You Now Understand

Lazy interest accrual: A global borrowIndex grows each time accrueInterest is called. Individual borrow balances are computed on demand: principal * currentBorrowIndex / snapshotInterestIndex. No iteration over all borrowers.

The exchange rate: (totalCash + totalBorrows - totalReserves) / totalSupply. As borrowers pay interest, totalBorrows grows, and each cToken becomes worth more underlying. Suppliers earn interest without any transaction touching their balance.

Cross-market risk: The Comptroller aggregates a user's collateral and borrows across all markets. A user's ETH deposit in one market backs their USDC borrow in another. This cross-market view is why the Comptroller exists as a separate contract.

Hypothetical liquidity: Before allowing a risky action (redeem, borrow), the Comptroller simulates the outcome and checks whether the user would still be solvent. This prevents users from accidentally undercollateralizing themselves.

The BorrowSnapshot pattern: Each borrower stores their principal and the borrowIndex at the time of their last interaction. This avoids the impossible task of updating every borrower's balance every block.

What Comes Next

The core lending protocol handles normal operations: supply, earn interest, borrow, repay. But what happens when a borrower's collateral drops in value and their debt exceeds their collateral? That is where liquidation comes in. Part 3 builds the liquidation mechanism (both the Comptroller policy side and the CToken execution side) and the final CErc20 integration layer that ties everything into a deployable contract.

The Final Test

The test below covers all core functions across all contracts built so far. It verifies math operations, interest rate calculations, exchange rate formulas, the Comptroller's risk checks, and the full borrow/repay cycle. Run it to confirm your complete core lending protocol works correctly.

Your Complete Protocol

Solution.sol
Solidity
Loading editor...