Source Code

(impl-trait .oracle-trait.oracle-trait)
(use-trait ft .ft-trait.ft-trait)

(define-read-only (to-fixed (a uint) (decimals-a uint))
  (contract-call? .math-v1-2 to-fixed a decimals-a))

(define-read-only (mul-to-fixed-precision (a uint) (decimals-a uint) (b-fixed uint))
  (contract-call? .math-v1-2 mul-to-fixed-precision a decimals-a b-fixed))

(define-read-only (mul (a uint) (b uint))
  (contract-call? .math-v1-2 mul a b))

(define-constant one-diko u1000000)
(define-constant one-stx u1000000)
(define-constant one-usda u1000000)

(define-constant err-panic (err u2999))
(define-constant err-unauthorized (err u3000))
(define-constant err-below-threshold (err u3001))
(define-constant err-above-threshold (err u3002))
(define-constant err-out-of-range (err u3003))
(define-constant err-stale-price (err u3004))
(define-constant err-pair-does-not-exist (err u3005))

(define-constant deployer tx-sender)

(define-constant dex-stx 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.wrapped-stx-token)
(define-constant dex-diko 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-token)

;; maximum difference of 1% from average dex diko price
(define-data-var max-delta uint u1000000)
;; 2USD
(define-data-var max-price uint u200000000)
;; 0.01USD
(define-data-var min-price uint u1000000)

(define-data-var validate-oracle-price bool false)

(define-public (set-validate-oracle-price (enabled bool))
  (begin
    (asserts! (is-eq tx-sender deployer) err-unauthorized)
    (ok (var-set validate-oracle-price enabled))
  )
)

(define-public (set-min-price (amount uint))
  (begin
    (asserts! (is-eq tx-sender deployer) err-unauthorized)
    (ok (var-set min-price amount))
  )
)

(define-public (set-max-price (amount uint))
  (begin
    (asserts! (is-eq tx-sender deployer) err-unauthorized)
    (ok (var-set max-price amount))
  )
)

(define-public (set-max-delta (amount uint))
  (begin
    (asserts! (is-eq tx-sender deployer) err-unauthorized)
    (ok (var-set max-delta amount))
  )
)

;; get the price from the oracle and use the average dex price for sanity checks
(define-public (get-asset-price (token <ft>))
  (let (
    (last-price (to-fixed (get last-price (contract-call? 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-oracle-v2-3 get-price "DIKO")) u6))
    ;; (last-price (to-fixed (get last-price (contract-call? .arkadiko-oracle get-price "DIKO")) u6))
  )
    (if (var-get validate-oracle-price)
      (try! (validate-price last-price))
      false
    )
    ;; sanity check
    (asserts! (> last-price (var-get min-price)) err-below-threshold)
    (asserts! (< last-price (var-get max-price)) err-above-threshold)

    (ok last-price)
  )
)

;; read-only version, non-functional
(define-read-only (get-price)
  (let (
    (last-price (to-fixed (get last-price (contract-call? 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-oracle-v2-3 get-price "DIKO")) u6))
    ;; (last-price (to-fixed (get last-price (contract-call? .arkadiko-oracle get-price "DIKO")) u6))
  )
    (asserts! (> last-price (var-get min-price)) err-below-threshold)
    (asserts! (< last-price (var-get max-price)) err-above-threshold)

    (ok last-price)
  )
)

(define-read-only (validate-price (oracle-price uint))
  (let (
    (average-dex-diko-price (try! (get-average-dex-diko-price)))
    (diff (mul average-dex-diko-price (var-get max-delta))))
    ;; ensure that price from oracle is between a range of the average dex price
    (asserts! (< oracle-price (+ average-dex-diko-price diff)) err-out-of-range)
    (asserts! (> oracle-price (- average-dex-diko-price diff)) err-out-of-range)
    (ok true)
  )
)

(define-read-only (get-average-dex-diko-price)
  (let (
    (last-block (- burn-block-height u1))
    (random-bytes (unwrap! (get-random-bytes last-block u2) err-panic))
    (rand-1 (mod (buff-to-uint-le (unwrap-panic (slice? random-bytes u0 u1))) u10))
    (rand-2 (mod (buff-to-uint-le (unwrap-panic (slice? random-bytes u1 u2))) u10))
    (heights (list last-block (- last-block rand-1) (- last-block rand-2)))
    (prices (get-diko-prices heights))
  )
    ;; average price from the last 3 blocks
    (ok (/ (try! (fold add-resp prices (ok u0))) (len heights)))
  )
)

(define-read-only (add-resp (amount-to-add (response uint uint)) (total (response uint uint)))
  (match amount-to-add
    amount (ok (+ (try! total) amount))
    bad-resp (err bad-resp)
  )
)

(define-read-only (get-random-bytes (height uint) (size uint))
  (match (get-block-info? vrf-seed height)
    vrf-seed (some (unwrap! (as-max-len? (unwrap! (slice? vrf-seed u0 size) none) u16) none))
    none)
)

(define-read-only (get-diko-prices (heights (list 10 uint)))
  (map get-diko-price-at heights)
)

(define-read-only (get-diko-price-at (height uint))
  (ok
    (at-block
      (unwrap-panic (get-block-info? id-header-hash height))
      (try! (get-diko-dex-price))
    )
  )
)

;; get exchange rate between stx/diko, convert stx amount to it's currency value
(define-read-only (get-diko-dex-price)
  (ok (mul-to-fixed-precision (try! (get-y-for-x dex-stx dex-diko one-diko)) u6 (try! (get-stx-price))))
)

(define-read-only (get-stx-price)
  (let (
    (oracle-data (contract-call? 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-oracle-v2-3 get-price "STX"))
    ;; (oracle-data (contract-call? .arkadiko-oracle get-price "STX"))
  )
    (asserts! (<= (- burn-block-height (get last-block oracle-data)) u10) err-stale-price)
    (ok (to-fixed (get last-price oracle-data) u6))
  )
)

;; get the value of 1 DIKO in STX using x*y=k curve
(define-read-only (get-y-for-x (contract-x principal) (contract-y principal) (dx uint))
  ;; ref: https://github.com/arkadiko-dao/arkadiko/blob/master/clarity/contracts/swap/arkadiko-swap-v2-1.clar#L473
  (match
    (contract-call? 'SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-swap-v2-1 get-pair-details contract-x contract-y)
    ;; (contract-call? .dex get-pair-details contract-x contract-y)
    pair
      (let (
        (balance-x (get balance-x (unwrap-panic pair)))
        (balance-y (get balance-y (unwrap-panic pair)))
        (dx-with-fees (/ (* u997 dx) u1000))
        (dy (/ (* balance-x dx-with-fees) (+ balance-y dx-with-fees)))
        )
        (ok dy)
      )
    err-res err-pair-does-not-exist
  )
)

Functions (18)

FunctionAccessArgs
set-max-pricepublicamount: uint
to-fixedread-onlya: uint, decimals-a: uint
mul-to-fixed-precisionread-onlya: uint, decimals-a: uint, b-fixed: uint
mulread-onlya: uint, b: uint
set-validate-oracle-pricepublicenabled: bool
set-min-pricepublicamount: uint
set-max-deltapublicamount: uint
get-asset-pricepublictoken: <ft>
get-priceread-only
validate-priceread-onlyoracle-price: uint
get-average-dex-diko-priceread-only
add-respread-onlyamount-to-add: (response uint uint
get-random-bytesread-onlyheight: uint, size: uint
get-diko-pricesread-onlyheights: (list 10 uint
get-diko-price-atread-onlyheight: uint
get-diko-dex-priceread-only
get-stx-priceread-only
get-y-for-xread-onlycontract-x: principal, contract-y: principal, dx: uint