Source Code

;; cryptic-amm - Automated Market Maker (AMM) DEX
;; Constant-product AMM swap protocol

(define-constant CONTRACT-OWNER tx-sender)
(define-constant FEE-RATE u30)
(define-constant FEE-DENOMINATOR u10000)
(define-constant MIN-LIQUIDITY u1000)
(define-constant ERR-OWNER-ONLY (err u100))
(define-constant ERR-INSUFFICIENT-LIQUIDITY (err u101))
(define-constant ERR-ZERO-AMOUNT (err u102))
(define-constant ERR-SLIPPAGE (err u103))
(define-constant ERR-POOL-EXISTS (err u104))
(define-constant ERR-NO-POOL (err u105))

(define-map liquidity-pools
  { token-a: principal, token-b: principal }
  { reserve-a: uint, reserve-b: uint, total-lp: uint, fee-earned: uint })

(define-map lp-balances
  { pool: { token-a: principal, token-b: principal }, provider: principal }
  uint)

(define-data-var total-volume uint u0)
(define-data-var protocol-fees-collected uint u0)

(define-private (get-amount-out (amount-in uint) (reserve-in uint) (reserve-out uint))
  (let ((amount-with-fee (* amount-in (- FEE-DENOMINATOR FEE-RATE)))
        (numerator (* amount-with-fee reserve-out))
        (denominator (+ (* reserve-in FEE-DENOMINATOR) amount-with-fee)))
    (/ numerator denominator)))

(define-public (add-liquidity
    (token-a principal) (token-b principal)
    (amount-a uint) (amount-b uint) (min-lp uint))
  (let ((pool-key { token-a: token-a, token-b: token-b }))
    (asserts! (> amount-a u0) ERR-ZERO-AMOUNT)
    (asserts! (> amount-b u0) ERR-ZERO-AMOUNT)
    (match (map-get? liquidity-pools pool-key)
      pool
        (let ((lp-minted (/ (* amount-a (get total-lp pool)) (get reserve-a pool))))
          (asserts! (>= lp-minted min-lp) ERR-SLIPPAGE)
          (map-set liquidity-pools pool-key
            (merge pool { reserve-a: (+ (get reserve-a pool) amount-a),
                          reserve-b: (+ (get reserve-b pool) amount-b),
                          total-lp: (+ (get total-lp pool) lp-minted) }))
          (ok lp-minted))
      (begin
        (asserts! (>= amount-a MIN-LIQUIDITY) ERR-INSUFFICIENT-LIQUIDITY)
        (map-set liquidity-pools pool-key
          { reserve-a: amount-a, reserve-b: amount-b, total-lp: amount-a, fee-earned: u0 })
        (ok amount-a)))))

(define-public (swap-exact-in
    (token-a principal) (token-b principal)
    (amount-in uint) (min-out uint))
  (let ((pool-key { token-a: token-a, token-b: token-b })
        (pool (unwrap! (map-get? liquidity-pools { token-a: token-a, token-b: token-b }) ERR-NO-POOL)))
    (asserts! (> amount-in u0) ERR-ZERO-AMOUNT)
    (let ((amount-out (get-amount-out amount-in (get reserve-a pool) (get reserve-b pool))))
      (asserts! (>= amount-out min-out) ERR-SLIPPAGE)
      (map-set liquidity-pools pool-key
        (merge pool { reserve-a: (+ (get reserve-a pool) amount-in),
                      reserve-b: (- (get reserve-b pool) amount-out) }))
      (var-set total-volume (+ (var-get total-volume) amount-in))
      (ok amount-out))))

(define-read-only (get-pool (token-a principal) (token-b principal))
  (ok (map-get? liquidity-pools { token-a: token-a, token-b: token-b })))
(define-read-only (quote-swap (amount-in uint) (reserve-in uint) (reserve-out uint))
  (ok (get-amount-out amount-in reserve-in reserve-out)))
(define-read-only (get-total-volume) (ok (var-get total-volume)))

Functions (6)

FunctionAccessArgs
get-amount-outprivateamount-in: uint, reserve-in: uint, reserve-out: uint
add-liquiditypublictoken-a: principal, token-b: principal, amount-a: uint, amount-b: uint, min-lp: uint
swap-exact-inpublictoken-a: principal, token-b: principal, amount-in: uint, min-out: uint
get-poolread-onlytoken-a: principal, token-b: principal
quote-swapread-onlyamount-in: uint, reserve-in: uint, reserve-out: uint
get-total-volumeread-only