Skip to content

vault-strategy: curated whitelist, dynamic assets, oracle-bounded slippage#81

Merged
mikemaccana merged 8 commits into
mainfrom
claude/vault-strategy-script-ujfx8x
Jun 29, 2026
Merged

vault-strategy: curated whitelist, dynamic assets, oracle-bounded slippage#81
mikemaccana merged 8 commits into
mainfrom
claude/vault-strategy-script-ujfx8x

Conversation

@mikemaccana

Copy link
Copy Markdown
Collaborator

What this does

Hardens the vault-strategy example along three lines that came out of reviewing the program with depositor-vs-manager trust in mind, and fixes its clean-checkout build. All changes are on the vault-strategy example only.

Curated asset registry (anti-fraud)

A Registry plus per-mint WhitelistEntry accounts, maintained by a protocol authority that is deliberately not the strategy manager. Each entry binds an approved mint to its official Pyth feed. New instructions: initialize_registry, whitelist_asset. This closes the two fraud vectors a manager-curated list leaves open: listing a token the manager mints themselves, and pairing a real mint with a feed the manager controls.

Dynamic assets

Strategies grow their portfolio with add_asset, which registers a whitelisted mint at the next index as an AssetConfig PDA (["asset", strategy, index]) and creates its vault. Assets occupy the contiguous range 0..asset_count (up to MAX_ASSETS = 8), which lets deposit and withdraw re-derive and require the complete set via remaining accounts — so NAV and in-kind payouts can never silently omit an asset. Replaces the previous fixed two-asset layout.

Oracle-bounded slippage

invest and rebalance no longer trust a caller-supplied minimum. They compute each swap leg's minimum output from the Pyth price and a strategy-level max_slippage_bps (set at creation, capped in code at 10%), and revert any fill that deviates beyond it.

Build fixes (needed for a clean checkout)

  • Boxed the mock-swap-router swap account structs, which overflowed the 4096-byte SBF stack frame under current platform-tools.
  • Documented the per-manifest build; building the whole workspace at once unifies the vault's cpi feature into the router build and strips its entrypoint.

Testing

cargo test — 15 LiteSVM tests pass, covering the full lifecycle (registry → whitelist → strategy → add-asset → deposit → invest → rebalance → fees → in-kind withdraw) and rejection paths: non-whitelisted asset, weight overflow, over-cap fee and slippage, oracle-bounded swap slippage, unregistered router, and incomplete asset accounts on deposit.

cargo build-sbf --manifest-path programs/mock-swap-router/Cargo.toml
cargo build-sbf --manifest-path programs/vault-strategy/Cargo.toml
cargo test --manifest-path programs/vault-strategy/Cargo.toml

Docs

README and CHANGELOG updated for the new design. A walkthrough video script (VIDEO_SCRIPT.md) is included and is being updated to match.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 8 commits June 28, 2026 00:10
Persona-driven 5-10 minute script explaining the vault-strategy example
through Maria (manager), Alice and Bob, with per-step state-transition and
token-movement ledgers and verified arithmetic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
Map the vault to a mutual fund / actively managed ETF (units, NAV pricing,
expense ratio, in-kind redemption), name current Solana peers (Drift Vaults,
Symmetry, Kamino), and contrast what actually differs onchain. Introduce the
cast as each actor first appears instead of upfront.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
Lead with the concept (an onchain mutual fund / actively managed ETF) instead
of granular outcome numbers, drop numbered Step headings for descriptive ones,
gloss USDC on first use, and note the vault passes through losses as well as
gains.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
Standardize on 'shares' (the program's term) throughout, define net asset
value and its 'net', restate custody as program-controlled with no manager
access, drop the dead Drift peer for Symmetry/Kamino/Meteora, and cut the
obvious oracle and bug asides.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
A vault is one single-asset token account (a Solana token account holds one
mint); the whole construct is the strategy or the fund. Reserve 'vault' for the
three per-asset accounts throughout, name which vault each token movement
touches, and explain the term where it first appears, matching the production
pattern (one token vault per asset plus a shares mint).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
Define vault as a single-asset account vs the multi-asset strategy (ERC-4626
sense), define the two target weights and the fixed two-asset limit, detail
exactly what the manager can and cannot do, clarify a share mint's address is
a PDA (a derived public key), contrast fee-by-minting-shares with offchain
expense ratios, and write the split as 40/60.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
…ppage

Add a Registry plus per-mint WhitelistEntry accounts curated by a protocol
authority (separate from managers), binding each approved mint to its official
Pyth feed. Strategies grow their portfolio with add_asset, which registers a
whitelisted mint at the next index as an AssetConfig PDA and creates its vault;
deposit and withdraw validate the complete 0..asset_count set via remaining
accounts so NAV and in-kind payouts always cover every asset.

Replace caller-supplied swap minimums with an oracle-anchored bound: invest and
rebalance compute each leg's minimum output from the Pyth price and a
strategy-level max_slippage_bps (capped in code).

Also fix the example's clean-checkout build: box the mock-swap-router swap
account structs (4096-byte SBF stack overflow) and document the per-manifest
build that avoids stripping the router entrypoint. Update README and CHANGELOG;
rewrite the test suite (15 tests) for the new API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
…ippage

Add Victor (registry authority) and the whitelist/add_asset steps, describe the
oracle-computed slippage floor in invest/rebalance, correct the PDA wording (a
PDA is an off-curve address with no private key, not a public key), and replace
the stale two-asset and caller-slippage footnotes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5vHRAwvmnXhz8tzcq3xHX
@mikemaccana mikemaccana merged commit 0d1c060 into main Jun 29, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants