On-Chain Vault Integration

A third-party smart contract vault can integrate with Kasu to give its depositors access to Kasu lending pool yields. The vault is KYB'd (allowlisted) on Kasu's side, so individual vault depositors do not need to complete KYC — the vault itself is the single, verified depositor.

Architecture Overview

┌─────────────────────────────────────────────┐
│                  Vault Contract              │
│                                              │
│  ┌──────────┐   ┌────────────────────────┐  │
│  │  USDC    │   │  Kasu Pool Allocations │  │
│  │  Buffer  │   │                        │  │
│  │          │   │  Pool A / Tranche 1    │  │
│  │  Instant │   │  Pool B / Tranche 2    │  │
│  │  In/Out  │   │  Pool C / Tranche 1    │  │
│  └──────────┘   └───────────┬────────────┘  │
│                              │               │
└──────────────────────────────┼───────────────┘

                    USDC approve + requestDeposit()


                ┌──────────────────────────────┐
                │    LendingPoolManager        │
                │    (Kasu Entry Point)        │
                └──────────────────────────────┘

Key design points:

  • The vault maintains a USDC liquidity buffer for instant user deposits and withdrawals, since Kasu deposits/withdrawals are processed during clearing (weekly epochs).

  • The vault is a single address allowlisted via KasuAllowList.allowUser(). No Compilot/NexeraID KYC signature is needed per transaction.

  • The vault operator configures which pools and tranches the vault allocates to. This can be a one-time configuration or dynamically managed.

  • All interactions go through LendingPoolManager — the vault calls the same user-facing functions as any other depositor.

Prerequisites

Before the vault can interact with Kasu:

1. Kasu Admin Allowlists the Vault

The Kasu Admin must call allowUser() on the KasuAllowList contract to allowlist the vault address:

Once allowlisted, the vault can call requestDeposit() directly (without the WithKyc variant and without KYC signatures appended to calldata).

2. USDC Approval

Before each deposit, the vault must approve the LendingPoolManager to spend USDC:

3. Contract Addresses

The vault needs to know the addresses of:

Contract
Purpose

LendingPoolManager

Entry point for all deposit/withdrawal operations

USDC

The deposit token

Target lending pool(s)

The pools to deposit into

Pool and tranche addresses can be discovered on-chain via ILendingPool.lendingPoolInfo() (see Reading Pool State).

For deployed addresses, see Deployed Addresses.

Core Operations

All vault interactions go through LendingPoolManager. The vault calls these functions as msg.sender.

Requesting a Deposit

Deposits are not instant. They are queued for the current epoch and processed at the next clearing.

Parameters:

Parameter
Value for Vault

lendingPool

Address of the target lending pool

tranche

Address of the target tranche (get from lendingPoolInfo().trancheAddresses)

maxAmount

USDC amount to deposit (6 decimals)

swapData

"" (empty bytes) — vault deposits USDC directly

fixedTermConfigId

0 for flexible deposit, or a valid config ID for fixed-term

depositData

"" (empty bytes) or any custom data for off-chain tracking

Returns: A D-NFT ID (dNftID) representing the pending deposit request. The vault receives this ERC-721 token from the pool's PendingPool contract.

Example:

Important: Deposits submitted during the clearing period (~48 hours at the end of each epoch) are accepted but queued for the next epoch, not the current one. Cancellations are not allowed during the clearing period.

Cancelling a Deposit Request

A pending deposit can be cancelled before clearing processes it. USDC is refunded to the vault.

Cancellations cannot be submitted during the clearing period.

Requesting a Withdrawal

Withdrawals are also queued and processed at the next clearing.

Parameters:

Parameter
Description

lendingPool

Address of the lending pool

tranche

Address of the tranche

amount

Number of tranche shares to withdraw (not USDC). Use ILendingPoolTranche.userActiveShares(vault) to get the vault's share balance.

Returns: A W-NFT ID (wNftID) representing the pending withdrawal request.

The USDC value of shares depends on the current exchange rate. Use ILendingPoolTranche.convertToAssets(shares) to estimate the USDC equivalent.

Important: Withdrawals may be partially filled during clearing if there isn't enough liquidity. Unfilled shares remain in the vault's position and can be re-requested in the next epoch.

Cancelling a Withdrawal Request

Cancellations cannot be submitted during the clearing period.

Fixed-Term Deposits

The vault can lock deposits for a fixed duration with a guaranteed interest rate. Fixed-term deposits cannot be withdrawn early.

Locking an existing deposit into a fixed term:

Requesting withdrawal of a matured fixed-term deposit:

Cancelling a fixed-term withdrawal request:

See Fixed Term Deposits for details on fixed-term configurations and maturity.

Claiming Repaid Losses

If a loss event occurs and is later repaid by the pool operator, the vault can claim its share:

See Losses & Recovery for the full loss lifecycle.

