Source Code


(use-trait sip-010 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)

;; ============DEF============
(define-constant OWNER tx-sender)
(define-constant VAULT-CA 'SP37N8PQ9F9ZQB4DY3516R1044YY1MDAEESFVX6A4.swap-vault) 
(define-constant ROUTE-CA 'SP37N8PQ9F9ZQB4DY3516R1044YY1MDAEESFVX6A4.swap-route)
(define-constant ROUTE-MEME-CA 'SP37N8PQ9F9ZQB4DY3516R1044YY1MDAEESFVX6A4.swap-route-memecrazy)
(define-constant FOUNDATION 'SPVRE11KGM8MWVQ35Y2TQP8ATKC3P6M3F5PGHAYK)
(define-constant MEME-POOL-CA 'SP2VACC9K38NVPBG8EKC5V9FTQ6JBKHY05RSVDWJ3.pool)

(define-constant err-not-contract-owner (err u1001))  
(define-constant err-not-call-by-route (err u1002))  
(define-constant err-get-pool-data (err u2001))
(define-constant err-token-pair-mismatch (err u2002))
(define-constant err-same-token-pair (err u2003))
(define-constant err-token-pair-exists (err u2004))
(define-constant err-check-token-reversed (err u2005))
(define-constant err-lp-get-total-supply (err u2006))
(define-constant err-non-positive-mint-amount (err u4001))
(define-constant err-non-positive-burn-amount (err u4002))  
(define-constant err-non-positive-swap-amount (err u4003))  
(define-constant err-non-positive-reserve (err u4004))  
(define-constant err-swap-amount-in-validation (err u4005))  
(define-constant err-swap-k-condition (err u4006))  
(define-constant err-overflow-check (err u4007))  
(define-constant err-fee-range-check (err u4008))  
(define-constant err-zero-revenue (err u4009))  

(define-data-var pool-id uint u0)

(define-map pools  
    uint {  
    pool-id: uint,
    token0: principal,
    token1: principal,
    reserve0: uint,
    reserve1: uint,
    trade-fee-0: (tuple (num uint) (den uint)),
    trade-fee-1: (tuple (num uint) (den uint)),
    protocol-fee: (tuple (num uint) (den uint)),
    revenue0: uint,
    revenue1: uint,
    fee0: uint,
    fee1: uint,
})

(define-map pool-id-map (tuple (token0 principal) (token1 principal)) uint)


;; ============FUNC============
(define-read-only (get-pool-id (token0 principal) (token1 principal))
    (map-get? pool-id-map {token0: token0, token1: token1}))
(define-read-only (find-pool-id (token0 principal) (token1 principal))
  (match (get-pool-id token0 token1)
         id (some id) (get-pool-id token1 token0)))
(define-read-only (get-pool-data (id uint)) 
    (map-get? pools id))
(define-read-only (get-pool-nums) 
    (var-get pool-id))
(define-read-only (check-if-token-reversed (id uint) (token0 principal) (token1 principal))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data))) 
        (if (and (is-eq token0 (get token0 pool-data)) (is-eq token1 (get token1 pool-data)))
            (ok false)  
        (if (and (is-eq token0 (get token1 pool-data)) (is-eq token1 (get token0 pool-data))) 
            (ok true) 
            err-token-pair-mismatch)) 
    )
)

(define-public (create-pool (token0-contract <sip-010>) (token1-contract <sip-010>) 
                            (trade-fee-0 (tuple (num uint) (den uint))) (trade-fee-1 (tuple (num uint) (den uint))) (protocol-fee (tuple (num uint) (den uint))))
    (let ((token0 (contract-of token0-contract))
          (token1 (contract-of token1-contract))
          (next-pool-id (+ (var-get pool-id) u1)))

        (asserts! (or (is-eq OWNER tx-sender) (is-eq MEME-POOL-CA tx-sender)) err-not-contract-owner)       
        (asserts! (not (is-eq token0 token1)) err-same-token-pair)                                       
        (asserts! (is-none (find-pool-id token0 token1)) err-token-pair-exists)                            
        
        (asserts! (and (< (get num trade-fee-0) (get den trade-fee-0))
                       (< (get num trade-fee-1) (get den trade-fee-1))
                       (< (get num protocol-fee) (get den protocol-fee))) err-fee-range-check)     

        (map-set pools 
            next-pool-id {
                pool-id: next-pool-id,
                token0: token0,
                token1: token1,
                reserve0: u0,
                reserve1: u0,
                trade-fee-0: trade-fee-0,
                trade-fee-1: trade-fee-1,
                protocol-fee: protocol-fee,
                revenue0: u0,
                revenue1: u0,
                fee0: u0,
                fee1: u0,
                })
        (map-set pool-id-map {token0: token0, token1: token1} next-pool-id)  
        (var-set pool-id next-pool-id)  
        (ok next-pool-id)
    )
)

(define-public (mint (id uint) (token0-contract <sip-010>) (token1-contract <sip-010>) (amount0 uint) (amount1 uint))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data))  
          (token0 (contract-of token0-contract))
          (token1 (contract-of token1-contract))
          (r0 (get reserve0 pool-data))
          (r1 (get reserve1 pool-data))
          
          (reversed (unwrap! (check-if-token-reversed id token0 token1) err-check-token-reversed))  
          (a0 (if reversed amount1 amount0))
          (a1 (if reversed amount0 amount1))
          
          (lp-supply (unwrap! (contract-call? .swap-lp-token lp-get-total-supply id) err-lp-get-total-supply))
          (liquidity (contract-call? .swap-math calc-mint r0 r1 a0 a1 lp-supply))
          (provider tx-sender))
        
        (asserts! (and (> a0 u0) (> a1 u0) (> liquidity u0)) err-non-positive-mint-amount)  

        (try! (contract-call? token0-contract transfer amount0 provider VAULT-CA none))
        (try! (contract-call? token1-contract transfer amount1 provider VAULT-CA none))    

        (try! (as-contract (contract-call? .swap-lp-token lp-mint id liquidity provider)))

        (try! (update-reserve id (+ r0 a0) (+ r1 a1)))

        (asserts! (and (> (* (+ lp-supply liquidity) (+ r0 a0)) u0)
                       (> (* (+ lp-supply liquidity) (+ r1 a1)) u0)
                       (> (* (+ r0 a0) (+ r1 a1)) u0)) err-overflow-check)       

        (ok liquidity)
    )
)

