Source Code

;; Website: https://boltproto.org
(define-constant ERR-PRECONDITION-FAILED (err u412)) 
(define-constant ERR-PRINCIPAL-NOT-FOUND (err u404)) 
(define-constant ERR-PERMISSION-DENIED (err u403))   
(define-constant ERR-INVALID-VALUE (err u400))       
(define-constant ERR-CYCLE-NOT-FINISHED (err u4121)) 
(define-constant ERR-ALREADY-CLAIMED (err u4122))    
(define-constant ERR-NO-ALLOCATION (err u4123))      
(define-constant ERR-PRIZE-POOL-EMPTY (err u4124))   
(define-constant ERR-EXPIRATION-PERIOD-NOT-MET (err u4131)) 
(define-constant ERR-NO-UNCLAIMED-PRIZE (err u4132))       
(define-constant START-BLOCK tenure-height)          
(define-constant TOTAL-CONSTELLATIONS u24)           
(define-constant BLOCKS-PER-CYCLE u144)              
(define-data-var manager principal tx-sender)                 
(define-data-var min-allocation uint u1000)                
(define-data-var treasury-distribution-period uint u3)        
(define-data-var prize-expiration-period uint u5)             
(define-data-var reward-claim-fee uint u100)                  
(define-data-var treasury uint u0)                            
(define-data-var team-fee uint u0)                            
(define-data-var allocation-percentages
    {
        current-cycle: uint,    
        treasury: uint,         
        team-fee: uint,         
        referral-reward: uint   
    }
    {
        current-cycle: u30,     
        treasury: u40,          
        team-fee: u25,          
        referral-reward: u5     
    }
)
(define-map cycle uint 
    {
        prize: uint,                          
        prize-claimed: uint,                  
        constellation-allocation: (list 24 uint), 
        allocation-claimed: uint              
    })
(define-map allocated-by-user
    {
        cycle-id: uint,    
        user: principal    
    }
    {
        constellation-allocation: (list 24 uint), 
        claimed: bool      
    })
(define-map referral-reward principal
    {
        amount: uint,      
        block-update: uint 
    })
