---
# System prepended metadata

title: Understanding Aave V2 Code (2/n) - Deposit Mechanism

---

# Understanding Aave V2 Code (2/n) - Deposit Mechanism
## TLDR
- **Deposit Flow**: Deposit assets → receive aTokens → balances grow automatically without transactions
- **Scaled Balance**: Stores normalized amount (÷ index), displays actual amount (× index) → scalable for millions of users
- **Asymmetric Interest**: Depositors earn linear, borrowers pay compound → built-in solvency buffer prevents bank runs
- **Dynamic Rates**: Self-adjusting based on utilization via two-slope interest rate model
- **Gas Optimizations**: Bitmap storage + 27-decimal Ray math for precision without rounding errors

## What's Deposit in Aave V2
When you deposit assets into Aave v2:
1. Your tokens go into the lending pool
2. You receive **aTokens** (e.g., USDC → aUSDC)
3. Your aToken balance automatically grows as you earn interest

## High-Level Flow
User deposits USDC → Receives aUSDC → Balance grows over time
```
┌──────────┐
│   User   │
└────┬─────┘
     │ 1. deposit(USDC, 10000)
     ▼
┌─────────────────────┐
│  LendingPool.sol    │
│                     │
│ 2. Validate deposit │
│ 3. Update state &   │
│    interest         │
│ 4. Transfer tokens  │
│ 5. Mint aTokens     │
└─────────────────────┘
     │
     ▼
┌─────────────────────┐
│   AToken.sol        │
│                     │
│ 6. Mint scaled amt  │
│ 7. Balance shows    │
│    growing value    │
└─────────────────────┘
```