Reading Pool State

The vault should read on-chain state to make informed allocation decisions and track its positions.

Pool Information

Vault Position (Per Tranche)

Each tranche is an ERC-4626 vault. The vault's position is tracked as tranche shares:

Pending Requests

APY & Yield

Reading the current interest rate (APY):

Each tranche has an epoch interest rate stored on-chain. This is the rate applied per epoch (7 days), not annualized:

To convert to APY (annualized):

Where 52.17857 is the number of 7-day epochs per year (365.25 / 7).

Accumulated yield for the vault:

There is no single on-chain view function that returns accumulated yield. Yield is embedded in the ERC-4626 share price — as interest accrues each epoch, each tranche share becomes worth more USDC.

To calculate the vault's accumulated yield, track deposits and withdrawals and compare against the current position value:

Where:

  • currentAssetValue = ILendingPoolTranche(tranche).userActiveAssets(vaultAddress)

  • totalDeposited = sum of all accepted deposit amounts (from DepositAccepted events)

  • totalWithdrawn = sum of all accepted withdrawal amounts (from WithdrawalAccepted events)

The vault contract should maintain its own accounting of deposited and withdrawn amounts, or index the relevant events off-chain:

Overall pool yield:

Total interest distributed to a pool's LPs is available via InterestApplied events emitted by the LendingPool contract at each clearing:

Epoch Timing

The vault should be aware of epoch boundaries and clearing periods. Deposits and withdrawals submitted during clearing are queued for the next epoch. Cancellations are blocked during clearing. The SystemVariables contract provides epoch timing:

Vault Lifecycle

1. Setup

  1. Deploy the vault contract with references to LendingPoolManager, USDC, and target pool addresses

  2. Complete KYB — the vault operator undergoes KYB verification with Kasu

  3. Kasu Admin allowlists the vault address via kasuAllowList.allowUser(vaultAddress)

  4. Configure allocations — define which pools and tranches to deposit into

2. Depositing into Kasu

  1. Vault accumulates USDC from its own depositors

  2. Based on allocation strategy, vault calls usdc.approve() then requestDeposit() for each target pool/tranche

  3. Deposit is queued — vault receives a D-NFT

  4. At the next clearing (end of epoch), the deposit is processed:

    • If accepted: USDC is transferred, vault receives tranche shares

    • If rejected (e.g., pool capacity reached): USDC is returned, D-NFT is burned

  5. Vault can cancel before clearing via cancelDepositRequest()

3. Earning Yield

  • Interest accrues automatically each epoch. Tranche shares increase in value relative to USDC.

  • The vault's position value can be tracked via userActiveAssets(vault).

  • No action is required from the vault to earn yield — it accrues passively.

4. Withdrawing from Kasu

  1. Vault calls requestWithdrawal() specifying the tranche shares to withdraw

  2. Withdrawal is queued — vault receives a W-NFT

  3. At the next clearing:

    • If accepted: tranche shares are burned, USDC is returned to the vault

    • If partially accepted: remaining shares stay in the vault's position

  4. Vault distributes received USDC to its own users

5. Handling Losses

If a loss event is reported on a pool where the vault has a position:

  1. Loss tokens (ERC-1155) may be minted to the vault address

  2. Loss tokens represent the vault's share of unrealized losses

  3. If the loss is later repaid, vault calls claimRepaidLoss() to recover USDC

Important Considerations

Timing

Operation
Timing

Deposit request

Instant (queued for current epoch)

Deposit execution

Next clearing (~weekly)

Withdrawal request

Instant (queued for current epoch)

Withdrawal execution

Next clearing (~weekly)

Interest accrual

Each epoch at clearing

Clearing period

~48 hours at end of epoch — deposits/withdrawals queue for next epoch, cancellations blocked

The vault should maintain a USDC buffer large enough to service its own user withdrawals between Kasu clearing cycles.

Deposit Limits

Each tranche has minimum and maximum deposit amounts. The vault must respect these:

These limits apply per deposit request, not cumulative. Multiple deposit requests can be submitted in the same epoch.

NFT Management

The vault receives ERC-721 tokens (D-NFTs and W-NFTs) from the PendingPool contract representing pending requests. The vault contract must be able to receive ERC-721 tokens (implement IERC721Receiver or use onERC721Received).

Similarly, loss tokens are ERC-1155. The vault must implement IERC1155Receiver if it needs to handle loss scenarios.

Gas Considerations

Each requestDeposit() and requestWithdrawal() call operates on a single pool and tranche. If the vault allocates across multiple pools/tranches, each requires a separate transaction.

Clearing Failures

If clearing does not execute for a given epoch (e.g., the pool's clearing manager does not trigger it), pending requests remain queued. They carry over to the next epoch's clearing. The vault can cancel pending requests at any time outside of the clearing period.

Last updated