Epochs & Clearing
Epochs
An epoch is a fixed 7-day time period that structures all operations in Kasu. All lending pools share the same system-wide epoch timing. Custom per-pool epochs are not supported.
Epoch Lifecycle
Epoch starts — A new operational period begins
KSU price update —
SystemVariables.updateKsuEpochTokenPrice()fetches the KSU price from the oracle. The price remains fixed for the epochRequest management — Liquidity Providers submit deposit and withdrawal requests. Requests can be canceled before clearing begins
Clearing period — The final 48 hours of the epoch. Deposit and withdrawal requests are processed. New requests submitted during this window are assigned to the next epoch
Epoch ends — The next epoch begins immediately
Clearing
Clearing is a multi-step process executed independently for each lending pool. Before clearing can begin, loyalty levels must be calculated for the current epoch by calling UserManager.batchCalculateUserLoyaltyLevels().
The Pool Clearing Manager initiates clearing by calling LendingPoolManager.doClearing().
Step 1: Apply Pool Interest to Tranches
The lending pool mints USDC-IOUs proportional to the aggregate interest for the epoch. These IOUs are distributed to each tranche based on its interest rate. Performance fees are calculated and allocated to the Fee Manager as Owed Fees.
Step 2: Calculate Pending Request Priority
The system loops over all pending requests up to the current epoch and aggregates them by tranche and loyalty level. This determines processing order:
Loyalty Level 2 deposits are processed first within each tranche
Loyalty Level 1 deposits are processed next
Loyalty Level 0 deposits are processed last
Withdrawal requests pending for 5+ epochs automatically receive Loyalty Level 2
Force Withdrawals receive the highest non-public priority level (processed before all LP requests)
This step can be batched across multiple transactions if the number of requests exceeds block gas limits.
Step 3: Calculate Accepted Amounts
Using the priority-sorted requests and the clearing configuration (draw amount, tranche ratios, excess percentages), the system calculates:
How much each tranche should accept in deposits
Which deposit requests are accepted, partially accepted, or rejected
Which withdrawal requests can be fulfilled from excess funds
Deposits fill tranches starting from Junior, with overflow to Mezzanine then Senior. Within each tranche, higher loyalty levels are processed first.
Step 4: Process Accepted Requests
The system loops over all requests and executes the calculated allocations:
Accepted deposits: USDC moves from Pending Pool to lending pool, tranche shares are minted to the user, D-NFT is burned
Rejected deposits: USDC is returned to the Liquidity Provider, D-NFT is burned
Accepted withdrawals: Tranche shares are returned to the lending pool, proportional USDC is sent to the user, W-NFT is burned (or updated if partial)
Pro-rata distribution is enforced — if 60% of a loyalty level's deposits are accepted into one tranche and 40% overflow to the next, each user receives the same 60/40 split.
This step can also be batched across multiple transactions.
Step 5: Draw Funds
USDC is automatically sent to the configured Draw Recipient address based on the draw amount set in the clearing configuration.
Post-Clearing: Pay Owed Fees
The Clearing Coordinator calls LendingPool.payOwedFees() to pay any outstanding fees from the pool's excess funds to the Fee Manager.
Missing a Clearing Period
If clearing is not executed during the clearing period, deposit and withdrawal requests cannot be processed for that epoch and no funds can be drawn. The doClearing() function must still be called to apply interest (Step 1) for accounting continuity.
Last updated