;; title: feature-flags
;; version:
;; summary:
;; description:
;; traits
;; Lottery Pool Smart Contract
;; Constants
(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_NOT_AUTHORIZED (err u100))
(define-constant ERR_LOTTERY_INACTIVE (err u102))
(define-constant ERR_INSUFFICIENT_BALANCE (err u103))
(define-constant ERR_INVALID_TICKET_PRICE (err u104))
(define-constant ERR_NO_WINNERS (err u105))
(define-constant ERR_NO_TICKETS (err u106))
(define-constant ERR_WITHDRAWAL_PERIOD_ENDED (err u107))
(define-constant ERR_LOTTERY_NOT_ENDED (err u108))
(define-constant ERR_WINNERS_ALREADY_SELECTED (err u109))
(define-constant ERR_INVALID_DURATION (err u110))
(define-constant ERR_INVALID_WITHDRAWAL_PERIOD (err u111))
(define-constant ERR_INVALID_WINNER_ID (err u112))
;; Data Variables
(define-data-var is-lottery-active bool false)
(define-data-var current-ticket-price uint u1000000) ;; 1 STX
(define-data-var current-lottery-pot uint u0)
(define-data-var total-tickets-sold uint u0)
(define-data-var number-of-winners uint u1)
(define-data-var lottery-end-block-height uint u0)
(define-data-var withdrawal-end-block-height uint u0)
(define-data-var organizer-fee-percentage uint u5) ;; 5% fee
(define-data-var prize-per-winner uint u0)
(define-data-var winners-selected bool false)
;; Maps
(define-map ticket-ownership {ticket-id: uint} {owner: principal})
(define-map user-ticket-count principal uint)
(define-map winners {winner-id: uint} {address: principal, claimed: bool})
;; Private Functions
(define-private (is-contract-owner)
(is-eq tx-sender CONTRACT_OWNER))
(define-private (validate-lottery-is-active)
(if (var-get is-lottery-active)
(ok true)
ERR_LOTTERY_INACTIVE))
(define-private (validate-sufficient-balance (required-balance uint))
(if (>= (stx-get-balance tx-sender) required-balance)
(ok true)
ERR_INSUFFICIENT_BALANCE))
(define-private (select-random-winner (random-seed uint) (ticket-id uint))
(mod (+ random-seed ticket-id) (var-get total-tickets-sold)))
(define-private (calculate-organizer-fee (total-amount uint))
(/ (* total-amount (var-get organizer-fee-percentage)) u100))
;; Public Functions
(define-public (start-new-lottery (duration-in-blocks uint) (withdrawal-period uint) (ticket-price uint) (winner-count uint) (fee-percentage uint))
(begin
(asserts! (is-contract-owner) ERR_NOT_AUTHORIZED)
(asserts! (> ticket-price u0) ERR_INVALID_TICKET_PRICE)
(asserts! (> winner-count u0) ERR_NO_WINNERS)
(asserts! (<= fee-percentage u20) ERR_NOT_AUTHORIZED) ;; Max 20% fee
(asserts! (not (var-get is-lottery-active)) ERR_NOT_AUTHORIZED)
(asserts! (> duration-in-blocks u0) ERR_INVALID_DURATION)
(asserts! (> withdrawal-period u0) ERR_INVALID_WITHDRAWAL_PERIOD)
(var-set is-lottery-active true)
(var-set current-ticket-price ticket-price)
(var-set current-lottery-pot u0)
(var-set total-tickets-sold u0)
(var-set number-of-winners winner-count)
(var-set lottery-end-block-height (+ stacks-block-height duration-in-blocks))
(var-set withdrawal-end-block-height (+ stacks-block-height withdrawal-period))
(var-set organizer-fee-percentage fee-percentage)
(var-set winners-selected false)
(ok true)))
(define-public (select-winners (random-seed uint))
(let ((winner-count (var-get number-of-winners))
(total-ticket-count (var-get total-tickets-sold)))
(begin
(asserts! (is-contract-owner) ERR_NOT_AUTHORIZED)
(asserts! (not (var-get is-lottery-active)) ERR_LOTTERY_INACTIVE)
(asserts! (not (var-get winners-selected)) ERR_WINNERS_ALREADY_SELECTED)
(asserts! (> total-ticket-count u0) ERR_NO_WINNERS)
(var-set winners-selected true)
(let ((selected-winners (fold select-winner-and-save
(list u0 u1 u2 u3 u4 u5 u6 u7 u8 u9)
{random-seed: random-seed, current-winner-id: u0, remaining-winners: winner-count})))
(ok (get current-winner-id selected-winners))))))
(define-private (select-winner-and-save (index uint) (context {random-seed: uint, current-winner-id: uint, remaining-winners: uint}))
(if (> (get remaining-winners context) u0)
(let ((winning-ticket-id (select-random-winner (get random-seed context) index))
(winner-address (get owner (unwrap-panic (map-get? ticket-ownership {ticket-id: (+ winning-ticket-id u1)})))))
(begin
(map-set winners {winner-id: (get current-winner-id context)} {address: winner-address, claimed: false})
{random-seed: (+ (get random-seed context) u1),
current-winner-id: (+ (get current-winner-id context) u1),
remaining-winners: (- (get remaining-winners context) u1)}))
context))
;; Read-Only Functions
(define-read-only (get-current-ticket-price)
(ok (var-get current-ticket-price)))
(define-read-only (get-current-lottery-pot)
(ok (var-get current-lottery-pot)))
(define-read-only (get-user-ticket-count (user-address principal))
(ok (default-to u0 (map-get? user-ticket-count user-address))))
(define-read-only (get-total-tickets-sold)
(ok (var-get total-tickets-sold)))
(define-read-only (check-if-lottery-is-active)
(ok (var-get is-lottery-active)))
(define-read-only (get-lottery-end-block-height)
(ok (var-get lottery-end-block-height)))
(define-read-only (get-withdrawal-end-block-height)
(ok (var-get withdrawal-end-block-height)))
(define-read-only (get-organizer-fee-percentage)
(ok (var-get organizer-fee-percentage)))
(define-read-only (get-winner-info (winner-id uint))
(ok (map-get? winners {winner-id: winner-id})))
(define-read-only (are-winners-selected)
(ok (var-get winners-selected)))