Source Code

;; StackStream Creator Registry Contract
;; Manages creator profiles, verification status, and content metadata

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-already-exists (err u102))
(define-constant err-insufficient-funds (err u103))
(define-constant err-unauthorized (err u104))
(define-constant err-invalid-input (err u105))

;; Registration and fee constants
(define-constant registration-fee u5000000) ;; 5 STX in microSTX
(define-constant update-fee u500000) ;; 0.5 STX in microSTX
(define-constant verification-stake u10000000) ;; 10 STX in microSTX
(define-constant platform-fee-percent u50) ;; 0.5% = 50/10000

;; Data Variables
(define-data-var total-creators uint u0)
(define-data-var last-badge-id uint u0)
(define-data-var platform-treasury principal contract-owner)

;; Data Maps
(define-map creators 
    principal 
    {
        username: (string-ascii 50),
        bio: (string-utf8 500),
        profile-image-url: (string-utf8 256),
        is-verified: bool,
        reputation-score: uint,
        total-content: uint,
        total-revenue: uint,
        registered-at: uint,
        verification-stake: uint
    }
)

(define-map creator-usernames (string-ascii 50) principal)

(define-map creator-badges 
    uint 
    {
        creator: principal,
        badge-type: (string-ascii 20),
        issued-at: uint
    }
)

(define-map content-metadata
    {creator: principal, content-id: uint}
    {
        title: (string-utf8 200),
        description: (string-utf8 1000),
        content-hash: (buff 32),
        price: uint,
        access-count: uint,
        revenue: uint,
        created-at: uint,
        is-active: bool
    }
)

(define-map creator-content-count principal uint)

;; SIP-009 NFT Trait for Creator Badges
(define-non-fungible-token creator-badge uint)

;; Private Functions

(define-private (calculate-platform-fee (amount uint))
    (/ (* amount platform-fee-percent) u10000)
)

(define-private (validate-username (username (string-ascii 50)))
    (let ((username-len (len username)))
        (and (>= username-len u3) (<= username-len u50))
    )
)

(define-private (increment-reputation (creator principal) (points uint))
    (match (map-get? creators creator)
        creator-data 
            (map-set creators creator 
                (merge creator-data {reputation-score: (+ (get reputation-score creator-data) points)})
            )
        false
    )
)

;; Public Functions

;; Register as a creator
(define-public (register-creator (username (string-ascii 50)) 
                                 (bio (string-utf8 500)) 
                                 (profile-image-url (string-utf8 256)))
    (let (
        (caller tx-sender)
        (platform-fee (calculate-platform-fee registration-fee))
    )
        ;; Validate input
        (asserts! (validate-username username) err-invalid-input)
        (asserts! (is-none (map-get? creators caller)) err-already-exists)
        (asserts! (is-none (map-get? creator-usernames username)) err-already-exists)
        
        ;; Transfer registration fee
        (try! (stx-transfer? registration-fee caller (var-get platform-treasury)))
        
        ;; Create creator profile
        (map-set creators caller {
            username: username,
            bio: bio,
            profile-image-url: profile-image-url,
            is-verified: false,
            reputation-score: u100, ;; Starting reputation
            total-content: u0,
            total-revenue: u0,
            registered-at: stacks-block-height,
            verification-stake: u0
        })
        
        ;; Map username to creator
        (map-set creator-usernames username caller)
        
        ;; Initialize content count
        (map-set creator-content-count caller u0)
        
        ;; Increment total creators
        (var-set total-creators (+ (var-get total-creators) u1))
        
        (ok true)
    )
)

;; Update creator profile metadata
(define-public (update-profile (bio (string-utf8 500)) (profile-image-url (string-utf8 256)))
    (let (
        (caller tx-sender)
        (creator-data (unwrap! (map-get? creators caller) err-not-found))
    )
        ;; Transfer update fee
        (try! (stx-transfer? update-fee caller (var-get platform-treasury)))
        
        ;; Update profile using replace-at pattern
        (map-set creators caller 
            (merge creator-data {
                bio: bio,
                profile-image-url: profile-image-url
            })
        )
        
        (ok true)
    )
)

;; Verify identity by staking tokens
(define-public (verify-identity)
    (let (
        (caller tx-sender)
        (creator-data (unwrap! (map-get? creators caller) err-not-found))
    )
        ;; Check if already verified
        (asserts! (not (get is-verified creator-data)) err-already-exists)
        
        ;; Transfer verification stake to platform treasury (held for verification)
        (try! (stx-transfer? verification-stake caller (var-get platform-treasury)))
        
        ;; Update verification status
        (map-set creators caller 
            (merge creator-data {
                is-verified: true,
                verification-stake: verification-stake,
                reputation-score: (+ (get reputation-score creator-data) u500) ;; Bonus reputation
            })
        )
        
        ;; Mint creator badge NFT
        (let ((badge-id (+ (var-get last-badge-id) u1)))
            (try! (nft-mint? creator-badge badge-id caller))
            (map-set creator-badges badge-id {
                creator: caller,
                badge-type: "VERIFIED",
                issued-at: stacks-block-height
            })
            (var-set last-badge-id badge-id)
        )
        
        (ok true)
    )
)