(define-public (burn (id uint) (token0-contract <sip-010>) (token1-contract <sip-010>) (liquidity uint))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data))  
          (token0 (contract-of token0-contract))
          (token1 (contract-of token1-contract))
          (reversed (unwrap! (check-if-token-reversed id token0 token1) err-check-token-reversed)) 
          (r0 (get reserve0 pool-data))
          (r1 (get reserve1 pool-data))
          (lp-supply (unwrap! (contract-call? .swap-lp-token lp-get-total-supply id) err-lp-get-total-supply))
          (amounts (contract-call? .swap-math calc-burn r0 r1 liquidity lp-supply))
          (a0 (get a0 amounts))
          (a1 (get a1 amounts))
          (provider tx-sender))

        (asserts! (and (> liquidity u0) (> lp-supply u0) (> a0 u0) (> a1 u0)) err-non-positive-burn-amount) 

        (try! (contract-call? .swap-lp-token lp-burn id liquidity provider))

        (try! (as-contract (contract-call? .swap-vault vault-token-out token0-contract (if reversed a1 a0) provider)))
        (try! (as-contract (contract-call? .swap-vault vault-token-out token1-contract (if reversed a0 a1) provider)))

        (try! (update-reserve id (- r0 a0) (- r1 a1)))

        (ok {amount0: (if reversed a1 a0), amount1: (if reversed a0 a1)})
    )
)

(define-public (swap (id uint) (token-in-contract <sip-010>) (token-out-contract <sip-010>) (amount-in uint) (amount-out uint))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data))  
          (token-in (contract-of token-in-contract))
          (token-out (contract-of token-out-contract))
          (reversed (unwrap! (check-if-token-reversed id token-in token-out) err-check-token-reversed))  
          (r-in (if reversed (get reserve1 pool-data) (get reserve0 pool-data)))  
          (r-out (if reversed (get reserve0 pool-data) (get reserve1 pool-data))) 
          (k (* r-in r-out))
          
          (trade-fee (if reversed (get trade-fee-1 pool-data) (get trade-fee-0 pool-data))) 
          (protocol-fee (get protocol-fee pool-data))
          (fee-total (contract-call? .swap-math div-ceil (* amount-in (get num trade-fee)) (get den trade-fee)))  
          (fee-protocol (/ (* fee-total (get num protocol-fee)) (get den protocol-fee)))  
          (fee-lp (- fee-total fee-protocol)) 
          (amount-in-real (- amount-in fee-total))  
          (sender tx-sender))

        (asserts! (or (is-eq contract-caller ROUTE-CA) (is-eq contract-caller ROUTE-MEME-CA)) err-not-call-by-route)  

        (asserts! (and (> amount-in u0) (> amount-out u0) (> amount-in-real u0)) err-non-positive-swap-amount) 
        (asserts! (and (> r-in u0) (> r-out u0)) err-non-positive-reserve) 
        (asserts! (and (< (get num trade-fee) (get den trade-fee))
                       (< (get num protocol-fee) (get den protocol-fee))) err-fee-range-check) 
        (asserts! (or (is-eq (get num trade-fee) u0) (> fee-lp u0)) err-fee-range-check) 
        (asserts! (is-eq amount-in (+ amount-in-real fee-protocol fee-lp)) err-swap-amount-in-validation)  
        (asserts! (>= (* (+ r-in amount-in-real) (- r-out amount-out)) k) err-swap-k-condition)   

        (try! (contract-call? token-in-contract transfer amount-in sender VAULT-CA none)) 
        (try! (as-contract (contract-call? .swap-vault vault-token-out token-out-contract amount-out sender))) 

        (try! (update-reserve id                                                
            (if reversed (- r-out amount-out) (+ r-in amount-in-real fee-lp))
            (if reversed (+ r-in amount-in-real fee-lp) (- r-out amount-out))))  
        (try! (add-revenue id token-in fee-protocol))
        (try! (add-lp-fee id token-in fee-lp))                                  

        (ok true)
    )
)

