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.
- 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
- Rust 1.70.0 or later
- Solana CLI 1.17.0 or later
- Anchor 0.30.0
- Bun 1.0.0 or later (for testing)
- Clone the repository:
git clone https://github.com/abdulbaqui17/AMM.git
cd AMM- Install dependencies:
yarn install
# or
bun install- Build the program:
anchor build# Build the Anchor program
anchor build
# The compiled program will be in target/deploy/amm.so# IDL and types are automatically generated during build
# Types will be available in target/types/amm.ts# Check program ID
solana address -k target/deploy/amm-keypair.json
# View program info
solana program show <PROGRAM_ID>This project uses pure TypeScript unit tests with Bun for fast, deterministic testing without needing a validator.
# 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 testsTest 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
$ bun test tests/
57 pass
0 fail
106 expect() calls
Ran 57 tests across 3 files. [~350ms]- β‘ 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
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
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 |
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();Deposit tokens into the pool and receive LP tokens.
await program.methods.addLiquidity(amountA, amountB)
.accounts({
user: user.publicKey,
pool: poolPda,
// ... other accounts
})
.rpc();Burn LP tokens to withdraw proportional share of pool tokens.
await program.methods.removeLiquidity(lpAmount)
.accounts({
user: user.publicKey,
pool: poolPda,
// ... other accounts
})
.rpc();Exchange one token for another with slippage protection.
await program.methods.swap(amountIn, minimumAmountOut)
.accounts({
user: user.publicKey,
pool: poolPda,
// ... other accounts
})
.rpc();- 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
x * y = k
Where x and y are token reserves, and k is the constant.
amount_out = (reserve_out * amount_in * (10000 - fee_bps)) /
(reserve_in * 10000 + amount_in * (10000 - fee_bps))
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
)
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
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- Program ID:
GusCwDKH6aEkejKcGKDoVpRaeYPBRHwxn1k5kGFK4Guu - Fee: 30 basis points (0.3%)
- LP Token Decimals: 6
- Network: Localnet (for testing), configurable for devnet/mainnet
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is open source and available under the MIT License.
Abdul Baqui
- GitHub: @abdulbaqui17
- 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.