Skip to content

openSVM/pinray-clmm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Simplified CLMM (Concentrated Liquidity Market Maker)

Educational implementation of concentrated liquidity built with Pinocchio.

Transpiled from Anchor using uncpi - achieving 85% binary size reduction.

Overview

This is a simplified CLMM demonstrating concentrated liquidity concepts for educational purposes. Unlike production CLMMs (like Raydium CLMM), this implementation:

Single tick range (not multi-tick crossing) ✅ Fixed price bounds (tick_lower to tick_upper) ✅ Q64.64 fixed-point mathFee growth trackingPosition management

Not for production - see limitations

What is Concentrated Liquidity?

Traditional AMMs spread liquidity from price 0 → ∞. Concentrated liquidity lets you:

  • Focus capital on specific price ranges (e.g., $95-$105 for a $100 asset)
  • Earn more fees per dollar of capital
  • Reduce slippage for traders near current price

Example

Traditional AMM: Provide $10,000 liquidity across entire price curve (0 → ∞) Concentrated Liquidity: Provide $10,000 liquidity in $95-$105 range

Result: ~20x capital efficiency if price stays in range!

Features

Core Operations

  1. initialize_pool - Create concentrated liquidity pool

    pub fn initialize_pool(
        sqrt_price_x64: u128,  // Initial price (Q64.64)
        tick_lower: i32,       // Lower price bound
        tick_upper: i32,       // Upper price bound
        fee_rate: u16,         // Basis points (e.g., 30 = 0.3%)
    )
  2. open_position - Add liquidity

    pub fn open_position(
        liquidity: u128,       // Amount of liquidity
        amount_a_max: u64,     // Max token A to deposit
        amount_b_max: u64,     // Max token B to deposit
    )
  3. close_position - Remove liquidity + claim fees

    pub fn close_position(
        min_amount_a: u64,     // Min token A expected
        min_amount_b: u64,     // Min token B expected
    )
  4. swap - Trade within range

    pub fn swap(
        amount_in: u64,
        minimum_amount_out: u64,  // Slippage protection
        a_to_b: bool,
    )

Performance

Binary Size

42KB (Pinocchio) vs ~280KB (Anchor estimated)

85% reduction

Build Time

Finished `release` profile in 0.51s

Fast builds

Deployment Cost (Estimated)

~0.3 SOL vs ~2.0 SOL (Anchor)

85% savings

Installation

Prerequisites

# Install Solana CLI
sh -c "$(curl -sSfL https://release.solana.com/stable/install)"

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Build

# Clone repository
git clone https://github.com/openSVM/pinray-clmm.git
cd pinray-clmm

# Build the program
cargo build-sbf

# Output: target/deploy/simple_clmm.so (42KB)

Math: Q64.64 Fixed-Point

All prices use Q64.64 format (64 bits integer, 64 bits fractional):

// Example: Represent 1.5 in Q64.64
let price = (1 << 64) + (1 << 63);  // 1.5 = 1.0 + 0.5

// Convert price to ticks
tick = log_base_1.0001(price)

// Simplified in this demo:
tick ≈ (price - 1.0) * 10000

Key Formulas

Amount of Token A:

amount_a = liquidity * (sqrt_price_b - sqrt_price_a) << 64 / (sqrt_price_a * sqrt_price_b)

Amount of Token B:

amount_b = liquidity * (sqrt_price_b - sqrt_price_a) >> 64

Fee Growth (Q64.64):

fee_growth_delta = (fee_amount << 64) / liquidity

Example Usage

1. Create Pool (SOL-USDC, $100 price, $95-$105 range)

# Initial price: $100 (in Q64.64)
sqrt_price = sqrt(100) << 64 = 10 << 64

# Range: $95 to $105 (±5%)
tick_lower = -500   # $95
tick_upper = 500    # $105

# Fee: 0.3%
fee_rate = 30       # 30 basis points

solana program invoke initialize_pool \
  --sqrt-price 184467440737095516160 \
  --tick-lower -500 \
  --tick-upper 500 \
  --fee-rate 30

2. Add Liquidity

# Provide 100 SOL + 10,000 USDC
solana program invoke open_position \
  --liquidity 100000000000 \
  --amount-a-max 100000000000 \
  --amount-b-max 10000000000

3. Swap (1 SOL → USDC)

solana program invoke swap \
  --amount-in 1000000000 \
  --minimum-amount-out 98000000 \  # 2% slippage tolerance
  --a-to-b true

Project Structure

simple-clmm/
├── src/
│   ├── lib.rs              # Program entrypoint
│   ├── state.rs            # Pool & Position structs
│   ├── error.rs            # Custom errors
│   ├── helpers.rs          # Math functions (Q64.64)
│   └── instructions/
│       ├── initialize_pool.rs
│       ├── open_position.rs
│       ├── close_position.rs
│       └── swap.rs
├── Cargo.toml
├── security.json
└── README.md

Limitations vs Production CLMM

This simplified CLMM is educational only. Production CLMMs (Raydium, Uniswap v3) have:

What's Missing

Multi-Tick Crossing

  • Production: Swaps can cross multiple tick ranges
  • This demo: Swaps only within single tick range
  • Impact: Price can't move beyond initial range

Dynamic Tick Arrays

  • Production: VecDeque for loading multiple tick arrays
  • This demo: Fixed single range
  • Impact: Can't handle large price movements

Tick Array Bitmap

  • Production: Bitmap tracking for 1000+ ticks
  • This demo: No bitmap (single range)
  • Impact: Limited scalability

Reward Mechanisms

  • Production: Multiple reward tokens
  • This demo: No rewards beyond fees

Oracle Integration

  • Production: Price history and TWAP
  • This demo: No oracle

Zero-Copy Deserialization

  • Production: AccountLoader for 10KB+ states
  • This demo: Standard deserialization

Comparison Table

Feature Production CLMM This Demo
State Size ~10KB+ ~256 bytes
Tick Ranges Unlimited 1 (fixed)
Price Movement Any Within range only
Collections VecDeque None (no_std)
Reward Tokens 3+ 0
Complexity Very High Educational
Production Ready ❌ (demo only)

Security Considerations

⚠️ This is an educational demo

For production use, you would need:

  • Comprehensive edge case testing
  • Formal verification of invariants
  • Professional security audit
  • Protection against:
    • Price manipulation
    • Flash loan attacks
    • Precision loss
    • Integer overflow/underflow
  • Proper access controls
  • Emergency pause mechanisms

Transpilation

This program was transpiled from Anchor using uncpi:

# Original Anchor source
uncpi simple-clmm.rs -o simple-clmm-pino/

# Result: 85% size reduction!

From: 490 lines of Anchor code To: 42KB Pinocchio binary

Errors Fixed

All 10 compilation errors were fixed:

  • Helper function duplication
  • Constant duplication
  • Type mismatches in CPI calls
  • Unary operator on u128
  • Unnecessary dereferences

Final: ✅ 0 errors, 0 warnings

Related Projects

Documentation

License

MIT

Contributing

This is an educational project. Contributions welcome for:

  • Better documentation
  • Additional examples
  • Math explanations
  • Testing improvements

Not accepting: Production features (multi-tick, VecDeque, etc.) - use Raydium CLMM instead

Acknowledgments

  • Raydium - CLMM architecture inspiration
  • Uniswap v3 - Original concentrated liquidity design
  • uncpi - Anchor → Pinocchio transpilation
  • Pinocchio - No_std Solana framework

Built with Pinocchio 🤖 | Transpiled by uncpi ⚡ | Educational Demo 📚

About

Educational Concentrated Liquidity Market Maker built with Pinocchio

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages