arkadiko-liquidation-pool-v1-1

SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR

Source Code

(impl-trait .arkadiko-liquidation-pool-trait-v1.liquidation-pool-trait)

;; Errors
(define-constant ERR-NOT-AUTHORIZED u32401)
(define-constant ERR-UNSTAKE-AMOUNT-EXCEEDED u32002)
(define-constant ERR-WITHDRAWAL-AMOUNT-EXCEEDED u32003)
(define-constant ERR-EMERGENCY-SHUTDOWN-ACTIVATED u32004)
(define-constant ERR-STAKE-NOT-UNLOCKED u32005)

;; Variables
(define-data-var fragments-per-token uint u1000000000000)
(define-data-var total-fragments uint u0)
(define-data-var shutdown-activated bool false)
(define-data-var lockup-blocks uint u4320)

;; ---------------------------------------------------------
;; Maps
;; ---------------------------------------------------------

(define-map staker-fragments 
  { 
    staker: principal,
  } 
  {
    fragments: uint
  }
)

(define-read-only (get-staker-fragments (staker principal))
  (default-to
    { fragments: u0 }
    (map-get? staker-fragments { staker: staker })
  )
)

(define-map staker-lockup 
  { 
    staker: principal,
  } 
  {
    start-block: uint
  }
)

(define-read-only (get-staker-lockup (staker principal))
  (default-to
    { start-block: u0 }
    (map-get? staker-lockup { staker: staker })
  )
)

(define-read-only (get-shutdown-activated)
  (or
    (unwrap-panic (contract-call? .arkadiko-dao get-emergency-shutdown-activated))
    (var-get shutdown-activated)
  )
)

;; @desc toggles the killswitch
(define-public (toggle-shutdown)
  (begin
    (asserts! (is-eq tx-sender (contract-call? .arkadiko-dao get-guardian-address)) (err ERR-NOT-AUTHORIZED))

    (ok (var-set shutdown-activated (not (var-get shutdown-activated))))
  )
)


;; ---------------------------------------------------------
;; Getters
;; ---------------------------------------------------------

;; @desc get current lockup time
(define-read-only (get-lockup-blocks)
  (ok (var-get lockup-blocks))
)

;; @desc get current total fragments
(define-read-only (get-total-fragments)
  (ok (var-get total-fragments))
)

;; @desc get current fragments per token
(define-read-only (get-fragments-per-token)
  (ok (var-get fragments-per-token))
)

;; @desc get tokens of given staker
;; @param staker; the staker to get tokens of
(define-read-only (get-tokens-of (staker principal))
  (let (
    (per-token (var-get fragments-per-token))
  )
    (if (is-eq per-token u0)
      (ok u0)
      (let (
        (user-fragments (get fragments (get-staker-fragments staker)))
      )
        (ok (/ user-fragments per-token))
      )
    )
  )
)

;; @desc get share % of user at given block
;; @param user; the user to get share of
;; @param block; block on which shares are calculated
(define-read-only (get-shares-at (user principal) (block uint))
  (let (
    (block-hash (unwrap-panic (get-block-info? id-header-hash block)))

    (user-fragments (get fragments (at-block block-hash (get-staker-fragments user))))
    (fragments-total (unwrap-panic (at-block block-hash (get-total-fragments))))
  )
    (if (is-eq fragments-total u0)
      (ok u0)
      (ok (/ (* user-fragments u10000000) fragments-total))
    )
  )
)

;; ---------------------------------------------------------
;; Stake / unstake
;; ---------------------------------------------------------

;; @desc stake USDA in pool
;; @param amount; amount to stake
(define-public (stake (amount uint))
  (let (
    (staker tx-sender)

    (user-fragments (get fragments (get-staker-fragments staker)))
    (add-user-fragments (* amount (var-get fragments-per-token)))
    (new-user-fragments (+ user-fragments add-user-fragments))
    (new-total-fragments (+ (var-get total-fragments) add-user-fragments))
  )
    (asserts! (not (get-shutdown-activated)) (err ERR-EMERGENCY-SHUTDOWN-ACTIVATED))

    ;; Transfer USDA
    (try! (contract-call? .usda-token transfer amount staker (as-contract tx-sender) none))

    ;; Update user tokens
    (map-set staker-fragments  { staker: staker } { fragments: new-user-fragments })

    ;; Update lockup
    (map-set staker-lockup  { staker: staker } { start-block: block-height })

    ;; Update total fragments
    (var-set total-fragments new-total-fragments)

    (ok amount)
  )
)

