Protocol Accounting

Lotus protocol accounting covering junior supply, free supply, interest cascade mechanics, bad debt allocation, and lazy accrual patterns.

Lotus uses tranche ordering to route liquidity, interest, and losses through a market:

  • Unused liquidity from junior tranches can be used by senior borrowers.

  • Interest and bad debt cascade to the current tranche and all more junior tranches, proportional to each tranche's share of available supply.

Junior Supply and Borrow

Assume a market has N tranches indexed [0 … N-1] from most senior to most junior.

The junior supply at tranche i is the total lender liquidity from tranche i through tranche N-1, including interest that has been accrued but not yet distributed. Intuitively, it is the liquidity accessible to a tranche ignoring borrowing activity.

jrSupply[i]=j=iN1(trancheSupplyAssets[j]+pendingInterest[j])jrSupply[i] = \sum_{j=i}^{N-1} (trancheSupplyAssets[j] + pendingInterest[j])

The junior borrow at tranche i is total borrower debt outstanding from tranche i through tranche N-1.

jrBorrow[i]=j=iN1trancheBorrowAssets[j]jrBorrow[i] = \sum_{j=i}^{N-1} trancheBorrowAssets[j]

The junior net supply is unused liquidity from tranche i through tranche N-1 . Junior net supply must always be ≥ 0.

jrNetSupply[i]=max(0, jrSupply[i]jrBorrow[i])jrNetSupply[i] = \max(0,\ jrSupply[i] - jrBorrow[i])

Free Supply and Utilization

The free supply at tranche i is the amount of loanToken that can be:

  • borrowed from tranche i, and/or

  • withdrawn by lenders from tranche i

It is the tightest constraint across the cascade from tranche 0 through tranche i, because any senior borrow demand can limit what is actually free at more junior tranches.

freeSupply[i]=minj[0,i]jrNetSupply[j]freeSupply[i] = \min_{j \in [0,i]} jrNetSupply[j]

The available supply at tranche i is the liquidity tranche i had access to before any borrowing in tranche i.

availableSupply[i]=jrNetSupply[i]+trancheBorrowAssets[i]availableSupply[i] = jrNetSupply[i] + trancheBorrowAssets[i]

Tranche supply utilization is the fraction of available supply attributable to suppliers who supplied specifically to tranche i.

trancheSupplyUtilization[i]=trancheSupplyAssets[i]availableSupply[i]trancheSupplyUtilization[i] = \frac{trancheSupplyAssets[i]}{availableSupply[i]}

Interest or bad debt generated from a borrow tranche cascades to more junior supply tranches based on trancheSupplyUtilization.


Interest & Fee Accrual

When Lotus accrues interest, it does two things:

  1. Accrues borrower interest for each tranche (increasing trancheBorrowAssets).

  2. Routes that interest to suppliers in the current tranche and more junior tranches using the tranche utilization weights.

Each tranche contributes to a running balance called cascadingInterest:

  • newly accrued trancheBorrowInterest

  • any previously stored pendingInterest

Each tranche i receives a share of the current cascadingInterest proportional to trancheSupplyUtilization[i]. Any remainder continues cascading to more junior tranches.

cascadingInterestcascadingInterest+trancheBorrowInterest+pendingInterestcascadingInterest \leftarrow cascadingInterest + trancheBorrowInterest + pendingInterest
trancheSupplyInteresttrancheSupplyUtilization[i]cascadingInteresttrancheSupplyInterest \leftarrow trancheSupplyUtilization[i] \cdot cascadingInterest
cascadingInterestcascadingInteresttrancheSupplyInterestcascadingInterest \leftarrow cascadingInterest - trancheSupplyInterest
spinner

Walkthrough (market with 3 tranches, 0=senior, 2=junior; 100 units of interest accrued in Tranche 0):

Step 1: Tranche 0 borrow interest accrues. Tranche 0 borrowers owe 100 units. cascadingInterest starts at 0, adds tranche[0].borrowInterest (100) and tranche[0].pendingInterest (0), yielding 100.

Step 2: Distribute to Tranche 0 suppliers. tranche[0].supplyUtilization = 40%. Tranche 0 suppliers receive 100 × 40% = 40 units. cascadingInterest = 100 − 40 = 60 (continues to T1).

Step 3: Distribute to Tranche 1 suppliers. cascadingInterest = 60 (from T0) + tranche[1].borrowInterest (0) + tranche[1].pendingInterest (0) = 60. tranche[1].supplyUtilization = 50%. Tranche 1 suppliers receive 60 × 50% = 30 units. cascadingInterest = 60 − 30 = 30 (continues to T2).

