;; Define constants
(define-constant PROTOCOL_ADMINISTRATOR tx-sender)
(define-constant ERR_UNAUTHORIZED_ACCESS (err u100))
(define-constant ERR_INVALID_SUBMISSION (err u101))
(define-constant ERR_DUPLICATE_ENTRY (err u102))
(define-constant ERR_NONEXISTENT_ITEM (err u103))
(define-constant ERR_INADEQUATE_BALANCE (err u104))
(define-constant ERR_INVALID_TOPIC (err u105))
(define-constant ERR_INVALID_FLAG (err u106))
(define-constant ERR_OVERFLOW (err u107))
(define-constant ERR_INVALID_APPRAISAL (err u108))
(define-constant ERR_INVALID_ITEM_ID (err u109))
(define-constant MIN_HYPERLINK_LENGTH u10)
(define-constant MAX_UINT u340282366920938463463374607431768211455)
;; Define data variables
(define-data-var submission-charge uint u10)
(define-data-var aggregate-submissions uint u0)
(define-data-var content-topics (list 10 (string-ascii 20)) (list "Technology" "Science" "Art" "Politics" "Sports"))
;; Define data maps
(define-map curated-items
{ item-identifier: uint }
{
originator: principal,
headline: (string-ascii 100),
hyperlink: (string-ascii 200),
topic: (string-ascii 20),
publication-epoch: uint,
appraisals: int,
gratuities: uint,
flags: uint
}
)
(define-map participant-appraisals
{ participant: principal, item-identifier: uint }
{ appraisal: int }
)
(define-map participant-credibility
{ participant: principal }
{ metric: int }
)
;; Helper function to check if an item exists
(define-private (item-exists (item-identifier uint))
(is-some (map-get? curated-items { item-identifier: item-identifier }))
)
;; Public functions
;; Submit new content for curation
(define-public (contribute-item (headline (string-ascii 100)) (hyperlink (string-ascii 200)) (topic (string-ascii 20)))
(let
(
(item-identifier (+ (var-get aggregate-submissions) u1))
)
(asserts! (and
(>= (len headline) u1)
(>= (len hyperlink) MIN_HYPERLINK_LENGTH)
(>= (len topic) u1)
) ERR_INVALID_SUBMISSION)
(asserts! (> item-identifier (var-get aggregate-submissions)) ERR_OVERFLOW)
(asserts! (is-some (index-of (var-get content-topics) topic)) ERR_INVALID_TOPIC)
(asserts! (>= (stx-get-balance tx-sender) (var-get submission-charge)) ERR_INADEQUATE_BALANCE)
(try! (stx-transfer? (var-get submission-charge) tx-sender PROTOCOL_ADMINISTRATOR))
(map-set curated-items
{ item-identifier: item-identifier }
{
originator: tx-sender,
headline: headline,
hyperlink: hyperlink,
topic: topic,
publication-epoch: stacks-block-height,
appraisals: 0,
gratuities: u0,
flags: u0
}
)
(var-set aggregate-submissions item-identifier)
(print { type: "new-item", item-identifier: item-identifier, originator: tx-sender })
(ok item-identifier)
)
)
;; Vote on curated content
(define-public (appraise-item (item-identifier uint) (appraisal int))
(let
(
(previous-appraisal (default-to 0 (get appraisal (map-get? participant-appraisals { participant: tx-sender, item-identifier: item-identifier }))))
(target-item (unwrap! (map-get? curated-items { item-identifier: item-identifier }) ERR_NONEXISTENT_ITEM))
(appraiser-standing (default-to { metric: 0 } (map-get? participant-credibility { participant: tx-sender })))
)
(asserts! (item-exists item-identifier) ERR_NONEXISTENT_ITEM)
(asserts! (or (is-eq appraisal 1) (is-eq appraisal -1)) ERR_INVALID_APPRAISAL)
(map-set participant-appraisals
{ participant: tx-sender, item-identifier: item-identifier }
{ appraisal: appraisal }
)
(map-set curated-items
{ item-identifier: item-identifier }
(merge target-item { appraisals: (+ (get appraisals target-item) (- appraisal previous-appraisal)) })
)
(map-set participant-credibility
{ participant: tx-sender }
{ metric: (+ (get metric appraiser-standing) appraisal) }
)
(print { type: "appraisal", item-identifier: item-identifier, appraiser: tx-sender, appraisal: appraisal })
(ok true)
)
)
;; Tip content creator
(define-public (reward-originator (item-identifier uint) (gratuity-amount uint))
(let
(
(target-item (unwrap! (map-get? curated-items { item-identifier: item-identifier }) ERR_NONEXISTENT_ITEM))
)
(asserts! (item-exists item-identifier) ERR_NONEXISTENT_ITEM)
(asserts! (>= (stx-get-balance tx-sender) gratuity-amount) ERR_INADEQUATE_BALANCE)
;; Update state before transfer
(map-set curated-items
{ item-identifier: item-identifier }
(merge target-item { gratuities: (+ (get gratuities target-item) gratuity-amount) })
)
;; Perform transfer last
(try! (stx-transfer? gratuity-amount tx-sender (get originator target-item)))
(print { type: "reward", item-identifier: item-identifier, from: tx-sender, to: (get originator target-item), amount: gratuity-amount })
(ok true)
)
)
;; Report content
(define-public (flag-item (item-identifier uint))
(let
(
(target-item (unwrap! (map-get? curated-items { item-identifier: item-identifier }) ERR_NONEXISTENT_ITEM))
)
(asserts! (item-exists item-identifier) ERR_NONEXISTENT_ITEM)
(asserts! (not (is-eq (get originator target-item) tx-sender)) ERR_INVALID_FLAG)
(map-set curated-items
{ item-identifier: item-identifier }
(merge target-item { flags: (+ (get flags target-item) u1) })
)
(print { type: "flag", item-identifier: item-identifier, flagger: tx-sender })
(ok true)
)
)
;; Get content details
(define-read-only (retrieve-item-details (item-identifier uint))
(map-get? curated-items { item-identifier: item-identifier })
)
;; Get user's vote on a specific content
(define-read-only (retrieve-participant-appraisal (participant principal) (item-identifier uint))
(get appraisal (map-get? participant-appraisals { participant: participant, item-identifier: item-identifier }))
)
;; Get total number of curated content
(define-read-only (retrieve-aggregate-submissions)
(var-get aggregate-submissions)
)
;; Get user reputation
(define-read-only (retrieve-participant-credibility (participant principal))
(default-to { metric: 0 } (map-get? participant-credibility { participant: participant }))
)
;; Get top content (limited by number of items)
(define-read-only (retrieve-top-items (limit uint))
(let
(
(item-count (var-get aggregate-submissions))
(actual-limit (if (> limit item-count) item-count limit))
)
(filter not-none
(map retrieve-item-if-valid (get-item-ids actual-limit))
)
)
)
(define-private (not-none (item (optional {
originator: principal,
headline: (string-ascii 100),
hyperlink: (string-ascii 200),
topic: (string-ascii 20),
publication-epoch: uint,
appraisals: int,
gratuities: uint,
flags: uint
})))
(is-some item)
)
(define-private (retrieve-item-if-valid (id uint))
(match (map-get? curated-items { item-identifier: id })
item (if (>= (get appraisals item) 0) (some item) none)
none
)
)
;; Updated get-item-ids function
(define-read-only (get-item-ids (count uint))
(filter is-non-zero (enumerate count))
)
;; Updated enumerate function
(define-private (enumerate (n uint))
(let ((limit (if (> n u10) u10 n)))
(list
(if (>= limit u1) u1 u0)
(if (>= limit u2) u2 u0)
(if (>= limit u3) u3 u0)
(if (>= limit u4) u4 u0)
(if (>= limit u5) u5 u0)
(if (>= limit u6) u6 u0)
(if (>= limit u7) u7 u0)
(if (>= limit u8) u8 u0)
(if (>= limit u9) u9 u0)
(if (>= limit u10) u10 u0)
)
)
)
;; Helper function to filter out zero values
(define-private (is-non-zero (n uint))
(not (is-eq n u0))
)
;; Admin functions
;; Set curation fee
(define-public (adjust-submission-charge (new-charge uint))
(begin
(asserts! (is-eq tx-sender PROTOCOL_ADMINISTRATOR) ERR_UNAUTHORIZED_ACCESS)
(asserts! (<= new-charge MAX_UINT) ERR_OVERFLOW)
(var-set submission-charge new-charge)
(print { type: "fee-change", new-charge: new-charge })
(ok true)
)
)
;; Remove content (only by contract owner)
(define-public (expunge-item (item-identifier uint))
(begin
(asserts! (is-eq tx-sender PROTOCOL_ADMINISTRATOR) ERR_UNAUTHORIZED_ACCESS)
(asserts! (item-exists item-identifier) ERR_NONEXISTENT_ITEM)
(map-delete curated-items { item-identifier: item-identifier })
(print { type: "item-expunged", item-identifier: item-identifier })
(ok true)
)
)
;; Add new category
(define-public (introduce-topic (new-topic (string-ascii 20)))
(begin
(asserts! (is-eq tx-sender PROTOCOL_ADMINISTRATOR) ERR_UNAUTHORIZED_ACCESS)
(asserts! (< (len (var-get content-topics)) u10) ERR_INVALID_TOPIC)
(asserts! (>= (len new-topic) u1) ERR_INVALID_TOPIC)
(var-set content-topics (unwrap-panic (as-max-len? (append (var-get content-topics) new-topic) u10)))
(print { type: "new-topic", topic: new-topic })
(ok true)
)
)