Skip to content

Settlement

Overview

Settlement is the periodic process of recalculating the vault's Net Asset Value (NAV), updating the Price Per Share (PPS), and collecting performance fees. This is a manual, off-chain-triggered operation — PPS does not update automatically on every block.

Access Control

Only the Accountant role may trigger settle(). Only the VaultOwner may call confirmSettlement().


Settlement Flow

sequenceDiagram
    actor Acct as Accountant
    participant Vault as KingsVault (ETH)
    participant Port as KPortfolio
    participant Pools as EarnPools (Aave/Morpho)
    participant Hyper as HyperStrategy (HyperEVM)
    participant Core as HyperCore (L1Read)

    Note over Acct,Core: Phase 1: Gather Total Assets
    Acct->>Vault: settle()
    Vault->>Port: totalValues()
    Port->>Pools: valuesOf() for each enabled pool
    Pools-->>Port: balance per pool
    Port-->>Vault: ETH-side total

    Note over Hyper,Core: Phase 1b: Cross-Chain NAV Report
    Hyper->>Core: L1Read (0x800) — vaultEquity
    Hyper->>Core: L1Read (0x800) — spotBalance
    Hyper-->>Vault: CCIP: totalAsset (vaultEquity + spotBalance + EVM idle)

    Note over Vault: Phase 2: Compute PPS
    Vault->>Vault: TotalAssets = ETH_total + Hyper_total
    Vault->>Vault: PPS = TotalAssets / totalSupply()

    Note over Vault: Phase 3: Performance Fee
    alt PPS > HWM (High Water Mark)
        Vault->>Vault: FeeShares = (PPS - HWM) * supply * feeRate / PPS
        Vault->>Vault: _mint(Manager, FeeShares)
        Vault->>Vault: Update HWM = PPS
    end

    Vault-->>Acct: Settled PPS

Step-by-Step

Phase 1: Gather Total Assets

Step Component Action Detail
1.1 Accountant Trigger settlement. vault.settle()
1.2 KingsVault Query ETH-side assets. Calls portfolio.totalValues() which iterates all enabled EarnPools.
1.3 KPortfolio Aggregate pool values. Sums valuesOf() from each pool + portfolio idle USDC.
1.4 HyperStrategy Query HyperCore state. Reads vaultEquity and spotBalance via L1Read precompile (0x800).
1.5 HyperStrategy Report to Ethereum. Sends totalAsset value back via CCIP ccipSend().
1.6 KingsVault Receive cross-chain report. _ccipReceive() processes settlement data message.

Phase 2: Compute PPS

Step Action Formula
2.1 Sum total assets. TotalAssets = Vault_Idle + Portfolio_Total + HyperCore_Equity + Pending_CCIP
2.2 Calculate PPS. PPS = TotalAssets / totalSupply()
2.3 Default PPS. If totalSupply() == 0, PPS defaults to 1.000000.

Phase 3: Performance Fee Collection

Fee is only charged when PPS exceeds the High Water Mark (HWM).

Step Action Formula
3.1 Check profit. PPS_current > PPS_HWM ?
3.2 Calculate fee shares. FeeShares = (PPS_current - PPS_HWM) * TotalSupply * feeRate / PPS_current
3.3 Mint to Manager. _mint(ManagerAddress, FeeShares)
3.4 Update HWM. PPS_HWM = PPS_current

Worked Example

Before settlement:

Parameter Value
TotalSupply 1,000,000 shares
PPS_HWM 1.10
Fee Rate 20%

Settlement data received:

Parameter Value
TotalAssets 1,200,000 USDC
PPS_current 1,200,000 / 1,000,000 = 1.20

Fee calculation:

  1. Profit check: 1.20 > 1.10 → profit exists.
  2. Total profit: (1.20 - 1.10) * 1,000,000 = 100,000 USDC
  3. Fee amount: 100,000 * 20% = 20,000 USDC
  4. Fee shares: 20,000 / 1.20 = 16,666.67 shares
  5. Mint 16,666.67 shares to Manager.
  6. Update HWM: 1.20.

After settlement:

Parameter Value
TotalSupply 1,016,666.67 shares
PPS (post-dilution) 1,200,000 / 1,016,666.67 ≈ 1.180

Dual Confirmation (Stage 1)

In Stage 1, settlement uses a two-step confirmation to guard against data anomalies:

  1. settle() — Accountant triggers NAV calculation and proposes a PPS.
  2. confirmSettlement() — VaultOwner reviews the proposed PPS off-chain and confirms it.

This ensures a human review step before the PPS is committed, protecting against oracle failures or compromised data feeds.


Security Considerations

  1. Stale PPS: If settlement is not run frequently, deposits and withdrawals execute at an outdated price, potentially disadvantaging one side.
  2. Fee Timing Attack: A compromised Accountant could delay settlement to accumulate more profit before triggering fee collection, or trigger prematurely.
  3. Cross-Chain Data Integrity: The HyperCore equity reported via CCIP must be validated against the expected sourceChainSelector and senderAddress. A forged settlement message could manipulate PPS.
  4. Bounded Iteration: totalValues() must iterate over a bounded number of pools to prevent out-of-gas reverts during settlement.