Source Code

;; @contract FOMO
;; @version 1
;; @desc
;; Treasure hunt on Stacks
;; 1/ In Stacking DAO FOMO, the claims have a linearly increasing price.
;; The claim price starts at 1 stSTX and increases by 0.1 stSTX with each claim.
;; The game stops if there's no claim for 24 hours.
;; The final key claimer (also called Master Key holder) unlocks the treasure vault.
;; 2/ Timer - The game has a built-in timer that counts down from 24 hours to 0.
;; Each key claim resets the timer to 24 hours.
;; Once the countdown elapses, the master key holder unlocks the grand prize.
;; 3/ When a key using stSTX is claimed, the funds are stored on the contract and allocated as follows:
;; - 70% goes to the winner prize pool [the last key claimer]
;; - 25% goes to the pool [all claim holders can burn their claim and claim the average of the pool]
;; - 5% goes to the protocol

;;-------------------------------------
;; Constants 
;;-------------------------------------

(define-constant ERR_GAME_NOT_STARTED u6660000)
(define-constant ERR_GAME_ENDED u6660001)
(define-constant ERR_CANNOT_CLAIM u6660002)
(define-constant ERR_GAME_NOT_ENDED u6660003)
(define-constant ERR_CLAIMER_NOT_WINNER u6660004)
(define-constant ERR_FEES_CLAIMED u6660005)
(define-constant ERR_WINNER_ALREADY_CLAIMED u6660006)

;;-------------------------------------
;; Variables 
;;-------------------------------------

(define-data-var current-winner principal tx-sender)
(define-data-var claim-cost uint u1000000) ;; 1 stSTX
(define-data-var increment uint u100000) ;; 0.1 stSTX
(define-data-var last-claim-burn-block-height uint burn-block-height)
(define-data-var nft-amount uint u0)
(define-data-var total-treasure uint u100000000)
(define-data-var has-claimed-fees bool false)
(define-data-var has-claimed-winner bool false)
(define-data-var game-started bool false)

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

(define-read-only (get-current-winner)
  (var-get current-winner)
)

(define-read-only (get-claim-cost)
  (var-get claim-cost)
)

(define-read-only (get-increment)
  (var-get increment)
)

(define-read-only (get-total-treasure)
  (var-get total-treasure)
)

(define-read-only (get-last-claim-burn-block-height)
  (var-get last-claim-burn-block-height)
)

(define-read-only (has-game-started)
  (var-get game-started)
)

(define-read-only (has-game-ended)
  (and (var-get game-started) (> burn-block-height (+ (var-get last-claim-burn-block-height) u144)))
)

;;-------------------------------------
;; Set 
;;-------------------------------------

(define-public (set-claim-cost (amount uint))
  (begin
    (try! (contract-call? .dao check-is-protocol tx-sender))

    (var-set claim-cost amount)
    (ok true)
  )
)

(define-public (set-increment (amount uint))
  (begin
    (try! (contract-call? .dao check-is-protocol tx-sender))

    (var-set increment amount)
    (ok true)
  )
)

(define-public (set-total-treasure (amount uint))
  (begin
    (try! (contract-call? .dao check-is-protocol tx-sender))

    (var-set total-treasure amount)
    (ok true)
  )
)

;;-------------------------------------
;; Main Logic
;;-------------------------------------

(define-public (buy-claim)
  (let (
    (next-claim-cost (+ (var-get claim-cost) (var-get increment)))
  )
    (asserts! (has-game-started) (err ERR_GAME_NOT_STARTED))
    (asserts! (not (has-game-ended)) (err ERR_GAME_ENDED))

    (try! (contract-call? .ststx-token transfer next-claim-cost tx-sender (as-contract tx-sender) none))
    (var-set current-winner tx-sender)
    (var-set claim-cost next-claim-cost)
    (var-set last-claim-burn-block-height burn-block-height)

    (try! (contract-call? .stacking-dao-fomo-nft mint-for-protocol tx-sender))
    (var-set nft-amount (+ (var-get nft-amount) u1))
    (var-set total-treasure (+ (var-get total-treasure) next-claim-cost))
    (ok true)
  )
)

(define-public (retrieve-winner (nft-id uint))
  (let (
    (ststx-balance (var-get total-treasure))
    (amount (/ (* ststx-balance u7000) u10000))
    (winner tx-sender)
  )
    (asserts! (has-game-ended) (err ERR_GAME_NOT_ENDED))
    (asserts! (is-eq (var-get current-winner) tx-sender) (err ERR_CLAIMER_NOT_WINNER))
    (asserts! (not (var-get has-claimed-winner)) (err ERR_WINNER_ALREADY_CLAIMED))

    (try! (as-contract (contract-call? .ststx-token transfer amount tx-sender winner none)))
    (try! (contract-call? .stacking-dao-fomo-nft burn-for-protocol nft-id))
    (var-set has-claimed-winner true)
    (ok amount)
  )
)

(define-public (retrieve-loser (nft-id uint))
  (let (
    (ststx-balance (var-get total-treasure))
    (amount (/ (* ststx-balance u2500) u10000))
    (loser tx-sender)
    (avg (/ amount (- (var-get nft-amount) u1)))
  )
    (asserts! (has-game-ended) (err ERR_GAME_NOT_ENDED))

    (try! (as-contract (contract-call? .ststx-token transfer avg tx-sender loser none)))
    (try! (contract-call? .stacking-dao-fomo-nft burn-for-protocol nft-id))
    (ok avg)
  )
)

;;-------------------------------------
;; Admin
;;-------------------------------------

(define-public (start-game)
  (begin
    (try! (contract-call? .dao check-is-protocol tx-sender))

    (var-set game-started true)
    (var-set last-claim-burn-block-height burn-block-height)
    (ok true)
  )
)

(define-public (retrieve-fees)
  (let (
    (ststx-balance (var-get total-treasure))
    (amount (/ (* ststx-balance u500) u10000))
    (admin tx-sender)
  )
    (try! (contract-call? .dao check-is-protocol tx-sender))
    (asserts! (has-game-ended) (err ERR_GAME_NOT_ENDED))
    (asserts! (not (var-get has-claimed-fees)) (err ERR_FEES_CLAIMED))

    (try! (as-contract (contract-call? .ststx-token transfer amount tx-sender admin none)))
    (var-set has-claimed-fees true)
    (ok amount)
  )
)

(define-public (rescue-funds)
  (let (
    (ststx-balance (unwrap-panic (contract-call? .ststx-token get-balance (as-contract tx-sender))))
    (admin tx-sender)
  )
    (try! (contract-call? .dao check-is-protocol tx-sender))

    (try! (as-contract (contract-call? .ststx-token transfer ststx-balance tx-sender admin none)))
    (ok ststx-balance)
  )
)

Functions (16)

FunctionAccessArgs
get-current-winnerread-only
get-claim-costread-only
get-incrementread-only
get-total-treasureread-only
get-last-claim-burn-block-heightread-only
has-game-startedread-only
has-game-endedread-only
set-claim-costpublicamount: uint
set-incrementpublicamount: uint
set-total-treasurepublicamount: uint
buy-claimpublic
retrieve-winnerpublicnft-id: uint
retrieve-loserpublicnft-id: uint
start-gamepublic
retrieve-feespublic
rescue-fundspublic