;; Unverify and refund stake (admin only for now, can be extended)
(define-public (refund-verification-stake)
    (let (
        (caller tx-sender)
        (creator-data (unwrap! (map-get? creators caller) err-not-found))
        (stake-amount (get verification-stake creator-data))
    )
        ;; Check if verified
        (asserts! (get is-verified creator-data) err-unauthorized)
        (asserts! (> stake-amount u0) err-insufficient-funds)
        
        ;; Refund stake from platform treasury
        (try! (stx-transfer? stake-amount (var-get platform-treasury) caller))
        
        ;; Update verification status
        (map-set creators caller 
            (merge creator-data {
                is-verified: false,
                verification-stake: u0
            })
        )
        
        (ok true)
    )
)

;; Add content metadata
(define-public (add-content (title (string-utf8 200))
                           (description (string-utf8 1000))
                           (content-hash (buff 32))
                           (price uint))
    (let (
        (caller tx-sender)
        (creator-data (unwrap! (map-get? creators caller) err-not-found))
        (current-count (default-to u0 (map-get? creator-content-count caller)))
        (content-id (+ current-count u1))
    )
        ;; Validate price
        (asserts! (> price u0) err-invalid-input)
        
        ;; Store content metadata
        (map-set content-metadata {creator: caller, content-id: content-id} {
            title: title,
            description: description,
            content-hash: content-hash,
            price: price,
            access-count: u0,
            revenue: u0,
            created-at: stacks-block-height,
            is-active: true
        })
        
        ;; Update counts
        (map-set creator-content-count caller content-id)
        (map-set creators caller 
            (merge creator-data {
                total-content: (+ (get total-content creator-data) u1)
            })
        )
        
        ;; Add reputation for content creation
        (increment-reputation caller u10)
        
        (ok content-id)
    )
)

;; Update content status (active/inactive)
(define-public (toggle-content-status (content-id uint))
    (let (
        (caller tx-sender)
        (content-key {creator: caller, content-id: content-id})
        (content-data (unwrap! (map-get? content-metadata content-key) err-not-found))
    )
        (map-set content-metadata content-key
            (merge content-data {
                is-active: (not (get is-active content-data))
            })
        )
        (ok true)
    )
)

;; Record content access (called by payment contracts)
(define-public (record-content-access (creator principal) (content-id uint) (revenue-amount uint))
    (let (
        (content-key {creator: creator, content-id: content-id})
        (content-data (unwrap! (map-get? content-metadata content-key) err-not-found))
        (creator-data (unwrap! (map-get? creators creator) err-not-found))
    )
        ;; Update content metrics
        (map-set content-metadata content-key
            (merge content-data {
                access-count: (+ (get access-count content-data) u1),
                revenue: (+ (get revenue content-data) revenue-amount)
            })
        )
        
        ;; Update creator revenue
        (map-set creators creator
            (merge creator-data {
                total-revenue: (+ (get total-revenue creator-data) revenue-amount)
            })
        )
        
        ;; Add reputation for successful sale
        (increment-reputation creator u5)
        
        (ok true)
    )
)

;; Read-only Functions

(define-read-only (get-creator (creator principal))
    (ok (map-get? creators creator))
)

(define-read-only (get-creator-by-username (username (string-ascii 50)))
    (match (map-get? creator-usernames username)
        creator-principal (ok (map-get? creators creator-principal))
        (ok none)
    )
)

(define-read-only (get-content-metadata (creator principal) (content-id uint))
    (ok (map-get? content-metadata {creator: creator, content-id: content-id}))
)

(define-read-only (get-creator-content-count (creator principal))
    (ok (default-to u0 (map-get? creator-content-count creator)))
)

(define-read-only (get-total-creators)
    (ok (var-get total-creators))
)

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

(define-read-only (get-badge-owner (badge-id uint))
    (ok (nft-get-owner? creator-badge badge-id))
)

;; Admin Functions

(define-public (set-platform-treasury (new-treasury principal))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (var-set platform-treasury new-treasury)
        (ok true)
    )
)

(define-public (adjust-creator-reputation (creator principal) (new-score uint))
    (let (
        (creator-data (unwrap! (map-get? creators creator) err-not-found))
    )
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (map-set creators creator 
            (merge creator-data {reputation-score: new-score})
        )
        (ok true)
    )
)

Functions (19)

FunctionAccessArgs
register-creatorpublicusername: (string-ascii 50
calculate-platform-feeprivateamount: uint
validate-usernameprivateusername: (string-ascii 50
increment-reputationprivatecreator: principal, points: uint
update-profilepublicbio: (string-utf8 500
verify-identitypublic
refund-verification-stakepublic
add-contentpublictitle: (string-utf8 200
toggle-content-statuspubliccontent-id: uint
record-content-accesspubliccreator: principal, content-id: uint, revenue-amount: uint
get-creatorread-onlycreator: principal
get-creator-by-usernameread-onlyusername: (string-ascii 50
get-content-metadataread-onlycreator: principal, content-id: uint
get-creator-content-countread-onlycreator: principal
get-total-creatorsread-only
get-creator-badgeread-onlybadge-id: uint
get-badge-ownerread-onlybadge-id: uint
set-platform-treasurypublicnew-treasury: principal
adjust-creator-reputationpubliccreator: principal, new-score: uint