Reference: A DeFi Program + dApp
This reference build walks a minimal lending pool: deposit SOL, mint share tokens, withdraw with pro-rata accounting. It ties together Anchor 0.32.1, LiteSVM 0.6.x tests, and a Next.js dApp using @solana/kit 7.0.0 - the shape most DeFi teams ship.
Recipe
Quick-reference recipe card - copy-paste ready.
programs/lending/ Anchor program (deposit, withdraw, pause)
tests/litesvm/ Exploit replay + happy path
app/ Next.js wallet + simulate + send
packages/idl/ Published IDL + codegen types
When to reach for this:
- Greenfield DeFi protocol architecture
- Onboarding full-stack Solana engineer
- Audit scope document baseline
- Comparing your layout to a known-good structure
Working Example
Program (Anchor 0.32.1 excerpt)
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod lending {
use super::*;
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
require!(!ctx.accounts.config.paused, LendingError::Paused);
// transfer SOL to vault; mint shares to user_position
Ok(())
}
}
#[account]
pub struct PoolConfig {
pub admin: Pubkey,
pub paused: bool,
pub total_shares: u64,
}Client (TypeScript excerpt)
import { createSolanaRpc } from "@solana/kit";
import { buildDepositIx } from "@lending/idl-client";
const rpc = createSolanaRpc(process.env.NEXT_PUBLIC_RPC_URL!);
export async function deposit(amount: bigint, wallet: Wallet) {
const ix = await buildDepositIx({ amount, user: wallet.publicKey });
const sim = await rpc.simulateTransaction(await wallet.sign(ix), { sigVerify: true }).send();
if (sim.value.err) throw new Error(JSON.stringify(sim.value.err));
return wallet.send(ix);
}Repo layout
lending-reference/
programs/lending/src/lib.rs
tests/litesvm/deposit_withdraw.rs
app/src/app/pool/page.tsx
packages/idl/lending.json
docs/adr/0001-upgradeable-pool.mdWhat this demonstrates:
- Pause guard on all mutating instructions
- IDL package consumed by Next.js app
- Simulation before user-facing send
- ADR slot for upgrade policy
Deep Dive
Account Model
| Account | Type | Purpose |
|---|---|---|
pool_config | PDA | Admin, pause, totals |
vault | PDA | Holds SOL lamports |
user_position | PDA | Per-user shares |
Release Train
anchor test+ LiteSVM on PR- Devnet deploy on merge to
main - Squads proposal for mainnet with verifiable hash
- Frontend promote when IDL version matches
Gotchas
- Client math duplicates on-chain - Share price drift exploits. Fix: Read totals from chain; display only.
- Missing pause in withdraw - Attacker drains during incident. Fix: Central
require!(!paused). - IDL not versioned - Client calls removed ix. Fix: Semver in
packages/idl. - Public RPC on launch - Rate limit outage. Fix: Dedicated write RPC in production env.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Pinocchio for hot ix | CU proven bottleneck | First version |
| Separate client repo | Multiple consumers | Small team overhead |
| Immutable program | Fixed simple pool | Need post-audit fixes |
FAQs
Why Anchor not Pinocchio here?
Velocity and audit familiarity outweigh CU savings until profiled.
Where Jupiter fit?
Separate CPI module; allowlist program ID in constants.
Indexer needed?
For history charts yes; MVP can poll PDAs via RPC.
Test validator role?
Manual debug; CI uses LiteSVM per manifest pins.
Mobile?
Add MWA path in app; same IDL client package.
Token shares SPL?
Yes - mint authority = pool PDA; see SPL token launch reference.
Upgrade policy?
Document in ADR; Squads 2-of-3 before mainnet TVL.
How small can this be?
This reference is teachable size; production adds oracles, liquidations, events.
Audit package?
Program + IDL + this architecture doc + threat model appendix.
Clone repo?
Use as template; replace program ID and regenerate keypairs per env.
Related
- Reference: An SPL Token Launch - share token mint
- Before/After: Optimizing CU & Rent - scale path
- Anchor Basics - framework fundamentals
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.