Smart Contracts
ChainSocial is built on MUD, a framework for on-chain applications. This section explains the architecture for developers who want to extend the protocol or integrate at the contract level.
Why MUD?
MUD provides:
- Structured Storage — Tables with schemas, not arbitrary mappings
- Modular Systems — Logic separated from data
- Upgradability — Add new systems without migrating data
- Access Control — Fine-grained permissions per table/system
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ World Contract │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Store (Tables) │ │
│ │ Profile, Post, Content, Follow, Reaction, Block, │ │
│ │ DirectMessage, Delegation, Notification, Plugin... │ │
│ └──────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Systems (Logic) │ │
│ │ ProfileSystem, PostCore, PostInlineSystem, │ │
│ │ PostBatchSystem, PostFeeSystem, FollowSystem, │ │
│ │ BlockSystem, ContentSystem, ReactionSystem, │ │
│ │ DelegationSystem, DirectMessageSystem... │ │
│ └──────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Access Control │ │
│ │ Namespace permissions, system-level access │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘Key Concepts
World — The single entry point. All calls go through the World, which routes to the appropriate system.
Systems — Stateless contracts with business logic. They read/write to tables and emit events.
Tables — On-chain storage with defined schemas. Tables belong to namespaces.
Namespace — A permission boundary. ChainSocial uses the chainsocial namespace.
Calling Systems
All ChainSocial systems are namespaced. Function calls look like:
IWorld(worldAddress).chainsocial__createPost(contentId, visibility);The double underscore (__) separates namespace from function name.
From TypeScript with viem:
import { encodeFunctionData } from 'viem'
import { worldAbi } from '@chainsocial/client'
const data = encodeFunctionData({
abi: worldAbi,
functionName: 'chainsocial__createPost',
args: [contentId, visibility]
})
await walletClient.sendTransaction({
to: worldAddress,
data
})System Categories
Identity (profiles, usernames), content storage, social graph (follow, block), messaging, notifications, moderation.
Post creation (standard, inline, batch), replies, quotes, attachments. Fee configuration and payment.
Permission delegation, EIP-712 signatures, on-behalf-of actions for gasless UX.
Relayer vaults, fee bounds, signed operation execution for meta-transactions.
Plugin registry, installation, consent, hooks. Extend the protocol permissionlessly.
ChainSocial ERC-20 token for fee payments.
Tables Reference
Key tables in the chainsocial namespace:
| Table | Purpose |
|---|---|
Profile | User profiles with username, timestamps, status |
ProfileField | Key-value profile metadata |
Post | Posts with content, visibility, timestamps |
PostStats | Like counts, reply counts |
Content | Content storage (inline, IPFS, URL) |
Follow | Follow relationships |
Block | Block relationships |
Reaction | Post reactions (likes) |
DirectMessage | DM content and metadata |
Conversation | Conversation summaries |
Delegation | Permission grants |
Notification | User notifications |
Plugin | Plugin registry |
PluginInstall | User plugin installations |
Extending the Protocol
MUD’s architecture means you can add new functionality without modifying existing contracts.
Adding a New System
- Create a new Solidity contract inheriting from
System - Deploy it to the World
- Grant it access to required tables
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { System } from "@latticexyz/world/src/System.sol";
import { Post, PostData } from "../codegen/index.sol";
contract TippingSystem is System {
function tipPost(bytes32 postId) external payable {
PostData memory post = Post.get(postId);
require(post.author != address(0), "Post not found");
// Send tip to author
(bool success,) = post.author.call{value: msg.value}("");
require(success, "Transfer failed");
}
}Adding a New Table
- Define the table schema in
mud.config.ts - Run code generation
- Create systems that read/write to the table
// mud.config.ts
export default mudConfig({
tables: {
Tip: {
keySchema: {
postId: "bytes32",
tipper: "address",
},
valueSchema: {
amount: "uint256",
timestamp: "uint256",
},
},
},
});Cross-System Calls
Systems can call each other through the World interface to preserve msg.sender:
import { IWorld } from "../codegen/world/IWorld.sol";
contract MySystem is System {
function createPostAndFollow(bytes32 contentId, address userToFollow) external {
// Create post
IWorld(_world()).chainsocial__createPost(contentId, 0);
// Follow user (preserves msg.sender)
IWorld(_world()).chainsocial__follow(userToFollow);
}
}Events and Indexing
ChainSocial uses MUD’s Store events for indexing. State changes are captured through MUD’s table write events rather than custom per-action events.
MUD automatically emits events when table records are created, updated, or deleted. The indexer listens for these Store events to build the queryable database.
Some systems emit custom events for specific operations:
ContentSystememitsContentCreatedDirectMessageSystememitsMessageSentDelegationSystememitsDelegationRegisteredVersionSystememitsProtocolVersionUpdated
Most other state changes (profiles, posts, follows, reactions, blocks) are indexed through MUD’s Store events rather than custom events.
Security Considerations
- Access Control — Check permissions in systems before state changes
- Reentrancy — Use checks-effects-interactions pattern
- Input Validation — Validate all inputs (addresses, content lengths)
- Delegation — Always check
isDelegateAuthorizedfor on-behalf-of actions
Deployment
ChainSocial uses MUD’s deployment tooling:
cd packages/contracts
pnpm mud deploy --rpc <RPC_URL>After deployment, archive build artifacts immediately. The via-IR optimizer produces non-deterministic bytecode, making verification impossible if artifacts are overwritten.
Contract Addresses
| Network | Chain ID | World Address |
|---|---|---|
| Base Mainnet | 8453 | 0x7405fCbEc24C00278b7e821Ace222f5CFfa6c6eA |
Next Steps
- Core Systems — Identity, content, social graph details
- Posts & Fees — Post creation and fee handling
- Plugins — Build extensions