solana-vault is a collection of tokenized vault programs and TypeScript SDK/CLI for building and maintaining yield-bearing vaults on Solana. The SDK provides deposit/withdraw operations, share accounting, preview functions, and modular extensions for fees, caps, access control, timelocks, and multi-asset portfolios.
The interface started off following the ERC-4626 specification adapted for Solana's account model. With time, more ERC's and features were also covered such as Centrifuge's ERC-7540, alongside novel onchain enforcements and implementations such as Tranched RWA vaults, streaming vault yield, vaults-of-vaults, and more.
| Version | Name | Balance Model | Privacy | Sync | Status |
|---|---|---|---|---|---|
| SVS-1 | Public Vault (Live) | Live balance | None | No sync needed | ✅ Devnet |
| SVS-2 | Public Vault (Stored) | Stored balance | None | Requires sync() | ✅ Devnet |
| SVS-3 | Private Vault (Live) | Live balance | Encrypted | No sync needed | ✅ Devnet |
| SVS-4 | Private Vault (Stored) | Stored balance | Encrypted | Requires sync() | ✅ Devnet |
| SVS-5 | Streaming Yield Vault | Interpolated balance | None | distribute_yield() + checkpoint() | ✅ Devnet |
| SVS-6 | Streaming Private Vault | Interpolated balance | Encrypted | distribute_yield() + checkpoint() | ✅ Devnet |
| SVS-7 | SOL Vault | Live balance | None | Native SOL wrapping | ✅ Devnet |
| SVS-8 | Multi-Asset Basket | Oracle-weighted | None | Weight rebalancing | ✅ Devnet |
| SVS-9 | Allocator Vault | Stored balance | None | CPI to child vaults | ✅ Devnet |
| SVS-10 | Async Vault (ERC-7540) | Stored balance | None | Request→Fulfill→Claim | ✅ Devnet |
| SVS-11 | Credit Markets Vault | Oracle NAV | KYC + Freeze | Async (request→approve→claim) | ✅ Devnet |
| SVS-12 | Tranched Vault | Stored balance | None | Manager-driven | ✅ Devnet |
Live Balance (SVS-1, SVS-3):
- Uses
asset_vault.amountdirectly for all calculations - External donations/yield immediately reflected in share price
- No sync timing attack vulnerability
- No sync() function needed
Stored Balance (SVS-2, SVS-4):
- Uses
vault.total_assetsstored in account - Requires
sync()call to recognize external donations - Authority controls when yield is recognized
- May be preferred for yield strategies that require controlled distribution
Streaming Balance (SVS-5):
- Uses
base_assets + accrued_stream_yieldcomputed at current timestamp - Yield distributed linearly over configurable duration via
distribute_yield(amount, duration) checkpoint()materializes accrued yield intobase_assets(permissionless)- Eliminates MEV from front-running discrete sync/yield operations
- Suited for payroll vaults, vesting schedules, DCA strategies
Async (SVS-10):
- Request→Fulfill→Claim lifecycle for deposits and redemptions
- Operator fulfills requests using vault price or oracle NAV
- Supports illiquid assets, RWA, and cross-chain strategies
- ERC-7540 equivalent with synchronous cancellation (ERC-7887)
Public (SVS-1, SVS-2):
- Token-2022 shares mint (no extensions)
- All balances visible on-chain
- Simple, auditable, production-ready
Private (SVS-3, SVS-4):
- Token-2022 with Confidential Transfers extension
- Share balances encrypted with ElGamal
- Only owner can decrypt their balance
- Requires Rust proof backend for ZK proof generation
| Program | Devnet | Localnet |
|---|---|---|
| SVS-1 | CzZyssz2PdLccWpbVi6a3wFKMmMqdf28U2RapNNRJSPX |
Same as devnet |
| SVS-2 | 7vnZM4aCsRapH9ft7Bo5ibTXNH2dvoxkj96c7JonLhoe |
Same as devnet |
| SVS-3 | CC4xQGxmwKusLW3ToqUzRAFjh7cL2iKsgfkz6qJSasYs |
Same as devnet |
| SVS-4 | EqRNvMTwczQjUhQL8wwrxJGALgz5VWsYne3d67e6ruCv |
Same as devnet |
| SVS-5 | HCp23XHzV4HJHXwLWwQj8aSTU1yjyzj8FCNLe6NybwXt |
Same as devnet |
| SVS-6 | oaT6wgNiwCqd7EGvB6Wb5ZFYUJXckk6LEhB7MWqXbyC |
Same as devnet |
| SVS-7 | CR2ccVacmbQ2DaXvR66W7gnmH7KuDCqbVW5VwnTczQUC |
Same as devnet |
| SVS-8 | HnZ9N8Y1v6jMhwDqo4Y76GfqjRArdinadgK67yLVFZbe |
Same as devnet |
| SVS-9 | AaADS3DCGkjhDEDbGkygbG9bNaziR9TPK2X7SMBYedws |
Same as devnet |
| SVS-10 | 4G5d6KutMpUaDPTVcv7FJBpPTGZej8rx3GyGnfiRdD6M |
Same as devnet |
| SVS-11 | CMeQ5Lx7AvjuW3DrzNvEkPZSdqKZjjhaTrAmgqBvPKHD |
Same as devnet |
| SVS-12 | EPwH58e5V1UXYkkD8JZ4bq7Wr2iRiC9fLj1S6BRRz2R |
Same as devnet |
| Mock Oracle | Heezh11y1FJPvrUjKetGsDJTFFNdHqXPz9bFsUiEJxdh |
Same as devnet |
| Mock SAS | GTTMWDHTZibyEpqNRr33RnBhgms262U6qHaGrjoHqEXg |
Same as devnet |
# Core SDK (SVS-1/SVS-2)
npm install @stbr/solana-vault
# Privacy SDK (SVS-3/SVS-4)
npm install @stbr/svs-privacy-sdk
# Backend (for private vault proof generation)
cd proofs-backend && cargo runimport { SolanaVault, ManagedVault, StreamingVault, AsyncVault } from "@stbr/solana-vault";
import { BN } from "@coral-xyz/anchor";
// SVS-1: Load live-balance vault
const vault = await SolanaVault.load(program, assetMint, 1);
// SVS-2: Load stored-balance vault (adds sync())
const managed = await ManagedVault.load(program, assetMint, 1);
// Preview deposit
const expectedShares = await vault.previewDeposit(new BN(1_000_000));
// Deposit with slippage protection
await vault.deposit(user, {
assets: new BN(1_000_000),
minSharesOut: expectedShares.mul(new BN(95)).div(new BN(100)),
});
// Redeem shares
const expectedAssets = await vault.previewRedeem(shares);
await vault.redeem(user, {
shares,
minAssetsOut: expectedAssets.mul(new BN(95)).div(new BN(100)),
});
// SVS-2 only: sync stored balance
await managed.sync(authority);
// SVS-5: Load streaming yield vault
const streaming = await StreamingVault.load(program, assetMint, 1);
// Distribute yield over 1 hour
await streaming.distributeYield(authority, new BN(1_000_000), new BN(3600));
// Permissionless checkpoint
await streaming.checkpoint();
// SVS-10: Async vault (request→fulfill→claim)
const asyncVault = await AsyncVault.load(program, assetMint, 1);
await asyncVault.requestDeposit(user, { assets: new BN(1_000_000) });
await asyncVault.fulfillDeposit(operator, { owner: user.publicKey });
await asyncVault.claimDeposit(user, { owner: user.publicKey });| Feature | Description |
|---|---|
| Inflation Attack Protection | Virtual offset mechanism prevents donation attacks |
| Vault-Favoring Rounding | All operations round to protect vault solvency |
| Slippage Protection | Min/max parameters prevent sandwich attacks |
| Multi-Vault Support | Multiple vaults per asset via vault_id |
| Emergency Controls | Pause/unpause and authority transfer |
| CPI-Composable Views | Preview functions callable from other programs |
SVS-1 includes optional on-chain modules for enforcing vault policies at the program level. Build with --features modules to enable.
| Module | Description |
|---|---|
svs-fees |
Entry/exit fees (max 10%), collected later via admin instruction |
svs-caps |
Global and per-user deposit caps with bypass prevention |
svs-locks |
Time-locked shares before redemption (max 1 year) |
svs-access |
Whitelist/blacklist with merkle proof verification |
Module PDAs are passed via remaining_accounts. If not passed, checks are skipped (backward compatible).
# Build SVS-1 with modules
anchor build -p svs-1 -- --features modulesThe TypeScript SDK includes modular extensions for common vault patterns:
| Module | Description |
|---|---|
fees |
Management, performance, and entry/exit fee calculation |
cap |
Global and per-user deposit caps |
emergency |
Emergency withdrawal with configurable penalty |
access-control |
Whitelist/blacklist with merkle proof verification |
multi-asset |
Portfolio allocation across multiple vaults |
timelock |
Governance proposal lifecycle management |
strategy |
CPI templates for deploying assets to external protocols |
The SDK includes a CLI for vault management:
# Install globally
npm install -g @stbr/solana-vault
# Initialize config
solana-vault config init
# Add vault alias
solana-vault config add-vault my-vault <ADDRESS> --variant svs-1 --asset-mint <MINT>
# Common operations
solana-vault info my-vault # View vault state
solana-vault balance my-vault # Check your balance
solana-vault deposit my-vault -a 1000000 # Deposit assets
solana-vault withdraw my-vault -a 500000 # Withdraw assets
solana-vault dashboard my-vault # Live monitoring
# Admin (authority only)
solana-vault pause my-vault # Emergency pause
solana-vault sync my-vault # Sync balance (SVS-2/4)
# Async vault (SVS-10)
solana-vault async request-deposit my-vault -a 1000000
solana-vault async fulfill-deposit my-vault --owner <PUBKEY>
solana-vault async claim-deposit my-vault --owner <PUBKEY>
solana-vault async request-redeem my-vault -s 500000
solana-vault async set-operator my-vault --operator <PUBKEY>Global flags: --dry-run, --yes, --output json, --keypair <path>, --url <rpc>
| Operation | User Action | Rounding | Favors |
|---|---|---|---|
| deposit | Pay exact assets → receive shares | Floor | Vault |
| mint | Receive exact shares → pay assets | Ceiling | Vault |
| withdraw | Receive exact assets → burn shares | Ceiling | Vault |
| redeem | Burn exact shares → receive assets | Floor | Vault |
+--------------------------------------------------------------------+
| Solana Vault Standard |
+--------------------------------------------------------------------+
| |
| PUBLIC VAULTS PRIVATE VAULTS |
| +------------------+ +------------------+ |
| | | | | |
| | SVS-1 | Live | SVS-3 | Live |
| | (No sync needed) | Balance | (No sync needed) | Balance |
| | | | | |
| +------------------+ +------------------+ |
| | | | | |
| | SVS-2 | Stored | SVS-4 | Stored |
| | (sync() for | Balance | (sync() for | Balance |
| | yield accrual) | | yield accrual) | |
| +------------------+ +--------+---------+ |
| | | |
| | SVS-5 | Streaming |
| | (distribute_yield| Balance |
| | + checkpoint) | |
| +------------------+ |
| | | |
| v v |
| +------------------+ +------------------+ |
| | SPL Token | | Token-2022 | |
| | (public u64) | | + CT Extension | |
| +------------------+ | (encrypted) | |
| +--------+---------+ |
| | |
| v |
| +------------------+ |
| | Proofs Backend | |
| | (Rust/Axum) | |
| +--------+---------+ |
| | |
| v |
| +------------------+ |
| | ZK ElGamal | |
| | Proof Program | |
| +------------------+ |
| |
| ASYNC VAULTS |
| +------------------+ |
| | | |
| | SVS-10 | Stored |
| | (Request→Fulfill | Balance |
| | →Claim) | + Oracle |
| | | |
| +------------------+ |
+--------------------------------------------------------------------+
Seeds: ["vault", asset_mint, vault_id (u64 LE)]
SVS-5 note: StreamVault uses seed
"stream_vault"instead of"vault".
const [vault] = PublicKey.findProgramAddressSync(
[Buffer.from("vault"), assetMint.toBuffer(), vaultId.toArrayLike(Buffer, "le", 8)],
programId
);Seeds: ["shares", vault_pubkey]
const [sharesMint] = PublicKey.findProgramAddressSync(
[Buffer.from("shares"), vault.toBuffer()],
programId
);| Instruction | Description |
|---|---|
initialize |
Create new vault |
deposit |
Deposit assets, receive shares |
mint |
Mint exact shares, pay assets |
withdraw |
Withdraw exact assets, burn shares |
redeem |
Burn shares, receive assets |
| Instruction | SVS-1 | SVS-2 | SVS-3 | SVS-4 | SVS-5 | Description |
|---|---|---|---|---|---|---|
pause |
✓ | ✓ | ✓ | ✓ | ✓ | Emergency pause vault |
unpause |
✓ | ✓ | ✓ | ✓ | ✓ | Resume operations |
transfer_authority |
✓ | ✓ | ✓ | ✓ | ✓ | Transfer admin rights |
sync |
✗ | ✓ | ✗ | ✓ | ✗ | Sync total_assets with balance |
distribute_yield |
✗ | ✗ | ✗ | ✗ | ✓ | Start streaming yield distribution |
checkpoint |
✗ | ✗ | ✗ | ✗ | ✓ | Materialize accrued yield (permissionless) |
| Instruction | Description |
|---|---|
preview_deposit |
Preview shares for asset deposit |
preview_mint |
Preview assets needed for share mint |
preview_withdraw |
Preview shares burned for asset withdrawal |
preview_redeem |
Preview assets received for share redemption |
convert_to_shares |
Convert asset amount to shares |
convert_to_assets |
Convert share amount to assets |
total_assets |
Get total vault assets |
max_deposit |
Get maximum deposit amount |
max_mint |
Get maximum mint amount |
max_withdraw |
Get maximum withdraw amount |
max_redeem |
Get maximum redeem amount |
SVS-3/SVS-4 view difference: max_withdraw returns the vault's total assets (not user-specific) and max_redeem returns u64::MAX, because encrypted share balances can't be read on-chain. SVS-1/SVS-2 return user-specific values based on owner_shares_account.amount.
SVS-5 view addition: get_stream_info returns current stream parameters (base_assets, stream_amount, stream_start, stream_end). All view functions use effective_total_assets(now) for share price computation.
| Instruction | Description |
|---|---|
configure_account |
Enable confidential mode on user account |
apply_pending |
Move pending balance to available |
| Code | Name | Description |
|---|---|---|
| 6000 | ZeroAmount | Amount must be > 0 |
| 6001 | SlippageExceeded | Slippage tolerance exceeded |
| 6002 | VaultPaused | Vault is paused |
| 6003 | InvalidAssetDecimals | Asset decimals > 9 |
| 6004 | MathOverflow | Arithmetic overflow |
| 6005 | DivisionByZero | Division by zero |
| 6006 | InsufficientShares | Not enough shares |
| 6007 | InsufficientAssets | Not enough assets |
| 6008 | Unauthorized | Not vault authority |
| 6009 | DepositTooSmall | Below minimum deposit |
| 6010 | AccountNotConfigured | Account not configured for confidential transfers |
| 6011 | PendingBalanceNotApplied | Pending balance not applied |
| 6012 | InvalidProof | Invalid ZK proof data |
| 6013 | ConfidentialTransferNotInitialized | CT extension not initialized |
| 6014 | InvalidCiphertext | Invalid ciphertext format |
| Event | Description |
|---|---|
VaultInitialized |
New vault created |
Deposit |
Assets deposited |
Withdraw |
Assets withdrawn |
VaultSynced |
Total assets synced (SVS-2, SVS-4 only) |
YieldStreamStarted |
Yield stream started (SVS-5 only) |
Checkpoint |
Yield materialized into base_assets (SVS-5 only) |
VaultStatusChanged |
Pause/unpause |
AuthorityTransferred |
Authority changed |
Key Features:
- Virtual offset inflation attack protection
- Vault-favoring rounding strategy
- Slippage protection on all operations
- Emergency pause mechanism
- Checked arithmetic throughout
- PDA bumps stored (not recalculated)
- SVS-1/SVS-3 use live balance (no sync timing attack)
Audit Status: 10 internal audit rounds completed (v1–v10), all findings resolved. No external audit yet.
# Build all programs
anchor build
# Run all tests (200+ tests, requires proof backend for SVS-3/SVS-4)
anchor test
# Run with modules feature (includes 16 module tests)
anchor build -p svs-1 -- --features modules && anchor test --skip-build
# Run SDK tests (460 tests)
cd sdk/core && npm test
# Run SVS-1 tests only
anchor test -- --grep "svs-1"
# Run specific test file
anchor test -- --grep "yield"
# Backend tests (19 tests)
cd proofs-backend && cargo test
# Start proof backend (required for SVS-3/SVS-4 CT tests)
cd proofs-backend && cargo runsolana-vault-standard/
├── programs/
│ ├── svs-1/ # Public vault, live balance
│ ├── svs-2/ # Public vault, stored balance
│ ├── svs-3/ # Private vault, live balance (beta)
│ ├── svs-4/ # Private vault, stored balance (beta)
│ ├── svs-5/ # Streaming yield vault
│ ├── svs-6/ # Streaming private vault
│ ├── svs-7/ # SOL vault (native SOL wrapping)
│ ├── svs-8/ # Multi-asset basket vault
│ ├── svs-9/ # Allocator vault (CPI to child vaults)
│ ├── svs-10/ # Async vault (ERC-7540)
│ ├── svs-11/ # Credit markets vault (async, oracle NAV, KYC)
│ ├── svs-12/ # Tranched vault, waterfall yield/loss
│ ├── mock-oracle/ # Mock oracle for testing
│ └── mock-sas/ # Mock SAS for testing
├── modules/
│ ├── svs-math/ # Shared math (mul_div, rounding, conversion)
│ ├── svs-fees/ # Entry/exit fee calculation
│ ├── svs-caps/ # Global/per-user deposit caps
│ ├── svs-locks/ # Time-locked shares
│ ├── svs-access/ # Whitelist/blacklist + merkle proofs
│ ├── svs-module-hooks/ # Module hook integration
│ ├── svs-rewards/ # Secondary reward distribution
│ └── svs-oracle/ # Oracle price validation
├── sdk/
│ ├── core/ # @stbr/solana-vault
│ └── privacy/ # @stbr/svs-privacy-sdk
├── proofs-backend/ # Rust proof generation backend
│ ├── src/
│ ├── Cargo.toml
│ ├── Dockerfile
│ └── README.md
├── tests/
│ ├── svs-{1..12}.ts # Per-program integration tests
│ ├── svs-11-sdk.ts # SVS-11 SDK tests
│ ├── svs-12-sdk.ts # SVS-12 SDK tests
│ ├── svs-9-e2e.ts # SVS-9 end-to-end tests
│ ├── modules.ts # Module integration tests
│ ├── helpers/
│ │ └── proof-client.ts # ZK proof backend client helpers
│ ├── admin-extended.ts # Admin function tests
│ ├── decimals.ts # Multi-decimal tests
│ ├── edge-cases.ts # Edge case tests
│ ├── full-lifecycle.ts # Full lifecycle tests
│ ├── invariants.ts # Invariant tests
│ ├── multi-user.ts # Multi-user tests
│ └── yield-sync.ts # Yield/live balance tests
└── docs/
├── ARCHITECTURE.md # Technical architecture
├── CLI.md # CLI reference
├── CONSTANTS.md # Constants reference
├── DEPLOYMENT.md # Deployment guide
├── ERC-4626-REFERENCE.md # Original ERC-4626 spec
├── ERRORS.md # Error codes
├── EVENTS.md # Event definitions
├── MODULES.md # Module system
├── PATTERNS.md # Design patterns
├── PRIVACY.md # Privacy model & proof backend
├── SDK.md # SDK usage guide
├── SECURITY.md # Attack vectors & mitigations
├── TESTING.md # Test guide & coverage
└── SVS-{1..12}.md # Per-program specifications
This project uses solana-claude for Claude Code integration — skills, rules, agents, and MCP servers for Solana development.
- ERC-4626 Standard
- ERC-4626 on Solana
- Token-2022 Confidential Transfers
- ZK ElGamal Proof Program
- Anchor Documentation
Apache 2.0
This software is provided "as is" without warranty. Use at your own risk. 10 internal audit rounds completed but no external audit. Private vaults (SVS-3, SVS-4) require the Rust proofs backend for full functionality.