Share-Based Accounting
How positions track balances efficiently using shares and indices
Why Shares?
Traditional balance tracking has problems at scale - updating every user's balance on every interest accrual is O(n) complexity and causes rounding errors to accumulate differently per user.
Share-based accounting solves this by updating a single global index (O(1) complexity), and deriving user balances on-demand by multiplying their shares by the current index. All users share the same index, eliminating drift.
Core Data Model
Position Structure
Each user position stores shares, not native balances:
deposit_scaled- supply sharesdebt_scaled- debt shares
Native balances are derived:
deposit_native = deposit_scaled × lending_indexdebt_native = debt_scaled × borrow_index
Pool Indices
Each pool maintains two indices that grow over time:
lending_index- cumulative supply growth (starts at 1.0)borrow_index- cumulative debt growth (starts at 1.0)last_updated- timestamp of last sync
Balance Calculation
Supply balance: deposit_native = deposit_scaled × lending_index
Debt balance: debt_native = debt_scaled × borrow_index
Share Operations
Minting Shares (Deposit/Borrow)
When a user deposits or borrows, shares are minted based on the current index:
shares = native_amount / index
Example Deposit: User deposits 100 tokens at lending_index = 1.05 → shares_minted = 100 / 1.05 = 95.24 shares
Burning Shares (Withdraw/Repay)
When a user withdraws or repays, shares are burned:
Example Withdraw: User withdraws after index grows to 1.10 → shares_burned = 95.24 shares → native_received = 95.24 × 1.10 = 104.76 tokens (earned 4.76 tokens interest)
Interest Accrual Example
Initial State (t=0):
- lending_index = 1.0, borrow_index = 1.0
- Alice deposits 1000 tokens → 1000 shares
- Bob borrows 500 tokens → 500 debt shares
After 1 Year:
- Pool utilization = 50%
- Borrow rate = 5.125%, Lending rate = 2.306%
- New indices: borrow_index = 1.0526, lending_index = 1.0231
Balances:
- Alice: 1000 shares × 1.0231 = 1023.1 tokens (+2.31% APY)
- Bob: 500 shares × 1.0526 = 526.3 tokens debt (+5.26% APY)
- Interest gap: 26.3 - 23.1 = 3.2 tokens (protocol revenue)
RAY Precision
All index calculations use RAY precision (1e27) to maintain accuracy. This matches Aave's implementation and provides enough precision for tokens with up to 9 decimals plus 18 digits of buffer.
Index Synchronization
Before any operation, the pool's indices must be synchronized to the current time:
This ensures all operations use up-to-date indices for accurate share calculations.
Key Invariants
- Indices never decrease - they only grow (monotonic)
- Shares only change on user actions - deposit/withdraw/borrow/repay/liquidate
- Protocol revenue = debt interest - supply interest
- All calculations use RAY precision (1e27)