;; title: swap-router
;; version: 1.0.0
;; summary: Multi-DEX swap router
;; description: Route swaps across DEXes for best price - Clarity 4
;; Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NO-ROUTE (err u6200))
(define-constant ERR-SLIPPAGE (err u6201))
;; DEX identifiers
(define-constant DEX-ALEX u1)
(define-constant DEX-STACKSWAP u2)
(define-constant DEX-VELAR u3)
(define-constant DEX-ARKADIKO u4)
;; Data Variables
(define-data-var total-routed-swaps uint u0)
(define-data-var total-savings uint u0)
;; Data Maps - Using stacks-block-time for Clarity 4
(define-map routed-swaps uint {
user: principal,
token-in: principal,
token-out: principal,
amount-in: uint,
amount-out: uint,
route: (list 5 uint), ;; List of DEX IDs used
gas-saved: uint,
timestamp: uint ;; Clarity 4: Unix timestamp
})
(define-map dex-prices { dex: uint, pair: (string-ascii 40) } {
price: uint,
last-updated: uint ;; Clarity 4: Unix timestamp
})
;; Public Functions
(define-public (execute-best-swap
(token-in principal)
(token-out principal)
(amount-in uint)
(min-amount-out uint))
(let (
(swap-id (var-get total-routed-swaps))
(best-route (find-best-route token-in token-out amount-in))
(amount-out (unwrap! best-route ERR-NO-ROUTE))
)
(asserts! (>= amount-out min-amount-out) ERR-SLIPPAGE)
(map-set routed-swaps swap-id {
user: tx-sender,
token-in: token-in,
token-out: token-out,
amount-in: amount-in,
amount-out: amount-out,
route: (list DEX-ALEX),
gas-saved: u0,
timestamp: stacks-block-time
})
(var-set total-routed-swaps (+ swap-id u1))
(print {
event: "routed-swap",
swap-id: swap-id,
amount-out: amount-out,
timestamp: stacks-block-time
})
(ok amount-out)
)
)
(define-public (update-dex-price
(dex uint)
(pair (string-ascii 40))
(price uint))
(begin
(asserts! (is-eq tx-sender CONTRACT-OWNER) (err u401))
(map-set dex-prices { dex: dex, pair: pair } {
price: price,
last-updated: stacks-block-time
})
(ok true)
)
)
;; Private Functions
(define-private (find-best-route
(token-in principal)
(token-out principal)
(amount-in uint))
(let (
(alex-quote (get-dex-quote DEX-ALEX token-in token-out amount-in))
(stackswap-quote (get-dex-quote DEX-STACKSWAP token-in token-out amount-in))
(velar-quote (get-dex-quote DEX-VELAR token-in token-out amount-in))
(arkadiko-quote (get-dex-quote DEX-ARKADIKO token-in token-out amount-in))
(best-quote (get-max-quote (list alex-quote stackswap-quote velar-quote arkadiko-quote)))
)
(ok best-quote)
)
)
(define-private (get-dex-quote (dex-id uint) (token-in principal) (token-out principal) (amount-in uint))
(match (map-get? dex-prices { dex: dex-id, pair: "STX-USDA" })
price-data (/ (* amount-in (get price price-data)) u1000000)
(/ (* amount-in u995) u1000) ;; Default 0.5% fee
)
)
(define-private (get-max-quote (quotes (list 10 uint)))
(fold max-of-two quotes u0)
)
(define-private (max-of-two (a uint) (b uint))
(if (> a b) a b)
)
(define-public (execute-multi-hop-swap
(route (list 5 uint))
(token-in principal)
(token-out principal)
(amount-in uint)
(min-amount-out uint))
(let (
(swap-id (var-get total-routed-swaps))
(amount-out (calculate-multi-hop-output route amount-in))
)
(asserts! (>= amount-out min-amount-out) ERR-SLIPPAGE)
(map-set routed-swaps swap-id {
user: tx-sender,
token-in: token-in,
token-out: token-out,
amount-in: amount-in,
amount-out: amount-out,
route: route,
gas-saved: u0,
timestamp: stacks-block-time
})
(var-set total-routed-swaps (+ swap-id u1))
(print {
event: "multi-hop-swap",
swap-id: swap-id,
route: route,
amount-out: amount-out,
timestamp: stacks-block-time
})
(ok amount-out)
)
)
(define-private (calculate-multi-hop-output (route (list 5 uint)) (amount-in uint))
(fold apply-hop-fee route amount-in)
)
(define-private (apply-hop-fee (dex-id uint) (amount uint))
(/ (* amount u997) u1000) ;; 0.3% fee per hop
)
;; Read-Only Functions
(define-read-only (get-routed-swap (swap-id uint))
(map-get? routed-swaps swap-id)
)
(define-read-only (get-dex-price (dex uint) (pair (string-ascii 40)))
(map-get? dex-prices { dex: dex, pair: pair })
)
(define-read-only (quote-best-route
(token-in principal)
(token-out principal)
(amount-in uint))
(find-best-route token-in token-out amount-in)
)
(define-read-only (get-total-savings)
(var-get total-savings)
)
;; Clarity 4 Enhanced Functions
;; 1. Clarity 4: principal-destruct? - Validate DEX and token principals
(define-read-only (validate-token-principal (token principal))
(principal-destruct? token)
)
;; 2. Clarity 4: int-to-utf8 - Format swap amounts and routes
(define-read-only (format-swap-amount (amount uint))
(ok (int-to-utf8 amount))
)
;; 3. Clarity 4: string-to-uint? - Parse DEX identifiers from strings
(define-read-only (parse-dex-id (dex-str (string-ascii 10)))
(match (string-to-uint? dex-str)
dex-id (if (<= dex-id u4) (ok dex-id) (err u997))
(err u998)
)
)
;; 4. Clarity 4: burn-block-height - Track swap routing with Bitcoin time
(define-read-only (get-swap-timestamps)
(ok {
stacks-time: stacks-block-time,
burn-time: burn-block-height
})
)