Deep dive into Rospeak's blockchain architecture, Sonic blockchain integration, smart contract implementations, and FeeM monetization system.
Rospeak chose Sonic blockchain as our foundation after extensive research and evaluation of multiple blockchain platforms. Here's why Sonic is the perfect fit for decentralized free speech:
FeeM (Fee Monetization) is Sonic blockchain's native system for rewarding network participants and enabling creator monetization. It's perfectly aligned with Rospeak's mission to enable direct creator compensation.
Creator Content → Blockchain Storage → User Interaction → FeeM Rewards
↓ ↓ ↓ ↓
Publishing Network Fees Engagement Direct Payments
Costs (Minimal) Rewards to Creators
Rospeak implements a comprehensive suite of smart contracts that work together to create a decentralized content ecosystem:
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract ContentRegistry is Ownable, ReentrancyGuard {
struct Content {
bytes32 contentHash; // IPFS hash of content
address creator; // Content creator address
uint256 timestamp; // Publication timestamp
string metadataURI; // Metadata location (IPFS)
uint256 accessPrice; // Price for premium content (in FeeM)
bool isActive; // Content status
uint256 views; // View count
uint256 earnings; // Total earnings
}
struct Creator {
address creatorAddress;
string profileURI; // Profile metadata IPFS hash
uint256 totalEarnings; // Lifetime earnings
uint256 contentCount; // Number of content pieces
uint256 reputation; // Creator reputation score
bool isVerified; // Verification status
}
// Mappings
mapping(bytes32 => Content) public contents;
mapping(address => Creator) public creators;
mapping(address => bytes32[]) public creatorContents;
mapping(bytes32 => address[]) public contentViewers;
// Events
event ContentPublished(
bytes32 indexed contentHash,
address indexed creator,
uint256 timestamp,
uint256 accessPrice
);
event ContentViewed(
bytes32 indexed contentHash,
address indexed viewer,
uint256 timestamp
);
event CreatorVerified(address indexed creator, uint256 timestamp);
// Modifiers
modifier onlyCreator(bytes32 _contentHash) {
require(contents[_contentHash].creator == msg.sender, "Not content creator");
_;
}
modifier contentExists(bytes32 _contentHash) {
require(contents[_contentHash].creator != address(0), "Content does not exist");
_;
}
/**
* @dev Publish new content to the blockchain
* @param _contentHash IPFS hash of the content
* @param _metadataURI IPFS hash of metadata
* @param _accessPrice Price for premium access (0 for free content)
*/
function publishContent(
bytes32 _contentHash,
string memory _metadataURI,
uint256 _accessPrice
) external nonReentrant {
require(_contentHash != bytes32(0), "Invalid content hash");
require(contents[_contentHash].creator == address(0), "Content already exists");
// Create content record
contents[_contentHash] = Content({
contentHash: _contentHash,
creator: msg.sender,
timestamp: block.timestamp,
metadataURI: _metadataURI,
accessPrice: _accessPrice,
isActive: true,
views: 0,
earnings: 0
});
// Update creator record
if (creators[msg.sender].creatorAddress == address(0)) {
creators[msg.sender] = Creator({
creatorAddress: msg.sender,
profileURI: "",
totalEarnings: 0,
contentCount: 1,
reputation: 100, // Starting reputation
isVerified: false
});
} else {
creators[msg.sender].contentCount++;
}
// Add to creator's content list
creatorContents[msg.sender].push(_contentHash);
emit ContentPublished(_contentHash, msg.sender, block.timestamp, _accessPrice);
}
/**
* @dev Record content view and handle payments for premium content
* @param _contentHash Hash of the content being viewed
*/
function viewContent(bytes32 _contentHash)
external
payable
contentExists(_contentHash)
nonReentrant
{
Content storage content = contents[_contentHash];
require(content.isActive, "Content is not active");
// Handle payment for premium content
if (content.accessPrice > 0) {
require(msg.value >= content.accessPrice, "Insufficient payment");
// Transfer payment to creator
payable(content.creator).transfer(content.accessPrice);
// Update earnings
contents[_contentHash].earnings += content.accessPrice;
creators[content.creator].totalEarnings += content.accessPrice;
// Refund excess payment
if (msg.value > content.accessPrice) {
payable(msg.sender).transfer(msg.value - content.accessPrice);
}
}
// Record view
contents[_contentHash].views++;
contentViewers[_contentHash].push(msg.sender);
emit ContentViewed(_contentHash, msg.sender, block.timestamp);
}
/**
* @dev Get content information
* @param _contentHash Hash of the content
* @return Content struct with all information
*/
function getContent(bytes32 _contentHash)
external
view
contentExists(_contentHash)
returns (Content memory)
{
return contents[_contentHash];
}
/**
* @dev Get creator's content list
* @param _creator Address of the creator
* @return Array of content hashes
*/
function getCreatorContent(address _creator)
external
view
returns (bytes32[] memory)
{
return creatorContents[_creator];
}
}
pragma solidity ^0.8.19;
import "./ContentRegistry.sol";
contract ReputationSystem {
ContentRegistry public contentRegistry;
struct Rating {
address rater;
uint8 score; // 1-5 rating
string comment;
uint256 timestamp;
}
struct ReputationMetrics {
uint256 totalRatings;
uint256 averageRating;
uint256 positiveInteractions;
uint256 negativeInteractions;
uint256 lastUpdated;
}
mapping(address => ReputationMetrics) public creatorMetrics;
mapping(bytes32 => Rating[]) public contentRatings;
mapping(address => mapping(bytes32 => bool)) public hasRated;
event ContentRated(
bytes32 indexed contentHash,
address indexed rater,
uint8 score,
uint256 timestamp
);
event ReputationUpdated(
address indexed creator,
uint256 newReputation,
uint256 timestamp
);
constructor(address _contentRegistry) {
contentRegistry = ContentRegistry(_contentRegistry);
}
/**
* @dev Rate content and update creator reputation
* @param _contentHash Hash of the content to rate
* @param _score Rating score (1-5)
* @param _comment Optional comment
*/
function rateContent(
bytes32 _contentHash,
uint8 _score,
string memory _comment
) external {
require(_score >= 1 && _score <= 5, "Invalid rating score");
require(!hasRated[msg.sender][_contentHash], "Already rated this content");
// Get content creator
ContentRegistry.Content memory content = contentRegistry.getContent(_contentHash);
address creator = content.creator;
// Add rating
contentRatings[_contentHash].push(Rating({
rater: msg.sender,
score: _score,
comment: _comment,
timestamp: block.timestamp
}));
hasRated[msg.sender][_contentHash] = true;
// Update reputation metrics
ReputationMetrics storage metrics = creatorMetrics[creator];
metrics.totalRatings++;
if (_score >= 4) {
metrics.positiveInteractions++;
} else if (_score <= 2) {
metrics.negativeInteractions++;
}
// Recalculate average rating
uint256 totalScore = 0;
Rating[] memory ratings = contentRatings[_contentHash];
for (uint i = 0; i < ratings.length; i++) {
totalScore += ratings[i].score;
}
metrics.averageRating = totalScore / ratings.length;
metrics.lastUpdated = block.timestamp;
emit ContentRated(_contentHash, msg.sender, _score, block.timestamp);
emit ReputationUpdated(creator, metrics.averageRating, block.timestamp);
}
}
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract GovernanceToken is ERC20, Ownable {
struct Proposal {
uint256 id;
address proposer;
string title;
string description;
uint256 votesFor;
uint256 votesAgainst;
uint256 startTime;
uint256 endTime;
bool executed;
mapping(address => bool) hasVoted;
mapping(address => bool) voteChoice; // true = for, false = against
}
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
uint256 public constant VOTING_PERIOD = 7 days;
uint256 public constant PROPOSAL_THRESHOLD = 1000 * 10**18; // 1000 tokens to propose
event ProposalCreated(
uint256 indexed proposalId,
address indexed proposer,
string title
);
event VoteCast(
uint256 indexed proposalId,
address indexed voter,
bool support,
uint256 weight
);
event ProposalExecuted(uint256 indexed proposalId);
constructor() ERC20("Rospeak Governance Token", "RGT") {
// Mint initial supply to contract deployer
_mint(msg.sender, 1000000 * 10**18); // 1M tokens
}
/**
* @dev Create a new governance proposal
* @param _title Title of the proposal
* @param _description Detailed description
*/
function createProposal(
string memory _title,
string memory _description
) external {
require(balanceOf(msg.sender) >= PROPOSAL_THRESHOLD, "Insufficient tokens to propose");
uint256 proposalId = proposalCount++;
Proposal storage proposal = proposals[proposalId];
proposal.id = proposalId;
proposal.proposer = msg.sender;
proposal.title = _title;
proposal.description = _description;
proposal.startTime = block.timestamp;
proposal.endTime = block.timestamp + VOTING_PERIOD;
proposal.executed = false;
emit ProposalCreated(proposalId, msg.sender, _title);
}
/**
* @dev Vote on a proposal
* @param _proposalId ID of the proposal
* @param _support True for yes, false for no
*/
function vote(uint256 _proposalId, bool _support) external {
Proposal storage proposal = proposals[_proposalId];
require(block.timestamp <= proposal.endTime, "Voting period ended");
require(!proposal.hasVoted[msg.sender], "Already voted");
uint256 voterBalance = balanceOf(msg.sender);
require(voterBalance > 0, "No voting power");
proposal.hasVoted[msg.sender] = true;
proposal.voteChoice[msg.sender] = _support;
if (_support) {
proposal.votesFor += voterBalance;
} else {
proposal.votesAgainst += voterBalance;
}
emit VoteCast(_proposalId, msg.sender, _support, voterBalance);
}
/**
* @dev Execute a successful proposal
* @param _proposalId ID of the proposal to execute
*/
function executeProposal(uint256 _proposalId) external {
Proposal storage proposal = proposals[_proposalId];
require(block.timestamp > proposal.endTime, "Voting still active");
require(!proposal.executed, "Already executed");
require(proposal.votesFor > proposal.votesAgainst, "Proposal failed");
proposal.executed = true;
// Implementation of proposal execution would go here
// This could involve calling other contracts or updating parameters
emit ProposalExecuted(_proposalId);
}
}
┌─────────────────────────────────────────────────────────────┐
│ APPLICATION LAYER │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Presentation │ │ Creator │ │ Governance │ │
│ │ Platforms │ │ Tools │ │ Interface │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ API GATEWAY │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Content API │ │ User Mgmt API │ │ Monetization API │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ SMART CONTRACT LAYER │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ ContentRegistry │ │ ReputationSystem │ │ GovernanceToken │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ SONIC BLOCKCHAIN │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ FeeM System │ │ Consensus │ │ Storage │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
// Pay creator for premium content access
async function payForContent(contentHash, creatorAddress, amount) {
const contract = new ethers.Contract(
CONTENT_REGISTRY_ADDRESS,
ContentRegistryABI,
signer
);
const transaction = await contract.viewContent(contentHash, {
value: ethers.utils.parseEther(amount.toString())
});
await transaction.wait();
return transaction.hash;
}
// Send tip to creator
async function tipCreator(creatorAddress, amount, message) {
const tipContract = new ethers.Contract(
TIP_CONTRACT_ADDRESS,
TipContractABI,
signer
);
const transaction = await tipContract.sendTip(
creatorAddress,
message,
{
value: ethers.utils.parseEther(amount.toString())
}
);
return transaction.wait();
}
// Subscribe to creator's premium content
async function subscribeToCreator(creatorAddress, duration) {
const subscriptionContract = new ethers.Contract(
SUBSCRIPTION_ADDRESS,
SubscriptionABI,
signer
);
const monthlyFee = await subscriptionContract.getCreatorSubscriptionFee(creatorAddress);
const totalFee = monthlyFee.mul(duration);
const transaction = await subscriptionContract.subscribe(
creatorAddress,
duration,
{ value: totalFee }
);
return transaction.wait();
}
Creator Content Revenue Distribution:
├── 85% → Creator (Direct payment)
├── 10% → Network Validators (FeeM rewards)
├── 3% → Platform Development Fund
└── 2% → Community Governance Treasury
contract FeeDistribution {
uint256 public constant CREATOR_SHARE = 85;
uint256 public constant VALIDATOR_SHARE = 10;
uint256 public constant DEVELOPMENT_SHARE = 3;
uint256 public constant GOVERNANCE_SHARE = 2;
address public developmentFund;
address public governanceTreasury;
function distributeRevenue(
address creator,
uint256 totalAmount
) external {
uint256 creatorAmount = (totalAmount * CREATOR_SHARE) / 100;
uint256 validatorAmount = (totalAmount * VALIDATOR_SHARE) / 100;
uint256 developmentAmount = (totalAmount * DEVELOPMENT_SHARE) / 100;
uint256 governanceAmount = (totalAmount * GOVERNANCE_SHARE) / 100;
// Transfer to creator
payable(creator).transfer(creatorAmount);
// Transfer to development fund
payable(developmentFund).transfer(developmentAmount);
// Transfer to governance treasury
payable(governanceTreasury).transfer(governanceAmount);
// Validator rewards handled by FeeM system automatically
}
}
// Bridge existing platform content to Rospeak
class ContentBridge {
constructor(apiKey, platformType) {
this.apiKey = apiKey;
this.platformType = platformType;
this.rospeak = new RospeakSDK({ apiKey });
}
// Import content from traditional platform
async importContent(platformContentId) {
const content = await this.fetchFromPlatform(platformContentId);
// Convert to Rospeak format
const rospeakContent = {
title: content.title,
body: content.body,
creator: content.author.address,
metadata: {
originalPlatform: this.platformType,
originalId: platformContentId,
importDate: new Date().toISOString(),
tags: content.tags || []
}
};
// Publish to blockchain
const result = await this.rospeak.content.publish(rospeakContent);
// Create cross-reference
await this.createCrossReference(platformContentId, result.hash);
return result;
}
// Sync engagement data
async syncEngagement(contentHash) {
const platformData = await this.fetchEngagementData(contentHash);
const blockchainData = await this.rospeak.content.get(contentHash);
// Combine engagement metrics
const combinedMetrics = {
totalViews: platformData.views + blockchainData.views,
totalLikes: platformData.likes + blockchainData.likes,
totalShares: platformData.shares + blockchainData.shares,
crossPlatformReach: true
};
return combinedMetrics;
}
}
// Help existing platforms migrate to Rospeak infrastructure
class PlatformMigrationTool {
constructor(platformConfig) {
this.config = platformConfig;
this.rospeak = new RospeakSDK(platformConfig.rospeak);
}
// Migrate user accounts
async migrateUsers(userBatch) {
const results = [];
for (const user of userBatch) {
try {
const rospeakUser = await this.rospeak.users.create({
address: user.walletAddress,
username: user.username,
profile: {
bio: user.bio,
avatar: user.avatar,
migrationDate: new Date().toISOString(),
originalPlatform: this.config.platformName
}
});
results.push({
success: true,
originalId: user.id,
rospeakAddress: rospeakUser.address
});
} catch (error) {
results.push({
success: false,
originalId: user.id,
error: error.message
});
}
}
return results;
}
// Migrate content library
async migrateContent(contentBatch) {
const results = [];
for (const content of contentBatch) {
try {
// Upload media to IPFS
const mediaHash = await this.uploadToIPFS(content.media);
// Create content on blockchain
const rospeakContent = await this.rospeak.content.publish({
title: content.title,
body: content.body,
creator: content.creator.address,
media: mediaHash,
metadata: {
originalId: content.id,
originalPlatform: this.config.platformName,
migrationDate: new Date().toISOString(),
originalEngagement: {
views: content.views,
likes: content.likes,
shares: content.shares
}
}
});
results.push({
success: true,
originalId: content.id,
rospeakHash: rospeakContent.hash
});
} catch (error) {
results.push({
success: false,
originalId: content.id,
error: error.message
});
}
}
return results;
}
}
// Example security patterns in our contracts
contract SecureContract is ReentrancyGuard, Ownable, Pausable {
using SafeMath for uint256;
modifier validAddress(address _addr) {
require(_addr != address(0), "Invalid zero address");
require(_addr != address(this), "Cannot be contract address");
_;
}
modifier validAmount(uint256 _amount) {
require(_amount > 0, "Amount must be positive");
require(_amount <= type(uint256).max, "Amount too large");
_;
}
function secureTransfer(address _to, uint256 _amount)
external
nonReentrant
whenNotPaused
validAddress(_to)
validAmount(_amount)
{
// Implementation with all security checks
}
}
// Multi-signature wallet for critical operations
contract MultiSigGovernance {
mapping(address => bool) public isOwner;
mapping(bytes32 => mapping(address => bool)) public confirmations;
mapping(bytes32 => bool) public executed;
uint256 public required; // Required confirmations
address[] public owners;
modifier onlyOwner() {
require(isOwner[msg.sender], "Not an owner");
_;
}
modifier notExecuted(bytes32 _txHash) {
require(!executed[_txHash], "Transaction already executed");
_;
}
function submitTransaction(
address _to,
uint256 _value,
bytes memory _data
) external onlyOwner returns (bytes32) {
bytes32 txHash = keccak256(abi.encodePacked(_to, _value, _data, block.timestamp));
confirmations[txHash][msg.sender] = true;
return txHash;
}
function confirmTransaction(bytes32 _txHash) external onlyOwner notExecuted(_txHash) {
confirmations[_txHash][msg.sender] = true;
if (getConfirmationCount(_txHash) >= required) {
executeTransaction(_txHash);
}
}
}
// Monitor blockchain activity and creator metrics
class BlockchainAnalytics {
constructor(web3Provider, contractAddresses) {
this.web3 = web3Provider;
this.contracts = contractAddresses;
}
// Track content publication metrics
async getContentMetrics(timeframe = '7d') {
const events = await this.getEvents('ContentPublished', timeframe);
return {
totalContent: events.length,
uniqueCreators: new Set(events.map(e => e.creator)).size,
averageContentPerDay: events.length / 7,
topCreators: this.getTopCreators(events),
contentCategories: this.categorizeContent(events)
};
}
// Monitor FeeM distribution
async getRevenueMetrics(timeframe = '30d') {
const payments = await this.getPaymentEvents(timeframe);
return {
totalRevenue: payments.reduce((sum, p) => sum + p.amount, 0),
averagePayment: payments.reduce((sum, p) => sum + p.amount, 0) / payments.length,
topEarningCreators: this.getTopEarners(payments),
revenueGrowth: this.calculateGrowthRate(payments)
};
}
// Track governance participation
async getGovernanceMetrics() {
const proposals = await this.getProposalEvents();
const votes = await this.getVoteEvents();
return {
activeProposals: proposals.filter(p => !p.executed).length,
participationRate: votes.length / this.getTotalTokenHolders(),
proposalSuccessRate: this.calculateSuccessRate(proposals),
averageVotingPower: this.calculateAverageVotingPower(votes)
};
}
}
// Monitor contract performance and gas usage
class ContractMonitor {
constructor(contracts) {
this.contracts = contracts;
this.metrics = new Map();
}
// Monitor transaction performance
async monitorTransactions() {
const web3 = new Web3(process.env.SONIC_RPC_URL);
// Listen for new blocks
web3.eth.subscribe('newBlockHeaders', (error, blockHeader) => {
if (error) {
console.error('Block subscription error:', error);
return;
}
this.analyzeBlock(blockHeader.number);
});
}
async analyzeBlock(blockNumber) {
const block = await web3.eth.getBlock(blockNumber, true);
// Filter our contract transactions
const ourTxs = block.transactions.filter(tx =>
this.contracts.includes(tx.to?.toLowerCase())
);
// Calculate metrics
const gasUsed = ourTxs.reduce((sum, tx) => sum + tx.gas, 0);
const avgGasPrice = ourTxs.reduce((sum, tx) => sum + tx.gasPrice, 0) / ourTxs.length;
this.updateMetrics({
blockNumber,
transactionCount: ourTxs.length,
totalGasUsed: gasUsed,
averageGasPrice: avgGasPrice,
timestamp: block.timestamp
});
}
}
// Cross-chain content synchronization
contract CrossChainBridge {
mapping(uint256 => mapping(bytes32 => bool)) public contentExists;
mapping(uint256 => address) public chainOracles;
event ContentBridged(
uint256 indexed fromChain,
uint256 indexed toChain,
bytes32 indexed contentHash
);
function bridgeContent(
uint256 _targetChain,
bytes32 _contentHash,
bytes memory _contentData
) external {
require(chainOracles[_targetChain] != address(0), "Target chain not supported");
// Verify content exists on source chain
require(contentExists[block.chainid][_contentHash], "Content not found");
// Emit bridge event for oracle to process
emit ContentBridged(block.chainid, _targetChain, _contentHash);
// Oracle will handle cross-chain message passing
}
}
Ready to integrate with Rospeak's blockchain infrastructure? Check out our Technical Documentation for API references and implementation guides, or join our Community to connect with other developers building on Sonic blockchain!