How Net Works
Net Protocol is a decentralized onchain messaging system that enables efficient storage and retrieval of messages across multiple dimensions. This technical overview explains the core mechanisms that make Net work.
Core Architecture
The Net Contract
Net Protocol is implemented as a single smart contract deployed at the same address across multiple EVM-compatible blockchains:
Contract Address: 0x00000000B24D62781dB359b07880a105cD0b64e6
The contract uses two main storage structures:
mapping(bytes32 hashVal => uint256[] messageIndexes) public hashToMessageIndexes- Multi-dimensional indexingaddress[] public messagePointers- SSTORE2 pointers to message data
Message Structure
Every message follows this standardized structure:
struct Message {
address app; // Contract address that sent the message
address sender; // User address who sent the message
uint256 timestamp; // Block timestamp when message was sent
bytes data; // Binary data payload
string text; // Human-readable text content
string topic; // Message topic/category for indexing
}
Multi-Dimensional Indexing System
Net's key innovation is its indexing system that enables efficient querying across multiple dimensions simultaneously.
Index Types
The system creates five types of indexes for each message:
- App Index:
keccak256(abi.encodePacked(app))- All messages from a specific app - App + User Index:
keccak256(abi.encodePacked(app, user))- User's messages in an app - App + Topic Index:
keccak256(abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic))- App messages by topic - App + User + Topic Index:
keccak256(abi.encodePacked(APP_USER_TOPIC_HASH_PREFIX, app, user, topic))- User's messages in app by topic - Global Index: Direct access via
messagePointersarray - All messages chronologically
Hash Prefixes
To prevent hash collisions between different index types, Net uses prefixes:
APP_TOPIC_HASH_PREFIX = 1APP_USER_TOPIC_HASH_PREFIX = 2
Message Sending Process
Direct Messages (sendMessage)
When a user sends a direct message:
- Validation: Checks that message is not empty (lines 114-116 in Net.sol)
- Index Creation: Updates all four hash indexes with
address(0)as app (lines 122-140) - Storage: Encodes and stores message using SSTORE2 (lines 146-163)
- Event: Emits
MessageSentevent with message index (line 143)
App Messages (sendMessageViaApp)
When an app sends a message on behalf of a user:
- Validation: Checks that message is not empty (lines 44-46 in Net.sol)
- Index Creation: Updates all four hash indexes with the app address (lines 52-78)
- Storage: Encodes and stores message using SSTORE2 (lines 84-101)
- Event: Emits
MessageSentViaAppevent with message index (line 81)
Storage with SSTORE2
Net uses SSTORE2 for gas-efficient message storage:
// Each message is stored individually
messagePointers.push(
SSTORE2.write(
abi.encode(
msg.sender, // app
sender, // sender
block.timestamp, // timestamp
data, // data
text, // text
topic // topic
)
)
);
This approach provides gas efficiency for larger data while maintaining individual message accessibility.
Message Retrieval
Single Message Retrieval
Messages are retrieved by reading from SSTORE2 and decoding:
function getMessage(uint256 idx) external view returns (Message memory) {
return decodeMessageAtIndex(idx);
}
function decodeMessageAtIndex(uint256 idx) public view returns (Message memory) {
return decodeMessage(SSTORE2.read(messagePointers[idx]));
}
Multi-Dimensional Querying
The indexing system enables efficient queries across different dimensions:
- By App:
getMessageForApp(idx, app)- Get message from specific app - By App + User:
getMessageForAppUser(idx, app, user)- Get user's message in app - By App + Topic:
getMessageForAppTopic(idx, app, topic)- Get app message by topic - By App + User + Topic:
getMessageForAppUserTopic(idx, app, user, topic)- Most specific query
Batch Retrieval
Range-based queries enable efficient batch operations:
getMessagesInRange(startIdx, endIdx)- Get multiple messages by global index rangegetMessagesInRangeForApp(startIdx, endIdx, app)- Get multiple messages from app- Similar functions for all index types
Error Handling
Net implements four custom errors for robust error handling:
MsgEmpty()- Reverted when attempting to send empty messagesInvalidRange()- Reverted when start index >= end indexInvalidStartIndex()- Reverted when start index is out of boundsInvalidEndIndex()- Reverted when end index is out of bounds
Cross-Chain Consistency
Net maintains the same contract address across all supported chains through CREATE2 deployment, enabling consistent cross-chain interactions and data portability.
Security Model
Permissionless Design
- No Access Control: Anyone can send messages (lines 42, 108 in Net.sol)
- No Censorship: Messages cannot be blocked or modified
- Immutable Storage: Once stored, messages cannot be changed
This architecture enables Net to serve as a foundational protocol for building fully onchain applications that can efficiently store, index, and retrieve data across multiple dimensions while maintaining decentralization and censorship resistance.