;; @desc unstake USDA from pool
;; @param amount; amount to unstake
(define-public (unstake (amount uint))
  (let (
    (staker tx-sender)

    (stake-start-block (get start-block (get-staker-lockup staker)))
    (user-fragments (get fragments (get-staker-fragments staker)))
    (remove-user-fragments (* amount (var-get fragments-per-token)))
  )
    (asserts! (not (get-shutdown-activated)) (err ERR-EMERGENCY-SHUTDOWN-ACTIVATED))
    (asserts! (>= user-fragments remove-user-fragments) (err ERR-UNSTAKE-AMOUNT-EXCEEDED))
    (asserts! (>= block-height (+ stake-start-block (var-get lockup-blocks))) (err ERR-STAKE-NOT-UNLOCKED))

    (let (
      (new-user-fragments (- user-fragments remove-user-fragments))
      (new-total-fragments (- (var-get total-fragments) remove-user-fragments))
    )
      ;; Transfer USDA
      (try! (as-contract (contract-call? .usda-token transfer amount (as-contract tx-sender) staker none)))

      ;; Update user tokens
      (map-set staker-fragments  { staker: staker } { fragments: new-user-fragments })

      ;; Update total fragments
      (var-set total-fragments new-total-fragments)

      (ok amount)
    )
  )
)


;; ---------------------------------------------------------
;; Withdraw
;; ---------------------------------------------------------

;; @desc max amount of USDA that can be withdrawn for liquidations
(define-read-only (max-withdrawable-usda)
  (let (
    (usda-balance (unwrap-panic (contract-call? .usda-token get-balance (as-contract tx-sender))))
    (usda-to-keep u1000000000) ;; always keep 1k USDA
  )
    (if (<= usda-balance usda-to-keep)
      (ok u0)
      (ok (- usda-balance usda-to-keep))
    )
  )
)

;; @desc withdraw USDA for liquidations (only for auction-engine)
;; @param amount; amount to withdraw
(define-public (withdraw (amount uint))
  (let (
    (sender tx-sender)

    (usda-balance (unwrap-panic (contract-call? .usda-token get-balance (as-contract tx-sender))))
    (new-usda-balance (- usda-balance amount))
    (new-fragments-per-token (/ (var-get total-fragments) new-usda-balance))
  )
    (asserts! (is-eq tx-sender (unwrap-panic (contract-call? .arkadiko-dao get-qualified-name-by-name "auction-engine"))) (err ERR-NOT-AUTHORIZED))
    (asserts! (<= amount (unwrap-panic (max-withdrawable-usda))) (err ERR-WITHDRAWAL-AMOUNT-EXCEEDED))

    ;; Transfer token
    (try! (as-contract (contract-call? .usda-token transfer amount (as-contract tx-sender) sender none)))

    ;; Update fragments-per-token
    (var-set fragments-per-token new-fragments-per-token)

    (ok amount)
  )
)

;; ---------------------------------------------------------
;; Update
;; ---------------------------------------------------------

(define-public (update-lockup (blocks uint))
  (begin
    (asserts! (is-eq tx-sender (contract-call? .arkadiko-dao get-dao-owner)) (err ERR-NOT-AUTHORIZED))

    (var-set lockup-blocks blocks)
    
    (ok true)
  )
)

Functions (14)

FunctionAccessArgs
get-staker-fragmentsread-onlystaker: principal
get-staker-lockupread-onlystaker: principal
get-shutdown-activatedread-only
toggle-shutdownpublic
get-lockup-blocksread-only
get-total-fragmentsread-only
get-fragments-per-tokenread-only
get-tokens-ofread-onlystaker: principal
get-shares-atread-onlyuser: principal, block: uint
stakepublicamount: uint
unstakepublicamount: uint
max-withdrawable-usdaread-only
withdrawpublicamount: uint
update-lockuppublicblocks: uint