A simple, secure Solana program for depositing and withdrawing SOL using Program Derived Addresses (PDAs).
Sol Vault is an Anchor-based Solana program that allows users to create personal vaults for storing SOL. Each user's vault is a PDA derived from their wallet address, ensuring secure and isolated storage.
- Deposit SOL: Transfer SOL from your wallet to your personal vault
- Withdraw SOL: Retrieve all SOL from your vault back to your wallet
- PDA-based Vaults: Each user has a unique vault address derived from their public key
- Rent-Exempt Validation: Ensures deposits meet minimum rent requirements
- Security Checks: Prevents double deposits and invalid operations
Before you begin, ensure you have the following installed:
-
Rust (v1.70.0 or later)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
Solana CLI (v1.18.0 or later)
sh -c "$(curl -sSfL https://release.solana.com/stable/install)" -
Anchor (v0.32.1)
cargo install --git https://github.com/coral-xyz/anchor --tag v0.32.1 anchor-cli
-
Node.js (v18 or later) and Yarn
# Install Node.js from https://nodejs.org npm install -g yarn
-
Clone the repository:
git clone <repository-url> cd sol_vault
-
Install dependencies:
yarn install
-
Build the program:
anchor build
-
Sync program keys:
anchor keys sync
sol_vault/
├── programs/
│ └── sol_vault/
│ └── src/
│ ├── lib.rs # Program entry point
│ ├── error.rs # Custom error definitions
│ ├── constants.rs # Program constants
│ ├── state.rs # State definitions (if any)
│ └── instructions/
│ ├── mod.rs # VaultAction account struct
│ ├── deposit.rs # Deposit instruction handler
│ └── withdraw.rs # Withdraw instruction handler
├── tests/
│ └── sol_vault.ts # TypeScript integration tests
├── Anchor.toml # Anchor configuration
└── README.md # This file
Afud3vbjgWYm8ySXuH1P1Ln5aDnbxDD2aZgYZpkeTMRG
Transfers SOL from the user's wallet to their vault.
Accounts:
signer(mut, signer): User's wallet accountvault_account(mut, PDA): User's vault account derived from["vault", signer.key]system_program: System program for transfers
Parameters:
amount(u64): Amount of lamports to deposit
Validations:
- Amount must be greater than the rent-exempt minimum (~890,880 lamports)
- Vault must not already contain funds
PDA Seeds:
[b"vault", signer.key.as_ref()]Transfers all SOL from the user's vault back to their wallet.
Accounts:
signer(mut, signer): User's wallet accountvault_account(mut, PDA): User's vault accountsystem_program: System program for transfers
Validations:
- Vault must contain lamports
# Run all tests on localnet
anchor test
# Run tests with logs
anchor test -- --features=debug
# Run specific test
anchor test -- --grep "Deposit"-
Start a local validator:
solana-test-validator
-
In another terminal, build and deploy:
anchor build anchor deploy
-
Run the tests:
anchor test --skip-local-validator
-
Set Solana CLI to devnet:
solana config set --url https://api.devnet.solana.com -
Airdrop SOL for deployment fees:
solana airdrop 2
-
Update
Anchor.tomlto include devnet configuration:[programs.devnet] sol_vault = "Afud3vbjgWYm8ySXuH1P1Ln5aDnbxDD2aZgYZpkeTMRG"
-
Deploy:
anchor build anchor deploy --provider.cluster devnet
-
Initialize the IDL:
anchor idl init -f target/idl/sol_vault.json <PROGRAM_ID> --provider.cluster devnet
-
Set Solana CLI to mainnet:
solana config set --url https://api.mainnet-beta.solana.com -
Update
Anchor.toml:[programs.mainnet] sol_vault = "Afud3vbjgWYm8ySXuH1P1Ln5aDnbxDD2aZgYZpkeTMRG"
-
Deploy:
anchor build --verifiable anchor deploy --provider.cluster mainnet
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { SolVault } from "../target/types/sol_vault";
// Setup
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.solVault as Program<SolVault>;
const user = provider.wallet.publicKey;
// Derive vault PDA
const [vaultPDA] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("vault"), user.toBuffer()],
program.programId
);
// Deposit 1 SOL
const depositAmount = new anchor.BN(1_000_000_000);
await program.methods
.deposit(depositAmount)
.accounts({
signer: user,
})
.rpc();
// Withdraw all SOL
await program.methods
.withdraw()
.accounts({
signer: user,
})
.rpc();| Code | Error | Description |
|---|---|---|
| 6000 | VaultAlreadyExists |
Attempted to deposit to a vault that already contains funds |
| 6001 | InvalidAmount |
Deposit amount is less than the rent-exempt minimum or vault is empty |
- PDA-based vaults: Ensures each user has a unique, isolated vault
- Rent-exempt validation: Prevents accounts from being closed by the runtime
- Overflow checks: Enabled in release profile to prevent arithmetic errors
- Signer validation: All operations require proper signatures
- Account ownership: Anchor validates account ownership automatically
- Single deposit only: Once a vault has funds, no additional deposits are allowed until withdrawn
- All-or-nothing withdrawal: Withdraw transfers all lamports; partial withdrawals not supported
- No access control: Any user can interact with their own vault (by design)
- Professional Audit: Have the code audited by a reputable security firm
- Extensive Testing: Test on devnet with real scenarios
- Admin Controls: Consider adding pause/emergency withdrawal features
- Upgradability: Ensure proper upgrade authority management
- Monitoring: Implement logging and monitoring for deployed programs
# Standard build
anchor build
# Verifiable build (for mainnet)
anchor build --verifiable
# Clean build
anchor clean && anchor build# Run all tests
anchor test
# Run with verbose output
RUST_LOG=debug anchor test
# Run without rebuilding
anchor test --skip-build# Format Rust code
cargo fmt
# Format TOML files
taplo fmt
# Format TypeScript tests
yarn prettier --write "tests/**/*.ts"# Run Clippy
cargo clippy -- -D warnings
# Check Anchor IDL
anchor idl parse -f programs/sol_vault/src/lib.rsContributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For questions or issues, please open an issue on GitHub or reach out to the development team.
Built with ❤️ using Anchor Framework