## Data Structures & Storage Layout
Before diving into the deposit code, we need to understand where and how Aave v2 stores its data. This will make the step-by-step walkthrough much clearer.
### Storage Architecture Overview
Aave V2 uses a clean separation between storage and logic:
```
┌─────────────────────────────────┐
│   LendingPoolStorage.sol        │  ← Defines storage layout
│   (State variables)             │
└─────────────────────────────────┘
            ↓
┌─────────────────────────────────┐
│   DataTypes.sol                 │  ← Defines struct schemas
│   (Data structures)             │
└─────────────────────────────────┘
            ↓
┌─────────────────────────────────┐
│   LendingPool.sol               │  ← Uses storage + types
│   (Business logic)              │
└─────────────────────────────────┘
```
### Key Data Structure
#### 1. ReserveData - The Core Structure
```solidity
// DataTypes.sol
struct ReserveData {
     // configuration
     ReserveConfigurationMap configuration;       // stores the reserve configuration

     // interest tracking
     uint128 liquidityIndex;                      // deposit multiplier
     uint128 variableBorrowIndex;                 // variable debt multiplier

     // current rates
     uint128 currentLiquidityRate;                // supply APY (what depositors earn)
     uint128 currentVariableBorrowRate;           // variable borrow APY (what borrowers pay)
     uint128 currentStableBorrowRate;             // stable borrow APY (what borrowers pay)

     // timestamp
     uint40 lastUpdateTimestamp;                  // last update time

     // token addresses
     address aTokenAddress;                       // address of interest-bearing token
     address stableDebtTokenAddress;              // address of stable debt token
     address variableDebtTokenAddress;            // address of variable debt token

     // interest rate strategy address
     address interestRateStrategyAddress;         // address of APY calculator contract

     // reserve ID
     uint8 id;                                    // reserve position
}
```
#### 2. ReserveConfigurationMap - Risk Parameters as Bitmap
```solidity
// DataTypes.sol
struct ReserveConfigurationMap {
     //bit 0-15: LTV
     //bit 16-31: Liq. threshold
     //bit 32-47: Liq. bonus
     //bit 48-55: Decimals
     //bit 56: Reserve is active
     //bit 57: reserve is frozen
     //bit 58: borrowing is enabled
     //bit 59: stable rate borrowing enabled
     //bit 60-63: reserved
     //bit 64-79: reserve factor
     uint256 data;
}
```
![reserveconfigmap](https://hackmd.io/_uploads/Hk4gr6xzZe.png)

(*Source: Aave v2 whitepaper*)

| Variable | Usage | 
|----------|----------|
| LTV (Loan-to-Value)  | Determine max borrow % of collateral   | 
| Liquidation threshold   | Determine when position can be liquidated   |
| Liquidation bonus   | Incentive paid to liquidators   |
| Decimals   | Token decimals  |
| Active flag   | Need to be active to accept deposit/ borrow   |
| Frozen flag  | Reserve frozen to prevent new deposits/ borrows in crisis   |
| Borrowing is enabled   | Can turn off borrowing while keeping deposits open   |
| Stable rate borrowing enabled   | Separates variable borrowing from stable borrowing  |
| Reserve factor   | Percentage of interest that goes to Aave treasury   |

Why bitmap?
- Gas efficient: All params in ONE storage slot, amazing compression
- Bit manipulation is cheap
- Can read entire config in one SLOAD

#### 3. UserConfigurationMap - User's Asset Usage
```solidity
// DataTypes.sol
struct UserConfigurationMap {
     uint256 data; // bitmap tracking which assets user uses
}
```
![userconfigmap](https://hackmd.io/_uploads/BJYZBalG-l.png)

(*Source: Aave v2 whitepaper*)

Two bits per Reserve
- Max 128 reserves
     - uint256 has 256 bits
     - So Aave v2 supports max 128 reserves
- Each reserve gets 2 bits
     - Bit 0 (even): Whether use is using this reserve as collateral
     - Bit 1 (odd): Whether user is borrowing this reserve
- State combinations
     - 00 : User has no interation with this reserve
     - 01 : Only borrowing (impossible)
     - 10 : Only collateral
     - 11 : Both borrowing and collateral

### Storage Layout in LendingPoolStorage
```solidity
// LendingPoolStorage.sol
contract LendingPoolStorage {
     // main storage

     // store all data for each reserve (incl. liquidity index, borrow index, current rate etc.)
     mapping(address => DataTypes.ReserveData) internal _reserves;
     // track which assets each user is using
     mapping(address => DataTypes.UserConfigurationMap) internal _usersConfig;
     // the list of the available reserves, structured as a mapping for gas savings reasons
     mapping(uint256 => address) internal _reservesList;
}
```
## Math & Key Concepts
Aave's deposit mechanism uses several mathematical concepts:

- **Ray Math (27 decimals)** - High-precision arithmetic
- **Interest Calculation**
     - Linear interest for depositors
     - Compound interest for borrowers
- **The Two Indexes**
     - Liquidity index (depositor growth)
     - Variable borrow index (borrower debt growth)
- **Scaled Balance** - Storage-efficient balance representation
- **Utilization Rate & Interest Rates** - How rates are determined

### 1. Ray Math - 27 Decimal Precision
Ray = 27 decimal precision number system used by Aave
```solidity
// WadRayMath.sol
uint256 internal constant WAD = 1e18;  // 18 decimals (standard ERC20)
uint256 internal constant RAY = 1e27;  // 27 decimals (Aave's precision)
```
Why 27 decimals?
- Problem with 18 decimals
     - Interest rate: 0.05% per day
     - Over 365 days with compounding => Rounding errors accumulate
     - Can lose significant value
- Solution with 27 decimals
     - Much more precise representation
     - Rounding errors 1 billion times smaller
     - Accurate compounding over years

### 2. Interest Calculation
Aave v2 uses **two different** interest calculation methods:

1. **Linear Interest** - For depositors (liquidity)
2. **Compound Interest** - For borrowers (debt)

**Why use two calculation methods?**
- Solvency guarantee
     - Over time, compound interest always out-runs linear interest
     - Therefore the contract always owes depositors slightly less than what borrowers are paying
     - The pool silently accumulates a small surplus instead of a deficit, so a “bank-run” can never leave late withdrawers without funds
- Gas optimization
     - Calculating linear interest onchain consumes less computation power and gas fee compared to compound interest calculation
#### 2a. Linear Interest
- Formula
     - `Linear Interest = 1 + (annualRate * timeElapsed / secondsPerYear)`
- Math notation
     - `I = 1 + (r × Δt / T)`
     - I = interest multiplier
     - r = annual rate (eg. 0.03)
     - Δt = seconds elapsed
     - T = seconds per year (31,536,600)

#### 2b. Compound Interest
- Formula
     - `Compound Interest = (1 + annualRate) ^ (timeElapsed / secondsPerYear)`
- Math notation
     - `I = (1 + r) ^ (Δt / T)`
- Problem: Exponentiation is expensive in Solidity
- Solution: Binomial approximation
     - `(1+x)^n = 1 + n*x + [n/2*(n-1)]*x^2 + [n/6*(n-1)*(n-2)*x^3...`
     - Aave v2 uses the first 3 terms for compound interest, which slighly underpays depositors and undercharge borrowers, with the advantages of great gas cost saving
- Example
     - Initial value of 1,000 USDC
     - Over time period, compounded value grows faster than linear value
     - The "Dust" (difference between the two) stays in the pool as solvency buffer
![linear_compound](https://hackmd.io/_uploads/r1Kfrpef-l.png)

### 3. The Two Indexes
Aave tracks growth using two separate indexes:
- Liquidity Index - Tracks how much depositors have earned
- Variable Borrow Index - Tracks how much variable debt borrowers owe
Both start at 1.0 and grow over time, but at different rates

#### 3a. Liquidity Index
- Definition: A cumulative growth factor that tracks all interest earned by depositors since the pool was created.
     ```solidity
     // ReserveData struct
     uint128 liquidityIndex;  // Starts at 1e27, grows using linear interest calculation
     ```
- Formula: `newIndex = oldIndex × (1 + rate × timeElapsed / secondsPerYear)`
- Usage in deposit flow
     - Updated by `updateState()`
     - Used by `getReserveNormalizedIncome()` to calculate current aToken balance

#### 3b. Variable Borrow Index
- Definition: A cumulative growth factor that tracks how much borrowers' variable debt has grown since the pool was created.
     ```solidity
     // ReserveData struct
     uint128 variableBorrowIndex;  // Starts at 1e27, grows using compound interest calculation
     ```
- Formula: `newIndex = oldIndex * (1 + rate)^ (timeElapsed / secondsPerYear)`
- Usage in deposit flow
     - Updated by `updateState()`

### 4. Scaled Balance
Scaled balance is a "normalized" balance that accounts for all interest accrued before a deposit/borrow, enabling automatic balance growth without storage updates

#### The Two-Balance System
Aave v2 uses two different balance concepts

**1. Scaled Balance (Internal):**
- What's stored in contract storage
- Never changes unless user deposits/withdraws
- Hidden from users

**2. Actual Balance (External):**
- What wallets display  
- Grow over time as interest accrues
- Calculated on-demand (not stored)

**Why This Design?**
- WITHOUT this system:
     - Every block, update every user's balance
     - O(n) gas cost per block
     - Extremely expensive for thousands of users
     - Impossible to scale
- WITH this system (smart):
     - Update only ONE index per block
     - O(1) gas cost
     - User's balance calculated on-read using: `scaledBalance × liquidity index`
     - Scale to millions of users
     - Gas efficient

#### Usage in the deposit flow
- Minting aToken for depositor: scaled balance
     - Formula: `scaled balance = actual balance / current index`
     - Code implementation
          ```solidity
          // AToken.sol - mint()
          uint256 amountScaled = amount.rayDiv(index);
          _mint(user, amountScaled);
          ```
- Reading balance: actual balance
     - Formula: `actual balance = scaled balance * current index`
     - Code implementation
          ```solidity
          // AToken.sol - balanceOf()
          function balanceOf(address user) public view returns (uint256) {
          return super.balanceOf(user).rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
          }
          ```
### 5. Utilization Rate & Interest Rates
Aave has **three interest rates** that all depend on **utilization rate**:
1. **Liquidity Rate** - What depositors earn
2. **Variable Borrow Rate** - What variable-rate debt borrowers pay
3. **Stable Borrow Rate** - What stable-rate debt borrowers pay
#### Utilization rate
- Definition: Percentage of deposited capital currently borrowed
- Formula: 
     - `Utilization rate = Total borrows / (Available liquidity + Total borrows)`
     - `Excess rate = 1 - Utilization rate`
- Kinked interest rate model
     - Below optimal utilization rate: Rates increase gradually (encourage borrowing)
     - Above optimal utilization rate: Rates spike dramatically (discourage borrowing, encourage deposits)
#### Variable / Stable borrow rate
- Below optimal: `borrow rate = base rate + (utilization / optimal) * slope1`
- Above optimal: `borrow rate = base rate + slope1 + ((utilization - optimal) / excess) * slope2`
- Example
     - Optimal utilization rate: 80%
     - Base rate: 2%
     - Slope 1 rate: 4%
     - Slope 2 rate: 5%
     ![interestRate](https://hackmd.io/_uploads/By2XB6eGZx.png)

#### Liquidity rate
- Formula
     - `liquidity rate = weighted avg borrow rate * utilization rate * (1 - reserve factor)`
     - `weighted avg borrow rate = (total variable debt * variable borrow rate + total stable debt * stable borrow rate) / total debt`

## Step by Step Code Walkthrough
Now that we understand the data structures and the relevant concepts & math, let's see how they're used in the deposit flow.
### Step 1: Entry Point - `deposit()`
Main purpose
- Deposit an amount of underlying asset into the reserve
- In return get the correspondent aTokens

```solidity
// LendingPool.sol
function deposit(
    address asset,       // asset to deposit
    uint256 amount,      // amount to deposit
    address onBehalfOf,  // the address that will receive the aTokens
    uint16 referralCode  // code used to register the integrator originating the ops
) external override whenNotPaused {
     // get refernce of the asset's current reserve
     DataTypes.ReserveData storage reserve = _reserves[asset];
     // validate a deposit action
     ValidationLogic.validateDeposit(reserve, amount);

     address aToken = reserve.aTokenAddress;
     // update 2 indexes (liquidity index, variable borrow index)
     reserve.updateState();
     // update 3 rates (stable borrow rate, variable borrow rate, liquidity rate)
     reserve.updateInterestRates(asset, aToken, amount, 0);
     // transfer deposited asset to aToken address
     IERC20(asset).safeTransferFrom(msg.sender, aToken, amount);
     // mint aTokens
     bool isFirstDeposit = IAToken(aToken).mint(onBehalfOf, amount, reserve.liquidityIndex);
     // enable the deposit as collateral by default on first deposit
     if (isFirstDeposit) {
          _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
          emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
     }
     // emit event
     emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode);
}
```
### Step 2: Get reserve of the asset
```solidity
DataTypes.ReserveData storage reserve = _reserves[asset];
```
- `DataTypes.ReserveData`, explained above, is a struct from DataTypes.sol that holds all info about a reserve
- `storage` gets a reference to the actual data stored on chain
- `_reserves[asset]` looks up the specific reserve for that asset, returns the `ReserveData` struct

### Step 3: Validate Deposit - `validateDeposit()`
```solidity
// ValidationLogic.sol
function validateDeposit(
     DataTypes.ReserveData storage reserve, // asset's current reserve
     uint256 amount                         // amount user want to deposit
) external view {
     // get reserve state floags from bit-packed config
     (bool isActive, bool isFrozen, , ) = reserve.configuration.getFlags();

     // deposit amount should not be 0
     require(amount != 0, Errors.VL_INVALID_AMOUNT);
     // reserve is active
     require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
     // reserve is not frozen
     require(!isFrozen, Errors.VL_RESERVE_FROZEN);
}

// ReserveConfiguration.sol
function getFlags(DataTypes.ReserveConfigurationMap storage self)
    internal
    view
    returns (
      bool,    // isActive
      bool,    // isFrozen
      bool,    // borrowingEnabled
      bool     // stableRateBorrowingEnabled
    )
{
     uint256 dataLocal = self.data;

     return (
          (dataLocal & ~ACTIVE_MASK) != 0,             // bit 56
          (dataLocal & ~FROZEN_MASK) != 0,             // bit 57
          (dataLocal & ~BORROWING_MASK) != 0,          // bit 58
          (dataLocal & ~STABLE_BORROWING_MASK) != 0    // bit 59
     );
}
```

### Step 4: Update Liquidity & Variable Borrow Index - `updateState()`
`updateState()` updates the two indexes so depositors and borrowers' balances grow automatically
```solidity
// ReserveLogic.sol
function updateState(DataTypes.ReserveData storage reserve) internal {
     // get the total variable debt
     uint256 scaledVariableDebt =
          IVariableDebtToken(reserve.variableDebtTokenAddress).scaledTotalSupply();
    
     // get previous borrow index
     uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex;
     
     // get previous liquidity index
     uint256 previousLiquidityIndex = reserve.liquidityIndex;
     
     // get last updated time
     uint40 lastUpdatedTimestamp = reserve.lastUpdateTimestamp;

     // update the liquidity index & variable borrow index based on time passed and interest rates
     // liquidity index: linear interest 1 * (1 + x * n)
     // variable debt index: compound interest 1 * (1 + x)^n
     (uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) =
          _updateIndexes(
          reserve,
          scaledVariableDebt,
          previousLiquidityIndex,
          previousVariableBorrowIndex,
          lastUpdatedTimestamp
          );
     
     // send a portion of the earned interest to Aave treasury based on reserve factor
     _mintToTreasury(
          reserve,
          scaledVariableDebt,
          previousVariableBorrowIndex,
          newLiquidityIndex,
          newVariableBorrowIndex,
          lastUpdatedTimestamp
     );
}
```
What it does:
1. Calculate accrued interest using the time elapsed and current interest rates
2. Update **liquidity index** (depositors' balances scale by this) using **linear interest**
3. Update **variable borrow index** (variable rate borrowers' debt scales by this) using **compound interest**
4. Mint treasury share (Aave keeps a percentage of interest earned)

Example:
- Before `updateState()`
     - liquidityIndex = 1.00 (starting value)
     - variableBorrowIndex = 1.00 (starting value for variable debt)
     - Time passed: 2 year
     - currentLiquidityRate = 0.03 (3% APY for depositors)
     - currentVariableBorrowRate = 0.05 (5% APY for variable borrowers)
- After `updateState()`
     - liquidityIndex = oldIndex × (1 + rate × time) = 1.00 * (1 + 0.03 * 2) = 1.06
     - variableBorrowIndex = oldIndex × (1 + rate)^time = 1.00 * (1 + 0.05)^2 = 1.1025
     - lastUpdateTimestamp = block.timestamp (updated)

### Step 5: Update Interest Rates - `updateInterestRates()`
`updateInterestRates()` recalculates the three interest rates based on current market condition (supply/ demand), then store them in the reserve
- current stable borrow rate
- current variable borrow rate
- current liquidity rate

```solidity
// ReserveLogic.sol
function updateInterestRates(
    DataTypes.ReserveData storage reserve,
    address reserveAddress,
    address aTokenAddress,
    uint256 liquidityAdded,
    uint256 liquidityTaken
  ) internal {
    // previous code ... (detailed will be explored in the later blog)
    
    // store the new rates
    reserve.currentLiquidityRate = uint128(vars.newLiquidityRate);
    reserve.currentStableBorrowRate = uint128(vars.newStableRate);
    reserve.currentVariableBorrowRate = uint128(vars.newVariableRate);
    
    // emit event
  }
```
What it does:
1. Gather market data: Collect current deposit and debt balances
2. Calculate utilization ratio: Determine how much of the pool is borrowed vs available
3. Apply two-slope model: Use different rate curves based on utilization level
4. Calculate three rates: Determine what depositors earn and what borrowers pay
5. Adjust for treasury fee: Reduce deposit rate by reserve factor percentage
6. Store new rates: Update reserve with updated three rates

### Step 6: Transfer Underlying Tokens to aToken contract - `safeTransferFrom()`
```solidity
IERC20(asset).safeTransferFrom(msg.sender, aToken, amount);
```
What it does:
- Transfer the actual underlying tokens (USDC, DAI, etc.) from the user to the aToken contract
- aToken contract is the vault that holds all deposited asset. When user deposits:
     - The deposited tokens go into the aToken pool
     - The aToken holds them as collateral/ reserve
     - User's balance grows as the vault earns interest

### Step 7: Mint aToken - `IAToken.mint()`
After tokens are transferred, Aave mints aTokens to represent your deposit. This is where the magic happens.

```solidity
bool isFirstDeposit = IAToken(aToken).mint(onBehalfOf, amount, reserve.liquidityIndex);

// tokenization/AToken.sol
function mint(
     address user,       // the address receiving the minted tokens
     uint256 amount,     // amount of tokens getting minted
     uint256 index       // the new liquidity index of the reserve
) external override onlyLendingPool returns (bool) {
     uint256 previousBalance = super.balanceOf(user);

     // amountScaled = amount / new index
     uint256 amountScaled = amount.rayDiv(index);
     require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
     
     // mint to the address normalized amount of aToken
     _mint(user, amountScaled);
     
     // emit event
     emit Transfer(address(0), user, amount);
     emit Mint(user, amount, index);
     
     // return true if previous balance was 0
     return previousBalance == 0;
}
```
What happens:
1. **Receive parameters from LendingPool:**
   - `user`: Alice's address
   - `amount`: 10,000 USDC (the deposit amount)
   - `index`: New liquidityIndex (e.g., 1.05e27)

2. **Calculate scaled amount:**
   - `amountScaled = amount / liquidityIndex`
   - Why divide? We're "deflating" the amount by all interest already accrued in the pool
   - This normalizes deposits made at different times

3. **Mint scaled aTokens:**
   - Stores `amountScaled` in the ERC20 `_balances` mapping
   - This is what lives in contract storage (not the full amount!)

4. **Emit events:**
   - Event shows `amount` (10,000) but stores `amountScaled` (9,523.81)
   - This is intentional - users see round numbers in events

5. **Return first deposit flag:**
   - Returns true if user's previous aToken balance was 0
   - Used to enable collateral automatically for first-time depositors

### Step 8: Balance Growth - `balanceOf()`
This is the most innovative part of Aave V2. User's aToken balance **grows automatically** without any transactions.

**The Two-Balance System:**
- **Scaled balance** (stored): Never changes unless you deposit/withdraw more
- **Actual balance** (calculated): Grows as liquidityIndex increases
- Formula: `actualBalance = scaledBalance × currentLiquidityIndex`

```solidity
// tokenization/AToken.sol
function balanceOf(address user) 
    public 
    view 
    override(IncentivizedERC20, IERC20)
    returns (uint256) 
{
     // Displayed balance = scaled balance * liquidity index (rebase as the index changes)
     return super.balanceOf(user). // get the scaled balance
          rayMul( // multiple
          _pool.getReserveNormalizedIncome(_underlyingAsset) // get updated liquidity index
     );
}

// LendingPool.sol
function getReserveNormalizedIncome(address asset)
     external
     view
     virtual
     override
returns (uint256)
{
     return _reserves[asset].getNormalizedIncome();
}

// ReserveLogic.sol
function getNormalizedIncome(DataTypes.ReserveData storage reserve)
    internal
    view
    returns (uint256)
{
     uint40 timestamp = reserve.lastUpdateTimestamp;

     // Check if the index already updated in this block by updateState()
     //solium-disable-next-line
     if (timestamp == uint40(block.timestamp)) {
          // if yes, just return the stored liquidityIndex
          return reserve.liquidityIndex;
     }
    
     // if not, calculate the latest liqudity index using linear interest calculation
     uint256 cumulated =
          MathUtils.calculateLinearInterest(reserve.currentLiquidityRate, timestamp).rayMul(
               reserve.liquidityIndex); 

     return cumulated;
}
```

**How it works:**
1. Get scaled balance from storage (what was minted during deposit)
2. Multiply by current liquidityIndex (which grows over time)
3. Result = actual balance that reflects all earned interest

**Example:**
```
Alice deposits 10,000 USDC at index 1.05:
- Scaled balance stored: 9,523.81
- Current index: 1.05
- Displayed balance: 9,523.81 × 1.05 = 10,000 ✅

One month later, index grows to 1.0526:
- Scaled balance: 9,523.81 (unchanged!)
- Current index: 1.0526
- Displayed balance: 9,523.81 × 1.0526 = 10,025 
- Alice earned 25 USDC with zero transactions!
```

The `getNormalizedIncome()` function returns the up-to-date `liquidityIndex`:
- If already updated this block → return stored index
- If not updated yet → calculate latest index using linear interest
- This ensures balance always reflects the most recent interest accrual

### Step 9: Enable Deposit as Collateral - `setUsingAsCollateral()`
```solidity
// if it's user's first deposit of this reserve
if (isFirstDeposit) {
     // enable to use this asset as collateral for borrowing
     _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
    
     emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
}

// configuration/UserConfiguration.sol
function setUsingAsCollateral(
     DataTypes.UserConfigurationMap storage self,
     uint256 reserveIndex,
     bool usingAsCollateral
) internal {
     // max number of reserve cap at 128
     require(reserveIndex < 128, Errors.UL_INVALID_INDEX);
     
     // set the bits to match the usingAsCollateral parameter
     self.data =
          (self.data & ~(1 << (reserveIndex * 2 + 1))) |
          (uint256(usingAsCollateral ? 1 : 0) << (reserveIndex * 2 + 1));
}
```

## Key Insights

**1. Scaled Balance Architecture: Gas Efficiency at Scale**
- **Storage**: Normalized amount (deposit ÷ liquidityIndex) - remains constant
- **Display**: Actual amount (scaledBalance × currentIndex) - calculated on-demand
- **Impact**: Single index update enables millions of balances to grow automatically without individual storage writes
- **Innovation**: Transforms O(n) per-block update cost into O(1), making the protocol economically viable at scale

**2. Asymmetric Interest Model: Built-in Solvency Guarantee**
- **Depositors earn**: Linear interest (gas-efficient, slightly conservative)
- **Borrowers pay**: Compound interest (economically fair, slightly higher)
- **Result**: Compound growth always outpaces linear growth over time
- **Safety mechanism**: The protocol accumulates a small surplus ("dust") instead of deficit, preventing bank-run scenarios where late withdrawers can't access funds

**3. Dynamic Interest Rate Model: Self-Balancing Market Mechanism**
- **Low utilization** → Lower rates → Incentivizes borrowing, discourages deposits
- **High utilization** → Higher rates → Incentivizes deposits, discourages borrowing
- **Two-slope (kinked) design**:
  - Below optimal utilization: Gradual rate increases maintain capital efficiency
  - Above optimal utilization: Steep rate increases protect liquidity availability
- **Outcome**: Market naturally stabilizes around optimal utilization without governance intervention

**4. Bitmap Storage Optimization: Maximum Information Density**
- **Reserve configuration**: All parameters packed into single uint256 (one SLOAD operation)
- **User configuration**: 2 bits per reserve × 128 reserves = 256 bits total
- **Reserve factor**: Protocol treasury fee (typically 10%) extracted during index updates

**5. Ray Math (27-Decimal Precision): Compounding Without Rounding Errors**
- **Standard ERC20**: 18 decimals (1e18) - insufficient for long-term interest calculations
- **Aave precision**: 27 decimals (1e27) - 1 billion times more precise
- **Necessity**: Prevents cumulative rounding errors in compound interest over years
- **Application**: All interest calculations, index updates, and rate computations use Ray math
- **Result**: Accurate balance growth even after thousands of compounding periods

## Reference
- Aave v2 whitepaper: https://github.com/aave/protocol-v2/blob/master/aave-v2-whitepaper.pdf
- Aave v2 repo: https://github.com/aave/protocol-v2

## Discussion
- Twitter: [@chloe_zhuX](https://x.com/Chloe_zhuX)
- Telegram: [@Chloe_zhu](https://t.me/chloe_zhu)
- GitHub: [@Chloezhu010](https://github.com/Chloezhu010)

---

*Last updated: Dec 5th, 2025*
*Part of my #LearnInPublic Defi series*