Skip to content

Latest commit

 

History

History
194 lines (148 loc) · 6.62 KB

File metadata and controls

194 lines (148 loc) · 6.62 KB

FlowVault — Backend (Solana Program)

Anchor/Rust smart contract for rate-limited escrow vaults on Solana.

See the root README for a full project overview and architecture diagrams.

Structure

backend/
├── programs/flowvault/src/
│   ├── lib.rs                 # Program entrypoint + instruction dispatcher
│   ├── errors.rs              # FlowVaultError enum (6 error codes)
│   ├── state/
│   │   ├── mod.rs             # Re-exports
│   │   └── escrow.rs          # EscrowState account struct (11 fields)
│   └── instructions/
│       ├── mod.rs             # Re-exports
│       ├── initialize.rs      # Create escrow PDA + vault PDA, deposit SOL
│       ├── withdraw.rs        # Rate-limited withdrawal with window reset logic
│       └── cancel.rs          # Drain vault + close escrow, return rent to sender
├── tests/
│   └── flowvault.ts           # 12 integration tests (Mocha + Chai)
├── scripts/
│   └── deploy-devnet.sh       # Build + deploy + copy IDL to frontend
├── migrations/
│   └── deploy.ts              # Anchor migration entrypoint
├── Anchor.toml                # Anchor workspace config
├── Cargo.toml                 # Rust workspace
├── package.json               # JS test dependencies (bun-managed)
└── rust-toolchain.toml        # Pinned Rust 1.89

Prerequisites

Tool Version Install
Rust 1.89+ rustup.rs
Solana CLI 2.x docs.solanalabs.com
Anchor CLI 0.32.1 anchor-lang.com
Node.js 20+ nodejs.org
Bun latest bun.sh

Verify:

rustc --version        # rustc 1.89.x
solana --version       # solana-cli 2.x.x
anchor --version       # anchor-cli 0.32.1
bun --version          # 1.x

Setup

All commands run from the backend/ directory.

cd backend

# Install JS test dependencies
bun install

# Build the Solana program (generates IDL + keypair)
anchor build

Commands

# Build the program
anchor build

# Run all 12 integration tests (spins up a local validator automatically)
anchor test

# Deploy to local validator (must be running solana-test-validator)
anchor deploy --provider.cluster localnet

# Deploy to devnet
anchor deploy --provider.cluster devnet

# Full devnet deployment (build + deploy + copy IDL to frontend)
bash scripts/deploy-devnet.sh

# Lint JS/TS files
bun run lint

# Format JS/TS files
bun run lint:fix

Running Locally

You need two terminals to run the full stack.

Terminal 1 — Local validator

solana-test-validator

Terminal 2 — Deploy + start frontend

# From backend/
anchor deploy --provider.cluster localnet

# From frontend/
cd ../frontend
bun dev

Open http://localhost:3000 and connect a wallet.

Tip: Get free devnet SOL with solana airdrop 2.

Testing

12 integration tests covering all instructions, validation, access control, and edge cases.

anchor test
# Test What It Verifies
1 Initialize — correct state Escrow created with all fields set correctly
2 Initialize — reject high spend limit spend_limit > amount is rejected
3 Initialize — reject zero amount amount = 0 is rejected
4 Withdraw — within limit Receiver withdraws within window spend limit
5 Withdraw — exceed window limit Exceeding remaining window allowance is rejected
6 Withdraw — window reset Full limit is available again after window expires
7 Withdraw — wrong signer Non-receiver wallet cannot withdraw
8 Cancel — reclaim funds Sender closes escrow and gets all SOL back
9 Cancel — wrong signer Non-sender wallet cannot cancel
10 Withdraw after cancel Closed escrow account cannot be used
11 Vault fully drained Withdrawal fails with InsufficientFunds
12 Multiple escrows Different seeds create independent vaults

Program Details

Program Addresses

Network Address
Devnet 5eyT6xJEG3Qen3QD59zNEdiE4vkYgJdnNtwjSQYCnbyb
Mainnet Not yet deployed

Account Structure

EscrowState — stores configuration and tracking data for one escrow.

Field Type Description
sender Pubkey Wallet that created and funded the escrow
receiver Pubkey Wallet authorized to withdraw
seed u64 Unique seed (enables multiple escrows per pair)
total_deposited u64 Lamports deposited at creation
spend_limit u64 Max lamports withdrawable per window
window_duration i64 Window length in seconds
window_start i64 Unix timestamp of current window start
withdrawn_in_window u64 Lamports withdrawn in current window
total_withdrawn u64 Lifetime total lamports withdrawn
bump u8 Escrow PDA bump seed
vault_bump u8 Vault PDA bump seed

PDA Seeds

Account Seeds Derivation
Escrow State "escrow" + sender + receiver + seed One PDA per sender/receiver/seed combination
Vault "vault" + escrow_state One vault per escrow, derived from escrow PDA

Error Codes

Code Name Message
6000 InvalidAmount Amount must be greater than zero
6001 InvalidSpendLimit Spend limit must be greater than zero and at most the deposit amount
6002 InvalidWindowDuration Window duration must be greater than zero
6003 SpendLimitExceeded Withdrawal would exceed the spend limit for this window
6004 InsufficientFunds Vault has insufficient funds for this withdrawal
6005 MathOverflow Arithmetic overflow

Security Considerations

Pattern Implementation
Checks-Effects-Interactions State is validated and updated before any SOL transfer via CPI
PDA-Enforced Authorization Vault funds can only move through program-signed CPI; no private keys involved
has_one Constraints withdraw enforces has_one = receiver; cancel enforces has_one = sender
Clean Account Closure close = sender returns rent and zeroes account data on cancellation
Overflow Protection All arithmetic uses checked_add with explicit MathOverflow errors
No Reinitialization Anchor's init constraint prevents double-initialization of escrow accounts