Comprehensive technical overview of the Rospeak decentralized free speech platform, including architecture, APIs, smart contracts, and integration guides.
Rospeak implements a revolutionary content-presentation separation architecture built on Sonic blockchain:
┌─────────────────────────────────────────────────────────────┐
│ PRESENTATION LAYER │
├─────────────────┬─────────────────┬─────────────────────────┤
│ Platform A │ Platform B │ Platform C...N │
│ (General) │ (Niche) │ (Regional/Specialized)│
└─────────────────┴─────────────────┴─────────────────────────┘
│
┌─────────────────┐
│ ROSPEAK API │
│ Content Access │
└─────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ BLOCKCHAIN STORAGE LAYER │
├─────────────────────────────────────────────────────────────┤
│ 🔗 Sonic Blockchain + FeeM Integration │
│ 📄 Content Storage Smart Contracts │
│ 👤 User Identity & Reputation System │
│ 💰 Monetization & Payment Processing │
│ 🗳️ Governance & Community Management │
└─────────────────────────────────────────────────────────────┘
Purpose: Permanent content storage and ownership tracking
contract ContentStorage {
struct Content {
bytes32 contentHash;
address creator;
uint256 timestamp;
string metadata;
bool isActive;
}
mapping(bytes32 => Content) public contents;
mapping(address => bytes32[]) public creatorContents;
event ContentPublished(bytes32 indexed contentHash, address indexed creator);
event ContentUpdated(bytes32 indexed contentHash, string metadata);
function publishContent(bytes32 _contentHash, string memory _metadata) external;
function updateMetadata(bytes32 _contentHash, string memory _metadata) external;
function getContent(bytes32 _contentHash) external view returns (Content memory);
}
Purpose: User identity, reputation, and profile management
contract UserRegistry {
struct User {
address userAddress;
string username;
string profileMetadata;
uint256 reputation;
bool isVerified;
uint256 joinDate;
}
mapping(address => User) public users;
mapping(string => address) public usernameToAddress;
event UserRegistered(address indexed user, string username);
event ProfileUpdated(address indexed user, string metadata);
function register(string memory _username, string memory _metadata) external;
function updateProfile(string memory _metadata) external;
function verifyUser(address _user) external; // Admin function
}
Purpose: Creator monetization through FeeM integration
contract FeeMonetization {
struct Payment {
address from;
address to;
uint256 amount;
bytes32 contentHash;
uint256 timestamp;
}
mapping(address => uint256) public creatorBalances;
mapping(bytes32 => uint256) public contentEarnings;
Payment[] public payments;
event PaymentMade(address indexed from, address indexed to, uint256 amount, bytes32 contentHash);
event RewardsWithdrawn(address indexed creator, uint256 amount);
function payCreator(address _creator, bytes32 _contentHash) external payable;
function withdrawRewards() external;
function getCreatorEarnings(address _creator) external view returns (uint256);
}
Purpose: Community-driven platform governance
contract Governance {
struct Proposal {
uint256 id;
address proposer;
string description;
uint256 votesFor;
uint256 votesAgainst;
uint256 deadline;
bool executed;
mapping(address => bool) hasVoted;
}
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
uint256 public votingPeriod = 7 days;
event ProposalCreated(uint256 indexed proposalId, address indexed proposer);
event VoteCast(uint256 indexed proposalId, address indexed voter, bool support);
function createProposal(string memory _description) external;
function vote(uint256 _proposalId, bool _support) external;
function executeProposal(uint256 _proposalId) external;
}
https://api.rospeak.com/v1
All API requests require authentication using API keys or Web3 wallet signatures:
// API Key Authentication
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
// Web3 Signature Authentication
headers: {
'X-Signature': 'SIGNED_MESSAGE',
'X-Address': 'USER_WALLET_ADDRESS',
'Content-Type': 'application/json'
}
GET /content/{contentHash}
Response:
{
"contentHash": "0x1234...",
"creator": "0xabcd...",
"title": "Content Title",
"body": "Content body text",
"metadata": {
"tags": ["blockchain", "free-speech"],
"category": "article",
"language": "en"
},
"timestamp": 1640995200,
"earnings": 150.75,
"interactions": {
"views": 1250,
"likes": 89,
"shares": 23
}
}
POST /content
Request Body:
{
"title": "My Article Title",
"body": "Article content here...",
"metadata": {
"tags": ["topic1", "topic2"],
"category": "article",
"language": "en"
},
"accessLevel": "public" // public, premium, subscriber
}
GET /content/search?q={query}&tags={tags}&creator={address}&limit={limit}&offset={offset}
GET /users/{address}
PUT /users/profile
GET /users/{address}/content?limit={limit}&offset={offset}
POST /payments
GET /earnings/{creatorAddress}
POST /earnings/withdraw
GET /governance/proposals
POST /governance/proposals
POST /governance/proposals/{id}/vote
npm install @rospeak/sdk
import { RospeakSDK } from '@rospeak/sdk';
const rospeak = new RospeakSDK({
apiKey: 'your-api-key',
network: 'mainnet' // or 'testnet'
});
// Publish content
const content = await rospeak.content.publish({
title: 'My First Post',
body: 'Hello, decentralized world!',
tags: ['introduction', 'blockchain']
});
// Get content
const retrievedContent = await rospeak.content.get(content.hash);
// Search content
const searchResults = await rospeak.content.search({
query: 'blockchain',
limit: 10
});
npm install @rospeak/react-components
import { ContentFeed, ContentCreator, UserProfile } from '@rospeak/react-components';
function App() {
return (
<div>
<ContentFeed
tags={['blockchain', 'tech']}
limit={20}
onContentClick={(content) => console.log(content)}
/>
<ContentCreator
onPublish={(content) => console.log('Published:', content)}
/>
<UserProfile
address="0x1234..."
showEarnings={true}
/>
</div>
);
}
pip install rospeak-sdk
from rospeak import RospeakSDK
sdk = RospeakSDK(api_key='your-api-key')
# Publish content
content = sdk.content.publish(
title='Python Integration',
body='Content from Python application',
tags=['python', 'integration']
)
# Search content
results = sdk.content.search(
query='python',
limit=10
)
for item in results:
print(f"{item.title} by {item.creator}")
// Initialize SDK
const rospeak = new RospeakSDK({
apiKey: process.env.ROSPEAK_API_KEY,
network: 'mainnet'
});
// Authenticate users
const authenticateUser = async (walletAddress, signature) => {
return await rospeak.users.authenticate(walletAddress, signature);
};
// Fetch and display content feed
const loadContentFeed = async (filters = {}) => {
const content = await rospeak.content.search({
...filters,
limit: 20,
sortBy: 'timestamp',
order: 'desc'
});
return content.map(item => ({
id: item.hash,
title: item.title,
creator: item.creator,
timestamp: item.timestamp,
preview: item.body.substring(0, 200) + '...'
}));
};
// Process creator payments
const supportCreator = async (creatorAddress, amount, contentHash) => {
const payment = await rospeak.payments.create({
recipient: creatorAddress,
amount: amount,
contentHash: contentHash,
currency: 'FeeM'
});
return payment;
};
// Implement platform-specific moderation
const moderateContent = async (contentHash, moderationRules) => {
const content = await rospeak.content.get(contentHash);
// Apply your platform's moderation logic
const isAllowed = applyModerationRules(content, moderationRules);
return {
allowed: isAllowed,
content: isAllowed ? content : null,
reason: isAllowed ? null : 'Violates community guidelines'
};
};
import { ethers } from 'ethers';
// Connect to user's wallet
const connectWallet = async () => {
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const accounts = await provider.send('eth_requestAccounts', []);
const signer = provider.getSigner();
return {
provider,
signer,
address: accounts[0]
};
}
throw new Error('No Web3 wallet found');
};
// Direct smart contract interaction
const publishToBlockchain = async (content, signer) => {
const contract = new ethers.Contract(
CONTENT_STORAGE_ADDRESS,
ContentStorageABI,
signer
);
const contentHash = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(JSON.stringify(content))
);
const tx = await contract.publishContent(
contentHash,
JSON.stringify(content.metadata)
);
await tx.wait();
return contentHash;
};
// Implement Redis caching for frequently accessed content
const redis = require('redis');
const client = redis.createClient();
const getCachedContent = async (contentHash) => {
const cached = await client.get(`content:${contentHash}`);
if (cached) {
return JSON.parse(cached);
}
const content = await rospeak.content.get(contentHash);
await client.setex(`content:${contentHash}`, 300, JSON.stringify(content));
return content;
};
// Efficient content pagination
const getContentPage = async (page = 1, limit = 20, filters = {}) => {
const offset = (page - 1) * limit;
return await rospeak.content.search({
...filters,
limit,
offset,
includeMetadata: true
});
};
// WebSocket connection for real-time content updates
const ws = new WebSocket('wss://api.rospeak.com/v1/realtime');
ws.on('message', (data) => {
const update = JSON.parse(data);
switch (update.type) {
case 'new_content':
handleNewContent(update.content);
break;
case 'payment_received':
handlePaymentUpdate(update.payment);
break;
case 'governance_vote':
handleGovernanceUpdate(update.proposal);
break;
}
});
// Validate content before publishing
const validateContent = (content) => {
const errors = [];
if (!content.title || content.title.length < 1) {
errors.push('Title is required');
}
if (!content.body || content.body.length < 10) {
errors.push('Content body must be at least 10 characters');
}
if (content.title.length > 200) {
errors.push('Title must be less than 200 characters');
}
return {
isValid: errors.length === 0,
errors
};
};
// Implement rate limiting for API calls
const rateLimit = require('express-rate-limit');
const contentPublishLimit = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // limit each IP to 10 requests per windowMs
message: 'Too many content publish attempts, please try again later'
});
app.post('/api/content', contentPublishLimit, publishContent);
const DOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const purify = DOMPurify(window);
// Sanitize user input
const sanitizeContent = (rawContent) => {
return {
title: purify.sanitize(rawContent.title),
body: purify.sanitize(rawContent.body, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a', 'ul', 'ol', 'li'],
ALLOWED_ATTR: ['href']
})
};
};
// Jest tests for SDK functions
const { RospeakSDK } = require('@rospeak/sdk');
describe('RospeakSDK', () => {
let sdk;
beforeEach(() => {
sdk = new RospeakSDK({
apiKey: 'test-key',
network: 'testnet'
});
});
test('should publish content', async () => {
const content = {
title: 'Test Content',
body: 'This is a test',
tags: ['test']
};
const result = await sdk.content.publish(content);
expect(result).toHaveProperty('hash');
expect(result.title).toBe(content.title);
});
});
// End-to-end testing with Playwright
const { test, expect } = require('@playwright/test');
test('complete content publishing flow', async ({ page }) => {
await page.goto('http://localhost:3000');
// Connect wallet
await page.click('[data-testid="connect-wallet"]');
// Create content
await page.fill('[data-testid="content-title"]', 'Test Article');
await page.fill('[data-testid="content-body"]', 'This is a test article');
await page.click('[data-testid="publish-button"]');
// Verify publication
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
});
# Dockerfile for Rospeak API
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rospeak-api
spec:
replicas: 3
selector:
matchLabels:
app: rospeak-api
template:
metadata:
labels:
app: rospeak-api
spec:
containers:
- name: api
image: rospeak/api:latest
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: rospeak-secrets
key: database-url
// Application monitoring with Prometheus
const prometheus = require('prom-client');
const httpRequestDuration = new prometheus.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status']
});
const contentPublishCounter = new prometheus.Counter({
name: 'content_published_total',
help: 'Total number of content items published'
});
// Middleware for request monitoring
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestDuration
.labels(req.method, req.route?.path || req.path, res.statusCode)
.observe(duration);
});
next();
});
For the latest technical updates and detailed implementation guides, join our developer community on Discord and follow our GitHub repositories.
rospeak for community supportReady to build on Rospeak? Start with our Getting Started guide and join our Community of developers and creators building the future of decentralized free speech!