Pause the vault (emergency). When paused: deposits and withdrawals are blocked. Settlements still work to allow position closures.
fn pause(env: soroban_sdk::Env) -> Result<(), NoetherError>
Deposit USDC and receive NOE tokens.
depositor - Address depositing USDCusdc_amount - Amount of USDC to deposit (7 decimals)Amount of NOE tokens received
noe_amount = usdc_amount * circulating_noe / aum (or 1:1 if first deposit)
fn deposit(
env: soroban_sdk::Env,
depositor: soroban_sdk::Address,
usdc_amount: i128,
min_noe_out: i128,
) -> Result
Calculate current AUM.
fn get_aum(env: soroban_sdk::Env) -> Result
Unpause the vault. Auto-cancels any open recovery proposal (L0-15) — leaving the emergency once the emergency is over must retract the break-glass.
fn unpause(env: soroban_sdk::Env) -> Result<(), NoetherError>
Swap the running WASM in place; LP balances and pool accounting are preserved across the upgrade.
fn upgrade(
env: soroban_sdk::Env,
new_wasm_hash: soroban_sdk::BytesN<32>,
) -> Result<(), NoetherError>
Withdraw USDC by returning NOE tokens.
withdrawer - Address withdrawingnoe_amount - Amount of NOE tokens to returnAmount of USDC returned
usdc_returned = noe_amount * aum / circulating_noe - withdrawal_fee
User must approve the vault to spend their NOE tokens before calling.
fn withdraw(
env: soroban_sdk::Env,
withdrawer: soroban_sdk::Address,
noe_amount: i128,
min_usdc_out: i128,
) -> Result
Get admin address.
fn get_admin(env: soroban_sdk::Env) -> Result
Check if paused.
fn is_paused(env: soroban_sdk::Env) -> bool
Transfer admin role. Requires both current admin and new admin authorization.
fn set_admin(
env: soroban_sdk::Env,
new_admin: soroban_sdk::Address,
) -> Result<(), NoetherError>
Initialize the vault with configuration.
admin - Admin address for configurationusdc_token - USDC token contract addressnoe_token - NOE token contract address (SAC-wrapped classic asset)market_contract - Market contract address (for settlement authorization)deposit_fee_bps - Fee on deposits in basis points (e.g., 30 = 0.3%)withdraw_fee_bps - Fee on withdrawals in basis pointsfn initialize(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
usdc_token: soroban_sdk::Address,
noe_token: soroban_sdk::Address,
market_contract: soroban_sdk::Address,
deposit_fee_bps: u32,
withdraw_fee_bps: u32,
) -> Result<(), NoetherError>
L1-23: pay a keeper bounty from the insurance buffer (market-only). Returns the amount actually paid = min(requested, buffer, vault USDC balance). A dry buffer returns 0 and NEVER errors — a bounty must never block a liquidation clear. Buffer is debited; USDC moves vault→keeper.
fn pay_bounty(
env: soroban_sdk::Env,
keeper: soroban_sdk::Address,
amount: i128,
) -> Result
Settle trader PnL with the vault. Called by the Market contract when positions are closed.
pnl - Profit/loss amount (positive = trader won, negative = trader lost)Trader WON (pnl > 0):
Trader LOST (pnl < 0):
receive_loss() separately to transfer the lossBreak-even (pnl = 0):
⚠️ ABI: (env, trader,
fn settle_pnl(
env: soroban_sdk::Env,
trader: soroban_sdk::Address,
pnl: i128,
) -> Result
Cover bankrupt-liquidation losses from the insurance buffer (L0-2).
Market-only. ACCOUNTING-ONLY — no token moves: the bad-debt USDC was
never collected, and the buffer's tokens already sit in the vault.
Moving covered from the buffer bucket into total_usdc offsets the
NAV drop the uncollected loss causes at close, 1:1 — NOE price stays
flat when the buffer covers and falls by exactly the LP-absorbed
remainder when it cannot. Returns the covered amount.
Spend rule: the ShortfallReserve is a DISJOINT bucket (never inside BufferBalance), so every buffer spender — winner payouts in settle_pnl, this draw, claim_shortfall's buffer leg — reads the same BufferBalance and can never touch earmarked repayment funds.
fn draw_buffer(env: soroban_sdk::Env, amount: i128) -> Result
Credit USDC the market just transferred into the buffer — liquidation penalties, protocol fee share, net trader losses (P5-6). Market-only, credited on receipt (the market transfers, then calls this).
fn fund_buffer(env: soroban_sdk::Env, amount: i128) -> Result<(), NoetherError>
Current global LP-principal cap (0 = unlimited).
fn get_aum_cap(env: soroban_sdk::Env) -> i128
Seed the insurance buffer from an admin-funded USDC transfer (P5-6). The admin must have approved / holds the USDC; it is pulled in and credited to the protocol-owned buffer (NOT LP value).
fn seed_buffer(
env: soroban_sdk::Env,
from: soroban_sdk::Address,
amount: i128,
) -> Result<(), NoetherError>
R-6: set the GLOBAL LP-principal cap (7 decimals; 0 = unlimited). The wave-size lever — bounds total_usdc across ALL depositors so absolute protocol size stays inside the soak plan. Admin only.
fn set_aum_cap(env: soroban_sdk::Env, cap: i128) -> Result<(), NoetherError>
Receive loss payment from Market contract. Called by Market after settle_pnl() when trader loses.
amount - The loss amount being transferred from Market to VaultThis function is optional but recommended for verification. The accounting was already updated in settle_pnl().
fn receive_loss(env: soroban_sdk::Env, amount: i128) -> Result<(), NoetherError>
Set an asset's net-skew cap (bps of AUM) (L0-14). Admin only.
fn set_skew_cap(
env: soroban_sdk::Env,
asset: soroban_sdk::Symbol,
bps: u32,
) -> Result<(), NoetherError>
fn get_asset_cap(env: soroban_sdk::Env, asset: soroban_sdk::Symbol) -> u32
Cumulative USDC an account has deposited (against the cap).
fn get_deposited(env: soroban_sdk::Env, who: soroban_sdk::Address) -> i128
Get current NOE price in USDC. Returns price with 7 decimals (1.0 = 10_000_000).
fn get_noe_price(env: soroban_sdk::Env) -> Result
Get NOE token address.
fn get_noe_token(env: soroban_sdk::Env) -> Result
Get current pool information.
fn get_pool_info(env: soroban_sdk::Env) -> Result
Cumulative winner profit the pool could not pay at close.
fn get_shortfall(env: soroban_sdk::Env) -> i128
Get total circulating NOE (held by users).
fn get_total_noe(env: soroban_sdk::Env) -> i128
One-shot init of the pre-declared recovery destination (called by the deploy script post-initialize). Changing it later requires upgrade().
fn init_recovery(
env: soroban_sdk::Env,
addr: soroban_sdk::Address,
) -> Result<(), NoetherError>
Set one asset's per-side OI cap (bps of AUM). Admin only.
fn set_asset_cap(
env: soroban_sdk::Env,
asset: soroban_sdk::Symbol,
bps: u32,
) -> Result<(), NoetherError>
Market-pushed exposure sync: sets one asset's unrealized trader PnL (folded into total UnrealizedPnl, which prices NOE via AUM) and releases reservation for closed positions in the same call. Positive unrealized PnL = traders winning = lower AUM.
fn sync_exposure(
env: soroban_sdk::Env,
asset: soroban_sdk::Symbol,
asset_unrealized_pnl: i128,
release: i128,
) -> Result<(), NoetherError>
Per-asset caps (L0-14): (cap_bps, cap_abs, skew_cap_bps, effective_cap_now). effective_cap_now = min(AUM×cap_bps, cap_abs) so one read feeds the api stats, specs, and headroom surfaces.
fn get_asset_caps(
env: soroban_sdk::Env,
asset: soroban_sdk::Symbol,
) -> (u32, i128, u32, i128)
Get total USDC in pool (accounting value).
fn get_total_usdc(env: soroban_sdk::Env) -> i128
Get USDC token address.
fn get_usdc_token(env: soroban_sdk::Env) -> Result
Cancel an open recovery proposal (admin).
fn cancel_recovery(env: soroban_sdk::Env) -> Result<(), NoetherError>
Claim short-paid winnings (L0-3). Pays min(owed, reserve + buffer, spendable balance), drawing the earmarked ShortfallReserve first and the insurance buffer for the remainder. Deliberately NOT pause-gated — winners must be able to claim during incidents (exit-only-pause philosophy, L0-15). Returns the amount paid; Ok(0) when nothing is owed or nothing is payable yet (call again after the next inflow).
fn claim_shortfall(
env: soroban_sdk::Env,
trader: soroban_sdk::Address,
) -> Result
Current per-account deposit cap (0 = unlimited).
fn get_deposit_cap(env: soroban_sdk::Env) -> i128
Get deposit fee in basis points.
fn get_deposit_fee(env: soroban_sdk::Env) -> u32
Get NOE balance for an address (queries token contract).
fn get_noe_balance(env: soroban_sdk::Env, user: soroban_sdk::Address) -> i128
L1-22 read-side (API coverage calc): aggregate + per-asset OI cap bps.
fn get_reserve_cap(env: soroban_sdk::Env) -> u32
Pay USDC from the insurance buffer to an address (L0-1: the ADL better-than-mark compensation). Market-only; caps at the spendable buffer AND the vault's physical balance net of the earmarked ShortfallReserve. Returns the amount actually paid.
fn pay_from_buffer(
env: soroban_sdk::Env,
to: soroban_sdk::Address,
amount: i128,
) -> Result
Set the per-account cumulative-deposit cap (7 decimals; 0 = unlimited). The guarded-launch lever (P6-6) — start low, raise on clean metrics. Admin only.
fn set_deposit_cap(env: soroban_sdk::Env, cap: i128) -> Result<(), NoetherError>
Update deposit fee.
fn set_deposit_fee(env: soroban_sdk::Env, fee_bps: u32) -> Result<(), NoetherError>
Set the aggregate reservation cap (bps of AUM). Admin only.
fn set_reserve_cap(env: soroban_sdk::Env, bps: u32) -> Result<(), NoetherError>
Execute a matured recovery proposal (admin, paused-only). Pays min(amount, balance) to the pre-declared RecoveryAddress and clears it.
fn execute_recovery(env: soroban_sdk::Env) -> Result<(), NoetherError>
Get actual USDC token balance held by vault.
fn get_usdc_balance(env: soroban_sdk::Env) -> Result
Get withdrawal fee in basis points.
fn get_withdraw_fee(env: soroban_sdk::Env) -> u32
Propose a timelocked recovery (admin, paused-only). Executable only after RECOVERY_TIMELOCK_SECS.
fn propose_recovery(env: soroban_sdk::Env, amount: i128) -> Result<(), NoetherError>
Trader-keyed loss receipt (market-only): receive_loss plus the
write-backs of the trader's shortfall books. A close simulated as a
LOSS never enters settle_pnl, so without this a sign flip between
simulate and apply (common near break-even) lands the win path's
ShortfallOwed / Shortfall / CumShortfall writes outside the frozen
footprint and traps every caller without the client-side guard.
receive_loss stays for markets that predate this entrypoint —
upgrade the vault BEFORE a market that calls this.
fn receive_loss_for(
env: soroban_sdk::Env,
trader: soroban_sdk::Address,
amount: i128,
) -> Result<(), NoetherError>
Update withdrawal fee.
fn set_withdraw_fee(env: soroban_sdk::Env, fee_bps: u32) -> Result<(), NoetherError>
Lifetime shortfall booked.
fn get_cum_shortfall(env: soroban_sdk::Env) -> i128
Set an asset's ABSOLUTE per-side OI cap in USD notional (L0-14). 0 = no absolute bound (bps-only). Admin only.
fn set_asset_cap_abs(
env: soroban_sdk::Env,
asset: soroban_sdk::Symbol,
max_notional: i128,
) -> Result<(), NoetherError>
L1-22: set the insurance-buffer target as bps of ReservedPayout (admin, ≤ 10_000; default 1000 = 10%).
fn set_buffer_target(env: soroban_sdk::Env, bps: u32) -> Result<(), NoetherError>
Current insurance buffer balance.
fn get_buffer_balance(env: soroban_sdk::Env) -> i128
A trader's outstanding claimable shortfall.
fn get_shortfall_owed(env: soroban_sdk::Env, trader: soroban_sdk::Address) -> i128
L1-22: route a protocol fee (already transferred into the vault by the
market) — fill the insurance buffer UP TO its target (10% of Reserved
Payout by default), then overflow the rest to overflow_to (treasury).
Market-only; NEVER touches LP value. Empty book (target 0) → all overflow.
fn route_protocol_fee(
env: soroban_sdk::Env,
amount: i128,
overflow_to: soroban_sdk::Address,
) -> Result<(), NoetherError>
fn get_last_deposit_ts(env: soroban_sdk::Env, who: soroban_sdk::Address) -> u64
Get market contract address.
fn get_market_contract(
env: soroban_sdk::Env,
) -> Result
Total committed max payouts for open positions.
fn get_reserved_payout(env: soroban_sdk::Env) -> i128
Update market contract address. Use with caution - this changes which contract can settle trades.
fn set_market_contract(
env: soroban_sdk::Env,
new_market: soroban_sdk::Address,
) -> Result<(), NoetherError>
View: the pre-declared recovery destination (None until init_recovery).
fn get_recovery_address(env: soroban_sdk::Env) -> Option
Reserve the max potential payout for a position being opened. REAL reservation (M-4/V-3): committed payouts accumulate in ReservedPayout and are released on close/liquidation via sync_exposure. Rejects when the aggregate reservation would exceed reserve_cap_bps of AUM, or when the asset's per-side OI (passed by the market, which tracks it) would exceed that asset's cap — both #82 OpenInterestCapExceeded. ⚠️ ABI: signature grew net_skew args in L0-14 — market and vault MUST promote together.
fn reserve_for_position(
env: soroban_sdk::Env,
asset: soroban_sdk::Symbol,
amount: i128,
asset_side_oi_after: i128,
net_skew_before: i128,
net_skew_after: i128,
) -> Result<(), NoetherError>
fn get_buffer_target_bps(env: soroban_sdk::Env) -> u32
View: the open recovery proposal (amount, execute_after), if any.
fn get_recovery_proposal(env: soroban_sdk::Env) -> Option<(i128, u64)>
USDC currently earmarked for shortfall repayment.
fn get_shortfall_reserve(env: soroban_sdk::Env) -> i128
L1-28 views: the cooldown window + an address's latest-deposit ts (the UI countdown source).
fn get_withdraw_cooldown(env: soroban_sdk::Env) -> u64
L1-28: set the post-deposit withdraw cooldown (admin, ≤ 1 day; 0 off).
fn set_withdraw_cooldown(env: soroban_sdk::Env, secs: u64) -> Result<(), NoetherError>
One asset's unrealized trader PnL as last pushed by the market.
fn get_asset_unrealized_pnl(env: soroban_sdk::Env, asset: soroban_sdk::Symbol) -> i128
Lifetime bankrupt losses the buffer absorbed.
fn get_cum_bad_debt_covered(env: soroban_sdk::Env) -> i128
Lifetime shortfall repaid.
fn get_cum_shortfall_repaid(env: soroban_sdk::Env) -> i128
Set the buffer-inflow share routed to shortfall repayment (bps). Admin.
fn set_shortfall_inflow_bps(
env: soroban_sdk::Env,
bps: u32,
) -> Result<(), NoetherError>
Lifetime bankrupt losses that fell through to LP NAV.
fn get_cum_bad_debt_lp_absorbed(env: soroban_sdk::Env) -> i128