Contract f41d29e8219cdf8ed2121471fe91a181ab5b5c07a59329939e8dcbbe624d9f7e

← Back to Index πŸ“₯ Download WASM

Meta

cliver 26.0.0#60f7458e7ecffddf2f2d91dc6d0d2db4fab03ecc
rssdkver 22.0.11#34f7f53ae31e0fd02aab436a9872e79fa671ca02
rsver 1.94.1

Instances

  • CAHHS2EFYMKKBYP3LTUFPDS2JSY4EPQLUDEUOFI5I7P7MOIBSJH5AUKQ
  • CCHJFS4OEKTLJLLL6OQXFIS2ECTJRA6WMUNXVS7MD6DKIIB6RTXNBZRW
  • CDYB5FK54OXV36AQ2TBK6V2K6KYN6RXNIID6HMCYUP7EJ4BEV7BAVIYB

Interface

Deposit amount of any whitelisted deposit asset and receive share tokens.

Multi-asset v2: if deposit_assets list is configured, any asset in that list is accepted. Non-base assets are oracle-priced to compute the base-asset-denominated deposit value used for share minting.

Legacy mode (no portfolio_assets configured): only base_asset accepted.

Flow (dHedge V2 model):

  1. Collect streaming management and performance fees.
  2. Snapshot NAV before transfer (oracle pricing).
  3. Pull amount of asset from from into vault.
  4. deposit_value = oracle.price(asset) Γ— amount (base-asset terms).
  5. total_shares = deposit_value Γ— total_supply / nav_before.
  6. Split entry fee as shares minted to manager.
  7. Update user's cost_basis for PnL tracking.

Returns

Number of share tokens minted to from.

Errors

  • [VaultError::Paused]
  • [VaultError::InvalidAmount]
  • [VaultError::AssetNotInPortfolio] β€” not in deposit asset list
  • [VaultError::DepositCapExceeded]
fn deposit(
    env: soroban_sdk::Env,
    amount: i128,
    from: soroban_sdk::Address,
    asset: soroban_sdk::Address,
    min_shares_out: i128,
) -> i128

Return the current NAV (vault base-asset balance + strategy values).

fn get_nav(env: soroban_sdk::Env) -> i128
fn get_name(env: soroban_sdk::Env) -> soroban_sdk::String

Burn share_amount of share tokens and receive a proportional fraction of every asset in the vault (multi-asset dHedge V2 withdrawal model).

Flow:

  1. Collect streaming management and performance fees.
  2. Validate share balance and cooldown.
  3. BURN SHARES FIRST (reentrancy protection).
  4. Update user's realized PnL.
  5. For each portfolio asset: transfer fraction Γ— balance to to.
  6. For each active guard: call withdraw_fraction(vault, num, den, to). Guards send their underlying tokens directly to to.

Legacy mode (no portfolio_assets configured): same proportional logic applied to base_asset only, plus legacy single-asset strategies.

Exit fee fraction stays in the vault β€” not transferred to manager.

Returns

Total value withdrawn in base-asset terms (for events / slippage check).

Errors

  • [VaultError::Paused]
  • [VaultError::InvalidAmount]
  • [VaultError::InsufficientShares]
  • [VaultError::CooldownActive]
fn withdraw(
    env: soroban_sdk::Env,
    share_amount: i128,
    from: soroban_sdk::Address,
    to: soroban_sdk::Address,
    min_base_out: i128,
) -> i128

Return the vault admin address.

fn get_admin(env: soroban_sdk::Env) -> soroban_sdk::Address
fn is_paused(env: soroban_sdk::Env) -> bool

Add an allowlisted member for private-pool deposits. Admin only.

fn add_member(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    member: soroban_sdk::Address,
)

Execute any authorised operation through a whitelisted guard contract.

This is the single unified dispatch entry-point replacing the old invest / unwind / invest_lp / unwind_lp / execute_trade family of functions.

Flow

  1. caller must be the registered manager or trader β€” both may call.
  2. guard must appear in ActiveGuards.
  3. fn_name must appear in AuthorizedOps(guard).
  4. NAV is snapshotted before dispatch.
  5. The vault injects its own address as the first argument, then appends the caller-supplied args. This ensures the guard can only act on behalf of the vault β€” the caller cannot substitute a different source address.
  6. guard.<fn_name>(vault, args…) is called directly by name.
  7. NAV is re-measured. If the drop exceeds max_loss_bps the transaction reverts (TVL guard).

