Source Code

;; Decentralized Publishing Contract
;; Publish and monetize content on-chain

(define-constant err-not-author (err u100))
(define-constant err-post-not-found (err u101))
(define-constant err-insufficient-payment (err u102))

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

(define-map posts
    uint
    {
        author: principal,
        title: (string-utf8 200),
        content-hash: (buff 32),
        timestamp: uint,
        paywall-amount: uint,
        earnings: uint,
        likes: uint
    }
)

(define-map post-access {post-id: uint, reader: principal} bool)
(define-map author-followers {author: principal, follower: principal} bool)

(define-public (publish-post
    (title (string-utf8 200))
    (content-hash (buff 32))
    (paywall-amount uint))
    (let ((post-id (var-get post-nonce)))
        (map-set posts post-id {
            author: tx-sender,
            title: title,
            content-hash: content-hash,
            timestamp: block-height,
            paywall-amount: paywall-amount,
            earnings: u0,
            likes: u0
        })
        (var-set post-nonce (+ post-id u1))
        (ok post-id)
    )
)

(define-public (purchase-access (post-id uint))
    (let
        (
            (post (unwrap! (map-get? posts post-id) err-post-not-found))
            (access-key {post-id: post-id, reader: tx-sender})
        )
        (asserts! (> (get paywall-amount post) u0) err-insufficient-payment)
        
        (try! (stx-transfer? (get paywall-amount post) tx-sender (get author post)))
        
        (map-set posts post-id (merge post {
            earnings: (+ (get earnings post) (get paywall-amount post))
        }))
        (map-set post-access access-key true)
        (ok true)
    )
)

(define-public (like-post (post-id uint))
    (let ((post (unwrap! (map-get? posts post-id) err-post-not-found)))
        (map-set posts post-id (merge post {
            likes: (+ (get likes post) u1)
        }))
        (ok true)
    )
)

(define-public (follow-author (author principal))
    (begin
        (map-set author-followers {author: author, follower: tx-sender} true)
        (ok true)
    )
)

(define-public (update-post-paywall (post-id uint) (new-amount uint))
    (let ((post (unwrap! (map-get? posts post-id) err-post-not-found)))
        (asserts! (is-eq tx-sender (get author post)) err-not-author)
        (map-set posts post-id (merge post {
            paywall-amount: new-amount
        }))
        (ok true)
    )
)

(define-read-only (get-post (post-id uint))
    (map-get? posts post-id)
)

(define-read-only (has-access (post-id uint) (reader principal))
    (match (map-get? posts post-id)
        post (or 
                (is-eq reader (get author post))
                (is-eq (get paywall-amount post) u0)
                (default-to false (map-get? post-access {post-id: post-id, reader: reader})))
        false
    )
)

(define-read-only (is-following (author principal) (follower principal))
    (default-to false (map-get? author-followers {author: author, follower: follower}))
)

Functions (8)

FunctionAccessArgs
publish-postpublictitle: (string-utf8 200
purchase-accesspublicpost-id: uint
like-postpublicpost-id: uint
follow-authorpublicauthor: principal
update-post-paywallpublicpost-id: uint, new-amount: uint
get-postread-onlypost-id: uint
has-accessread-onlypost-id: uint, reader: principal
is-followingread-onlyauthor: principal, follower: principal