A Solana-based vault system that allows vault admins to deposit tokens into different protocols or convert them to different tokens to generate yield.
This project contains two programs:
yo-vaults: Allows anyone to create a vault where users can deposit funds. Vault admins can then convert user deposits to different tokens or deploy them across various protocols to generate yield.
kamino-adapter: A wrapper around the Kamino protocol that enables vault admins to deposit funds into the Kamino lending protocol.
A PDA that stores:
- Vault admin
- Base mint (the SPL token mint used for deposits)
- Yo token mint (shares token)
- On-chain configuration for token allocation across protocols
Admins can update the configuration to modify how vault funds are distributed across different protocols.
A PDA used to:
- Sign all CPI transactions related to a vault
- Store total vault funds in its Associated Token Accounts (ATAs)
- Sign instructions for trusted adapter interactions
Stores the list of trusted adapter program IDs that can receive vault deposits via CPI. This account can only be updated by the protocol admin, not by individual vault creators.
- initialize: Initializes a new vault account. Optionally allows the creator to make an initial deposit.
- deposit: Deposits funds into the vault and mints share tokens to the user.
- manage_trusted_adapters: Allows protocol admins to add or remove trusted adapter programs.
- process_weight_deposit: Triggers a weighted deposit into integrated protocols. Can be called by vault admins or permissionlessly. Includes validation checks to ensure only authorized instructions are invoked.
- update_config: Allows vault admins to update the vault configuration and allocation weights (e.g., 20% to Kamino, 30% to another protocol).
- deposit: Invoked via CPI from the yo-vaults program to deposit funds into the Kamino lending protocol.
The program currently uses simple arithmetic operations with Rust's built-in checked_* functions for overflow protection. A dedicated Number or Decimal struct may be implemented in the future as mathematical complexity increases.
anchor build
anchor keys sync
anchor testTests are located in tests/yo-vaults-complete-flow.ts and use the keypair from user.json.
To enable local testing of Kamino integration, we use a modified USDC mint on localnet with updated authority. The mint authority was changed using this code:
use base64::{engine::general_purpose, Engine as _};
let mint_account_data_base_64 = "AQAAAJj+huiNm+Lqi8HMpIeLKYjCQPUrhCS/tA7Rot3LXhmb19GMG0ohJgAGAQEAAABicKqKWcWUBbRShshncubNEm6bil06OFNtN/e0FOi2Zw==";
let data_decoded = general_purpose::STANDARD
.decode(mint_account_data_base_64)
.unwrap();
let mut mint_account = spl_token::state::Mint::unpack(&data_decoded).unwrap();
mint_account.mint_authority =
Option::Some(pubkey!("VCe4fh7rWH5JKczbtsFhxwVGH5VAvFUBvgjYk3wmsec")).into();
let account_size = spl_token::state::Mint::LEN;
let mut updated_mint_data = vec![0; account_size];
spl_token::state::Mint::pack(mint_account, &mut updated_mint_data).unwrap();
let encoded_base_64 = general_purpose::STANDARD.encode(&updated_mint_data);
dbg!(encoded_base_64);This modification enables USDC minting on localnet for testing purposes.
The last tests in the yo-vaults-complete-flow will not work:
The Kamino instruction currently fails on localnet because slots start from 0. The warp_to_slot function either doesn't work correctly or requires excessive time with larger values.
Potential Solutions:
- Modify the Klend program and test against the modified version
- Update specific Kamino values to prevent slot subtraction failures (similar to the mint authority modification)