Arguments

  • caller β€” Manager or trader address (must require_auth()).
  • guard β€” Active guard contract address.
  • fn_name β€” Guard function name to call (e.g. "supply", `"swap
fn execute_op(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    guard: soroban_sdk::Address,
    fn_name: soroban_sdk::Symbol,
    args: soroban_sdk::Vec,
) -> soroban_sdk::Val
fn get_trader(env: soroban_sdk::Env) -> soroban_sdk::Address

Register the oracle contract used to price strategy positions. Manager only.

Once set, nav() will call oracle.get_price(price_token) for each strategy that has a price token registered via [set_strategy_oracle_token].

Errors

  • [VaultError::NotAdmin]
fn set_oracle(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    oracle: soroban_sdk::Address,
)

Transfer the trader role to a new address. Manager only.

After this call only new_trader can call execute_trade.

Errors

  • [VaultError::NotManager]
fn set_trader(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    new_trader: soroban_sdk::Address,
)

Return the vault's factory reference address.

fn get_factory(env: soroban_sdk::Env) -> Option
fn get_manager(env: soroban_sdk::Env) -> soroban_sdk::Address

Transfer the manager role to a new address.

The vault admin or the current manager may authorise this call.

Errors

  • [VaultError::NotManager]
fn set_manager(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    new_manager: soroban_sdk::Address,
)

Return the fee-recipient treasury address.

fn get_treasury(env: soroban_sdk::Env) -> soroban_sdk::Address

Return the PnL breakdown for a user.

All values are in base-asset terms (PRICE_PRECISION-scaled where noted).

fn get_user_pnl(env: soroban_sdk::Env, user: soroban_sdk::Address) -> UserPnLReport

Perform the one-time anti-inflation seed deposit. Factory only.

The factory calls this after transferring seed_amount of base_asset directly into the vault. This function mints seed_amount shares to a burn address (all-zeros), ensuring total_supply > 0 from day one and eliminating the first-depositor inflation attack.

Can only be called once per vault (enforced via SeedDeposited flag).

Errors

  • [VaultError::SeedAlreadyDeposited]
fn seed_deposit(env: soroban_sdk::Env, caller: soroban_sdk::Address, seed_amount: i128)

Set or update the treasury address. Admin only.

fn set_treasury(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    treasury: soroban_sdk::Address,
)
fn is_ops_paused(env: soroban_sdk::Env) -> bool

Remove an allowlisted member for private-pool deposits. Admin only.

fn remove_member(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    member: soroban_sdk::Address,
)

Initialize the vault. Runs atomically at deployment via CreateContract.

Errors

  • [VaultError::InvalidAmount] β€” if any fee exceeds its cap.
fn __constructor(env: soroban_sdk::Env, params: VaultParams)
fn get_base_asset(env: soroban_sdk::Env) -> soroban_sdk::Address

Pause deposits and withdrawals. Admin only.

fn pause_deposits(env: soroban_sdk::Env, caller: soroban_sdk::Address)

Return the current share price (NAV / total_supply) in PRICE_PRECISION units.

fn get_share_price(env: soroban_sdk::Env) -> i128
fn get_share_token(env: soroban_sdk::Env) -> soroban_sdk::Address
fn is_private_pool(env: soroban_sdk::Env) -> bool

Set the vault's maximum deposit cap (in base-asset units). Manager only.

A cap of 0 means uncapped (no limit). Set to a positive value to prevent the vault from accepting deposits beyond that NAV ceiling.

Errors

  • [VaultError::NotManager]
fn set_deposit_cap(env: soroban_sdk::Env, caller: soroban_sdk::Address, cap: i128)

Register a strategy guard contract as active for this vault.

Errors

  • [VaultError::NotManager]
  • [VaultError::GuardNotAuthorized] β€” not in factory whitelist
  • [VaultError::GuardAlreadyActive]
  • [VaultError::TooManyGuards]
fn add_active_guard(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    guard: soroban_sdk::Address,
)

Return the manager's display name, or None if not set.

fn get_manager_name(env: soroban_sdk::Env) -> Option

Pause manager operations (execute_op). Admin only.

fn pause_operations(env: soroban_sdk::Env, caller: soroban_sdk::Address)

Update the exit fee. Manager only. Capped at [MAX_ENTRY_EXIT_FEE_BPS].

Errors

  • [VaultError::NotManager] / [VaultError::InvalidAmount]
fn set_exit_fee_bps(env: soroban_sdk::Env, caller: soroban_sdk::Address, bps: u32)

Set or update the manager's display name. Admin or manager only.

fn set_manager_name(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    name: soroban_sdk::String,
)

Set the maximum NAV loss allowed per manager operation. Manager only.

After every invest, unwind, invest_lp, unwind_lp, and execute_trade the vault checks:

nav_after β‰₯ nav_before Γ— (1 βˆ’ max_loss_bps / 10_000)

If the check fails the transaction reverts with [VaultError::TvlGuardTripped], preventing the manager from silently draining TVL through repeated high-slippage operations.

A typical production value is 100 (1 % per transaction).

Setting 0 is rejected because a zero tolerance disables the NAV-loss guard entirely, which would allow a manager to execute a damaging operation without any on-chain slippage protection. Use the default of [DEFAULT_MAX_LOSS_BPS] (1 000 bps = 10 %) or another non-zero value.

Errors

  • [VaultError::NotManager]
  • [VaultError::InvalidAmount] β€” if bps == 0 or bps > FEE_DENOMINATOR
fn set_max_loss_bps(env: soroban_sdk::Env, caller: soroban_sdk::Address, bps: u32)

Update the annual management fee. Manager only. Capped at [MAX_MGMT_FEE_BPS].

The timestamp is NOT reset; accrued-since-last-collection will use the old rate for the elapsed period and the new rate going forward (standard fund accounting).

Errors

  • [VaultError::NotManager] / [VaultError::InvalidAmount]
fn set_mgmt_fee_bps(env: soroban_sdk::Env, caller: soroban_sdk::Address, bps: u32)

Update the performance fee. Manager only. Capped at [MAX_PERF_FEE_BPS].

Errors

  • [VaultError::NotManager] / [VaultError::InvalidAmount]
fn set_perf_fee_bps(env: soroban_sdk::Env, caller: soroban_sdk::Address, bps: u32)

Enable or disable private-pool mode. Admin only.

fn set_private_pool(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    is_private: bool,
)

Unpause deposits and withdrawals. Admin only.

fn unpause_deposits(env: soroban_sdk::Env, caller: soroban_sdk::Address)

Add an asset to the deposit-allowed list. Must be in portfolio assets.

Errors

  • [VaultError::NotManager]
  • [VaultError::AssetNotInPortfolio]
  • [VaultError::AssetAlreadyPresent]
fn add_deposit_asset(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    asset: soroban_sdk::Address,
)

Return the list of active guard contracts for this vault.

fn get_active_guards(env: soroban_sdk::Env) -> soroban_sdk::Vec
fn is_member_allowed(env: soroban_sdk::Env, member: soroban_sdk::Address) -> bool

Update the entry fee. Manager only. Capped at [MAX_ENTRY_EXIT_FEE_BPS].

Errors

  • [VaultError::NotManager] / [VaultError::InvalidAmount]
fn set_entry_fee_bps(env: soroban_sdk::Env, caller: soroban_sdk::Address, bps: u32)
fn get_announced_fees(env: soroban_sdk::Env) -> AnnouncedFees

Return the authorized function names for a guard.

fn get_authorized_ops(
    env: soroban_sdk::Env,
    guard: soroban_sdk::Address,
) -> soroban_sdk::Vec

Return the vault's current deposit asset list.

fn get_deposit_assets(env: soroban_sdk::Env) -> soroban_sdk::Vec

Return portfolio assets currently included in bounded NAV scans.

fn get_tracked_assets(env: soroban_sdk::Env) -> soroban_sdk::Vec

Set the authorized function names for a guard contract. Manager only.

Only the listed function names may be dispatched by the trader through execute_op for the given guard.

fn set_authorized_ops(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    guard: soroban_sdk::Address,
    ops: soroban_sdk::Vec,
)

Synchronize a portfolio asset into or out of the bounded NAV index.

This is permissionless so unsolicited token transfers to the vault can be included in NAV without requiring a manager action. The asset must already be configured as a portfolio asset.

fn sync_asset_balance(env: soroban_sdk::Env, asset: soroban_sdk::Address)

Unpause manager operations (execute_op). Admin only.

fn unpause_operations(env: soroban_sdk::Env, caller: soroban_sdk::Address)

Add an asset to the vault's portfolio asset list.

The asset must be in the factory's global authorized asset list. The oracle must be set before adding non-base assets (needed for NAV).

Errors

  • [VaultError::NotManager]
  • [VaultError::AssetNotAuthorized] β€” not in factory whitelist
  • [VaultError::AssetAlreadyPresent] β€” already in portfolio
  • [VaultError::TooManyAssets] β€” MAX_PORTFOLIO_ASSETS reached
fn add_portfolio_asset(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    asset: soroban_sdk::Address,
)

Commit the latest announced fee-increase schedule once delay elapsed.

fn commit_fee_increase(env: soroban_sdk::Env, caller: soroban_sdk::Address)

Return active guards that currently contribute non-zero strategy value to NAV and withdrawals.

fn get_position_guards(env: soroban_sdk::Env) -> soroban_sdk::Vec

Remove a strategy guard contract from the active list.

Errors

  • [VaultError::NotManager]
  • [VaultError::StrategyNotWhitelisted] β€” not in active list
  • [VaultError::GuardHasActivePosition] β€” guard still holds positions
fn remove_active_guard(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    guard: soroban_sdk::Address,
)

Synchronize an active guard into or out of the bounded position index.

This is permissionless so strategy value changes caused by external yield, rewards, or testnet repair scripts can be reflected without forcing a full active-guard scan in every user action.

fn sync_guard_position(env: soroban_sdk::Env, guard: soroban_sdk::Address)

Permissionlessly settle pending management and performance fees.

Fees are deterministic from vault state: the caller cannot choose the fee amount, recipient, NAV, or timestamp. This lets keepers, users, UIs, or the manager sync fee accounting even when no deposit/withdraw occurs.

Returns the number of fee shares minted to the treasury.

fn collect_pending_fees(env: soroban_sdk::Env) -> i128

Return the vault's current portfolio asset list.

fn get_portfolio_assets(
    env: soroban_sdk::Env,
) -> soroban_sdk::Vec

Remove an asset from the deposit-allowed list.

Does not remove from portfolio assets. No constraint on balance.

Errors

  • [VaultError::NotManager]
  • [VaultError::AssetNotInPortfolio] β€” not in deposit list
fn remove_deposit_asset(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    asset: soroban_sdk::Address,
)

Announce a fee-increase schedule that can be committed after timelock.

fn announce_fee_increase(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    entry_fee_bps: u32,
    exit_fee_bps: u32,
    mgmt_fee_bps: u32,
    perf_fee_bps: u32,
)

Cancel any previously announced fee-increase schedule.

fn renounce_fee_increase(env: soroban_sdk::Env, caller: soroban_sdk::Address)
fn get_exit_cooldown_secs(env: soroban_sdk::Env) -> u64
fn is_value_guard_enabled(env: soroban_sdk::Env) -> bool

Remove an asset from the vault's portfolio asset list.

Errors

  • [VaultError::NotManager]
  • [VaultError::AssetNotInPortfolio]
  • [VaultError::AssetHasBalance] β€” vault still holds this token
  • [VaultError::AssetInUseByGuard] β€” a guard has an active position using this asset
fn remove_portfolio_asset(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    asset: soroban_sdk::Address,
)

Set per-user exit cooldown in seconds. Manager only.

fn set_exit_cooldown_secs(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    secs: u64,
)

Toggle same-ledger value-manipulation guard. Manager only.

fn set_value_guard_enabled(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    enabled: bool,
)
fn share_transfers_enabled(env: soroban_sdk::Env) -> bool
fn pnl_tracking_is_accurate(env: soroban_sdk::Env) -> bool
fn get_exit_remaining_cooldown(
    env: soroban_sdk::Env,
    user: soroban_sdk::Address,
) -> u64

Enable or disable transferable vault shares. Admin only.

Shares are non-transferable by default so exit cooldown and per-user PnL accounting remain accurate. If transfers are enabled, cooldown becomes a same-address friction control and PnL becomes informational unless a future transfer-aware accounting design is added.

fn set_share_transfers_enabled(
    env: soroban_sdk::Env,
    caller: soroban_sdk::Address,
    enabled: bool,
)
fn exit_cooldown_is_hard_control(env: soroban_sdk::Env) -> bool

Imports

WebAssembly Text (WAT) β–Ά