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];
}
}