Skip to content

jvr0x/solana-lending

Repository files navigation

Solana Lending Protocol

A simplified lending protocol built on Solana using the Anchor framework. This project demonstrates core DeFi lending mechanics including deposits, withdrawals, and borrowing with collateralization.

⚠️ Educational Project: This is a simplified implementation for learning purposes. The math models and feature set have been intentionally simplified. NOT production-ready or audited.


Overview

This lending protocol allows users to:

  • Deposit SOL or USDC to earn interest
  • Withdraw deposited assets plus accrued interest
  • Borrow against deposited collateral
  • Track positions using a share-based accounting system

Key Simplifications

For educational clarity, this implementation simplifies:

  1. Interest Calculations: Uses simple interest rather than compound interest formulas
  2. Asset Support: Limited to SOL and USDC (expandable but kept minimal)
  3. Price Feeds: Integrates Pyth oracles but with simplified staleness checks
  4. Risk Models: Basic LTV (Loan-to-Value) and liquidation thresholds
  5. Fixed-Point Math: Simple precision scaling instead of advanced DeFi math libraries

This makes the codebase easier to understand while demonstrating core concepts.


Features

✅ Implemented

  • Multi-token support (SOL, USDC)
  • Share-based deposit tracking (similar to Aave/Compound)
  • Interest accrual over time
  • Collateral-based borrowing
  • Basic liquidation parameters (LTV, liquidation threshold)
  • Pyth price oracle integration
  • PDA-based account architecture

🚧 Simplified/Not Included

  • Complex compound interest calculations (uses simple interest)
  • Dynamic interest rates (fixed rates for simplicity)
  • Liquidation execution
  • Flash loans
  • Multiple collateral types per user
  • Advanced risk management

Architecture

Program Structure

programs/lending/src/
├── lib.rs              # Program entrypoint and instruction handlers
├── state.rs            # Account structures (Bank, User)
├── instructions/
│   ├── admin.rs        # InitBank, InitUser
│   ├── deposit.rs      # Deposit logic
│   ├── withdraw.rs     # Withdraw with interest
│   └── borrow.rs       # Borrow against collateral
├── constants.rs        # Pyth feed IDs, precision constants
└── error.rs            # Custom error codes

Core Accounts

Bank Account

Stores protocol state for each supported token:

  • Total deposits and deposit shares
  • Total borrowed and borrow shares
  • Interest rate (as fixed-point integer)
  • Liquidation parameters (LTV, threshold, bonus)

PDA: [mint_address]

User Account

Tracks individual user positions:

  • Deposited amounts and shares (SOL and USDC)
  • Borrowed amounts and shares (SOL and USDC)
  • Last update timestamps for interest calculation

PDA: [user_pubkey]

Bank Token Account

Holds the actual tokens deposited into the protocol.

PDA: [b"treasury", mint_address]


Getting Started

Prerequisites

  • Rust 1.75+
  • Solana CLI 1.18+
  • Anchor 0.30.1+
  • Node.js 18+

Installation

  1. Clone the repository

    git clone <repo-url>
    cd lending
  2. Install dependencies

    npm install --legacy-peer-deps
    cargo build
  3. Build the program

    anchor build

Testing

This project uses solana-bankrun for fast, deterministic testing with time manipulation (crucial for interest calculations).

# Run all tests
npm test

# Or using Anchor
anchor test

Key test features:

  • Time warping to test interest accrual
  • Integration with Pyth price feeds (devnet)
  • Multi-step transaction flows

Usage

Initialize a Bank

Creates a new lending market for a token:

