Skip to main content
All Vanna contracts use WAD fixed-point arithmetic with 10¹⁸ as the representation of 1.0. This page documents every formula used in the protocol.

WAD Arithmetic

Constants

Core Operations

All intermediate math uses floor division (mul_wad_down, div_wad_down). This means rounding errors accumulate against the protocol, not in the protocol’s favor.

Decimal Conversion

Every asset has native decimals (XLM: 7, USDC: 6). Balances are converted to WAD at protocol entry and back to native decimals at exit.
Example (XLM, 7 decimals):

Interest Rate Model

Utilization Ratio

Where liquidity_wad is the pool’s current asset balance in WAD.

Borrow Rate Per Second

Vanna uses a smooth polynomial curve (not a kinked two-slope model):
With: The util^32 and util^64 terms are computed via WAD exponentiation (rpow_wad). At low utilization the curve is nearly linear. At high utilization the polynomial terms dominate, pushing rates up sharply.

Annual Rate Derivation

To get the annualized rate for display:

Interest Accrual

Rate Factor

Computed at every borrow or repayment (update_state()):

State Update

If now == last_updated the function exits early — no double-accrual within the same ledger.

Live (Preview) Borrows

When computing health factors, the protocol uses live borrows (including interest that has accrued since the last state update but not yet written to storage):
This ensures borrow shares issued right now correctly reflect the current debt level.

Borrow Share Accounting

Borrows are tracked via shares, not raw amounts. This lets interest accrue globally without updating each user’s record.

Issuing Shares (on Borrow)

Burning Shares (on Repay)

Computing User Debt

Note: user debt is computed from borrows_wad (stored, slightly stale), while share issuance uses borrows_live (fresh). This is intentional — it prevents over-issuance of shares.

Origination Fee

On every borrow, a one-time fee is charged:
The fee is sent from the pool to the protocol treasury. The borrower receives borrow_amount - origination_fee.

vToken Exchange Rate

vTokens represent a proportional share of a pool’s total assets (pool_balance + borrows_wad).

Minting on Deposit

Redeeming on Withdrawal

Exchange Rate

The implicit exchange rate grows as interest accrues:
As borrows_wad grows with interest, total_assets grows, and each vToken is worth more underlying.

Health Factor

The health factor is a ratio of total collateral value to total debt value.
Healthy: HF > 1.1 × WAD (strictly greater than)
Liquidatable: HF ≤ 1.1 × WAD

Collateral Valuation

Different collateral types are valued differently: Raw tokens (XLM, USDC):
Blend b-tokens (BLEND_XLM, BLEND_USDC):
Where b_rate is fetched from the Blend pool’s reserve data. LP tracking tokens (AQ_XLM_USDC, SS_XLM_USDC):

Borrow-Time Check (Gross-Asset Model)

When evaluating a new borrow, both the new borrow and existing borrows count as assets:
This means same-asset leverage (borrow XLM, deploy to Blend XLM) correctly shows HF > 1 instead of near zero.

Withdraw-Time Check

Liquidation Check

Uses pure collateral (not gross-asset model):

Constants


Oracle Price Conversion

Prices from the Reflector oracle come as (price: u128, decimals: u32). The RiskEngine converts to WAD:
Example:

Token Symbol Canonicalization

Before price lookup, the RiskEngine maps wrapped token symbols to their underlying asset:

Soroswap/Aquarius AMM Formulas

Optimal Liquidity Amount (Add Liquidity)

Given pool reserves (R_a, R_b) and desired inputs (A_desired, B_desired):

Swap Output (Soroswap, 0.3% fee)

Actual output from reserves (constant product, x × y = k):

Storage TTL

All persistent storage keys are extended with a TTL to prevent ledger entry expiry: Extensions are applied on every write and on reads for frequently accessed keys.