Source Code

;; FROG Social Feed v1 (Hybrid)
;; - Publish post costs 50 FROG
;; - Like post costs 5 FROG
;; - On-chain stores content-hash only

(define-constant contract-owner tx-sender)

(define-constant err-not-owner (err u400))
(define-constant err-invalid-post (err u401))
(define-constant err-post-not-found (err u404))
(define-constant err-already-liked (err u405))
(define-constant err-cannot-like-own-post (err u406))
(define-constant err-invalid-fee (err u407))

(define-data-var treasury principal tx-sender)
(define-data-var post-fee uint u50)
(define-data-var like-fee uint u5)
(define-data-var last-post-id uint u0)

(define-constant reputation-publish-points u10)
(define-constant reputation-like-received-points u2)

(define-map author-reputation
  {author: principal}
  {points: uint}
)

(define-map posts
  {post-id: uint}
  {
    author: principal,
    content-hash: (string-ascii 64),
    created-at: uint,
    like-count: uint
  }
)

(define-map likes
  {post-id: uint, liker: principal}
  {liked: bool}
)

(define-private (is-owner)
  (is-eq tx-sender contract-owner))

(define-private (charge-fee (amount uint) (payer principal))
  (contract-call? .frog-token-v3 transfer amount payer (var-get treasury) none))

(define-private (read-reputation (who principal))
  (get points (default-to {points: u0} (map-get? author-reputation {author: who}))))

(define-private (add-reputation (who principal) (delta uint))
  (let ((current (read-reputation who)))
    (map-set author-reputation {author: who} {points: (+ current delta)})))

(define-read-only (get-social-config)
  (ok {
    treasury: (var-get treasury),
    post-fee: (var-get post-fee),
    like-fee: (var-get like-fee),
    last-post-id: (var-get last-post-id)
  }))

(define-read-only (get-post (post-id uint))
  (ok (map-get? posts {post-id: post-id})))

(define-read-only (get-author-reputation (who principal))
  (ok (read-reputation who)))

(define-read-only (has-liked (post-id uint) (who principal))
  (is-some (map-get? likes {post-id: post-id, liker: who})))

(define-read-only (get-frog-balance (who principal))
  (unwrap-panic (contract-call? .frog-token-v3 get-balance who)))

(define-public (publish-post (content-hash (string-ascii 64)))
  (let (
      (hash-len (len content-hash))
      (next-id (+ (var-get last-post-id) u1))
    )
    (asserts! (> hash-len u0) err-invalid-post)
    (try! (charge-fee (var-get post-fee) tx-sender))
    (map-set posts
      {post-id: next-id}
      {
        author: tx-sender,
        content-hash: content-hash,
        created-at: stacks-block-height,
        like-count: u0
      })
    (add-reputation tx-sender reputation-publish-points)
    (var-set last-post-id next-id)
    (ok next-id)))

(define-public (like-post (post-id uint))
  (match (map-get? posts {post-id: post-id})
    post
      (begin
        (asserts! (not (is-eq tx-sender (get author post))) err-cannot-like-own-post)
        (asserts! (not (is-some (map-get? likes {post-id: post-id, liker: tx-sender}))) err-already-liked)

        (try! (charge-fee (var-get like-fee) tx-sender))

        (map-set likes {post-id: post-id, liker: tx-sender} {liked: true})
        (map-set posts
          {post-id: post-id}
          {
            author: (get author post),
            content-hash: (get content-hash post),
            created-at: (get created-at post),
            like-count: (+ (get like-count post) u1)
          })
        (add-reputation (get author post) reputation-like-received-points)
        (ok (+ (get like-count post) u1)))
    err-post-not-found))

(define-public (set-post-fee (amount uint))
  (begin
    (asserts! (is-owner) err-not-owner)
    (asserts! (> amount u0) err-invalid-fee)
    (var-set post-fee amount)
    (ok amount)))

(define-public (set-like-fee (amount uint))
  (begin
    (asserts! (is-owner) err-not-owner)
    (asserts! (> amount u0) err-invalid-fee)
    (var-set like-fee amount)
    (ok amount)))

(define-public (set-treasury (next principal))
  (begin
    (asserts! (is-owner) err-not-owner)
    (var-set treasury next)
    (ok next)))

Functions (14)

FunctionAccessArgs
is-ownerprivate
charge-feeprivateamount: uint, payer: principal
read-reputationprivatewho: principal
add-reputationprivatewho: principal, delta: uint
get-social-configread-only
get-postread-onlypost-id: uint
get-author-reputationread-onlywho: principal
has-likedread-onlypost-id: uint, who: principal
get-frog-balanceread-onlywho: principal
publish-postpubliccontent-hash: (string-ascii 64
like-postpublicpost-id: uint
set-post-feepublicamount: uint
set-like-feepublicamount: uint
set-treasurypublicnext: principal