Token-Based Content Subscription System Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Token-Based Content Subscription System Development
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Token Content Subscription System Development

Token-gating content is not Patreon on blockchain. Principal difference: payments through smart contract without middleman, creator receives income directly, subscription can be NFT with secondary market, access verified on-chain without centralized authorization server.

Implementing this correctly is harder than it looks — especially for verifying access to off-chain content (video, articles, files).

Subscription Models: ERC-20 vs ERC-721 vs ERC-1155

ERC-20 staking: user stakes certain amount of creator's tokens — gets access. Simple model, but stake freezes liquidity.

ERC-721 subscription NFT: each active subscription — separate NFT with expiry timestamp in metadata or contract. Sellable, transferable. Ideal for "lifetime" subscriptions or limited tiers.

ERC-1155 timed access: semi-fungible tokens tied to period. E.g., tokenId = 202504 — access for April 2025. Saves gas with batch transfers, logical for monthly subscriptions.

contract ContentSubscription {
    struct SubscriptionTier {
        uint256 pricePerMonth;      // in wei or ERC-20 tokens
        address paymentToken;       // address(0) = native ETH
        uint256 maxSubscribers;     // 0 = unlimited
        string contentCID;          // IPFS CID for encrypted content
        bytes32 encryptionKeyHash;  // hash of encryption key for this tier
    }
    
    struct Subscription {
        uint256 tierId;
        uint256 expiresAt;
        uint256 startedAt;
        bool autoRenew;
    }
    
    mapping(uint256 => SubscriptionTier) public tiers;
    mapping(address => mapping(uint256 => Subscription)) public subscriptions;
    
    address public creator;
    uint256 public platformFeeBps = 250; // 2.5%
    
    modifier onlyCreator() {
        require(msg.sender == creator, "Not creator");
        _;
    }
    
    function subscribe(uint256 tierId, uint256 months, bool autoRenew) external payable {
        SubscriptionTier memory tier = tiers[tierId];
        uint256 totalCost = tier.pricePerMonth * months;
        
        if (tier.paymentToken == address(0)) {
            require(msg.value >= totalCost, "Insufficient ETH");
        } else {
            IERC20(tier.paymentToken).transferFrom(msg.sender, address(this), totalCost);
        }
        
        Subscription storage sub = subscriptions[msg.sender][tierId];
        
        // Renew existing or new subscription
        uint256 currentExpiry = sub.expiresAt > block.timestamp 
            ? sub.expiresAt 
            : block.timestamp;
        
        sub.expiresAt = currentExpiry + months * 30 days;
        sub.tierId = tierId;
        sub.autoRenew = autoRenew;
        if (sub.startedAt == 0) sub.startedAt = block.timestamp;
        
        _distributeRevenue(tier, totalCost);
        
        emit Subscribed(msg.sender, tierId, sub.expiresAt);
    }
    
    function isSubscribed(address user, uint256 tierId) external view returns (bool) {
        return subscriptions[user][tierId].expiresAt > block.timestamp;
    }
    
    function _distributeRevenue(SubscriptionTier memory tier, uint256 amount) internal {
        uint256 platformFee = amount * platformFeeBps / 10000;
        uint256 creatorAmount = amount - platformFee;
        
        if (tier.paymentToken == address(0)) {
            payable(creator).transfer(creatorAmount);
            payable(platform).transfer(platformFee);
        } else {
            IERC20(tier.paymentToken).transfer(creator, creatorAmount);
            IERC20(tier.paymentToken).transfer(platform, platformFee);
        }
    }
}

Verifying Access to Encrypted Content

Can't store content on-chain and pointless. Standard scheme: content encrypted and uploaded to IPFS, encryption key given only to verified subscribers.

Problem: who gives the key? If centralized server — no point in blockchain. Solution — Lit Protocol or Threshold Network: decentralized node network stores key shards and grants access only on on-chain condition.

import { LitNodeClient, checkAndSignAuthMessage } from '@lit-protocol/lit-node-client';

// Access condition: active subscription to tier 1
const accessControlConditions = [
    {
        contractAddress: SUBSCRIPTION_CONTRACT_ADDRESS,
        standardContractType: '',
        chain: 'ethereum',
        method: 'isSubscribed',
        parameters: [':userAddress', '1'],  // tierId = 1
        returnValueTest: {
            comparator: '=',
            value: 'true'
        }
    }
];

// Encrypt content (creator does on upload)
async function encryptContent(content) {
    const client = new LitNodeClient();
    await client.connect();
    
    const authSig = await checkAndSignAuthMessage({ chain: 'ethereum' });
    
    const { encryptedString, symmetricKey } = await LitJsSdk.encryptString(content);
    
    const encryptedSymmetricKey = await client.saveEncryptionKey({
        accessControlConditions,
        symmetricKey,
        authSig,
        chain: 'ethereum'
    });
    
    return {
        encryptedContent: encryptedString,
        encryptedKey: encryptedSymmetricKey
    };
}

// Decrypt (user on read)
async function decryptContent(encryptedContent, encryptedKey) {
    const client = new LitNodeClient();
    await client.connect();
    
    const authSig = await checkAndSignAuthMessage({ chain: 'ethereum' });
    
    const symmetricKey = await client.getEncryptionKey({
        accessControlConditions,
        toDecrypt: encryptedKey,
        chain: 'ethereum',
        authSig
    });
    
    return await LitJsSdk.decryptString(encryptedContent, symmetricKey);
}

Monetization Models for Creator

Model Description Pros Cons
Flat subscription Fixed monthly price Predictable income No premium tiers
Tiered access Basic / Pro / VIP Flexible, maximizes revenue Harder to manage
Pay-per-content Each piece separately Monetizes hit content User friction
NFT membership Lifetime subscription as NFT Secondary market = extra income One-time payment
Hybrid Base tier + individual buys Optimal balance Most complex

NFT membership deserves attention: creator gets royalty from secondary sales (ERC-2981). If early holder resells their spot — creator gets 5–10% of resale price automatically.

Auto-Renewal via Chainlink Automation

Auto-renewal needs external trigger — smart contract can't call itself by schedule.

Chainlink Automation checks condition checkUpkeep() and calls performUpkeep() if needed:

contract AutoRenewSubscription is AutomationCompatibleInterface {
    function checkUpkeep(bytes calldata) external view override 
        returns (bool upkeepNeeded, bytes memory performData) 
    {
        // Find expiring subscriptions with autoRenew=true
        address[] memory toRenew = _findExpiringSubscriptions();
        upkeepNeeded = toRenew.length > 0;
        performData = abi.encode(toRenew);
    }
    
    function performUpkeep(bytes calldata performData) external override {
        address[] memory toRenew = abi.decode(performData, (address[]));
        
        for (uint256 i = 0; i < toRenew.length; i++) {
            _attemptRenewal(toRenew[i]);
        }
    }
    
    function _attemptRenewal(address subscriber) internal {
        // Try to charge, if sufficient balance — renew
        // On failure — event, user notification
    }
}

Development Timeline

Basic subscription system with one tier, Lit Protocol integration and simple frontend — 4–6 weeks. Full-featured platform with tiered access, NFT membership, auto-renewal and creator analytics — 10–14 weeks.