Source Code

;; Stacks Tip Jar - Creator Monetization
;; Accept tips and donations on Stacks

;; Constants
(define-constant err-owner-only (err u100))
(define-constant err-invalid-amount (err u101))
(define-constant err-creator-not-found (err u102))

;; Data Variables
(define-data-var total-tips uint u0)
(define-data-var total-creators uint u0)
(define-data-var total-tippers uint u0)

;; Creator profiles
(define-map creators principal
  {
    name: (string-utf8 64),
    bio: (string-utf8 256),
    total-received: uint,
    tip-count: uint,
    registered-at: uint
  }
)

;; Tip history
(define-map tips uint
  {
    from: principal,
    to: principal,
    amount: uint,
    message: (optional (string-utf8 128)),
    block: uint
  }
)

(define-data-var tip-nonce uint u0)

;; Tipper stats
(define-map tipper-stats principal
  {
    total-tipped: uint,
    tip-count: uint,
    creators-supported: uint
  }
)

;; Track unique creator support
(define-map supporter-creator { supporter: principal, creator: principal } bool)

;; Read-only functions
(define-read-only (get-creator (creator principal))
  (map-get? creators creator)
)

(define-read-only (get-tip (tip-id uint))
  (map-get? tips tip-id)
)

(define-read-only (get-tipper-stats (tipper principal))
  (default-to 
    { total-tipped: u0, tip-count: u0, creators-supported: u0 }
    (map-get? tipper-stats tipper)
  )
)

(define-read-only (is-creator-registered (creator principal))
  (is-some (map-get? creators creator))
)

(define-read-only (get-platform-stats)
  {
    total-tips: (var-get total-tips),
    total-creators: (var-get total-creators),
    total-tippers: (var-get total-tippers),
    total-tip-count: (var-get tip-nonce)
  }
)

;; Public functions

;; Register as a creator
(define-public (register-creator (name (string-utf8 64)) (bio (string-utf8 256)))
  (begin
    (asserts! (not (is-creator-registered tx-sender)) err-owner-only)
    
    (map-set creators tx-sender {
      name: name,
      bio: bio,
      total-received: u0,
      tip-count: u0,
      registered-at: stacks-block-height
    })
    
    (var-set total-creators (+ (var-get total-creators) u1))
    
    (ok { creator: tx-sender, registered: true })
  )
)

;; Update creator profile
(define-public (update-profile (name (string-utf8 64)) (bio (string-utf8 256)))
  (match (map-get? creators tx-sender)
    creator
    (begin
      (map-set creators tx-sender 
        (merge creator { name: name, bio: bio })
      )
      (ok true)
    )
    err-creator-not-found
  )
)

;; Send a tip (accounting only - STX goes to treasury)
(define-public (send-tip (creator principal) (amount uint) (message (optional (string-utf8 128))))
  (let (
    (tip-id (var-get tip-nonce))
    (is-new-supporter (not (default-to false (map-get? supporter-creator { supporter: tx-sender, creator: creator }))))
    (tipper-stat (get-tipper-stats tx-sender))
    (is-first-tip (is-eq (get tip-count tipper-stat) u0))
  )
    (asserts! (> amount u0) err-invalid-amount)
    (asserts! (is-creator-registered creator) err-creator-not-found)
    
    ;; Record tip
    (map-set tips tip-id {
      from: tx-sender,
      to: creator,
      amount: amount,
      message: message,
      block: stacks-block-height
    })
    
    ;; Update creator stats
    (match (map-get? creators creator)
      c
      (map-set creators creator 
        (merge c {
          total-received: (+ (get total-received c) amount),
          tip-count: (+ (get tip-count c) u1)
        })
      )
      false
    )
    
    ;; Update tipper stats
    (map-set tipper-stats tx-sender {
      total-tipped: (+ (get total-tipped tipper-stat) amount),
      tip-count: (+ (get tip-count tipper-stat) u1),
      creators-supported: (if is-new-supporter 
                           (+ (get creators-supported tipper-stat) u1)
                           (get creators-supported tipper-stat))
    })
    
    ;; Mark supporter-creator relationship
    (if is-new-supporter
      (map-set supporter-creator { supporter: tx-sender, creator: creator } true)
      false
    )
    
    ;; Update globals
    (var-set tip-nonce (+ tip-id u1))
    (var-set total-tips (+ (var-get total-tips) amount))
    (if is-first-tip
      (var-set total-tippers (+ (var-get total-tippers) u1))
      false
    )
    
    (ok { tip-id: tip-id, amount: amount, to: creator })
  )
)

;; Get recent tips for a creator
(define-read-only (get-creator-tip-count (creator principal))
  (match (map-get? creators creator)
    c (get tip-count c)
    u0
  )
)

Functions (9)

FunctionAccessArgs
get-creatorread-onlycreator: principal
get-tipread-onlytip-id: uint
get-tipper-statsread-onlytipper: principal
is-creator-registeredread-onlycreator: principal
get-platform-statsread-only
register-creatorpublicname: (string-utf8 64
update-profilepublicname: (string-utf8 64
send-tippubliccreator: principal, amount: uint, message: (optional (string-utf8 128
get-creator-tip-countread-onlycreator: principal