Source Code

;; ============================================================
;;
;; Rewritten: Buy Gems & Buy Hearts distribute on 5-Mar-2025
;;   - 80% STX -> PROGRESSIVE_WALLET
;;   - 20% STX -> KRYPTOMIND
;; No burn, no swap, no STONE router integration.
;; ============================================================

;; =======================
;; Error & Constant Codes
;; =======================
(define-constant ERR-NOT-AUTHORIZED          (err u401))
(define-constant ERR-INSUFFICIENT-FUNDS      (err u402))
(define-constant INVALID-GEMS-COUNT          (err u403))
(define-constant INVALID-STX-BALANCE         (err u404))
(define-constant ERR-TRANSFER-PROGRESSIVE    (err u406))
(define-constant ERR-TRANSFER-KRYPTOMIND     (err u407))
(define-constant INVALID-HEART-COUNT         (err u409))
(define-constant ERR-ENTER-NEW-WALLET        (err u501))
(define-constant ERR-INVALID-DISTRIBUTION    (err u505))
(define-constant ERR-INVALID-PERCENTAGE      (err u601))
(define-constant ERR-STX-LIMIT-EXCEEDED      (err u504))

(define-constant HUNDRED-PERCENT u10000)

;; Max STX amounts for hearts/gems
(define-constant MAX-STX-HEARTS u4000000)
(define-constant MAX-STX-GEMS   u1000000)

;; ===========================================
;; Public Variables - All Using 10000 Scaling
;; ===========================================
;; Default: 80% progressive, 20% kryptomind
(define-data-var percentage-progressive uint u8000) ;; 80.00%
(define-data-var percentage-kryptomind  uint u2000) ;; 20.00%

;; ==========================
;; Public Wallet Variables
;; ==========================
(define-data-var KRYPTOMIND         principal 'SP2RVTWWBB5KYFY2F0G4V054FETC6R5Q12ZCZ6QCC)
(define-data-var PROGRESSIVE_WALLET principal 'SP2HYW9F9YXEE8ACZ7PE268VB7QME0JDJJVDPHFS5)

;; ==========================
;; Other Public Variables
;; ==========================
(define-data-var progressive-pool uint u0)
(define-data-var contract-owner  principal tx-sender)

;; ==================
;; Maps
;; ==================
(define-map user-gems   {user: principal} {gems: uint})
(define-map user-hearts {user: principal} {hearts: uint})
(define-map user-contest-inventory principal {hearts: uint, gems: uint})

;; ==========================================
;; Private Helper: Ownership Check
;; ==========================================
(define-private (check-is-owner)
  (ok (asserts! (is-eq tx-sender (var-get contract-owner)) ERR-NOT-AUTHORIZED))
)

;; ==========================================
;; Setter Functions (Ownership Required)
;; ==========================================
(define-public (set-contract-owner (owner principal))
  (begin
    (try! (check-is-owner))
    (asserts! (not (is-eq owner (var-get contract-owner))) ERR-ENTER-NEW-WALLET)
    (var-set contract-owner owner)
    (ok owner)
  )
)

;; Set 2-way distribution: progressive + kryptomind must equal 100%
(define-public (set-primary-percentages (new-progressive uint) (new-kryptomind uint))
  (begin
    (try! (check-is-owner))
    (asserts! (is-eq (+ new-progressive new-kryptomind) HUNDRED-PERCENT)
              ERR-INVALID-DISTRIBUTION)
    (asserts! (> new-progressive u0) ERR-INVALID-PERCENTAGE)
    (asserts! (> new-kryptomind u0) ERR-INVALID-PERCENTAGE)

    (var-set percentage-progressive new-progressive)
    (var-set percentage-kryptomind new-kryptomind)

    (ok { progressive: new-progressive, krypto: new-kryptomind })
  )
)

(define-public (set-kryptomind-wallet (new-wallet principal))
  (begin
    (try! (check-is-owner))
    (asserts! (not (is-eq new-wallet (var-get KRYPTOMIND))) ERR-ENTER-NEW-WALLET)
    (var-set KRYPTOMIND new-wallet)
    (ok new-wallet)
  )
)

(define-public (set-progressive-wallet (new-wallet principal))
  (begin
    (try! (check-is-owner))
    (asserts! (not (is-eq new-wallet (var-get PROGRESSIVE_WALLET))) ERR-ENTER-NEW-WALLET)
    (var-set PROGRESSIVE_WALLET new-wallet)
    (ok new-wallet)
  )
)

;; ==========================
;; Getter Functions
;; ==========================
(define-read-only (get-kryptomind-wallet)      (ok (var-get KRYPTOMIND)))
(define-read-only (get-progressive-wallet)     (ok (var-get PROGRESSIVE_WALLET)))
(define-read-only (get-contract-owner)         (ok (var-get contract-owner)))
(define-read-only (get-progressive-pool-balance) (var-get progressive-pool))

(define-read-only (get-percentage-progressive) (ok (var-get percentage-progressive)))
(define-read-only (get-percentage-kryptomind)  (ok (var-get percentage-kryptomind)))

(define-read-only (get-user-contest-inventory (user principal))
  (map-get? user-contest-inventory user))

(define-read-only (get-user-gems (user principal))
  (ok (default-to {gems: u0} (map-get? user-gems {user: user}))))

(define-read-only (get-user-hearts (user principal))
  (ok (default-to {hearts: u0} (map-get? user-hearts {user: user}))))

;; ========================================
;; Purchase Gems
;; Distribution:
;;   80% STX -> PROGRESSIVE_WALLET
;;   20% STX -> KRYPTOMIND
;; ========================================
(define-public (buy-gems (gems-count uint))
  (begin
    ;; Validate gem bundles
    (asserts!
      (or (is-eq gems-count u5)
          (is-eq gems-count u25)
          (is-eq gems-count u50)
          (is-eq gems-count u100))
      INVALID-GEMS-COUNT)

    ;; Determine required STX
    (let ((required-stx
            (if (is-eq gems-count u5)
                u200000
                (if (is-eq gems-count u25)
                    u400000
                    (if (is-eq gems-count u50)
                        u700000
                        (if (is-eq gems-count u100)
                            u1000000
                            u0))))))
      (asserts! (>= (stx-get-balance tx-sender) required-stx) INVALID-STX-BALANCE)
      (asserts! (<= required-stx MAX-STX-GEMS) ERR-STX-LIMIT-EXCEEDED)

      ;; 80% progressive, 20% kryptomind
      ;; NOTE: share-krypto is computed as remainder to avoid rounding dust.
      (let (
        (share-progressive
          (/ (* required-stx (var-get percentage-progressive)) HUNDRED-PERCENT))
        (share-krypto
          (- required-stx
             (/ (* required-stx (var-get percentage-progressive)) HUNDRED-PERCENT)))
      )
        ;; progressive stx
        (unwrap! (stx-transfer? share-progressive tx-sender (var-get PROGRESSIVE_WALLET))
                 ERR-TRANSFER-PROGRESSIVE)

        ;; kryptomind stx
        (unwrap! (stx-transfer? share-krypto tx-sender (var-get KRYPTOMIND))
                 ERR-TRANSFER-KRYPTOMIND)

        ;; update user gems
        (map-set user-gems {user: tx-sender}
          {gems: (+ (get gems (default-to {gems: u0}
                                 (map-get? user-gems {user: tx-sender})))
                    gems-count)})

        ;; event
        (let ((ev
                {op: "buy-gems",
                 user: tx-sender,
                 gems-count: gems-count,
                 required-stx: required-stx,
                 progressive-share: share-progressive,
                 kryptomind-share: share-krypto}))
          (print ev)
          (ok ev)
        )
      )
    )
  )
)

;; ========================================
;; Purchase Hearts
;; Distribution:
;;   80% STX -> PROGRESSIVE_WALLET
;;   20% STX -> KRYPTOMIND
;; ========================================
(define-public (buy-hearts (heart-count uint))
  (begin
    (asserts!
      (or (is-eq heart-count u3)
          (is-eq heart-count u10)
          (is-eq heart-count u25)
          (is-eq heart-count u50))
      INVALID-HEART-COUNT)

    (let ((required-stx
            (if (is-eq heart-count u3)
                u1000000
                (if (is-eq heart-count u10)
                    u2000000
                    (if (is-eq heart-count u25)
                        u3000000
                        (if (is-eq heart-count u50)
                            u4000000
                            u0))))))
      (asserts! (>= (stx-get-balance tx-sender) required-stx) INVALID-STX-BALANCE)
      (asserts! (<= required-stx MAX-STX-HEARTS) ERR-STX-LIMIT-EXCEEDED)

      (let (
        (share-progressive
          (/ (* required-stx (var-get percentage-progressive)) HUNDRED-PERCENT))
        (share-krypto
          (- required-stx
             (/ (* required-stx (var-get percentage-progressive)) HUNDRED-PERCENT)))
      )
        ;; progressive stx
        (unwrap! (stx-transfer? share-progressive tx-sender (var-get PROGRESSIVE_WALLET))
                 ERR-TRANSFER-PROGRESSIVE)

        ;; kryptomind stx
        (unwrap! (stx-transfer? share-krypto tx-sender (var-get KRYPTOMIND))
                 ERR-TRANSFER-KRYPTOMIND)

        ;; update user hearts
        (let ((old-hearts
                (get hearts (default-to {hearts: u0}
                          (map-get? user-hearts {user: tx-sender})))))
          (map-set user-hearts {user: tx-sender}
                   {hearts: (+ old-hearts heart-count)}))

        ;; event
        (let ((ev
                {op: "buy-hearts",
                 user: tx-sender,
                 heart-count: heart-count,
                 required-stx: required-stx,
                 progressive-share: share-progressive,
                 kryptomind-share: share-krypto}))
          (print ev)
          (ok ev)
        )
      )
    )
  )
)

;; ========================================
;; Enter Contest
;; - User pays fixed 0.5 STX (500000 microSTX) to Progressive Pool
;; - Awards: +75 gems, +5 hearts
;; - Also updates contest-inventory map
;; ========================================
(define-public (enter-contest)
  (begin
    (asserts! (>= (stx-get-balance tx-sender) u500000) INVALID-STX-BALANCE)
    (unwrap! (stx-transfer? u500000 tx-sender (var-get PROGRESSIVE_WALLET))
             ERR-TRANSFER-PROGRESSIVE)
    (var-set progressive-pool (+ (var-get progressive-pool) u500000))

    (let (
      (old-gems
        (get gems (default-to {gems: u0}
                  (map-get? user-gems {user: tx-sender}))))
      (old-hearts
        (get hearts (default-to {hearts: u0}
                  (map-get? user-hearts {user: tx-sender}))))
      (old-contest
        (default-to {hearts: u0, gems: u0}
                    (map-get? user-contest-inventory tx-sender)))
    )
      ;; new totals
      (map-set user-gems {user: tx-sender} {gems: (+ old-gems u75)})
      (map-set user-hearts {user: tx-sender} {hearts: (+ old-hearts u5)})

      ;; also update the contest-inventory
      (map-set user-contest-inventory tx-sender
        {hearts: (+ (get hearts old-contest) u5),
         gems:   (+ (get gems   old-contest) u75)})

      (let ((ev
              {op: "enter-contest",
               user: tx-sender,
               hearts-gained: u5,
               gems-gained: u75,
               total-pool: (var-get progressive-pool)}))
        (print ev)
        (ok ev)
      )
    )
  )
)

Functions (17)

FunctionAccessArgs
check-is-ownerprivate
set-contract-ownerpublicowner: principal
set-primary-percentagespublicnew-progressive: uint, new-kryptomind: uint
set-kryptomind-walletpublicnew-wallet: principal
set-progressive-walletpublicnew-wallet: principal
get-kryptomind-walletread-only
get-progressive-walletread-only
get-contract-ownerread-only
get-progressive-pool-balanceread-only
get-percentage-progressiveread-only
get-percentage-kryptomindread-only
get-user-contest-inventoryread-onlyuser: principal
get-user-gemsread-onlyuser: principal
get-user-heartsread-onlyuser: principal
buy-gemspublicgems-count: uint
buy-heartspublicheart-count: uint
enter-contestpublic