Skip to content

Subodhkd001/anchor-amm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

βš“ Anchor AMM β€” Solana Automated Market Maker

A decentralized Automated Market Maker (AMM) built on Solana using the Anchor framework. Implements a constant-product curve (x * y = k) for trustless token swaps, liquidity provisioning, and LP token management β€” fully on-chain.


πŸ“ Architecture Overview

graph TD
    Client["πŸ–₯️ Client / dApp<br/>TypeScript + Anchor SDK"]
    Solana["⚑ Solana Localnet<br/>Program ID: Abckz5L...rLWN"]
    Program["πŸ“¦ AMM Program<br/>lib.rs"]

    Initialize["πŸ—οΈ initialize<br/>seed Β· fee Β· authority"]
    Deposit["πŸ’° deposit<br/>add liquidity Β· mint LP"]
    Withdraw["🏧 withdraw<br/>remove liquidity · burn LP"]
    Swap["πŸ”„ swap<br/>is_x Β· amount_in Β· min_out"]

    State["πŸ—ƒοΈ Config PDA<br/>seed Β· fee Β· locked<br/>mint_x Β· mint_y<br/>config_bump Β· lp_bump"]

    Client -->|RPC calls| Solana
    Solana --> Program
    Program --> Initialize
    Program --> Deposit
    Program --> Withdraw
    Program --> Swap
    Initialize -->|creates| State
    Deposit -->|reads| State
    Withdraw -->|reads| State
    Swap -->|reads| State
Loading

🏦 On-Chain Account Structure

graph TD
    Wallet["πŸ‘€ Initializer Wallet<br/>Payer + Signer"]

    Config["πŸ”‘ Config PDA<br/>seeds: b'config' + seed<br/>─────────────────────<br/>seed Β· fee Β· locked<br/>mint_x Β· mint_y<br/>config_bump Β· lp_bump"]

    VaultX["🏦 Vault X ATA<br/>holds Token X<br/>authority = Config"]
    VaultY["🏦 Vault Y ATA<br/>holds Token Y<br/>authority = Config"]
    MintLP["πŸͺ™ LP Mint PDA<br/>seeds: b'lp' + config.key<br/>authority = Config<br/>decimals = 6"]

    Wallet -->|initialize| Config
    Config -->|owns| VaultX
    Config -->|owns| VaultY
    Config -->|mint authority| MintLP
Loading

πŸ’° Deposit Flow

flowchart TD
    A(["πŸ‘€ deposit<br/>amount_lp Β· max_x Β· max_y"])
    B{Pool locked?}
    C["❌ PoolLocked"]
    D{Pool empty?<br/>supply = 0<br/>vault_x = 0<br/>vault_y = 0}
    E["x = max_x<br/>y = max_y"]
    F["ConstantProduct::<br/>xy_deposit_amounts_from_l()<br/>xΒ·y proportional to k"]
    G{x ≀ max_x<br/>AND y ≀ max_y?}
    H["❌ SlippageExceeded"]
    I["CPI: transfer<br/>user_x ──► vault_x"]
    J["CPI: transfer<br/>user_y ──► vault_y"]
    K["CPI: mint_to<br/>LP tokens ──► user_lp"]
    L(["βœ… Done"])

    A --> B
    B -->|YES| C
    B -->|NO| D
    D -->|YES| E
    D -->|NO| F
    E --> G
    F --> G
    G -->|NO| H
    G -->|YES| I
    I --> J
    J --> K
    K --> L
Loading

πŸ”„ Swap Flow

flowchart TD
    A(["πŸ‘€ swap<br/>is_x Β· amount_in Β· min_out"])
    B{Pool locked?}
    C["❌ PoolLocked"]
    D{LP supply = 0?}
    E["❌ NoLiquidityInPool"]
    F["ConstantProduct::init<br/>vault_x Β· vault_y Β· supply Β· fee"]
    G["c.swap<br/>LiquidityPair::X or Y<br/>calculates res.deposit<br/>and res.withdraw"]
    H["CPI: transfer<br/>user_in ──► vault_in<br/>amount = res.deposit"]
    I["CPI: transfer w/ signer<br/>vault_out ──► user_out<br/>amount = res.withdraw"]
    J(["βœ… Done"])

    A --> B
    B -->|YES| C
    B -->|NO| D
    D -->|YES| E
    D -->|NO| F
    F --> G
    G --> H
    H --> I
    I --> J
Loading

🏧 Withdraw Flow

flowchart TD
    A(["πŸ‘€ withdraw<br/>amount_lp Β· min_x Β· min_y"])
    B{Pool locked?}
    C["❌ PoolLocked"]
    D["ConstantProduct::<br/>xy_withdraw_amounts_from_l()<br/>calculate proportional x, y"]
    E{x β‰₯ min_x<br/>AND y β‰₯ min_y?}
    F["❌ SlippageExceeded"]
    G["CPI: burn<br/>LP tokens from user_lp"]
    H["CPI: transfer w/ signer<br/>vault_x ──► user_x"]
    I["CPI: transfer w/ signer<br/>vault_y ──► user_y"]
    J(["βœ… Done"])

    A --> B
    B -->|YES| C
    B -->|NO| D
    D --> E
    E -->|NO| F
    E -->|YES| G
    G --> H
    H --> I
    I --> J
Loading

πŸ” CPI & PDA Signer Pattern

