Decentralized Patreon Alternative

What it does:
Enables fans to support creators through recurring on-chain subscriptions or memberships without intermediaries.

Why it matters:
Ensures transparent, automated payments to creators, reduces platform fees, and gives fans verifiable proof of membership and perks.

How it works:

  • Creators register their subscription tiers with pricing, duration, and perks

  • Fans subscribe by sending recurring payments on-chain

  • Smart contract tracks active subscriptions and automatically renews or expires them

  • Revenue can be split among multiple stakeholders (creators, collaborators, platforms)

  • Perks or content access are granted based on active subscription status

  • Subscription and payment history is immutable and auditable

  • Integrates with NFTs for exclusive content access or gamified fan rewards

      // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title CreatorSubscription
 * @author Nam
 * @notice On-chain recurring subscriptions for creators and fans
 */
contract CreatorSubscription {

    struct SubscriptionTier {
        uint256 price; // in wei
        uint256 duration; // in seconds
        string perks; // description or IPFS link
    }

    struct Creator {
        mapping(uint256 => SubscriptionTier) tiers;
        uint256 tierCount;
        mapping(address => uint256) subscriberExpiry; // tracks subscription expiration
    }

    mapping(address => Creator) public creators;

    // -------------------- EVENTS --------------------

    event TierCreated(address indexed creator, uint256 tierId, uint256 price, uint256 duration);
    event Subscribed(address indexed creator, address indexed subscriber, uint256 tierId, uint256 expiry);

    // -------------------- CREATOR MANAGEMENT --------------------

    function createTier(uint256 _price, uint256 _duration, string calldata _perks) external {
        require(_price > 0, "Price must be >0");
        require(_duration > 0, "Duration must be >0");

        Creator storage c = creators[msg.sender];
        c.tierCount += 1;
        c.tiers[c.tierCount] = SubscriptionTier(_price, _duration, _perks);

        emit TierCreated(msg.sender, c.tierCount, _price, _duration);
    }

    // -------------------- SUBSCRIPTION MANAGEMENT --------------------

    function subscribe(address _creator, uint256 _tierId) external payable {
        Creator storage c = creators[_creator];
        SubscriptionTier storage tier = c.tiers[_tierId];

        require(msg.value == tier.price, "Incorrect payment");

        if (block.timestamp > c.subscriberExpiry[msg.sender]) {
            c.subscriberExpiry[msg.sender] = block.timestamp + tier.duration;
        } else {
            c.subscriberExpiry[msg.sender] += tier.duration;
        }

        payable(_creator).transfer(msg.value);

        emit Subscribed(_creator, msg.sender, _tierId, c.subscriberExpiry[msg.sender]);
    }

    function isSubscribed(address _creator, address _subscriber) external view returns (bool) {
        return block.timestamp <= creators[_creator].subscriberExpiry[_subscriber];
    }
}