;; stx-token market for kcvdao v2. (220429)  

;; (use-trait ft-trait .trait-sip-010.sip-010-trait)
(use-trait sip010-token .sip010-ft-trait.sip010-ft-trait) 

;; Constant values
(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-BAD-REQUESTED (err u400))
(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-FORBIDDEN (err u403))
(define-constant ERR-INVALID-TOKEN (err u201))
(define-constant ERR-INVALID-POOL (err u202))
(define-constant ERR-INVALID-LIQUIDITY (err u203))
(define-constant ERR-EXCEEDS-BALANCE (err u204))

(define-constant ONE_6 (pow u10 u6)) ;; 6 decimal places

;; data 
(define-data-var pool-active bool false)
(define-data-var deposited-token-balance uint u0)
(define-data-var deposited-stx-balance uint u0)
(define-data-var trade-cnt uint u0)

(define-map swap-pool-map
  principal ;; SIP-010  
  {    
    balance-stx: uint,
    balance-token: uint,
    swap-rate-token-to-stx: uint,
    swap-rate-stx-to-token: uint    
  }
)

;; func
(define-read-only (get-swap-rate-token-to-stx (sip010-token <sip010-token>))
  (get swap-rate-token-to-stx (map-get? swap-pool-map (contract-of sip010-token))))

(define-read-only (get-swap-rate-stx-to-token (sip010-token <sip010-token>))
  (get swap-rate-stx-to-token (map-get? swap-pool-map (contract-of sip010-token))))
 
(define-read-only (get-balance-stx (sip010-token <sip010-token>))
  (get balance-stx (map-get? swap-pool-map (contract-of sip010-token))))
  
(define-read-only (get-balance-token (sip010-token <sip010-token>))
  (get balance-token (map-get? swap-pool-map (contract-of sip010-token))))

(define-read-only (get-map-info (sip010-token <sip010-token>))
  (map-get? swap-pool-map (contract-of sip010-token)))

(define-read-only (get-pool-active)
    (var-get pool-active))

(define-read-only (get-trade-count)
    (var-get trade-cnt))

(define-public (set-pool-active (flag bool))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (ok (var-set pool-active flag))))

(define-read-only (get-decimals)
    (ok u6)
)

