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

  1. Epoch starts — A new operational period begins

  2. KSU price updateSystemVariables.updateKsuEpochTokenPrice() fetches the KSU price from the oracle. The price remains fixed for the epoch

  3. Request management — Liquidity Providers submit deposit and withdrawal requests. Requests can be canceled before clearing begins

  4. 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

  5. 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