sequenceDiagram
    participant User
    participant AMM as AMM Program
    participant Config as Config PDA
    participant SPL as SPL Token Program

    Note over User,SPL: Deposit β€” user signs directly
    User->>AMM: deposit(amount, max_x, max_y)
    AMM->>SPL: transfer(user_x β†’ vault_x, authority=user)
    AMM->>SPL: transfer(user_y β†’ vault_y, authority=user)
    AMM->>SPL: mint_to(user_lp, authority=Config PDA)
    Config-->>SPL: signs via signer_seeds ["config", seed, bump]
    SPL-->>User: LP tokens received βœ…

    Note over User,SPL: Swap β€” vault out requires PDA signer
    User->>AMM: swap(is_x, amount_in, min_out)
    AMM->>SPL: transfer(user_in β†’ vault_in, authority=user)
    AMM->>SPL: transfer(vault_out β†’ user_out, authority=Config PDA)
    Config-->>SPL: signs via signer_seeds ["config", seed, bump]
    SPL-->>User: output tokens received βœ…
Loading

πŸ“ Project Structure

anchor-amm/
β”œβ”€β”€ Anchor.toml                  # Workspace config, cluster, wallet
β”œβ”€β”€ Cargo.toml                   # Workspace root
β”œβ”€β”€ package.json                 # Anchor SDK, Mocha, Chai
β”œβ”€β”€ tsconfig.json                # TypeScript config for tests
β”œβ”€β”€ rust-toolchain.toml          # Pinned Rust 1.89.0
β”‚
β”œβ”€β”€ migrations/
β”‚   └── deploy.ts                # Anchor deploy script
β”‚
β”œβ”€β”€ programs/amm/src/
β”‚   β”œβ”€β”€ lib.rs                   # Entrypoint β€” routes all 4 instructions
β”‚   β”œβ”€β”€ constants.rs             # Program-wide constants
β”‚   β”œβ”€β”€ error.rs                 # Custom AmmError codes
β”‚   β”‚
β”‚   β”œβ”€β”€ instructions/
β”‚   β”‚   β”œβ”€β”€ initialize.rs        # Pool init β€” Config PDA + vaults + LP mint
β”‚   β”‚   β”œβ”€β”€ deposit.rs           # Add liquidity, mint LP tokens
β”‚   β”‚   β”œβ”€β”€ withdraw.rs          # Remove liquidity, burn LP tokens
β”‚   β”‚   └── swap.rs              # Token swap via constant product curve
β”‚   β”‚
β”‚   └── state/
β”‚       └── config.rs            # Config account definition
β”‚
└── tests/
    └── amm.ts                   # Integration tests (Mocha + Anchor)

πŸ› οΈ Instructions

initialize(seed, fee, authority)

Account Role
initializer Payer + signer
mint_x / mint_y The two tokens forming the pair
config PDA β€” central pool state
mint_lp PDA β€” LP token mint (authority = config)
vault_x / vault_y ATAs holding pool reserves

deposit(amount, max_x, max_y)

Param Description
amount LP tokens to mint
max_x Max Token X to deposit (slippage guard)
max_y Max Token Y to deposit (slippage guard)

withdraw(amount, min_x, min_y)

Param Description
amount LP tokens to burn
min_x Min Token X expected back (slippage guard)
min_y Min Token Y expected back (slippage guard)

swap(is_x, amount_in, min_amount_out)

Param Description
is_x true = sell Token X, false = sell Token Y
amount_in Amount of input token to sell
min_amount_out Minimum output expected (slippage guard)

πŸ” Config Account

pub struct Config {
    pub seed: u64,                 // Unique pool identifier
    pub authority: Option<Pubkey>, // Optional admin (can lock pool)
    pub mint_x: Pubkey,            // Token X mint address
    pub mint_y: Pubkey,            // Token Y mint address
    pub fee: u16,                  // Swap fee in basis points (30 = 0.3%)
    pub locked: bool,              // Emergency lock flag
    pub config_bump: u8,           // PDA bump for config
    pub lp_bump: u8,               // PDA bump for LP mint
}

🧩 Core Concepts

Constant Product Curve (x * y = k) β€” The invariant governing all swaps and liquidity ops. The constant-product-curve crate handles all math β€” deposit ratios, swap output amounts, and fees.

Config PDA β€” Central pool account derived from a seed. Multiple independent pools can coexist by using different seeds.

LP Tokens β€” Minted to liquidity providers proportional to their pool share. Burning LP tokens returns the underlying assets.

Slippage Protection β€” Every instruction takes a min/max bound. If the pool ratio moves beyond tolerance, the transaction reverts.

PDA Vault Authority β€” Both vaults are ATAs owned by Config PDA. The program signs outgoing transfers using CpiContext::new_with_signer with seeds ["config", seed, bump] β€” no private key needed.


πŸš€ Getting Started

Prerequisites

git clone https://github.com/Subodhkd001/anchor-amm.git
cd anchor-amm
yarn install
anchor build
anchor test

πŸ§ͺ Tech Stack

Layer Technology
Smart Contract Rust + Anchor 0.32.1
Curve Math constant-product-curve
Token Standard SPL Token (anchor-spl)
Tests TypeScript + Mocha + Chai
Network Solana Localnet

πŸ“ License

ISC

About

A Solana AMM built with Anchor

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors