Source Code

;; PEPE Burn-to-Play Competition Contract
;; Daily competition where highest burner wins 90% of total burned
;; 10% gets permanently burned, 1% taken as fee

;; Constants
(define-constant BURN-ADDRESS 'SP000000000000000000002Q6VF78) 
(define-constant THIS-CONTRACT (as-contract tx-sender))
(define-constant FAKTORY 'SM3NY5HXXRNCHS1B65R78CYAC1TQ6DEMN3C0DN74S) 

;; Epoch system using Bitcoin block timing
(define-constant EPOCH-LENGTH u144) ;; ~1 day at ~10min/block
(define-constant GENESIS-BLOCK burn-block-height)

;; Percentages (basis points for precision)
(define-constant WINNER-PERCENTAGE u9000) ;; 90%
(define-constant BASIS-POINTS u10000)     ;; 100%

;; Error constants
(define-constant ERR-UNAUTHORIZED (err u401))
(define-constant ERR-INVALID-AMOUNT (err u402))
(define-constant ERR-NO-BURNS-THIS-EPOCH (err u403))
(define-constant ERR-ALREADY-SETTLED (err u404))
(define-constant ERR-TOKEN-TRANSFER-FAILED (err u405))
(define-constant ERR-INSUFFICIENT-PARTICIPANTS (err u406))
(define-constant ERR-EPOCH-NOT-ENDED (err u407))

;; Data structures
(define-map epoch-burns
  { user: principal, epoch: uint }
  { amount: uint, block-height: uint }
)

(define-map epoch-totals
  uint ;; epoch
  { 
    total-burned: uint,
    participant-count: uint,
    highest-burner: (optional principal),
    highest-amount: uint,
    settled: bool
  }
)

(define-map user-total-burns
  principal
  uint ;; total amount burned across all epochs
)

;; Helper functions
(define-read-only (current-epoch) 
  (/ (- burn-block-height GENESIS-BLOCK) EPOCH-LENGTH))

(define-read-only (calc-epoch-start (epoch uint))
  (+ GENESIS-BLOCK (* EPOCH-LENGTH epoch)))

(define-read-only (calc-epoch-end (epoch uint))
  (- (+ GENESIS-BLOCK (* EPOCH-LENGTH (+ epoch u1))) u1))

(define-read-only (is-epoch-ended (epoch uint))
  (> burn-block-height (calc-epoch-end epoch)))

(define-read-only (get-epoch-total (epoch uint))
  (default-to 
    { total-burned: u0, participant-count: u0, highest-burner: none, highest-amount: u0, settled: false }
    (map-get? epoch-totals epoch)))

(define-read-only (get-user-burn-for-epoch (user principal) (epoch uint))
  (default-to 
    { amount: u0, block-height: u0 }
    (map-get? epoch-burns { user: user, epoch: epoch })))

(define-read-only (get-user-total-burns (user principal))
  (default-to u0 (map-get? user-total-burns user)))

(define-read-only (get-blocks-until-epoch-end)
  (let ((current (current-epoch)))
    (if (>= burn-block-height (calc-epoch-end current))
        u0
        (- (calc-epoch-end current) burn-block-height))))

;; Main burn function
(define-public (burn-to-compete (amount uint))
  (let (
    (current (current-epoch))
    (user tx-sender)
    (existing-burn (get-user-burn-for-epoch user current))
    (epoch-data (get-epoch-total current))
  )

    ;; Check epoch isn't already settled
    (asserts! (not (get settled epoch-data)) ERR-ALREADY-SETTLED)

    ;; Must burn a positive amount
    (asserts! (> amount u0) ERR-INVALID-AMOUNT)
    
    ;; Transfer PEPE tokens to this contract first
    (try! (contract-call? 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz transfer 
           amount 
           user 
           THIS-CONTRACT 
           (some 0x6920676f7420746865206a75696365))) ;; "i got the juice"
    
    ;; Calculate new amounts
    (let (
      (previous-amount (get amount existing-burn))
      (new-total-amount (+ previous-amount amount))
      (new-epoch-total (+ (get total-burned epoch-data) amount))
      (new-participant-count (if (is-eq previous-amount u0) 
                                (+ (get participant-count epoch-data) u1)
                                (get participant-count epoch-data)))
      (is-new-highest (> new-total-amount (get highest-amount epoch-data)))
      (new-highest-burner (if is-new-highest (some user) (get highest-burner epoch-data)))
      (new-highest-amount (if is-new-highest new-total-amount (get highest-amount epoch-data)))
    )
      ;; Update user's burn for this epoch
      (map-set epoch-burns 
        { user: user, epoch: current }
        { amount: new-total-amount, block-height: burn-block-height })
      
      ;; Update epoch totals
      (map-set epoch-totals current {
        total-burned: new-epoch-total,
        participant-count: new-participant-count,
        highest-burner: new-highest-burner,
        highest-amount: new-highest-amount,
        settled: false
      })
      
      ;; Update user's total burns across all time
      (map-set user-total-burns user 
        (+ (get-user-total-burns user) amount))
      
      ;; Emit event
      (print {
        contract: THIS-CONTRACT,
        token-contract: 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz,
        event: "burn-to-compete",
        user: user,
        epoch: current,
        amount: amount,
        total-user: new-total-amount,
        block-height: burn-block-height,
        is-leader: is-new-highest,
        total-burned: new-epoch-total,
        participant-count: new-participant-count,
        highest-burner: new-highest-burner,
        highest-amount: new-highest-amount,
        settled: false
      })
      
      (ok true)
    )
  )
)

;; Settle epoch - distribute rewards and burn tokens
(define-public (settle-epoch (epoch uint))
  (let (
    (epoch-data (get-epoch-total epoch))
    (total-burned (get total-burned epoch-data))
    (participant-count (get participant-count epoch-data))
    (highest-burner (get highest-burner epoch-data))
  )
    ;; Check that epoch actually had burns
    (asserts! (> total-burned u0) ERR-NO-BURNS-THIS-EPOCH)

    ;; Check epoch has ended
    (asserts! (is-epoch-ended epoch) ERR-EPOCH-NOT-ENDED)
    
    ;; Check not already settled
    (asserts! (not (get settled epoch-data)) ERR-ALREADY-SETTLED)
    
    ;; Check minimum participants (2)
    (asserts! (>= participant-count u2) ERR-INSUFFICIENT-PARTICIPANTS)
    
    ;; Check we have a highest burner
    (asserts! (is-some highest-burner) ERR-NO-BURNS-THIS-EPOCH)
    
    (let (
      (winner (unwrap-panic highest-burner))
      (winner-amount (/ (* total-burned WINNER-PERCENTAGE) BASIS-POINTS))
      (remaining-amount (- total-burned winner-amount))
      (fee-amount (/ remaining-amount u10))        ;; 10% of remaining = 1% of total
      (burn-amount (- remaining-amount fee-amount)) ;; 90% of remaining = 9% of total
    )
      ;; Send winner their reward (90%)
      (if (> winner-amount u0)
            (try! (as-contract (contract-call? 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz transfer 
                    winner-amount 
                    THIS-CONTRACT 
                    winner 
                    (some 0x6920676f7420746865206a75696365))))
            true) 
      
      ;; Burn tokens (9%)
      (if (> burn-amount u0)
            (try! (as-contract (contract-call? 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz transfer 
                    burn-amount 
                    THIS-CONTRACT 
                    BURN-ADDRESS 
                    (some 0x70657065206275726e)))) ;; "pepe burn"
            true) 
      
      ;; Send fee to contract owner (1%)
      (if (> fee-amount u0)
            (try! (as-contract (contract-call? 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz transfer 
                    fee-amount 
                    THIS-CONTRACT 
                    FAKTORY
                    (some 0x6920676f7420746865206a75696365)))) 
            true) 
      
      ;; Mark epoch as settled
      (map-set epoch-totals epoch 
        (merge epoch-data { settled: true }))
      
      ;; Emit settlement event
      (print {
        contract: THIS-CONTRACT,
        token-contract: 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz,
        event: "epoch-settled",
        epoch: epoch,
        total-burned: total-burned,
        participant-count: participant-count,
        highest-burner: highest-burner,
        highest-amount: (get highest-amount epoch-data),
        settled: true,
        winner: winner,
        winner-amount: winner-amount,
        burn-amount: burn-amount,
        fee-amount: fee-amount,
        block-height: burn-block-height,
      })
      
      (ok true)
    )
  )
)

;; Refund function for epochs with only 1 participant
(define-public (refund-solo-epoch (epoch uint))
  (let (
    (epoch-data (get-epoch-total epoch))
    (total-burned (get total-burned epoch-data))
    (participant-count (get participant-count epoch-data))
    (highest-burner (get highest-burner epoch-data))
  )
    ;; Check that epoch actually had burns
    (asserts! (> total-burned u0) ERR-NO-BURNS-THIS-EPOCH)

    ;; Check epoch has ended
    (asserts! (is-epoch-ended epoch) ERR-EPOCH-NOT-ENDED)
    
    ;; Check not already settled
    (asserts! (not (get settled epoch-data)) ERR-ALREADY-SETTLED)
    
    ;; Check exactly 1 participant
    (asserts! (is-eq participant-count u1) ERR-INSUFFICIENT-PARTICIPANTS)
    
    ;; Check we have a highest burner
    (asserts! (is-some highest-burner) ERR-NO-BURNS-THIS-EPOCH)
    
    (let ((solo-user (unwrap-panic highest-burner)))
      ;; Refund all tokens to the solo participant
      (try! (as-contract (contract-call? 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz transfer 
             total-burned 
             THIS-CONTRACT 
             solo-user 
             (some 0x6920676f7420746865206a75696365))))
      
      ;; Mark epoch as settled
      (map-set epoch-totals epoch 
        (merge epoch-data { settled: true }))
      
      ;; Emit refund event
      (print {
        contract: THIS-CONTRACT,
        token-contract: 'SP1Z92MPDQEWZXW36VX71Q25HKF5K2EPCJ304F275.tokensoft-token-v4k68639zxz,
        event: "epoch-refunded",
        epoch: epoch,
        solo-user: solo-user,
        total-burned: total-burned,
        participant-count: participant-count,
        highest-burner: highest-burner,
        highest-amount: (get highest-amount epoch-data),
        settled: true,
      })
      
      (ok true)
    )
  )
)

Functions (11)

FunctionAccessArgs
current-epochread-only
calc-epoch-startread-onlyepoch: uint
calc-epoch-endread-onlyepoch: uint
is-epoch-endedread-onlyepoch: uint
get-epoch-totalread-onlyepoch: uint
get-user-burn-for-epochread-onlyuser: principal, epoch: uint
get-user-total-burnsread-onlyuser: principal
get-blocks-until-epoch-endread-only
burn-to-competepublicamount: uint
settle-epochpublicepoch: uint
refund-solo-epochpublicepoch: uint