A constant product AMM smart contract for Solana, built with Anchor and tested with TypeScript. This project demonstrates a simple DEX pool supporting liquidity provision, token swaps, and withdrawals, using the SPL Token standard.
- Initialize: Create a new AMM pool with two vaults and an LP token mint
- Deposit: Add liquidity to the pool and receive LP tokens
- Swap: Swap between the two pool tokens using the constant product formula (x*y=k)
- Withdraw: Burn LP tokens to withdraw your share of the pool
- Slippage protection and pool locking
.
├── programs/amm/ # Rust smart contract (Anchor)
│ ├── src/
│ │ ├── instructions/ # Rust instruction handlers (initialize, deposit, swap, withdraw)
│ │ ├── state/ # Pool state definitions
│ │ ├── error.rs # Custom error codes
│ │ └── lib.rs # Program entrypoint
│ ├── Cargo.toml
│ └── ...
├── tests/amm.ts # TypeScript integration tests (Anchor, Mocha)
├── Anchor.toml # Anchor config
└── README.md # This file
- Solana CLI
- Anchor CLI
- Node.js (v16+ recommended)
- Yarn or npm
- Install dependencies
yarn install # or npm install - Build the program
anchor build
- Deploy to localnet or devnet
anchor deploy # For devnet: anchor deploy --provider.cluster devnet
The test suite covers the full AMM lifecycle: pool creation, deposit, swap (both directions), and withdrawal.
anchor testThis will:
- Build and deploy the program
- Run the TypeScript tests in
tests/amm.ts
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Amm } from "../target/types/amm";
const program = anchor.workspace.amm as Program<Amm>;
// Initialize pool
await program.methods
.initialize(seed, fee, null)
.accounts({ ... })
.signers([initializer])
.rpc();
// Deposit liquidity
await program.methods
.deposit(new anchor.BN(100_000), new anchor.BN(100_000), new anchor.BN(200_000))
.accounts({ ... })
.signers([user])
.rpc();
// Swap tokens
await program.methods
.swap(new anchor.BN(10_000), new anchor.BN(1), true)
.accounts({ ... })
.signers([user])
.rpc();
// Withdraw liquidity
await program.methods
.withdraw(new anchor.BN(lpBalance), new anchor.BN(1), new anchor.BN(1))
.accounts({ ... })
.signers([user])
.rpc();- The program uses Anchor's PDA and CPI patterns for secure token management.
- All pool state is stored in a
Configaccount (seeprograms/amm/src/state/mod.rs). - Errors are defined in
programs/amm/src/error.rsand surfaced to the client. - The test suite (
tests/amm.ts) demonstrates full pool lifecycle and can be used as a reference for integration. - For custom features (e.g., pool locking, authority), see the Rust source and expand as needed.
This project is for educational purposes and is not audited. Use at your own risk.