Skip to main content

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 indexing
  • address[] 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:

  1. App Index: keccak256(abi.encodePacked(app)) - All messages from a specific app
  2. App + User Index: keccak256(abi.encodePacked(app, user)) - User's messages in an app
  3. App + Topic Index: keccak256(abi.encodePacked(APP_TOPIC_HASH_PREFIX, app, topic)) - App messages by topic
  4. App + User + Topic Index: keccak256(abi.encodePacked(APP_USER_TOPIC_HASH_PREFIX, app, user, topic)) - User's messages in app by topic
  5. Global Index: Direct access via messagePointers array - All messages chronologically

Hash Prefixes​

To prevent hash collisions between different index types, Net uses prefixes:

  • APP_TOPIC_HASH_PREFIX = 1
  • APP_USER_TOPIC_HASH_PREFIX = 2

Message Sending Process​

Direct Messages (sendMessage)​

When a user sends a direct message:

  1. Validation: Checks that message is not empty (lines 114-116 in Net.sol)
  2. Index Creation: Updates all four hash indexes with address(0) as app (lines 122-140)
  3. Storage: Encodes and stores message using SSTORE2 (lines 146-163)
  4. Event: Emits MessageSent event with message index (line 143)

App Messages (sendMessageViaApp)​

When an app sends a message on behalf of a user:

  1. Validation: Checks that message is not empty (lines 44-46 in Net.sol)
  2. Index Creation: Updates all four hash indexes with the app address (lines 52-78)
  3. Storage: Encodes and stores message using SSTORE2 (lines 84-101)
  4. Event: Emits MessageSentViaApp event 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 range
  • getMessagesInRangeForApp(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 messages
  • InvalidRange() - Reverted when start index >= end index
  • InvalidStartIndex() - Reverted when start index is out of bounds
  • InvalidEndIndex() - 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.