Source Code

;; Faktory Fun
;; Buy with memecoins approved via Velar

(use-trait faktory-dex 'SP3XXMS38VTAWTVPE5682XSBFXPTH7XCPEBTX8AN2.faktory-dex-trait-v1.dex-trait) 
(use-trait faktory-token 'SP3XXMS38VTAWTVPE5682XSBFXPTH7XCPEBTX8AN2.faktory-trait-v1.sip-010-trait) 
(use-trait ft-trait 'SP2AKWJYC7BNY18W1XXKPGP0YVEK63QJG4793Z2D4.sip-010-trait-ft-standard.sip-010-trait)
(use-trait fees-trait 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-fees-trait_v1_0_0.univ2-fees-trait)
(use-trait pool-trait 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-pool-trait_v1_0_0.univ2-pool-trait)

;; Constants
(define-constant ERR-NOT-OWNER (err u401))
(define-constant ERR-ALREADY-ADDED (err u402))
(define-constant ERR-INSUFFICIENT-STX-OUT (err u403))
(define-constant ERR-INVALID-DEX (err u404))
(define-constant ERR-INVALID-TOKEN (err u405))
(define-constant ERR-NOT-FOUND (err u406))
(define-constant ERR-PATH-ALREADY-EXISTS (err u407))
(define-constant ERR-NO-PATH-FOR-TOKEN (err u408))

(define-data-var contract-owner principal tx-sender)
(define-private (check-owner)
  (ok (asserts! (is-eq contract-caller (var-get contract-owner)) ERR-NOT-OWNER)))

(define-public (set-owner (new-owner principal))
  (begin
    (try! (check-owner))
    (ok (var-set contract-owner new-owner))))

(define-read-only (get-owner)
  (var-get contract-owner))

(define-public (add-token (token principal))
  (begin
    (try! (check-owner))
    (asserts! (not (is-valid-token token)) ERR-ALREADY-ADDED)
    (ok (map-set valid-tokens token true))))

(define-public (remove-token (token principal))
  (begin
    (try! (check-owner))
    (asserts! (is-valid-token token) ERR-NOT-FOUND)
    (ok (map-delete valid-tokens token))))

(define-public (add-dex (dex principal))
  (begin
    (try! (check-owner))
    (asserts! (not (is-valid-dex dex)) ERR-ALREADY-ADDED)
    (ok (map-set valid-dexes dex true))))

(define-public (remove-dex (dex principal))
  (begin
    (try! (check-owner))
    (asserts! (is-valid-dex dex) ERR-NOT-FOUND)
    (ok (map-delete valid-dexes dex))))

;; Define allowed DEXes and tokens ;; add all verified token-dexes
(define-constant BATCH-1-DEXES
 (list 
   'SP3NDZ2HXSCT0MZSJGZHYNA382DM6163KYT61524M.stx-faktory-dex
   'SPW3QV5C6TWDEJPKJB5M0JY9HPVGECM6A2Y45978.fak-faktory-dex
   'SP3MZ2SM81W87D29GZFS1R9R6NZHM8VAJ9XRHSVER.stux-faktory-dex
   'SP1R6FXP2A1Y8YATR98AGMEJHWND62H9WZAD6DB1Z.genius-ai-dao-faktory-dex
   'SP2G7NMH8FMJB1PF5M36CWV5ZMPXD3C5EWVS5WT4Y.faktory-faktory-dex
   'SPEPK2R1X08X3J45NJG1KN2NP8GW2G973E06KVJ6.fakdoge-faktory-dex
   'SP14ZYP25NW67XZQWMCDQCGH9S178JT78QJYE6K37.rapha-faktory-dex
   'SP7S3EY6FS1PJHJN6S3NV71RYQ7CKGABE5SDAT9N.supacoinstx-faktory-dex
   'SP2Z2CBMGWB9MQZAF5Z8X56KS69XRV3SJF4WKJ7J9.sweet-yamz-faktory-dex
   'SPKWB8ZX1Y9KVZX76X5JEGYQYQM1KCR5H8M2TCGN.dog-faktory-dex
   'SP2YE97WPR9C184MQ4RVM6AP1J629750Z1N48N82S.fuck-stacks-faktory-dex
   'SPCK2258XQFCF8RM4XSJ1Y7SW8E3DWX6X8S1BPV7.pepecoinstx-faktory-dex
   'SP3MABP6J5W8GXTXPTM62JQTAQPAVGGH9RYKRYZGQ.dog-to-the-moon-on-stx-faktory-dex
   'SP3FKPV0AFQWME4Q77T8E05K2977MMKRFMD1AJ7CV.stx-faktory-dex
   'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.geek-faktory-dex
   'SP61N7K3A9Z6M291Q89B5S2Z2BE5QYWYSRTDJM09.rapha-the-cloner-faktory-dex
   'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.the-ticker-is-1-faktory-dex
   'SP3H44FFW63CPHWF5RKCQK8SMJZV5DMGFZA1W71RY.qunche-faktory-dex
   'SP15WAVKQNT241YVCGQMJS777E17H9TS96M21Q5DX.the-ticker-is-2-faktory-dex
   'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.the-ticker-is-3-faktory-dex
   'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.paper-fund-faktory-dex
   'SP31ER8WTA6RM08Z0GNTY786T4PW6SYKFTNMTPRSV.slack-faktory-dex
   'SP3QF8RJ3CE59RBAHC96YS6DRSVKYADCF2730P023.phenomenon--faktory-dex
   'SP218F71JZ4R2ERQDKEBGA1FKVAQNZBM3HK7W8EA7.the-love-token-faktory-dex
   'SP218F71JZ4R2ERQDKEBGA1FKVAQNZBM3HK7W8EA7.the-peace-token-faktory-dex
   'SP2SY571GC9GSJEHSW1W7M9KF1EACC5NZ60KPRDBQ.sookie-faktory-dex
   'SPDXC0NM3YQDHV1HN3V9P5Y4P26QWY709NB86EYB.theartist-faktory-dex
   'SP376Y7METTJAT372GYDGD225YE20A01GAV7KJFKN.mogul-faktory-dex
   'SP3E8B51MF5E28BD82FM95VDSQ71VK4KFNZX7ZK2R.frog-faktory-dex
   'SP14FSJX1Q9EV6RA2GP2WZ3RNK6DX7057QNXC4Z9B.lunacat-nebula-nibs-faktory-dex
   'SP1GR38P4KNCQRC1BD5HC97DP36W2MBZFZ4WC0NET.the-happy-captain--faktory-dex
   'SPV00QHST52GD7D0SEWV3R5N04RD4Q1PMA3TE2MP.frankthepug-faktory-dex
 ))

(define-constant BATCH-1-TOKENS
  (list 
    'SP3NDZ2HXSCT0MZSJGZHYNA382DM6163KYT61524M.stx-faktory
    'SPW3QV5C6TWDEJPKJB5M0JY9HPVGECM6A2Y45978.fak-faktory
    'SP3MZ2SM81W87D29GZFS1R9R6NZHM8VAJ9XRHSVER.stux-faktory
    'SP1R6FXP2A1Y8YATR98AGMEJHWND62H9WZAD6DB1Z.genius-ai-dao-faktory
    'SP2G7NMH8FMJB1PF5M36CWV5ZMPXD3C5EWVS5WT4Y.faktory-faktory
    'SPEPK2R1X08X3J45NJG1KN2NP8GW2G973E06KVJ6.fakdoge-faktory
    'SP14ZYP25NW67XZQWMCDQCGH9S178JT78QJYE6K37.rapha-faktory
    'SP7S3EY6FS1PJHJN6S3NV71RYQ7CKGABE5SDAT9N.supacoinstx-faktory
    'SP2Z2CBMGWB9MQZAF5Z8X56KS69XRV3SJF4WKJ7J9.sweet-yamz-faktory
    'SPKWB8ZX1Y9KVZX76X5JEGYQYQM1KCR5H8M2TCGN.dog-faktory
    'SP2YE97WPR9C184MQ4RVM6AP1J629750Z1N48N82S.fuck-stacks-faktory
    'SPCK2258XQFCF8RM4XSJ1Y7SW8E3DWX6X8S1BPV7.pepecoinstx-faktory
    'SP3MABP6J5W8GXTXPTM62JQTAQPAVGGH9RYKRYZGQ.dog-to-the-moon-on-stx-faktory
    'SP3FKPV0AFQWME4Q77T8E05K2977MMKRFMD1AJ7CV.stx-faktory
    'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.geek-faktory
    'SP61N7K3A9Z6M291Q89B5S2Z2BE5QYWYSRTDJM09.rapha-the-cloner-faktory
    'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.the-ticker-is-1-faktory
    'SP3H44FFW63CPHWF5RKCQK8SMJZV5DMGFZA1W71RY.qunche-faktory
    'SP15WAVKQNT241YVCGQMJS777E17H9TS96M21Q5DX.the-ticker-is-2-faktory
    'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.the-ticker-is-3-faktory
    'SP3S2565C4DP2MGR3CMANMGYDCDA314Q258CG2R7C.paper-fund-faktory
    'SP31ER8WTA6RM08Z0GNTY786T4PW6SYKFTNMTPRSV.slack-faktory
    'SP3QF8RJ3CE59RBAHC96YS6DRSVKYADCF2730P023.phenomenon--faktory
    'SP218F71JZ4R2ERQDKEBGA1FKVAQNZBM3HK7W8EA7.the-love-token-faktory
    'SP218F71JZ4R2ERQDKEBGA1FKVAQNZBM3HK7W8EA7.the-peace-token-faktory
    'SP2SY571GC9GSJEHSW1W7M9KF1EACC5NZ60KPRDBQ.sookie-faktory
    'SPDXC0NM3YQDHV1HN3V9P5Y4P26QWY709NB86EYB.theartist-faktory
    'SP376Y7METTJAT372GYDGD225YE20A01GAV7KJFKN.mogul-faktory
    'SP3E8B51MF5E28BD82FM95VDSQ71VK4KFNZX7ZK2R.frog-faktory
    'SP14FSJX1Q9EV6RA2GP2WZ3RNK6DX7057QNXC4Z9B.lunacat-nebula-nibs-faktory
    'SP1GR38P4KNCQRC1BD5HC97DP36W2MBZFZ4WC0NET.the-happy-captain--faktory
    'SPV00QHST52GD7D0SEWV3R5N04RD4Q1PMA3TE2MP.frankthepug-faktory
  ))

;; Buy with memecoins approved
;; Token Constants
(define-constant SBTC-TOKEN 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token)
(define-constant WSTX-TOKEN 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.wstx)
(define-constant SHARE-FEE-TO 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-share-fee-to) 

(define-map token-paths 
  principal 
  {
    path-type: (string-ascii 1),  
    pool: principal,
    pool-id: uint,
    d: principal,
    e: principal,
    f: bool,
    univ2-pool: (optional principal),
    univ2-fees: (optional principal)
  }
)

(map-set token-paths SBTC-TOKEN 
  {
    path-type: "v",
    pool: 'SP20X3DC5R091J8B6YPQT638J8NR1W83KN6TN5BJY.univ2-pool-v1_0_0-0070,
    pool-id: u21000070,
    d: SBTC-TOKEN,
    e: WSTX-TOKEN, 
    f: false,
    univ2-pool: (some 'SP20X3DC5R091J8B6YPQT638J8NR1W83KN6TN5BJY.univ2-pool-v1_0_0-0070),
    univ2-fees: (some 'SP20X3DC5R091J8B6YPQT638J8NR1W83KN6TN5BJY.univ2-fees-v1_0_0-0070)
  })

;; Path management functions
(define-public (add-token-path 
    (token principal)
    (path-type (string-ascii 1))
    (pool principal)
    (pool-id uint)
    (d principal)
    (e principal)
    (f bool)
    (univ2-pool (optional principal))
    (univ2-fees (optional principal)))
  (begin
    (try! (check-owner))
    (asserts! (is-none (map-get? token-paths token)) ERR-PATH-ALREADY-EXISTS)
    (ok (map-set token-paths token {
        path-type: path-type,
        pool: pool,
        pool-id: pool-id,
        d: d,
        e: e,
        f: f,
        univ2-pool: univ2-pool,
        univ2-fees: univ2-fees
    }))))

(define-public (remove-token-path (token principal))
  (begin
    (try! (check-owner))
    (ok (map-delete token-paths token))))

;; Read functions
(define-read-only (get-token-path (token principal))
  (map-get? token-paths token))

;; Helper to get path for token
(define-private (get-path (token principal))
  (match (map-get? token-paths token)
    path-data (ok (list 
      {   
        a: (get path-type path-data),  
        b: (get pool path-data),
        c: (get pool-id path-data),
        d: (get d path-data),
        e: (get e path-data),
        f: (get f path-data),
      }))
    ERR-NO-PATH-FOR-TOKEN))

(define-private (get-path-adds (token principal))
  (match (map-get? token-paths token)
    path-data (ok {
        univ2-pool: (get univ2-pool path-data),
        univ2-fees: (get univ2-fees path-data)
    })
    ERR-NO-PATH-FOR-TOKEN))

;; Maps for validation
(define-map valid-dexes principal bool)
(define-map valid-tokens principal bool)

;; Helper functions to initialize maps
(define-private (add-valid-dex (dex principal))
  (map-set valid-dexes dex true))

(define-private (add-valid-token (token principal))
  (map-set valid-tokens token true))

;; Validation functions
(define-read-only (is-valid-dex (dex principal))
  (default-to false (map-get? valid-dexes dex)))

(define-read-only (is-valid-token (token principal))
  (default-to false (map-get? valid-tokens token)))

(define-public (buy
    (token-amount uint)
    (token <ft-trait>) 
    (min-stx-out uint)
    (dex <faktory-dex>)
    (ft <faktory-token>)
    (pool <pool-trait>)
    (fees <fees-trait>))
        (let (
            (path (try! (get-path (contract-of token))))
            (adds (try! (get-path-adds (contract-of token))))
            ) 

        ;; Validate DEX and token
        (asserts! (is-valid-dex (contract-of dex)) ERR-INVALID-DEX)
        (asserts! (is-valid-token (contract-of ft)) ERR-INVALID-TOKEN)
        
        ;; Execute Velar swap
        (let ((swap-result 
            (try! (contract-call? 
                'SP20X3DC5R091J8B6YPQT638J8NR1W83KN6TN5BJY.path-apply_staging 
                apply
                path
                token-amount
                (some token)  
                (some WSTX-TOKEN)  ;; token2
                none none none
                (some SHARE-FEE-TO)
                (some pool) ;; univ2v2-pool-1
                none none none ;; univ2v2-pools 2-4
                (some fees) ;; univ2v2-fee-1
                none none none ;; univ2v2-fees 2-4
                none none none none ;; curve-pools 1-4
                none none none none ;; curve-fees 1-4
                none none none none ;; ststx-pools 1-4
                none none none none ;; ststx-proxies 1-4
            ))))
            
            (let ((stx-amount (get amt-out (get swap4 swap-result))))
                (asserts! (>= stx-amount min-stx-out) ERR-INSUFFICIENT-STX-OUT)
                
                ;; Use STX to buy from the provided DEX
                (try! (contract-call? 
                    dex
                    buy
                    ft
                    stx-amount))
                    
                (ok {
                    token-in: token-amount,
                    stx-amount: stx-amount
                })))))

;; Initialize maps
(begin
    (map add-valid-dex BATCH-1-DEXES)
    (map add-valid-token BATCH-1-TOKENS)
    (print "Generic DEX Proxy Contract initialized"))

Functions (17)

FunctionAccessArgs
check-ownerprivate
set-ownerpublicnew-owner: principal
get-ownerread-only
add-tokenpublictoken: principal
remove-tokenpublictoken: principal
add-dexpublicdex: principal
remove-dexpublicdex: principal
add-token-pathpublictoken: principal, path-type: (string-ascii 1
remove-token-pathpublictoken: principal
get-token-pathread-onlytoken: principal
get-pathprivatetoken: principal
get-path-addsprivatetoken: principal
add-valid-dexprivatedex: principal
add-valid-tokenprivatetoken: principal
is-valid-dexread-onlydex: principal
is-valid-tokenread-onlytoken: principal
buypublictoken-amount: uint, token: <ft-trait>, min-stx-out: uint, dex: <faktory-dex>, ft: <faktory-token>, pool: <pool-trait>, fees: <fees-trait>