Step 4: Distribute to Tranche 2 suppliers. cascadingInterest = 30 (from T1) + tranche[2].borrowInterest (0) + tranche[2].pendingInterest (0) = 30. tranche[2].supplyUtilization = 100% (most junior). Tranche 2 suppliers receive 30 × 100% = 30 units. cascadingInterest = 0 (complete).

100 units interest from T0 borrowers distributed: 40 to T0 suppliers (40%), 30 to T1 suppliers (50% × 60), 30 to T2 suppliers (100% × 30). Junior suppliers (T2) supported senior borrowers (T0) and earned interest proportional to their utilization.


Bad Debt Allocation

If a liquidation generates bad debt, the loss is deducted from suppliers in the current tranche and more junior tranches using the same utilization weighting.

At tranche i:

trancheSupplyBadDebttrancheSupplyUtilization[i]cascadingBadDebttrancheSupplyBadDebt \leftarrow trancheSupplyUtilization[i] \cdot cascadingBadDebt
cascadingBadDebtcascadingBadDebttrancheSupplyBadDebtcascadingBadDebt \leftarrow cascadingBadDebt - trancheSupplyBadDebt
spinner

Walkthrough (market with 3 tranches, 0=senior, 2=junior; 50 units of bad debt from liquidation in Tranche 1):

Step 1: Bad debt originates in Tranche 1. Liquidation in T1 results in a 50-unit shortfall (collateral value 200, debt owed 250). cascadingBadDebt = 50.

Step 2: Allocate loss to Tranche 1 suppliers. tranche[1].supplyUtilization = 60%. Tranche 1 suppliers absorb 50 × 60% = 30 units. tranche[1].supplyAssets decreases by 30. cascadingBadDebt = 50 − 30 = 20 (continues to T2).

Step 3: Allocate remaining loss to Tranche 2 suppliers. cascadingBadDebt = 20 (from T1). tranche[2].supplyUtilization = 100% (most junior). Tranche 2 suppliers absorb 20 × 100% = 20 units. cascadingBadDebt = 0 (complete). T0 suppliers absorb nothing. Senior tranches are not exposed to T1 risk.

circle-info

Suppliers who earn interest from a tranche's borrowers also absorb bad debt from those borrowers in the same proportion (trancheSupplyUtilization). Risk and reward are symmetric via the cascade mechanism.

Risk and reward are symmetric: suppliers who earn interest from a tranche's borrowers also absorb bad debt from those borrowers in the same proportion.


Lazy Interest Accrual

Interest accrues lazily during operations that touch tranche state. Borrower-side interest can be accrued independently from supplier-side interest distribution. Two important accounting facts:

  • trancheBorrowAssets includes interest accrued up to lastUpdate.

  • trancheSupplyAssets may not include all interest accrued up to lastUpdate, because supplier interest depends on cascading interest from tranches 0 ... i.

To fully update trancheSupplyAssets[i], Lotus processes borrow interest and pending interest for all tranches more senior than (and including) i and distributes the resulting cascade using utilization weights.

Borrowing

In borrow(), repay(), and withdrawCollateral(), Lotus accrues borrower interest only for the specified tranche.

Newly accrued interest is stored in pendingInterest until a supply-side operation needs accurate supplier balances.

Lending

supply() and withdraw() require up-to-date supplier accounting. Lotus iterates from tranche 0 through the target tranche index and:

  1. accruing borrow interest,

  2. pulling pendingInterest into cascadingInterest,

  3. allocating supplier interest to trancheSupplyAssets,

  4. distributing fees,

  5. carrying any remainder forward as pendingInterest in the next tranche

Withdraw gas/accuracy option

Lenders can opt out of interest accrual on withdraw() (shouldAccrueInterest = false). This avoids the gas cost of sweeping senior tranches but uses stale supplier accounting, so the withdrawing lender receives fewer loanToken units than with full accrual.

Liquidation

  • If a liquidation produces no bad debt, Lotus accrues interest like other borrow-side operations (tranche-local only).

  • If a liquidation produces bad debt, Lotus accrues interest for the entire market so loss allocation uses up-to-date balances.

Fee Accrual

A Tranche.fee fraction of trancheSupplyInterest is distributed to the protocol’s feeRecipient by inflating supply shares.

Fees are capped by the global MAX_FEE. If the fee is updated via setFee(), Lotus accrues interest first so the change applies to up-to-date state.

See Also

  • Learn → Liquidity Flow for the introductory explanation of cascading supply

  • Learn → Protocol Math for the full mathematical derivation

  • Reference → Admin for fee configuration

Last updated