Skip to content

abdulbaqui17/AMM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

54 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Solana Constant Product AMM

A production-grade Automated Market Maker (AMM) built on Solana using the Anchor framework. This AMM implements the constant product formula (x * y = k) similar to Uniswap V2.

πŸš€ Features

  • Constant Product Formula: Implements x * y = k invariant
  • Liquidity Provision: Users can add/remove liquidity and receive LP tokens
  • Token Swaps: Efficient token swapping with configurable fees
  • 0.3% Trading Fee: Standard 30 basis points fee on swaps
  • Slippage Protection: Built-in minimum output amount validation
  • Safe Math: All operations use checked arithmetic to prevent overflow
  • PDA-based Architecture: Secure pool management using Program Derived Addresses

πŸ“‹ Prerequisites

πŸ› οΈ Installation

  1. Clone the repository:
git clone https://github.com/abdulbaqui17/AMM.git
cd AMM
  1. Install dependencies:
yarn install
# or
bun install
  1. Build the program:
anchor build

πŸ—οΈ How to Build

Build the Solana Program

# Build the Anchor program
anchor build

# The compiled program will be in target/deploy/amm.so

Generate TypeScript Types

# IDL and types are automatically generated during build
# Types will be available in target/types/amm.ts

Verify the Build

# Check program ID
solana address -k target/deploy/amm-keypair.json

# View program info
solana program show <PROGRAM_ID>

πŸ§ͺ How to Test Locally

This project uses pure TypeScript unit tests with Bun for fast, deterministic testing without needing a validator.

Quick Test

# Run all tests (57 tests across 3 files)
bun test tests/

# Run specific test file
bun test tests/amm-math.test.ts       # 21 math tests
bun test tests/amm-state.test.ts      # 14 state tests
bun test tests/amm-invariant.test.ts  # 22 invariant tests

Test Suite Coverage

Test Files:

File Tests Purpose
amm-math.test.ts 21 tests Pure math functions (sqrt, swap, quote)
amm-state.test.ts 14 tests State transitions (add/remove liquidity)
amm-invariant.test.ts 22 tests Invariants, slippage, edge cases

Total: 57 tests covering:

  • βœ… Integer square root calculations
  • βœ… Swap output calculations (with fees)
  • βœ… Quote/proportional calculations
  • βœ… First liquidity provider logic
  • βœ… Subsequent liquidity provider logic
  • βœ… Remove liquidity calculations
  • βœ… Constant product invariant (x * y = k)
  • βœ… Slippage protection
  • βœ… Edge cases (zero inputs, overflow protection)
  • βœ… Fee mechanics
  • βœ… Price impact calculations

Test Results

$ bun test tests/

 57 pass
 0 fail
 106 expect() calls
Ran 57 tests across 3 files. [~350ms]

Why Pure TypeScript Tests?

  • ⚑ Fast: All tests run in ~350ms (no validator needed)
  • 🎯 Deterministic: Same results every time
  • πŸ”§ No Dependencies: No Anchor, SPL, or validator required
  • πŸš€ CI/CD Friendly: Runs anywhere Node.js/Bun is available
  • πŸ“Š Comprehensive: Tests all math, state, and invariant logic

πŸ“ Project Structure

AMM/
β”œβ”€β”€ programs/
β”‚   └── amm/
β”‚       └── src/
β”‚           β”œβ”€β”€ lib.rs                    # Program entry point
β”‚           β”œβ”€β”€ state.rs                  # Pool state definition
β”‚           β”œβ”€β”€ error.rs                  # Custom error codes
β”‚           β”œβ”€β”€ math.rs                   # AMM math helpers
β”‚           └── instructions/
β”‚               β”œβ”€β”€ initialize_pool.rs    # Create new pool
β”‚               β”œβ”€β”€ add_liquidity.rs      # Deposit tokens
β”‚               β”œβ”€β”€ remove_liquidity.rs   # Withdraw tokens
β”‚               └── swap.rs               # Token exchange
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ amm-math.test.ts                 # Pure math unit tests
β”‚   β”œβ”€β”€ amm-state.test.ts                # State transition tests
β”‚   └── amm-invariant.test.ts            # Invariant & safety tests
β”œβ”€β”€ Anchor.toml                           # Anchor configuration
└── package.json                          # Node.js dependencies

