Contract b8c6819aacb6067984e5eff04f0cf53f24c81f32dda364b94346e5d7e8a2ceb3

← Back to Index 📥 Download WASM

Meta

rssdkver 21.7.7#5da789c50b18a4c2be53394138212fed56f0dfc4
rsver 1.96.0

Instances

  • CCKLYRVPC7V3N46C22MOPGLPWFLMCBTEZXLFH6USLMOUI34M2TIGBJZG

Interface

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.

Arguments

  • depositor - Address depositing USDC
  • usdc_amount - Amount of USDC to deposit (7 decimals)

Returns

Amount of NOE tokens received

Formula

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.

Arguments

  • withdrawer - Address withdrawing
  • noe_amount - Amount of NOE tokens to return

Returns

Amount of USDC returned

Formula

usdc_returned = noe_amount * aum / circulating_noe - withdrawal_fee

Note

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.

Arguments

  • admin - Admin address for configuration
  • usdc_token - USDC token contract address
  • noe_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 points
fn 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.

Arguments

  • pnl - Profit/loss amount (positive = trader won, negative = trader lost)

Settlement Logic

Trader WON (pnl > 0):

  • Vault transfers profit amount to Market contract
  • Market then pays trader: collateral + profit
  • Vault's total_usdc decreases by pnl

Trader LOST (pnl < 0):

  • Only update accounting here (Vault cannot pull from Market)
  • Market must call receive_loss() separately to transfer the loss
  • This respects Soroban's auth model: contracts can only spend own tokens

Break-even (pnl = 0):

  • No transfers needed, just emit event Returns the profit actually paid out. A winner's close can never hard-revert here: the payout is capped at what the pool holds and any unpaid remainder is booked as a CLAIMABLE per-trader shortfall (L0-3: repaid from future buffer inflows via claim_shortfall). Losses are credited ONLY when the USDC actually arrives, via receive_loss.

⚠️ 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.

Arguments

  • amount - The loss amount being transferred from Market to Vault

Flow

  1. Market calls settle_pnl(negative_pnl) - updates accounting
  2. Market transfers loss amount to Vault
  3. Market calls receive_loss(amount) - Vault verifies receipt

This 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

Imports

WebAssembly Text (WAT) ▶