(define-public (deposit-stx (deposit-amount uint) (sip010-token <sip010-token>))
  (begin
    (try! (stx-transfer? deposit-amount tx-sender (as-contract tx-sender)))    
    (let
      ((token-y (contract-of sip010-token))
      (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
      (balance-stx (get balance-stx pool))      
      (pool-updated (merge pool { balance-stx: (+ balance-stx deposit-amount) })))
      (map-set swap-pool-map token-y pool-updated)
      (ok pool-updated)
    )
  )
)
 
(define-public (deposit-token (deposit-amount uint) (sip010-token <sip010-token>))
  (begin
    (try! (contract-call? sip010-token transfer deposit-amount tx-sender (as-contract tx-sender) none))           
    (let
      ((token-y (contract-of sip010-token))
      (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
      (balance-token (get balance-token pool))      
      (pool-updated (merge pool { balance-token: (+ balance-token deposit-amount) })))
      (map-set swap-pool-map token-y pool-updated)
      (ok pool-updated)
    )
  )
) 

(define-public (withdraw-stx (withdraw-amount uint) (sip010-token <sip010-token>) (withdraw-to principal))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (try! (stx-transfer? withdraw-amount (as-contract tx-sender) withdraw-to))
    (let
      ((token-y (contract-of sip010-token))
      (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
      (balance-stx (get balance-stx pool))      
      (pool-updated (merge pool { balance-stx: (- balance-stx withdraw-amount) })))
      (ok pool-updated)
    )
  ))

(define-public (withdraw-token (withdraw-amount uint) (sip010-token <sip010-token>) (withdraw-to principal))
   (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (try! (contract-call? sip010-token transfer withdraw-amount (as-contract tx-sender) withdraw-to none))
    (let
      ((token-y (contract-of sip010-token))
      (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
      (balance-token (get balance-token pool))      
      (pool-updated (merge pool { balance-token: (- balance-token withdraw-amount) })))
      (ok pool-updated)
    )
  ))

(define-public (init-swap-pool-default (sip010-token <sip010-token>))    
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (let
      (
        (pool-updated {
          balance-stx: u0,
          balance-token: u0,
          swap-rate-token-to-stx: u750,
          swap-rate-stx-to-token: u1300 ;; Unit base: 1,000,000          
        })
        (token-y (contract-of sip010-token))
      )
      (map-set swap-pool-map token-y pool-updated)          
      ;; (set-pool-active true)  
      (ok true)
    )    
  )
)

(define-public (init-swap-pool (new-swap-rate-token-to-stx uint) (new-swap-rate-stx-to-token uint) (sip010-token <sip010-token>))    
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (let
      (
        (pool-updated {
          balance-stx: u0,
          balance-token: u0,
          swap-rate-token-to-stx: new-swap-rate-token-to-stx,
          swap-rate-stx-to-token: new-swap-rate-stx-to-token ;; Unit base: 1,000,000          
        })
        (token-y (contract-of sip010-token))
      )
      (map-set swap-pool-map token-y pool-updated)          
      ;; (set-pool-active true)  
      (ok true)
    )    
  )
)

(define-public (set-swap-rate-stx-token (new-rate-stx-to-token uint) (new-rate-token-to-stx uint) (sip010-token <sip010-token>))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (let
      ( (token-y (contract-of sip010-token))
        (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
        (pool-updated (merge pool { swap-rate-token-to-stx: new-rate-token-to-stx, swap-rate-stx-to-token: new-rate-stx-to-token })))
      (map-set swap-pool-map token-y pool-updated)    
      (ok pool-updated)
    )    
  )  
)

(define-public (simple-swap-stx-to-token (swap-amount uint) (sip010-token <sip010-token>))    
  (begin    
    (asserts! (> swap-amount u0) ERR-INVALID-LIQUIDITY)                
    (asserts! (<= swap-amount u10000000000) ERR-INVALID-LIQUIDITY)                
    (asserts! (is-eq (var-get pool-active) true) ERR-INVALID-POOL)
    (let
      (
        (token-y (contract-of sip010-token))
        (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
        (balance-stx (get balance-stx pool))
        (balance-token (get balance-token pool))
        (swap-rate-stx-to-token (get swap-rate-stx-to-token pool))

        (dx-net-fees swap-amount) ;; swap fee is zero 
        (dy (/ (* swap-rate-stx-to-token dx-net-fees) ONE_6)) 
        (pool-updated
          (merge pool
            {
              balance-stx: (+ balance-stx swap-amount),
              balance-token: (- balance-token dy)                        
            }
          )
        )
        (sender tx-sender)
      )
      (asserts! (<= dy balance-token) ERR-EXCEEDS-BALANCE)  
      (try! (stx-transfer? swap-amount tx-sender (as-contract tx-sender)))
      (try! (as-contract (contract-call? sip010-token transfer dy (as-contract tx-sender) sender none)))
      (var-set trade-cnt (+ (var-get trade-cnt) u1))

      ;; update map
      (map-set swap-pool-map token-y pool-updated)      
      (ok pool-updated))            
  )
)
 
(define-public (simple-swap-token-to-stx (swap-amount uint) (sip010-token <sip010-token>))
  (begin    
    (asserts! (> swap-amount u0) ERR-INVALID-LIQUIDITY)                
    (asserts! (<= swap-amount u10000000) ERR-INVALID-LIQUIDITY)                
    (asserts! (is-eq (var-get pool-active) true) ERR-INVALID-POOL)
    (let
      (
        (token-y (contract-of sip010-token))
        (pool (unwrap! (map-get? swap-pool-map token-y) ERR-INVALID-POOL))
        (balance-stx (get balance-stx pool))
        (balance-token (get balance-token pool))
        (swap-rate-token-to-stx (get swap-rate-token-to-stx pool))
        
        (dx-net-fees swap-amount) ;; swap fee is zero
        (dy (* swap-rate-token-to-stx dx-net-fees) )                          
        (pool-updated
          (merge pool
            {
              balance-token: (+ balance-token swap-amount),                     
              balance-stx: (- balance-stx dy)             
            }
          )
        )
        (sender tx-sender)
      )      
      (asserts! (<= dy balance-stx) ERR-EXCEEDS-BALANCE)  
      ;; (asserts! (<= dy balance-stx) (err dy))        
      (try! (contract-call? sip010-token transfer swap-amount sender (as-contract tx-sender) none))     
      (try! (as-contract (stx-transfer? dy (as-contract tx-sender) sender)))
      (var-set trade-cnt (+ (var-get trade-cnt) u1))

      ;; update map
      (map-set swap-pool-map token-y pool-updated)
      (ok pool-updated))            
  )
)