Contract Map
Vanna Protocol is composed of 14 Soroban smart contracts divided into five functional groups.| Group | Contracts | Role |
|---|---|---|
| Entry | AccountManager, LendingPoolXLM, LendingPoolUSDC | User-facing entry points |
| Per-User State | SmartAccount (one per user) | Holds collateral, debt, and external positions |
| Risk | RiskEngine, RateModel | Health checks and interest rate computation |
| Infrastructure | Registry, Oracle, TrackingToken, vXLM, vUSDC | Address resolution, price feeds, position tokens |
| Deployment | DeployerContract, DeployerLPoolContract | Factory contracts for new SmartAccount instances |
Layer Diagram
Contract Descriptions
AccountManager
The single entry point for all margin operations. Users never call SmartAccount directly — every operation passes through AccountManager, which:- Authenticates the caller
- Asks the RiskEngine whether the operation is allowed
- Calls the appropriate LendingPool to issue or collect debt
- Calls the SmartAccount to update balances and execute external protocol calls
- Emits events
create_account, borrow, repay, deposit_collateral_tokens, withdraw_collateral_balance, liquidate, close_account
SmartAccount (Per-User)
Each user who opens a margin account gets their own deployed SmartAccount contract — a separate on-chain instance with its own storage. This isolates risk: a bug in one account cannot affect another. The AccountManager deploys SmartAccounts via the DeployerContract using a deterministic salt. Closed accounts are recycled into an inactive pool and reused on next open to save deployment cost. SmartAccount stores:CollateralTokensListandCollateralBalanceWAD(symbol)— raw collateralBorrowedTokensList— symbols with outstanding debtIsAccountActive,HasDebt— account state flags- External positions are tracked via TrackingTokens (not stored here)
execute(target, action, ...) which routes to Blend, Aquarius, or Soroswap based on action type.
LendingPools (XLM · USDC)
Two separate pool contracts, one per asset. Each pool:- Accepts deposits and mints vTokens (vXLM, vUSDC) proportional to share of pool
- Tracks outstanding borrows using a borrow shares model
- Calls
update_state()before every borrow/repay to accrue interest - Has two privileged functions only callable by AccountManager:
lend_to()andcollect_from()
RiskEngine
A stateless contract that reads position data from SmartAccount and LendingPools, prices everything via Oracle, and returns a boolean (allowed / not allowed) for every gated operation. Three guard functions:is_borrow_allowed(symbol, amount, account)— gross-asset modelis_withdraw_allowed(symbol, amount, account)— net-asset modelis_account_healthy(balance, debt)— raw comparator (1.1× threshold)
RateModel
Computes the per-second borrow rate given current pool utilization. Uses a smooth polynomial curve (not a kinked two-slope model):update_state().
Registry
An on-chain address book. Every protocol contract resolves peer addresses through the Registry at runtime — no hardcoded addresses in business logic. This makes upgrades safe: update the Registry entry, not every contract.Oracle
A thin passthrough to the Reflector oracle. Exposesget_price_latest(symbol) returning (price: u128, decimals: u32). The RiskEngine converts these to WAD format for collateral valuation.
TrackingToken
A single contract that tracks balances for synthetic position tokens — one per tracked position type:| Symbol | Represents |
|---|---|
BLEND_XLM | XLM deposited into Blend pool |
BLEND_USDC | USDC deposited into Blend pool |
AQ_XLM_USDC | Aquarius XLM/USDC LP position |
SS_XLM_USDC | Soroswap XLM/USDC LP position |
vTokens (vXLM · vUSDC)
Standard fungible tokens representing LP share in a lending pool. Exchange rate grows over time as borrowers repay interest. Holders earn yield passively by holding vTokens.Key Data Flows
Deposit Flow (LP Supply)
Borrow Flow (Margin Account)
Liquidation Flow
External Protocol Deployment (Blend)
Authorization Model
| Caller | Can call |
|---|---|
| User wallet | AccountManager, LendingPool (deposit/redeem) |
| AccountManager | SmartAccount (all write functions), LendingPool (lend_to, collect_from) |
| SmartAccount | TrackingToken (mint/burn), external protocols (Blend, Aquarius, Soroswap) |
| Anyone | AccountManager.liquidate() — no auth required, anyone can liquidate |
Fixed-Point Arithmetic
All balances, prices, and rates are stored in WAD format (10¹⁸ = 1.0). Asset amounts are converted to WAD at protocol boundaries:mul_wad_down and div_wad_down (floor division) to prevent rounding in the protocol’s favor.
For the full formula reference, see Math Reference.
