Разработка системы токенизированного контента
Токенизированный контент — модель, где создатели выпускают своё творчество как токены (NFT или fungible), а читатели/зрители получают финансовое участие в успехе этого контента. Это выход за рамки простого «купи NFT» к динамической экономике вокруг контента.
Модели токенизации контента
Collect NFT (Lens Protocol модель)
Каждая публикация = уникальный NFT который можно collect (купить). Создатель устанавливает лимит (например, только 100 копий) и цену. Первые buyers получают early supporter статус и потенциальный upside при перепродаже.
Fractional content ownership
Контент (статья, музыкальный трек, видео) представлен NFT, а право на долю доходов от него разделено на ERC-20 фракции. Покупая токены — получаешь долю royalties.
Bonding curve tokens
Каждый контент имеет собственный токен на bonding curve. Чем больше людей покупает — тем дороже. Ранние покупатели выигрывают от роста.
Subscription tokens (Creator Coins)
Токен дающий доступ к контенту создателя за период (месяц, год). ERC-20 с expire логикой или NFT с временными атрибутами.
Smart contract: collect с роялти
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
contract TokenizedContent is ERC721, IERC2981 {
struct ContentItem {
address creator;
string contentURI; // IPFS CID
uint256 price; // в wei
uint256 maxSupply; // 0 = unlimited
uint256 currentSupply;
uint256 royaltyPercent; // basis points
bool paywalled; // требует ли collect для просмотра
ContentType contentType;
}
enum ContentType { ARTICLE, IMAGE, VIDEO, MUSIC, EBOOK, NEWSLETTER }
mapping(uint256 => ContentItem) public contentItems;
mapping(uint256 => mapping(address => bool)) public hasCollected;
uint256 public platformFee = 250; // 2.5%
address public platform;
// Создание контента с параметрами монетизации
function publishContent(
string calldata contentURI,
uint256 price,
uint256 maxSupply,
uint256 royaltyPercent,
bool paywalled,
ContentType contentType
) external returns (uint256 contentId) {
require(royaltyPercent <= 2000, "Royalty too high"); // max 20%
contentId = ++_contentCounter;
contentItems[contentId] = ContentItem({
creator: msg.sender,
contentURI: contentURI,
price: price,
maxSupply: maxSupply,
currentSupply: 0,
royaltyPercent: royaltyPercent,
paywalled: paywalled,
contentType: contentType,
});
emit ContentPublished(contentId, msg.sender, contentURI, price, contentType);
}
// Collect (покупка) контента
function collect(uint256 contentId) external payable returns (uint256 tokenId) {
ContentItem storage item = contentItems[contentId];
require(item.creator != address(0), "Content not found");
require(msg.value == item.price, "Wrong price");
require(
item.maxSupply == 0 || item.currentSupply < item.maxSupply,
"Max supply reached"
);
item.currentSupply++;
// Распределение платежа
uint256 fee = (msg.value * platformFee) / 10000;
uint256 creatorProceeds = msg.value - fee;
payable(platform).transfer(fee);
payable(item.creator).transfer(creatorProceeds);
// Минт NFT collect токена
tokenId = ++_tokenCounter;
_mint(msg.sender, tokenId);
hasCollected[contentId][msg.sender] = true;
// Маппинг tokenId → contentId
tokenToContent[tokenId] = contentId;
emit Collected(contentId, tokenId, msg.sender, msg.value);
}
// ERC-2981 royalties для secondary market
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external view override returns (address receiver, uint256 royaltyAmount)
{
uint256 contentId = tokenToContent[tokenId];
ContentItem storage item = contentItems[contentId];
receiver = item.creator;
royaltyAmount = (salePrice * item.royaltyPercent) / 10000;
}
// Доступ к paywalled контенту
function canAccessContent(uint256 contentId, address user)
external view returns (bool)
{
ContentItem storage item = contentItems[contentId];
if (!item.paywalled) return true;
if (item.creator == user) return true;
if (hasCollected[contentId][user]) return true;
return false;
}
}
Bonding curve для Creator Coins
contract CreatorCoin is ERC20 {
// Bonding curve: price = reserveRatio * totalSupply / reserveBalance
uint256 public reserveBalance;
uint256 public reserveRatio = 500000; // 50% (в ppm, 1_000_000 = 100%)
address public creator;
uint256 public creatorFee = 500; // 5%
function buy(uint256 minReturn) external payable returns (uint256 tokensReturned) {
tokensReturned = calculatePurchaseReturn(
totalSupply(),
reserveBalance,
uint32(reserveRatio),
msg.value
);
require(tokensReturned >= minReturn, "Slippage exceeded");
uint256 fee = (msg.value * creatorFee) / 10000;
reserveBalance += msg.value - fee;
payable(creator).transfer(fee);
_mint(msg.sender, tokensReturned);
emit Buy(msg.sender, msg.value, tokensReturned);
}
function sell(uint256 amount, uint256 minReturn) external returns (uint256 ethReturned) {
ethReturned = calculateSaleReturn(
totalSupply(),
reserveBalance,
uint32(reserveRatio),
amount
);
require(ethReturned >= minReturn, "Slippage exceeded");
_burn(msg.sender, amount);
reserveBalance -= ethReturned;
payable(msg.sender).transfer(ethReturned);
emit Sell(msg.sender, amount, ethReturned);
}
}
Token gating контента
// Backend: проверка доступа к contenta
async function checkContentAccess(
userAddress: string,
contentId: string
): Promise<{ hasAccess: boolean; reason?: string }> {
const content = await db.getContent(contentId);
if (!content.isTokenGated) return { hasAccess: true };
// Проверяем владение NFT
if (content.requiredNFT) {
const balance = await nftContract.balanceOf(userAddress);
if (balance > 0n) return { hasAccess: true };
}
// Проверяем creator coin holdings
if (content.requiredCreatorCoinAmount) {
const coinBalance = await creatorCoinContract.balanceOf(userAddress);
if (coinBalance >= content.requiredCreatorCoinAmount) {
return { hasAccess: true };
}
return {
hasAccess: false,
reason: `Hold ${formatUnits(content.requiredCreatorCoinAmount, 18)} $CREATOR to access`,
};
}
// Проверяем collect
const hasCollected = await contentContract.hasCollected(contentId, userAddress);
if (hasCollected) return { hasAccess: true };
return { hasAccess: false, reason: "Collect to access" };
}
Аналитика для создателей
interface CreatorDashboard {
totalEarned: bigint; // всего заработано
totalCollects: number; // сколько раз собрали
uniqueCollectors: number; // уникальных коллекторов
topContent: Array<{
contentId: string;
title: string;
collects: number;
earned: bigint;
}>;
revenueByDay: Array<{ date: string; revenue: bigint }>;
secondarySalesRoyalties: bigint; // доход от вторичных продаж
}
Разработка базовой системы токенизированного контента (collect + paywall + creator dashboard) — 5-7 недель. Bonding curve creator coins добавляют 3-4 недели.







