fn admin(env: soroban_sdk::Env) -> soroban_sdk::Address
fn keeper(env: soroban_sdk::Env) -> Option
fn router(env: soroban_sdk::Env) -> Option
Replace the Registry Wasm. Auth: admin (checked BEFORE the swap).
The gen-1 Registry shipped WITHOUT this ("holds no funds, keep it dumb") and that immutability backfired: the 2026-08-01 audit fixes touched Registry code, and with Factory + every Strategy holding this address permanently, the only patch path was discarding the entire fleet. The admin already controls everything the Registry decides (whitelist, router, keeper, fees), so an admin-gated upgrade adds repairability without adding power.
fn upgrade(env: soroban_sdk::Env, new_wasm_hash: soroban_sdk::BytesN<32>)
Rotate the admin (the 2-of-3 multisig address). Auth: current admin.
fn set_admin(env: soroban_sdk::Env, new_admin: soroban_sdk::Address)
Some = upsert, None = remove. Enforces the two fee caps loudly:
fee_bps ≤ MAX_FEE_BPS, and no non-zero fee_bps while the treasury is
unset (set the treasury first). Auth: admin.
fn set_vault(
env: soroban_sdk::Env,
vault: soroban_sdk::Address,
info: Option,
) -> Result<(), soroban_sdk::Error>
(treasury, rebalance_delta_bps) — the protocol-wide fee config read by
every Strategy on the withdraw/rebalance path.
fn fee_config(env: soroban_sdk::Env) -> (Option, u32)
Set/rotate the fleet-wide keeper address (key rotation in one tx). Auth: admin.
fn set_keeper(env: soroban_sdk::Env, keeper: soroban_sdk::Address)
Set the Soroswap router (used from T2). Auth: admin.
fn set_router(env: soroban_sdk::Env, router: soroban_sdk::Address)
Read a vault's record (None if not whitelisted). Bumps the entry's TTL on
read so an ACTIVELY-USED listing can't silently archive and revert new
deposits until re-listed (the Strategy reads this inside every invest, so a
vault in active use stays alive; a real tx persists the bump, a bare simulate
does not).
fn vault_info(env: soroban_sdk::Env, vault: soroban_sdk::Address) -> Option
Deploy-time init. Stores admin; every other key follows the read-default
rule (Router/Treasury/Keeper ⇒ None, RebalanceDeltaBps ⇒ 0,
KeeperEnabled ⇒ false) and is written only when first set.
fn __constructor(env: soroban_sdk::Env, admin: soroban_sdk::Address)
fn keeper_enabled(env: soroban_sdk::Env) -> bool
Set the protocol-wide treasury + rebalance surcharge. Validates
delta_bps ≤ BPS − MAX_FEE_BPS so fee_bps + delta_bps ≤ 10_000 for every
vault by construction. Once set, the treasury stays Some. Auth: admin.
fn set_fee_config(
env: soroban_sdk::Env,
treasury: soroban_sdk::Address,
delta_bps: u32,
) -> Result<(), soroban_sdk::Error>
Opt asset in/out of the set a KEEPER may name as rebalance_swap's
asset_out. Auth: admin.
Why this exists: rebalance_swap takes a caller-supplied path and
amount_out_min with no on-chain price oracle, and the same keeper can
call rebalance_withdraw first in the SAME transaction — so without a
bound the reachable amount is an entire invested position, not the idle
float. Every hop of the path is checked against this list, not just the
output (an endpoint-only check is trivially routed around via
[allowed, EVIL, allowed]).
What this does NOT do. It narrows the total-loss case; it does not
eliminate it. Allowlisting ASSETS says nothing about pool DEPTH: a
compromised keeper can seed the canonical pair between two allowlisted
assets with dust and still dump a whole position into it at
amount_out_min = 1. The real residual bound is the depth of the
shallowest canonical pair among allowlisted assets — which an attacker can
influence. Only the T3 oracle floor closes this; do not read this l
fn set_swap_asset(env: soroban_sdk::Env, asset: soroban_sdk::Address, allowed: bool)
Global kill-switch — fleet-wide halt of keeper-driven rebalances. Auth: admin.
fn set_keeper_enabled(env: soroban_sdk::Env, enabled: bool)
Is asset allowlisted as a keeper-path swap output? Read-default false.
fn swap_asset_allowed(env: soroban_sdk::Env, asset: soroban_sdk::Address) -> bool