await program.methods
  .initBank(
    new BN(750_000),  // liquidationThreshold (75%)
    new BN(800_000)   // maxLtv (80%)
  )
  .accounts({
    signer: signer.publicKey,
    mint: usdcMint,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .rpc();

Initialize User Account

await program.methods
  .initUser(usdcMint)
  .accounts({
    signer: signer.publicKey,
  })
  .rpc();

Deposit

await program.methods
  .deposit(new BN(1_000_000))  // Amount in base units
  .accounts({
    signer: signer.publicKey,
    mint: usdcMint,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .rpc();

Withdraw

await program.methods
  .withdraw(new BN(500_000))  // Amount to withdraw
  .accounts({
    signer: signer.publicKey,
    mint: usdcMint,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .rpc();

Key Concepts

Share-Based Accounting

Instead of tracking raw token amounts, the protocol uses shares:

  • Deposit shares: Represent your portion of the total deposits
  • Borrow shares: Represent your portion of total borrows

As interest accrues, the ratio of total_deposits / total_shares increases, so your shares become worth more tokens.

Example:

Time 0: Deposit 100 USDC → Get 100 shares
        Pool: 100 USDC, 100 shares

Time 1: Interest accrues +10 USDC
        Pool: 110 USDC, 100 shares

Withdraw: 100 shares = (100 * 110) / 100 = 110 USDC

Fixed-Point Arithmetic

All interest rates and calculations use scaled integers to avoid floating-point non-determinism:

  • Interest rate: 50_000 = 5% (scaled by 1,000,000)
  • LTV: 750_000 = 75% (scaled by 1,000,000)

This ensures validators always compute identical results.

PDA (Program Derived Addresses)

All program-owned accounts use PDAs for security:

  • Bank: Derived from mint address
  • User: Derived from user's public key
  • Treasury: Derived from "treasury" + mint

This prevents unauthorized access and enables deterministic address generation.


Security Considerations

⚠️ This is an educational project and has NOT been audited.

Known Limitations

  1. No Floating-Point: All math uses integers, but some calculations may lose precision
  2. Basic Interest Model: Simple interest instead of realistic DeFi models
  3. Fixed Interest Rates: Real protocols use dynamic rates based on utilization
  4. Limited Error Handling: Production code needs more comprehensive checks
  5. No Liquidation Bot: Liquidation logic exists but no automated execution

If Building on This

Before production use:

  • Professional security audit
  • Comprehensive test coverage (edge cases, exploits)
  • Dynamic interest rate model
  • Oracle manipulation protection
  • Emergency pause mechanism
  • Timelock for parameter changes
  • Proper decimal handling for all tokens

Project Configuration

Anchor.toml

[programs.localnet]
lending = "F7rde3WqWNoRPWF18aUcK9yEenSAZ8ZavdQQbhSsmwG8"

[provider]
cluster = "localnet"
wallet = "~/.config/solana/id.json"

Pyth Price Feeds (Devnet)

  • SOL/USD: 0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d
  • USDC/USD: 0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a

Development Notes

Why Simplified Math?

Real DeFi protocols use complex formulas like:

  • Continuous compounding: P * e^(rt)
  • Dynamic interest rates based on utilization curves
  • Multi-step liquidation cascades

This implementation uses simple interest to focus on:

  • Solana/Anchor program structure
  • Account management and PDAs
  • CPI (Cross-Program Invocation) patterns
  • Share-based accounting

The core patterns are production-ready; the math can be upgraded.

Why Limited Assets?

Supporting only SOL and USDC:

  • Simplifies testing and oracle integration
  • Reduces storage requirements
  • Makes the code easier to understand
  • Still demonstrates multi-asset patterns

Adding more tokens is straightforward (just deploy more Bank accounts).


Testing Strategy

Unit Tests (Rust)
  └─ Pure math functions (interest calculations, share conversions)

Integration Tests (Bankrun)
  ├─ Deposit/withdraw flows
  ├─ Interest accrual over time
  ├─ Borrow/repay cycles
  └─ Edge cases (zero balances, overflow)

Manual Testing (Devnet)
  └─ End-to-end user flows with real Pyth prices

Contributing

This is an educational project! Feel free to:

  • Add more sophisticated interest models
  • Implement liquidation execution
  • Add new asset types
  • Improve error handling
  • Write more tests

Resources

Solana & Anchor

DeFi Concepts

Testing


License

MIT License - See LICENSE file for details


Disclaimer

This software is provided "as is" for educational purposes. Use at your own risk. Not financial advice. Not production-ready.

About

A simplified lending protocol built on Solana.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published