Risk and Security Model
The safety mechanisms built into Upshift Stellar vaults, from layered AUM rate limits to pause controls, admin transfer safety, and the wallet-attribution invariant.
AUM Change Limits
The vault enforces both per-call and cumulative-window rate limits on every move of deployed_assets. Limits are asymmetric (increases and decreases are configured separately), denominated in basis points of the pre-move deployed_assets, and applied by the same shared helper used by every aggregate-mutating function (update_deployed_assets, update_wallet_deployed, update_wallet_deployed_batch, and remove_wallet_and_reconcile).
- Per-call limits:
set_aum_limits(increase_bps, decrease_bps)caps how muchdeployed_assetscan change in a single call. Decreases are typically configured tighter than increases - Cumulative window limits:
set_aum_window_limits(window_duration, cumulative_increase_bps, cumulative_decrease_bps)caps the sum of changes within a fixed tumbling window (minimum 1 hour, maximum 7 days; default 24 hours). The window resets entirely on expiry, and changing limits resets it immediately so stale counters never interact with new configuration. Cumulative limits are measured against abase_deployedsnapshot captured at window start, not the live value - Zero-boundary behavior: when
deployed_assets == 0, percentage-based limits are undefined and skipped. The admin controls risk at this boundary through operator key management and the subaccount whitelist
Calls that exceed the per-call limit revert with AumChangeExceedsLimit; calls that exceed the cumulative limit revert with AumCumulativeChangeExceedsLimit.
Pause Mechanism
The admin can instantly halt user-facing operations via pause(). While paused:
deposit,mint,withdraw, andredeemall revert;max_deposit,max_mint,max_withdraw, andmax_redeemall return 0add_subaccountreverts (no new strategies or wallets can be onboarded mid-incident)- Operator increases to
deployed_assets(and any per-wallet tracker increase, including a single positive entry inside an otherwise net-negativeupdate_wallet_deployed_batch) revert withVaultPaused. Decreases remain permitted so the operator can recognize losses and pull capital back withdraw_from_subaccountcontinues to operate so the curator can return capital- The admin can unpause at any time via
unpause()
The asymmetry is deliberate: a pause must not let a compromised operator inflate share prices by booking phantom gains, but it must still allow loss recognition and capital recovery during an emergency.
Admin Transfer Safety
Admin role transfers use a two-step nomination process with an explicit deadline:
- Current admin calls
propose_admin(new_admin, deadline). This records a pending nominee and an absolute ledger-timestamp expiry - Nominated admin calls
accept_admin(). The pending nominee mustrequire_authand the call must arrive before the deadline
If the nomination expires (AdminProposalExpired) it must be re-issued. The current admin can cancel a pending proposal at any time via cancel_admin_proposal. Self-nominations (new_admin == admin) and zero/past deadlines are rejected at proposal time. This prevents accidental or malicious ownership changes; the deadline also prevents a long-lived pending nomination from being exploited later.
Operator changes are a single-step admin action via set_operator.
Wallet-Attribution Invariant
For Wallet subaccounts the vault maintains a per-wallet WalletNetDeployed tracker that is moved in lockstep with the aggregate deployed_assets on every routine operator action.
Σ WalletNetDeployed[w] == deployed_assetsThe invariant is enforced by deposit_to_subaccount, withdraw_from_subaccount, update_wallet_deployed, update_wallet_deployed_batch, and remove_wallet_and_reconcile. The vault also enforces a per-wallet over-pull guard: withdraw_from_subaccount rejects pulls that exceed the wallet's tracker (WalletOverWithdraw), so an operator cannot silently consume another wallet's share of deployed_assets while informally recognizing a gain or recovering dust.
Two escape hatches can break the invariant by design — update_deployed_assets (aggregate-only) and seed_wallet_net_deployed (per-wallet, admin-only, with a WalletSeedBelowTracker guard that prevents zeroing a tracker without a matching aggregate write-down). Both are reserved for emergency storage corrections; off-chain monitoring compares get_deployed_assets() against get_wallet_deployed_assets() and alerts on divergence.
Contract Upgradeability
The vault implements OpenZeppelin's UpgradeableInternal trait, gated on require_admin.
Audit History
A separate audit has been conducted for the Stellar contracts and is available here.
Curator Model
How an appointed curator moves Stellar vault capital across whitelisted Strategy and EOA subaccounts within admin-set bounds.
HyperCore Relayer
A long-running service that detects deposits arriving on HyperCore, bridges them to HyperEVM, and deposits them into a tokenized vault on the user's behalf.