πŸ”§ Program Instructions

Overview

The AMM program provides four core instructions for managing liquidity pools:

Instruction Description
initialize_pool Create a new liquidity pool for two SPL tokens
add_liquidity Deposit tokens and receive LP tokens
remove_liquidity Burn LP tokens and withdraw tokens
swap Exchange one token for another

1. Initialize Pool

Creates a new liquidity pool for two SPL tokens.

Note: Vaults and LP mint must be created before calling this instruction.

await program.methods.initializePool()
  .accounts({
    payer: payer.publicKey,
    pool: poolPda,
    tokenMintA: mintA,
    tokenMintB: mintB,
    vaultA: vaultA,
    vaultB: vaultB,
    lpMint: lpMint,
    systemProgram: SystemProgram.programId,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .rpc();

2. Add Liquidity

Deposit tokens into the pool and receive LP tokens.

await program.methods.addLiquidity(amountA, amountB)
  .accounts({
    user: user.publicKey,
    pool: poolPda,
    // ... other accounts
  })
  .rpc();

3. Remove Liquidity

Burn LP tokens to withdraw proportional share of pool tokens.

await program.methods.removeLiquidity(lpAmount)
  .accounts({
    user: user.publicKey,
    pool: poolPda,
    // ... other accounts
  })
  .rpc();

4. Swap

Exchange one token for another with slippage protection.

await program.methods.swap(amountIn, minimumAmountOut)
  .accounts({
    user: user.publicKey,
    pool: poolPda,
    // ... other accounts
  })
  .rpc();

πŸ” Security Features

  • Checked Arithmetic: All math operations use checked arithmetic to prevent overflow
  • PDA Authority: Pool controls vaults and LP mint via PDA
  • Input Validation: Validates mint ordering, zero amounts, and slippage limits
  • Constraint Checks: Anchor constraints verify all account relationships

πŸ“Š AMM Math

Constant Product Formula

x * y = k

Where x and y are token reserves, and k is the constant.

Swap Calculation

amount_out = (reserve_out * amount_in * (10000 - fee_bps)) / 
             (reserve_in * 10000 + amount_in * (10000 - fee_bps))

LP Token Calculation

For first liquidity provider:

lp_tokens = sqrt(amount_a * amount_b)

For subsequent providers:

lp_tokens = min(
  amount_a * total_lp_supply / reserve_a,
  amount_b * total_lp_supply / reserve_b
)

πŸ› Troubleshooting

Build Issues

Error: anchor-lang version mismatch

# Update Anchor.toml to match installed version
[toolchain]
anchor_version = "0.30.0"

Stack frame warnings during build

  • These are warnings about BPF stack usage
  • The program compiles successfully and works correctly
  • Addressed by using Box<Account<'info, T>> for large structures

Test Issues

Tests not running

# Make sure Bun is installed
curl -fsSL https://bun.sh/install | bash

# Run tests
bun test tests/

Import errors in tests

# Reinstall dependencies
rm -rf node_modules bun.lockb
bun install

πŸ“ Development Notes

  • Program ID: GusCwDKH6aEkejKcGKDoVpRaeYPBRHwxn1k5kGFK4Guu
  • Fee: 30 basis points (0.3%)
  • LP Token Decimals: 6
  • Network: Localnet (for testing), configurable for devnet/mainnet

🀝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This project is open source and available under the MIT License.

πŸ”— Resources

πŸ‘€ Author

Abdul Baqui

⭐ Acknowledgments

  • Built with Anchor Framework
  • Inspired by Uniswap V2 and Raydium AMM designs
  • Thanks to the Solana developer community

Note: This is a learning/demonstration project. For production use, conduct thorough security audits and testing.

About

Constant product AMM on Solana with Anchor - liquidity pools, swaps, and LP tokens

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages