Source Code

;; Achievement Badge System Contract
;; Award and track user achievements

(define-constant contract-owner tx-sender)
(define-constant err-not-authorized (err u100))
(define-constant err-already-earned (err u101))
(define-constant err-badge-not-found (err u102))

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

(define-map badges
    uint
    {
        name: (string-ascii 50),
        description: (string-utf8 200),
        image-uri: (string-ascii 200),
        creator: principal,
        total-awarded: uint,
        active: bool
    }
)

(define-map user-badges {user: principal, badge-id: uint} uint) ;; timestamp
(define-map user-badge-count principal uint)

(define-public (create-badge
    (name (string-ascii 50))
    (description (string-utf8 200))
    (image-uri (string-ascii 200)))
    (let ((badge-id (var-get badge-nonce)))
        (map-set badges badge-id {
            name: name,
            description: description,
            image-uri: image-uri,
            creator: tx-sender,
            total-awarded: u0,
            active: true
        })
        (var-set badge-nonce (+ badge-id u1))
        (ok badge-id)
    )
)

(define-public (award-badge (user principal) (badge-id uint))
    (let
        (
            (badge (unwrap! (map-get? badges badge-id) err-badge-not-found))
            (badge-key {user: user, badge-id: badge-id})
        )
        (asserts! (is-eq tx-sender (get creator badge)) err-not-authorized)
        (asserts! (get active badge) err-badge-not-found)
        (asserts! (is-none (map-get? user-badges badge-key)) err-already-earned)
        
        (map-set user-badges badge-key block-height)
        (map-set user-badge-count user 
            (+ u1 (default-to u0 (map-get? user-badge-count user))))
        (map-set badges badge-id (merge badge {
            total-awarded: (+ (get total-awarded badge) u1)
        }))
        (ok true)
    )
)

(define-public (revoke-badge (user principal) (badge-id uint))
    (let
        (
            (badge (unwrap! (map-get? badges badge-id) err-badge-not-found))
            (badge-key {user: user, badge-id: badge-id})
        )
        (asserts! (is-eq tx-sender (get creator badge)) err-not-authorized)
        (asserts! (is-some (map-get? user-badges badge-key)) err-badge-not-found)
        
        (map-delete user-badges badge-key)
        (map-set user-badge-count user
            (- (default-to u1 (map-get? user-badge-count user)) u1))
        (ok true)
    )
)

(define-public (deactivate-badge (badge-id uint))
    (let ((badge (unwrap! (map-get? badges badge-id) err-badge-not-found)))
        (asserts! (is-eq tx-sender (get creator badge)) err-not-authorized)
        (map-set badges badge-id (merge badge {active: false}))
        (ok true)
    )
)

(define-read-only (get-badge (badge-id uint))
    (map-get? badges badge-id)
)

(define-read-only (has-badge (user principal) (badge-id uint))
    (is-some (map-get? user-badges {user: user, badge-id: badge-id}))
)

(define-read-only (get-user-badge-count (user principal))
    (default-to u0 (map-get? user-badge-count user))
)

(define-read-only (get-badge-earned-block (user principal) (badge-id uint))
    (map-get? user-badges {user: user, badge-id: badge-id})
)

Functions (8)

FunctionAccessArgs
create-badgepublicname: (string-ascii 50
award-badgepublicuser: principal, badge-id: uint
revoke-badgepublicuser: principal, badge-id: uint
deactivate-badgepublicbadge-id: uint
get-badgeread-onlybadge-id: uint
has-badgeread-onlyuser: principal, badge-id: uint
get-user-badge-countread-onlyuser: principal
get-badge-earned-blockread-onlyuser: principal, badge-id: uint