This project implements an Automated Market Maker (AMM) on the Solana blockchain using the Anchor framework. It enables:
- Creation and management of liquidity pools for token pairs
- Token swaps with minimal slippage and slippage protection
- Secure deposit and withdrawal of liquidity
The system is built around a single state account:
#[account]
pub struct Config {
pub seed: u64,
pub authority: Option<Pubkey>,
pub mint_x: Pubkey,
pub mint_y: Pubkey,
pub fee: u16,
pub locked: bool,
pub config_bump: u8,
pub lp_bump: u8,
}This state account stores:
seed: Unique identifier for different pool configurationsauthority: Optional admin key that can lock the poolmint_x&mint_y: Token pair in the poolfee: Swap fee in basis pointslocked: Pool lock statusconfig_bump: Bump for Config account PDAlp_bump: Bump for Liquidity Provider PDA
The Initialize context creates a new liquidity pool:
#[derive(Accounts)]
#[instruction(seed: u64)]
pub struct Initialize <'info> {
#[account(mut)]
pub initializer: Signer<'info>,
pub mint_x: Account<'info, Mint>,
pub mint_y: Account<'info, Mint>,
#[account(
init,
payer = initializer,
seeds = [b"lp", config.key.as_ref()],
bump,
mint::decimals = 6,
mint::authority = config,
)]
pub mint_lp: Account<'info, Mint>,
// Additional accounts...
}Implementation:
impl<'info> Initialize<'info> {
pub fn init(&mut self, seed: u64, fee: u16, authority: Option<Pubkey>, bumps: InitializeBumps) -> Result<()> {
self.config.set_inner(Config {
seed,
authority,
mint_x: self.mint_x.key(),
mint_y: self.mint_y.key(),
fee,
locked: false,
config_bump: bumps.config,
lp_bump: bumps.mint_lp,
});
Ok(())
}
}Users deposit tokens to the liquidity pool and receive LP tokens:
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut)]
pub user: Signer<'info>,
pub mint_x: Account<'info, Mint>,
pub mint_y: Account<'info, Mint>,
// Additional accounts...
}Key implementation:
impl<'info> Deposit<'info> {
pub fn deposit (
&mut self,
amount: u64, // Amount of LP tokens user wants to "claim"
max_x: u64, // Maximum token X user will deposit
max_y: u64, // Maximum token Y user will deposit
) -> Result<()> {
// Check pool not locked
// Calculate proportional deposit amounts
// Handle deposits and LP token minting
}
}Users can burn LP tokens to withdraw liquidity:
pub fn withdraw(
&mut self,
amount: u64, // LP tokens to burn
min_x: u64, // Minimum token X to receive
min_y: u64, // Minimum token Y to receive
) -> Result<()> {
// Validate withdrawal conditions
// Calculate withdrawal amounts
// Check slippage protection
// Transfer tokens and burn LP tokens
}Users can swap between pool tokens:
#[derive(Accounts)]
pub struct Swap<'info> {
#[account(mut)]
pub user: Signer<'info>,
pub mint_x: Account<'info, Mint>,
pub mint_y: Account<'info, Mint>,
// Additional accounts...
}Implementation:
pub fn swap(&mut self, is_x: bool, amount: u64, min: u64) -> Result<()> {
// Verify pool not locked
// Initialize constant product curve
// Calculate swap amounts
// Perform token transfers
}- PDA-based ownership for vaults
- Slippage protection for all operations
- Optional authority for pool locking
- Constant product formula for price determination