(define-read-only (get-manager)
  (var-get manager)
)
(define-public (set-manager (new-manager principal))
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (ok (var-set manager new-manager))
  )
)
(define-public (set-min-allocation (new-min-allocation uint))
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (asserts! (> new-min-allocation u0) ERR-INVALID-VALUE)
    (ok (var-set min-allocation new-min-allocation))
  )
)
(define-public (set-treasury-distribution-period (new-count uint))
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (asserts! (> new-count u0) ERR-INVALID-VALUE)
    (ok (var-set treasury-distribution-period new-count))
  )
)
(define-public (set-team-fee (new-fee uint))
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (asserts! (is-eq new-fee new-fee) ERR-INVALID-VALUE) 
    (ok (var-set team-fee new-fee))
  )
)
(define-public (set-reward-claim-fee (new-fee uint))
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (asserts! (> new-fee u0) ERR-INVALID-VALUE)
    (ok (var-set reward-claim-fee new-fee))
  )
)
(define-public (set-prize-expiration-period (new-count uint))
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (asserts! (> new-count u0) ERR-INVALID-VALUE)
    (ok (var-set prize-expiration-period new-count))
  )
)
(define-public (set-allocation-percentages (current-cycle-percent uint) (treasury-percent uint) (team-fee-percent uint) (referral-reward-percent uint) )
  (begin
    (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
    (asserts! (is-eq (+ (+ (+ current-cycle-percent treasury-percent) team-fee-percent) referral-reward-percent) u100) ERR-PRECONDITION-FAILED)
    (ok (var-set allocation-percentages {
        current-cycle: current-cycle-percent,
        treasury: treasury-percent,
        team-fee: team-fee-percent,
        referral-reward: referral-reward-percent
    }))
  )
)
(define-read-only (get-random-number-from-block (block uint))
    (buff-to-uint-be (unwrap-panic (as-max-len? (unwrap-panic (slice? (unwrap-panic (get-tenure-info? vrf-seed block)) u16 u32)) u16)))
)
(define-read-only (get-blocks-per-cycle) 
    BLOCKS-PER-CYCLE
)
(define-read-only (get-start-block) 
    START-BLOCK
)
(define-read-only (get-treasury) 
    (var-get treasury)
)
(define-read-only (get-team-fee) 
    (var-get team-fee)
)
(define-read-only (get-treasury-distribution-period) 
    (var-get treasury-distribution-period)
)
(define-read-only (get-prize-expiration-period)
    (var-get prize-expiration-period)
)
(define-read-only (get-allocation-percentages) 
    (var-get allocation-percentages)
)
(define-read-only (get-min-allocation) 
    (var-get min-allocation)
)
(define-read-only (get-reward-claim-fee) 
    (var-get reward-claim-fee)
)
(define-read-only (get-current-cycle-id)
    (/ (- tenure-height START-BLOCK) BLOCKS-PER-CYCLE)
)
(define-read-only (get-constellation-block (cycle-id uint)) 
    (- (+ (* BLOCKS-PER-CYCLE (+ cycle-id u1)) START-BLOCK) u1)
)
(define-read-only (get-constellation (cycle-id uint))
    (mod (get-random-number-from-block (get-constellation-block cycle-id)) TOTAL-CONSTELLATIONS)
)
(define-read-only (get-referral-reward (user principal))
    (default-to
        {
            amount: u0,
            block-update: u0
        }
        (map-get? referral-reward user))
)
(define-read-only (get-allocated-by-user (cycle-id uint) (user principal))
    (default-to
        {
            constellation-allocation: (list u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0),
            claimed: false
        } 
        (map-get? allocated-by-user { cycle-id: cycle-id, user: user }))
)
(define-read-only (get-cycle (cycle-id uint))
    (default-to
        {
            prize: u0,
            prize-claimed: u0,
            constellation-allocation: (list u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0 u0),
            allocation-claimed: u0
        }
        (map-get? cycle cycle-id))
)
(define-read-only (get-cycle-status (cycle-id uint))
    (let
        (
            (cycle-data (get-cycle cycle-id))
            (current-cycle-id (get-current-cycle-id))
            (cycle-end-block (get-constellation-block cycle-id))
        )
        (asserts! (< cycle-id current-cycle-id) ERR-PRECONDITION-FAILED)
        (ok
                {
                        cycle-prize: (get prize cycle-data),
                        cycle-prize-claimed: (get prize-claimed cycle-data),
                        cycle-constellation-allocation: (get constellation-allocation cycle-data),
                        cycle-allocation-claimed: (get allocation-claimed cycle-data),
                        cycle-winning-constellation: (get-constellation cycle-id),
                        cycle-end-block: cycle-end-block,
                        blockchain-stacks-height: stacks-block-height,
                        blockchain-tenure-height: tenure-height
                }
        )
    )
)
(define-read-only (get-cycle-user-status (cycle-id uint) (user principal))
  (let
    (
      (cycle-data (get-cycle cycle-id))
      (user-allocation-data (get-allocated-by-user cycle-id user))
      (current-cycle-id (get-current-cycle-id))
      (cycle-end-block (get-constellation-block cycle-id))
    )
    (asserts! (< cycle-id current-cycle-id) ERR-PRECONDITION-FAILED)
    (ok
        {
            cycle-prize: (get prize cycle-data),
            cycle-prize-claimed: (get prize-claimed cycle-data),
            cycle-constellation-allocation: (get constellation-allocation cycle-data),
            cycle-allocation-claimed: (get allocation-claimed cycle-data),
            cycle-winning-constellation: (get-constellation cycle-id),
            cycle-end-block: cycle-end-block,
            user-constellation-allocation: (get constellation-allocation user-allocation-data),
            user-claimed: (get claimed user-allocation-data),
            blockchain-stacks-height: stacks-block-height,
            blockchain-tenure-height: tenure-height
        }
    )
  )
)
(define-read-only (get-current-cycle-user-status (user principal))
    (let
        (
            (current-cycle-id (get-current-cycle-id))
            (cycle-data (get-cycle current-cycle-id))
            (user-allocation-data (get-allocated-by-user current-cycle-id user))
            (cycle-end-block (get-constellation-block current-cycle-id))
        )
        (ok
            {
                cycle-id: current-cycle-id,
                cycle-prize: 
                    (if (is-eq (get prize cycle-data) u0)
                        (/ (var-get treasury) (var-get treasury-distribution-period))
                        (get prize cycle-data)),
                cycle-prize-claimed: (get prize-claimed cycle-data),
                cycle-constellation-allocation: (get constellation-allocation cycle-data),
                cycle-allocation-claimed: (get allocation-claimed cycle-data),
                cycle-end-block: cycle-end-block,
                user-constellation-allocation: (get constellation-allocation user-allocation-data),
                blockchain-stacks-height: stacks-block-height,
                blockchain-tenure-height: tenure-height
            }
        )
    )
)
(define-read-only (get-current-cycle)
    (let
        (
            (current-cycle-id (get-current-cycle-id))
            (cycle-data (get-cycle current-cycle-id))
            (cycle-end-block (get-constellation-block current-cycle-id))
        )
        (ok
            {
                cycle-id: current-cycle-id,
                cycle-prize: 
                    (if (is-eq (get prize cycle-data) u0)
                        (/ (var-get treasury) (var-get treasury-distribution-period))
                        (get prize cycle-data)),
                cycle-prize-claimed: (get prize-claimed cycle-data),
                cycle-constellation-allocation: (get constellation-allocation cycle-data),
                cycle-allocation-claimed: (get allocation-claimed cycle-data),
                cycle-end-block: cycle-end-block,
                blockchain-stacks-height: stacks-block-height,
                blockchain-tenure-height: tenure-height
            }
        )
    )
)
(define-public (deposit-treasury (amount uint)) 
    (begin 
        (asserts! (> amount u0) ERR-INVALID-VALUE)
        (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer amount tx-sender (as-contract tx-sender) none))
        (var-set treasury (+ (var-get treasury) amount))
        (ok true)
    )
)
(define-public (withdraw-treasury (amount uint) (recipient principal))
    (begin
        (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
        (asserts! (> amount u0) ERR-INVALID-VALUE)
        (let (
            (treasury-available (var-get treasury))
        )
            (asserts! (<= amount treasury-available) ERR-PRECONDITION-FAILED)
            (try! (as-contract (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer amount tx-sender recipient none)))
            (var-set treasury (- treasury-available amount))
            (ok true)
        )
    )
)
(define-public (withdraw-contract-funds (amount uint))
    (begin
        (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
        (let (
                (fund-available (unwrap-panic (as-contract (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token get-balance tx-sender ))))
            )
            (asserts! (<= amount fund-available) ERR-PRECONDITION-FAILED)
            (try! (as-contract (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer amount tx-sender (var-get manager) none)))
            (ok true)
        )
    )
)
(define-public (claim-reward (cycle-id uint))
    (begin 
        (asserts! (< cycle-id (get-current-cycle-id)) ERR-CYCLE-NOT-FINISHED)
        (let (
            (user contract-caller)
            (user-allocation (get-allocated-by-user cycle-id user))
            (cycle-data (get-cycle cycle-id))
            (winning-constellation (get-constellation cycle-id))
            (user-constellation-allocation (unwrap-panic (element-at? (get constellation-allocation user-allocation) winning-constellation)))
            (total-constellation-allocation (unwrap-panic (element-at? (get constellation-allocation cycle-data) winning-constellation)))
            (prize-remained (- (get prize cycle-data) (get prize-claimed cycle-data)))
            (constellation-allocation-remained (- total-constellation-allocation (get allocation-claimed cycle-data)))
            )
            (asserts! (not (get claimed user-allocation)) ERR-ALREADY-CLAIMED)
            (asserts! (> user-constellation-allocation u0) ERR-NO-ALLOCATION)
            (asserts! (> prize-remained u0) ERR-PRIZE-POOL-EMPTY)
            (let (
                    (user-prize (/ (* prize-remained user-constellation-allocation) constellation-allocation-remained))
                    (user-reward (if (> user-prize prize-remained) prize-remained user-prize))
                )
                (map-set cycle cycle-id 
                    (merge cycle-data { 
                        allocation-claimed: (+ (get allocation-claimed cycle-data) user-constellation-allocation),
                        prize-claimed: (+ (get prize-claimed cycle-data) user-reward)
                        }))   
                (map-set allocated-by-user { cycle-id: cycle-id, user: user } 
                    (merge user-allocation { claimed: true }))
                (try! (as-contract (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer user-reward tx-sender user none)))
                (ok true)
            )
        )
    )
)
(define-public (recover-expired-prizes (cycle-id uint))
    (begin 
        (let (
            (current-cycle-id (get-current-cycle-id))
            (expiration-period (get-prize-expiration-period))
        )
            (asserts! (>= (- current-cycle-id cycle-id) expiration-period) ERR-EXPIRATION-PERIOD-NOT-MET)
            (let (
                (cycle-data (get-cycle cycle-id))
                (unclaimed-prize (- (get prize cycle-data) (get prize-claimed cycle-data)))
            )
                (asserts! (> unclaimed-prize u0) ERR-NO-UNCLAIMED-PRIZE)
                (map-set cycle cycle-id 
                    (merge cycle-data { 
                        prize-claimed: (get prize cycle-data)
                    }))
                (var-set treasury (+ (var-get treasury) unclaimed-prize))
                (ok unclaimed-prize)
            )
        )
    )
)
(define-public (recover-zero-winner-cycle (cycle-id uint))
    (begin 
        (asserts! (< cycle-id (get-current-cycle-id)) ERR-CYCLE-NOT-FINISHED)
        (let (
            (cycle-data (get-cycle cycle-id))
            (winning-constellation (get-constellation cycle-id))
            (total-constellation-allocation (unwrap-panic (element-at? (get constellation-allocation cycle-data) winning-constellation)))
            (unclaimed-prize (- (get prize cycle-data) (get prize-claimed cycle-data)))
        )
            (asserts! (> unclaimed-prize u0) ERR-NO-UNCLAIMED-PRIZE)
            (asserts! (is-eq total-constellation-allocation u0) ERR-PRECONDITION-FAILED)
            (map-set cycle cycle-id 
                (merge cycle-data { 
                    prize-claimed: (get prize cycle-data)
                }))
            (var-set treasury (+ (var-get treasury) unclaimed-prize))
            (ok unclaimed-prize)
        )
    )
)
(define-public (allocate (amount uint) (constellation uint) (referral-user principal))
    (begin 
        (asserts! (>= amount (var-get min-allocation)) ERR-PRECONDITION-FAILED)
        (asserts! (< constellation TOTAL-CONSTELLATIONS) ERR-INVALID-VALUE)
        (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer amount tx-sender (as-contract tx-sender) none))
        (let
            (
                (current-cycle-id (get-current-cycle-id))
                (current-cycle (get-cycle current-cycle-id))
                (current-allocation-by-user (get-allocated-by-user current-cycle-id tx-sender))
            )
            (map-set cycle current-cycle-id 
                (merge current-cycle {
                    prize: (+ (calculate-prize-with-treasury-addition (get prize current-cycle)) (distribute-allocation amount referral-user)),
                    constellation-allocation: (update-constellation-allocation amount constellation (get constellation-allocation current-cycle))
                }))
            (map-set allocated-by-user { cycle-id: current-cycle-id, user: tx-sender } 
                { 
                    constellation-allocation: (update-constellation-allocation amount constellation (get constellation-allocation current-allocation-by-user)), 
                    claimed: false 
                })
            (ok true)
        )
    )
)
(define-public (claim-referral-reward)
    (let (
        (recipient tx-sender)
        (user-reward (get-referral-reward recipient))
        (reward-amount (get amount user-reward))
        (fee (var-get reward-claim-fee))
        (final-reward-amount (- reward-amount fee))
    )
        (asserts! (> reward-amount fee) ERR-PRECONDITION-FAILED)
        (try! (as-contract (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer final-reward-amount tx-sender recipient none)))
        (var-set team-fee (+ (var-get team-fee) fee))
        (map-set referral-reward recipient {
            amount: u0,
            block-update: stacks-block-height
        })
        (ok final-reward-amount)
    )
)
(define-public (claim-user-referral-reward (user principal))
    (begin
        (asserts! (is-eq contract-caller (var-get manager)) ERR-PERMISSION-DENIED)
        (let (
            (user-reward (get-referral-reward user))
            (reward-amount (get amount user-reward))
            (update-block (get block-update user-reward))
            (current-cycle-id (get-current-cycle-id))
            (expiration-period (var-get prize-expiration-period))
            (cycles-since-update (if (> update-block u0)
                                      (/ (- tenure-height update-block) BLOCKS-PER-CYCLE)
                                      u0))
        )
            (asserts! (> reward-amount u0) ERR-PRECONDITION-FAILED)
            (asserts! (>= cycles-since-update expiration-period) ERR-PRECONDITION-FAILED)
            (try! (as-contract (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer reward-amount tx-sender (var-get manager) none)))
            (map-set referral-reward user {
                amount: u0,
                block-update: stacks-block-height
            })
            (ok reward-amount)
        )
    )
)
(define-private (calculate-prize-with-treasury-addition (current-prize uint))
    (if (is-eq u0 current-prize)
        (let (
                (current-treasury (get-treasury))
                (prize (/ current-treasury (get-treasury-distribution-period)))
            )
            (var-set treasury (- current-treasury prize))
            prize
        )
        current-prize
    )
)
(define-private (update-constellation-allocation (amount uint) (constellation uint) (constellation-allocation (list 24 uint)))
    (let (
            (current-constellation-allocation (unwrap-panic (element-at? constellation-allocation constellation)))
            (new-constellation-allocation (unwrap-panic (replace-at? constellation-allocation constellation (+ current-constellation-allocation amount))))
        )
        new-constellation-allocation
    )
)
(define-private (distribute-allocation (amount uint) (referral-user principal))
    (let (
            (current-allocation-percentages (get-allocation-percentages))
            (current-cycle-allocation (/ (* amount (get current-cycle current-allocation-percentages)) u100))
            (treasury-allocation (/ (* amount (get treasury current-allocation-percentages)) u100))
            (referral-reward-allocation (/ (* amount (get referral-reward current-allocation-percentages)) u100))
            (team-fee-allocation (- (- (- amount current-cycle-allocation) treasury-allocation) referral-reward-allocation))
        )
        (var-set treasury (+ treasury-allocation (get-treasury)))
        (var-set team-fee (+ team-fee-allocation (get-team-fee)))
        (map-set referral-reward referral-user 
            {
                amount: (+ (get amount (get-referral-reward referral-user)) referral-reward-allocation), 
                block-update: stacks-block-height 
            })
        current-cycle-allocation
    )
)

Functions (39)

FunctionAccessArgs
get-managerread-only
set-managerpublicnew-manager: principal
set-min-allocationpublicnew-min-allocation: uint
set-treasury-distribution-periodpublicnew-count: uint
set-team-feepublicnew-fee: uint
set-reward-claim-feepublicnew-fee: uint
set-prize-expiration-periodpublicnew-count: uint
get-random-number-from-blockread-onlyblock: uint
get-blocks-per-cycleread-only
get-start-blockread-only
get-treasuryread-only
get-team-feeread-only
get-treasury-distribution-periodread-only
get-prize-expiration-periodread-only
get-allocation-percentagesread-only
get-min-allocationread-only
get-reward-claim-feeread-only
get-current-cycle-idread-only
get-constellation-blockread-onlycycle-id: uint
get-constellationread-onlycycle-id: uint
get-referral-rewardread-onlyuser: principal
get-allocated-by-userread-onlycycle-id: uint, user: principal
get-cycleread-onlycycle-id: uint
get-cycle-statusread-onlycycle-id: uint
get-cycle-user-statusread-onlycycle-id: uint, user: principal
get-current-cycle-user-statusread-onlyuser: principal
get-current-cycleread-only
deposit-treasurypublicamount: uint
withdraw-treasurypublicamount: uint, recipient: principal
withdraw-contract-fundspublicamount: uint
claim-rewardpubliccycle-id: uint
recover-expired-prizespubliccycle-id: uint
recover-zero-winner-cyclepubliccycle-id: uint
allocatepublicamount: uint, constellation: uint, referral-user: principal
claim-referral-rewardpublic
claim-user-referral-rewardpublicuser: principal
calculate-prize-with-treasury-additionprivatecurrent-prize: uint
update-constellation-allocationprivateamount: uint, constellation: uint, constellation-allocation: (list 24 uint
distribute-allocationprivateamount: uint, referral-user: principal