(define-public (collect (id uint) (token0-contract <sip-010>) (token1-contract <sip-010>))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data))
          (token0 (contract-of token0-contract))
          (token1 (contract-of token1-contract))
          (reversed (unwrap! (check-if-token-reversed id token0 token1) err-check-token-reversed))
          (revenue0 (if reversed (get revenue1 pool-data) (get revenue0 pool-data)))
          (revenue1 (if reversed (get revenue0 pool-data) (get revenue1 pool-data))))

        (asserts! (or (is-eq OWNER tx-sender)) err-not-contract-owner)  
        (asserts! (or (> revenue0 u0) (> revenue1 u0)) err-zero-revenue)  

        (if (> revenue0 u0) (try! (as-contract (contract-call? .swap-vault vault-token-out token0-contract revenue0 FOUNDATION))) true) 
        (if (> revenue1 u0) (try! (as-contract (contract-call? .swap-vault vault-token-out token1-contract revenue1 FOUNDATION))) true)

        (ok (map-set pools id (merge pool-data {revenue0: u0, revenue1: u0})))
    )
)

(define-public (set-trade-fee (id uint) (trade-fee-0 (tuple (num uint) (den uint))) (trade-fee-1 (tuple (num uint) (den uint))))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data)))

        (asserts! (or (is-eq OWNER tx-sender) (is-eq ROUTE-CA tx-sender) (is-eq ROUTE-MEME-CA tx-sender)) err-not-contract-owner) 
        (asserts! (and (< (get num trade-fee-0) (get den trade-fee-0))
                       (< (get num trade-fee-1) (get den trade-fee-1))) err-fee-range-check) 

        (ok (map-set pools id (merge pool-data {trade-fee-0: trade-fee-0, trade-fee-1: trade-fee-1})))
    )
)

(define-public (set-protocol-fee (id uint) (protocol-fee (tuple (num uint) (den uint))))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data))) 

        (asserts! (or (is-eq OWNER tx-sender) (is-eq ROUTE-CA tx-sender) (is-eq ROUTE-MEME-CA tx-sender)) err-not-contract-owner) 
        (asserts! (< (get num protocol-fee)  (get den protocol-fee)) err-fee-range-check) 

        (ok (map-set pools id (merge pool-data {protocol-fee: protocol-fee} )))
    )
)


(define-private (update-reserve (id uint) (r0 uint) (r1 uint))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data)))
    (ok (map-set pools id (merge pool-data {reserve0: r0, reserve1: r1})))))
(define-private (add-revenue (id uint) (token principal) (revenue uint))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data)))
        (if (is-eq token (get token0 pool-data))
            (ok (map-set pools id (merge pool-data {revenue0: (+ (get revenue0 pool-data) revenue)})))
            (ok (map-set pools id (merge pool-data {revenue1: (+ (get revenue1 pool-data) revenue)}))))))
(define-private (add-lp-fee (id uint) (token principal) (fee uint))
    (let ((pool-data (unwrap! (get-pool-data id) err-get-pool-data)))
        (if (is-eq token (get token0 pool-data))
            (ok (map-set pools id (merge pool-data {fee0: (+ (get fee0 pool-data) fee)})))
            (ok (map-set pools id (merge pool-data {fee1: (+ (get fee1 pool-data) fee)}))))))
    

Functions (15)

FunctionAccessArgs
get-pool-idread-onlytoken0: principal, token1: principal
find-pool-idread-onlytoken0: principal, token1: principal
get-pool-dataread-onlyid: uint
get-pool-numsread-only
check-if-token-reversedread-onlyid: uint, token0: principal, token1: principal
create-poolpublictoken0-contract: <sip-010>, token1-contract: <sip-010>, trade-fee-0: (tuple (num uint, den: uint
mintpublicid: uint, token0-contract: <sip-010>, token1-contract: <sip-010>, amount0: uint, amount1: uint
burnpublicid: uint, token0-contract: <sip-010>, token1-contract: <sip-010>, liquidity: uint
swappublicid: uint, token-in-contract: <sip-010>, token-out-contract: <sip-010>, amount-in: uint, amount-out: uint
collectpublicid: uint, token0-contract: <sip-010>, token1-contract: <sip-010>
set-trade-feepublicid: uint, trade-fee-0: (tuple (num uint, den: uint
set-protocol-feepublicid: uint, protocol-fee: (tuple (num uint, den: uint
update-reserveprivateid: uint, r0: uint, r1: uint
add-revenueprivateid: uint, token: principal, revenue: uint
add-lp-feeprivateid: uint, token: principal, fee: uint