Source Code

;; Crowdfund Analytics Contract
;; On-chain analytics for crowdfund platform
;; Tracks campaigns, success rates, and backer stats

(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u500))
(define-constant err-not-authorized (err u501))

(define-data-var total-campaigns uint u0)
(define-data-var successful-campaigns uint u0)
(define-data-var failed-campaigns uint u0)
(define-data-var total-raised uint u0)
(define-data-var total-backers uint u0)
(define-data-var total-contributions uint u0)

(define-map authorized-reporters principal bool)

;; Category stats
(define-map category-stats (string-ascii 30)
  {
    campaign-count: uint,
    successful: uint,
    total-raised: uint,
    avg-goal: uint
  }
)

;; Monthly stats
(define-map monthly-stats uint
  {
    month-block: uint,
    new-campaigns: uint,
    successful: uint,
    total-raised: uint,
    new-backers: uint,
    avg-contribution: uint
  }
)

(define-data-var month-count uint u0)

;; Backer stats
(define-map backer-stats principal
  {
    campaigns-backed: uint,
    total-contributed: uint,
    successful-exits: uint,
    refunds-received: uint,
    first-backed: uint,
    last-backed: uint
  }
)

;; Read-only
(define-read-only (get-platform-stats)
  {
    total-campaigns: (var-get total-campaigns),
    successful: (var-get successful-campaigns),
    failed: (var-get failed-campaigns),
    total-raised: (var-get total-raised),
    total-backers: (var-get total-backers),
    success-rate-bps: (if (> (var-get total-campaigns) u0)
      (/ (* (var-get successful-campaigns) u10000) (var-get total-campaigns))
      u0)
  }
)

(define-read-only (get-category-stats (category (string-ascii 30)))
  (map-get? category-stats category)
)

(define-read-only (get-backer-stats (backer principal))
  (map-get? backer-stats backer)
)

(define-read-only (get-monthly-stats (month-id uint))
  (map-get? monthly-stats month-id)
)

(define-read-only (is-reporter (r principal))
  (default-to false (map-get? authorized-reporters r))
)

;; Public functions
(define-public (add-reporter (reporter principal))
  (begin
    (asserts! (is-eq tx-sender contract-owner) err-owner-only)
    (map-set authorized-reporters reporter true)
    (ok reporter)
  )
)

(define-public (record-campaign-created (category (string-ascii 30)) (goal uint))
  (begin
    (asserts! (is-reporter tx-sender) err-not-authorized)
    (var-set total-campaigns (+ (var-get total-campaigns) u1))

    (match (map-get? category-stats category)
      stats
      (map-set category-stats category (merge stats {
        campaign-count: (+ (get campaign-count stats) u1),
        avg-goal: (/ (+ (* (get avg-goal stats) (get campaign-count stats)) goal) (+ (get campaign-count stats) u1))
      }))
      (map-set category-stats category {
        campaign-count: u1, successful: u0, total-raised: u0, avg-goal: goal
      })
    )
    (ok { total: (var-get total-campaigns) })
  )
)

(define-public (record-campaign-result
    (category (string-ascii 30))
    (raised uint)
    (succeeded bool)
    (backer-count uint))
  (begin
    (asserts! (is-reporter tx-sender) err-not-authorized)

    (if succeeded
      (var-set successful-campaigns (+ (var-get successful-campaigns) u1))
      (var-set failed-campaigns (+ (var-get failed-campaigns) u1))
    )

    (var-set total-raised (+ (var-get total-raised) raised))

    (match (map-get? category-stats category)
      stats
      (map-set category-stats category (merge stats {
        successful: (if succeeded (+ (get successful stats) u1) (get successful stats)),
        total-raised: (+ (get total-raised stats) raised)
      }))
      false
    )
    (ok { succeeded: succeeded, raised: raised })
  )
)

(define-public (record-contribution (backer principal) (amount uint) (is-new-backer bool))
  (begin
    (asserts! (is-reporter tx-sender) err-not-authorized)

    (if is-new-backer (var-set total-backers (+ (var-get total-backers) u1)) false)
    (var-set total-contributions (+ (var-get total-contributions) amount))

    (match (map-get? backer-stats backer)
      stats
      (map-set backer-stats backer (merge stats {
        campaigns-backed: (+ (get campaigns-backed stats) u1),
        total-contributed: (+ (get total-contributed stats) amount),
        last-backed: stacks-block-height
      }))
      (map-set backer-stats backer {
        campaigns-backed: u1,
        total-contributed: amount,
        successful-exits: u0,
        refunds-received: u0,
        first-backed: stacks-block-height,
        last-backed: stacks-block-height
      })
    )
    (ok { backer: backer, amount: amount })
  )
)

(define-public (record-monthly-snapshot
    (new-campaigns uint)
    (successful uint)
    (raised uint)
    (new-backers uint)
    (avg-contribution uint))
  (let ((month-id (var-get month-count)))
    (asserts! (is-reporter tx-sender) err-not-authorized)
    (map-set monthly-stats month-id {
      month-block: stacks-block-height,
      new-campaigns: new-campaigns,
      successful: successful,
      total-raised: raised,
      new-backers: new-backers,
      avg-contribution: avg-contribution
    })
    (var-set month-count (+ month-id u1))
    (ok month-id)
  )
)

Functions (10)

FunctionAccessArgs
get-platform-statsread-only
get-category-statsread-onlycategory: (string-ascii 30
get-backer-statsread-onlybacker: principal
get-monthly-statsread-onlymonth-id: uint
is-reporterread-onlyr: principal
add-reporterpublicreporter: principal
record-campaign-createdpubliccategory: (string-ascii 30
record-campaign-resultpubliccategory: (string-ascii 30
record-contributionpublicbacker: principal, amount: uint, is-new-backer: bool
record-monthly-snapshotpublicnew-campaigns: uint, successful: uint, raised: uint, new-backers: uint, avg-contribution: uint