A decentralized exchange (DEX) built on Solana using the Anchor framework. This project implements a fully functional Automated Market Maker with liquidity pools, token swaps, and comprehensive frontend interface.
Deployed Frontend URL: https://program-limitofzero.vercel.app/
- Create AMM: Initialize a new AMM instance with custom fee structure and index
- Create Pool: Set up liquidity pools for any token pair
- Add Liquidity: Provide liquidity to pools and receive LP tokens
- Swap Tokens: Trade tokens through the AMM with automatic price calculation
- Withdraw Liquidity: Remove liquidity from pools and receive tokens back
- View Pools: Browse all active pools with real-time reserves and fees
- Wallet Integration: Connect with Phantom, Solflare, and other Solana wallets
- Token Management: Create tokens, mint tokens, and manage saved token addresses
- Real-time Data: View pool reserves, token balances, and exchange rates
- Slippage Protection: Automatic slippage calculation and minimum output recommendations
- User Share Display: See your liquidity share percentage in pools
- Transaction Status: Detailed success/error feedback
- Node.js 18+ and npm/yarn
- Rust and Anchor framework installed
- Solana CLI tools installed
- A Solana wallet (Phantom, Solflare, etc.)
git clone <repository-url>
cd program-limitofzerocd anchor_project/amm
anchor buildcd ../../frontend
yarnprogram-limitofzero/
βββ anchor_project/
β βββ amm/
β βββ programs/
β β βββ amm/
β β βββ src/
β β β βββ lib.rs # Main program entry
β β β βββ states.rs # Account structures
β β β βββ errors.rs # Custom error types
β β β βββ instructions/ # Program instructions
β β βββ Cargo.toml
β βββ tests/ # TypeScript tests
β βββ Anchor.toml
βββ frontend/
β βββ src/
β β βββ app/ # Next.js app router
β β βββ components/ # React components
β β βββ contexts/ # React contexts (PoolsContext)
β β βββ hooks/ # Custom hooks (useSavedMints)
β β βββ lib/ # Utilities and program setup
β βββ public/
β βββ amm.json # Program IDL
βββ README.md
The program is deployed on Solana Devnet with the following ID:
Program ID: 264uMZcS5Mcpe5EzAP6P2SoGQE4j7KtpSe6U8mSQZeAN
Create a .env.local file in the frontend/ directory:
# Network configuration (devnet, mainnet, localnet)
NEXT_PUBLIC_SOLANA_NETWORK=devnet
# Optional: Custom RPC URL (for localnet)
# NEXT_PUBLIC_SOLANA_RPC_URL=http://127.0.0.1:8899
# Program ID
NEXT_PUBLIC_PROGRAM_ID=264uMZcS5Mcpe5EzAP6P2SoGQE4j7KtpSe6U8mSQZeANFor local development, start a local Solana validator:
solana-test-validatorcd frontend
yarn devOpen http://localhost:3000 in your browser.
cd anchor_project/amm
anchor test- Click "Connect Wallet" in the top navigation
- Select your wallet (Phantom, Solflare, etc.)
- Approve the connection
Prerequisites:
- You can use any existing SPL tokens - you don't need to create new tokens. Simply use the mint addresses of any SPL tokens you already have (e.g., USDC, SOL, or any other SPL token).
- If you already have 2 SPL tokens with their mint addresses, you can skip to Step 3.5 (Create AMM) if you haven't created an AMM yet, or proceed directly to Step 3.6 (Create the Pool).
- If you don't have tokens yet and want to create test tokens, follow the steps below starting from Step 3.1 to create them using Dev Tools.
To create a liquidity pool, you need two tokens to pair. You can use any existing SPL tokens or create new ones. Follow these steps:
- Navigate to the "Dev Tools" tab
- In the "Create Token Mint" section:
- Enter a Token Name (e.g., "My First Token")
- Enter a Token Symbol (e.g., "MFT")
- Set Decimals (default: 9)
- Click "Create Mint"
- Copy the generated Mint Address (it will be displayed after creation)
- The token will be automatically saved to your saved mints list
- In the "Mint Tokens" section of Dev Tools:
- The mint address should already be filled (from the created mint above)
- Enter the Supply amount (e.g., "1000000" for 1 million tokens)
- Click "Mint Tokens"
- Wait for the transaction to confirm
- You should now have tokens in your wallet balance
- In the "Create Token Mint" section again:
- Enter a different Token Name (e.g., "My Second Token")
- Enter a different Token Symbol (e.g., "MST")
- Set Decimals (e.g., 9)
- Click "Create Mint"
- Copy the new Mint Address
- In the "Mint Tokens" section:
- The new mint address should be filled
- Enter the Supply amount (e.g., "1000000")
- Click "Mint Tokens"
- Wait for the transaction to confirm
- Navigate to the "Create AMM" tab
- Enter a Fee (in basis points, max 9999, e.g., 30 for 0.3%)
- Enter an Index (unique identifier for the AMM, e.g., 1)
- Click "Create AMM"
- Wait for the transaction to confirm
- Remember the AMM Index - you'll need it for creating the pool
- Navigate to the "Create Pool" tab
- In the "Mint A Address" field:
- Select Token A from the dropdown (or paste the mint address)
- You'll see the token name/symbol displayed if available
- In the "Mint B Address" field:
- Select Token B from the dropdown (or paste the mint address)
- Enter the AMM Index (the same index you used when creating the AMM)
- Click "Create Pool"
- Wait for the transaction to confirm
Note: You can also use existing tokens from other pools by selecting them from the dropdown in the "Mint Tokens" section of Dev Tools, which shows all tokens present in active pools.
- Navigate to "Add Liquidity" tab
- Select an existing pool from the dropdown (or enter manually)
- Enter amounts for Token A and Token B
- Use "Use Recommended" to match pool ratio
- View your share percentage in the pool
- Click "Add Liquidity"
- Go to "Swap" tab
- Select a pool from the dropdown
- Choose swap direction (A to B or B to A)
- Enter the amount to swap
- View exchange rate and estimated output
- Adjust slippage tolerance if needed
- Click "Swap"
- Navigate to "Withdraw Liquidity" tab
- Select a pool you have LP tokens for
- View your LP token balance
- Enter amount to withdraw (or use quick buttons: 25%, 50%, 75%, 100%)
- View estimated token outputs
- Click "Withdraw Liquidity"
- Create Token Mint: Create new SPL tokens with custom name, symbol, and decimals
- Mint Tokens: Mint tokens to your wallet (requires mint authority)
- Token Selector: Choose tokens from active pools for minting
-
create_amm: Initialize a new AMM instance
- Parameters:
fee(u16),index(u16) - Creates AMM PDA with seeds:
["AMM", index]
- Parameters:
-
create_pool: Create a liquidity pool for a token pair
- Creates pool PDA, LP mint, and pool token accounts
- Seeds:
["AMM_POOL", amm, mint_a, mint_b]
-
add_liquidity: Add tokens to a pool
- Parameters:
amount_a(u64),amount_b(u64) - Mints LP tokens proportional to liquidity provided
- Calculates optimal amounts to maintain pool ratio
- Parameters:
-
swap: Exchange tokens through the pool
- Parameters:
is_swap_a(bool),amount(u64),min_out_amount(u64) - Uses constant product formula (x * y = k)
- Applies AMM fee to input amount
- Parameters:
-
withdraw_liquidity: Remove liquidity from a pool
- Parameters:
amount(u64) - LP token amount to burn - Returns proportional amounts of both tokens
- Parameters:
The program uses Program Derived Addresses (PDAs) for deterministic account generation:
- AMM PDA:
["AMM", index]- Stores AMM configuration - Pool PDA:
["AMM_POOL", amm, mint_a, mint_b]- Stores pool state - Pool Authority PDA:
["AMM_POOL_AUTHORITY", amm, mint_a, mint_b]- Controls pool token accounts - LP Mint PDA:
["AMM_MINT_LIQUIDITY", amm, mint_a, mint_b]- LP token mint
#[account]
pub struct Amm {
pub admin: Pubkey, // Admin wallet address
pub index: u16, // Unique AMM index
pub fee: u16, // Fee in basis points (0-9999)
}
#[account]
pub struct AmmPool {
pub amm: Pubkey, // AMM this pool belongs to
pub mint_a: Pubkey, // First token mint
pub mint_b: Pubkey, // Second token mint
}The project includes comprehensive tests covering both happy and unhappy paths:
tests/amm.ts- AMM creation teststests/pool.ts- Pool creation teststests/add_liquidity.ts- Liquidity addition teststests/swap.ts- Token swap teststests/withdraw_liquidity.ts- Liquidity withdrawal tests
Happy Path Tests:
- Create AMM with valid parameters
- Create multiple pools with different indices
- Add liquidity to new and existing pools
- Swap tokens in both directions
- Withdraw liquidity and receive tokens
- Handle different token decimals
Unhappy Path Tests:
- Cannot create AMM with duplicate index
- Cannot create AMM with fee >= 10000
- Cannot create pool with same token pair twice
- Cannot add liquidity with zero amounts
- Cannot swap with insufficient balance
- Cannot swap with output below minimum
- Cannot withdraw more LP tokens than owned
Run tests:
cd anchor_project/amm
anchor test- Fee Validation: Fees are validated to be less than MAX_FEE_BPS (10000)
- Amount Validation: All amounts must be greater than zero
- Balance Checks: Insufficient balance errors are properly handled
- Slippage Protection: Minimum output amounts prevent unfavorable swaps
- PDA Signing: Pool authority uses PDA seeds for secure signing
cd anchor_project/amm
anchor build
anchor deploy --provider.cluster devnetThe frontend is deployed on vercel:
- Vercel (recommended)
- Netlify
- Any static hosting service
cd frontend
yarn run build
# Deploy the 'out' or '.next' directory- Anchor: Solana program framework
- Rust: Program language
- TypeScript: Tests and frontend
- Next.js: Frontend framework
- React: UI library
- @solana/web3.js: Solana JavaScript SDK
- @coral-xyz/anchor: Anchor TypeScript client
- @solana/spl-token: SPL Token library
- Tailwind CSS: Styling
Note: This AMM is deployed on Solana Devnet for educational purposes.