Skip to main content
Case Study · AMM Decentralized Exchange

Engineering an Automated Market Maker DEX on Bitcoin L2.

A permissionless Automated Market Maker (AMM) decentralized exchange built on the Stacks blockchain using Clarity smart contracts. Enables constant-product ($x \cdot y = k$) liquidity pool creation, token swapping for SIP-010 assets, dynamic fee distribution, and slippage protection.

Clarity 3Constant Product (x*y=k)SIP-010 TokensLiquidity PoolsNext.js 15Stacks Connect
00 — Executive Summary

Trustless Liquidity & Trading for Bitcoin L2 Tokens.

Decentralized exchanges rely on algorithmic liquidity pools rather than traditional order books. The Stacks AMM DEX implements a permissionless market maker where users swap any SIP-010 compliant tokens, provide liquidity to earn a 0.3% protocol fee, and mint transferable LP tokens representing their pool share.

01 — Problem

Overcoming Liquidity Fragmentation on Bitcoin.

Centralized Exchange Risks

Trading Stacks ecosystem tokens on centralized order books introduces custodial counterparty risks and withdrawal limits.

Slippage & Front-Running

Swaps executed without minimum output assertions can suffer extreme slippage or sandwich attacks in mempools.

Dynamic Trait Interface

Interfacing with generic fungible tokens in Clarity requires strict trait compliance (SIP-010) without introducing security vulnerabilities.

02 — Contract Architecture

SIP-010 Trait Implementation & Token Ordering.

To prevent duplicate pools for reciprocal pairs (e.g. STX/ALEX vs ALEX/STX), the contract enforces lexicographical principal sorting by comparing consensus buffers before pool instantiation:

;; SIP-010 Trait & Token Ordering Enforcement in contracts/amm.clar
(use-trait ft-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)

(define-private (correct-token-ordering (token-0 principal) (token-1 principal)) 
  (let (
    (token-0-buff (unwrap-panic (to-consensus-buff? token-0)))
    (token-1-buff (unwrap-panic (to-consensus-buff? token-1)))
  )
    (asserts! (< token-0-buff token-1-buff) ERR_INCORRECT_TOKEN_ORDERING)
    (ok true)
  )
)

(define-read-only (get-pool-id (pool-info {token-0: <ft-trait>, token-1: <ft-trait>, fee: uint})) 
  (let (
    (buff (unwrap-panic (to-consensus-buff? pool-info)))
  )
    (hash160 buff)
  )
)
03 — Mathematical Model

Constant Product Curve ($x \cdot y = k$) & Swap Pricing.

When swapping token input dx for outputdy, a 0.3% liquidity provider fee is deducted (dx * 997 / 1000):

;; Swap Output Calculation with 0.3% Fee in Clarity
(define-read-only (get-swap-output (amount-in uint) (reserve-in uint) (reserve-out uint))
  (let
    ((amount-in-with-fee (* amount-in u997))
     (numerator (* amount-in-with-fee reserve-out))
     (denominator (+ (* reserve-in u1000) amount-in-with-fee)))
    (/ numerator denominator)))
04 — Smart Contract Functions

Clarity Smart Contract Public Functions & Errors.

create-poolpublic

Initialize a new trading pool between two SIP-010 tokens with initial liquidity deposit.

add-liquiditypublic

Deposit proportional token reserves into pool, minting LP tokens to liquidity provider.

remove-liquiditypublic

Burn LP tokens to redeem proportional underlying token reserves plus accumulated 0.3% fees.

swap-exact-tokens-for-tokenspublic

Execute token swap along x*y=k curve with minimum output amount slippage protection.

get-reservesread-only

Query current token reserves and pool invariant for exact price impact calculation.

get-pool-idread-only

Compute 20-byte SHA-160 hash of token-0, token-1, and fee as unique pool identifier.

AMM Protocol Error Codes

ERR_POOL_ALREADY_EXISTS (u200)

Pool already exists for the given pair of SIP-010 tokens and fee tier.

ERR_INCORRECT_TOKEN_ORDERING (u201)

Enforces lexicographical principal ordering (token-0 < token-1) to avoid duplicate reciprocal pools.

ERR_INSUFFICIENT_LIQUIDITY_MINTED (u202)

Initial liquidity deposit does not meet the MINIMUM_LIQUIDITY (u1000) threshold.

ERR_INSUFFICIENT_LIQUIDITY_OWNED (u203)

Provider does not own enough LP tokens to execute requested withdrawal.

ERR_INSUFFICIENT_INPUT_AMOUNT (u205)

Swap input token amount is zero or below minimum execution amount.

ERR_INSUFFICIENT_LIQUIDITY_FOR_SWAP (u206)

Pool reserves are lower than requested swap output amount.

05 — Technology Stack

Production Tech Stack & Architecture.

LayerTechnologyArchitectural Rationale
Smart ContractsClarity 3 · SIP-010 StandardDecidable Clarity smart contracts implementing Constant Product AMM formulas for Stacks fungible tokens
Frontend PortalNext.js 15 · TypeScript · Tailwind CSSResponsive decentralized exchange interface with live swap quote calculations and pool analytics
Wallet Provider@stacks/connect · Leather · XversePermissionless Web3 wallet authentication and transaction broadcast integration
Contract TestingClarinet · VitestSimulated Stacks blockchain environment verifying pool creation, liquidity minting, and swap slippage
06 — System Metrics

Verified Protocol Metrics.

x · y = k
Constant Product Invariant
0.3%
Liquidity Fee to LPs
SIP-010
Fungible Token Standard
Permissionless
Pool Creation
Slippage
Min Output Protection
Stacks L2
Bitcoin Consensus Security