Games have always been the proving ground for breakthrough technology. Take GPUs, for example — the same hardware now powering massive AI models advanced primarily due to video game demand. And the current AR and VR boom? That, too, has its roots in game development.
We also have blockchains, which bring value by offering trustless authority: they ensure something happened and record exactly how it happened. This concept could be invaluable for many industries like finance and gaming (think of the Steam Community Market). But wouldn’t it be fantastic to have a version without a 15% fee on every transaction and the walled garden of SteamBucks?
However, interacting with blockchains and especially smart contracts, has always been a pain.
Imagine this: you get a brilliant idea to recreate your favorite game, Minecraft, on a blockchain. You dive in, spending weeks wrestling with Solidity to implement movement and block placements, deploying contracts, and juggling countless methods for reading and writing to them. In Web2, you’d have neat libraries like viem and ethers.js, but doing this in game engines like Unity or Unreal Engine? It’s a whole different nightmare. Sure, you might try Nethereum for Unity, only to find it requires an ancient version of Unity, or Etherlinker for Unreal Engine, which only works with UE4.27. Ugh.
Then come the skyrocketing gas fees and the endless MetaMask popups every time you attempt a networked action — not to mention latencies stretching into the tens of seconds.
And let’s not forget our commitment to the open internet — a core tenet of Web3 that often gets lost in favor of walled gardens and profit. To keep the internet truly open, we need a registry that tracks everything happening, so anyone can view and react in real time.
Imagine if anyone could build a minimap (see dynmap) for your Minecraft world, replay every event exactly as it happened, or even fork your world for their own fun? Now, picture every game with an API like Bungie’s Destiny 2 API. Kudos to Bungie for making it freely available — sparking amazing fan tools like Destiny Item Manager, light.gg, bray.tech, and Today in Destiny. We’ve seen what happens if you can open up the platform in Web2. The potential for brilliant platforms on a truly open and discoverable Web3 is simply mind-blowing.
Some groups have tried tackling this problem before. Solutions like MUD address some issues, but they fall short because:
- They don’t integrate seamlessly with an open Web3 model.
- They aren’t compatible with high-performance L1 blockchains that deliver rapid finality, low latency, and high throughput — crucial for real-time gaming and dynamic applications.
- They lack smooth, simple integration across popular platforms like React, Unreal Engine, or Unity.
- They force you to work with complex, pre-written smart contracts, tying you into a rigid architecture.
We wanted to build on-chain Minecraft. It had to have:
- Real-time interaction.
- Open discoverability of events and state.
- Great integration with existing game engines.
- Ease of implementation.
So we built Etherbase!
And because effortless scalability is a must, we designed it to work best with Somnia.
Introducing Etherbase: A New Approach
Etherbase is an early-stage prototype designed to simplify on-chain interactions while maintaining openness and discoverability. Development will progress alongside Somnia’s maturity and community feedback.
Etherbase Contract: The Registry Layer
The Etherbase contract is the discoverable registry of everything you can do with Etherbase. It stores the ABI of any contracts you want, and you can deploy Etherbase Source contracts which are automatically registered, eliminating the need to write Solidity manually.
In the future, different platforms may leverage these registries, just like OpenSea catalogs NFTs, even though they’re stored on-chain.
Want to query available Source or custom contracts? Simple:
mapping(address => CustomContract) public customContracts;```
Etherbase Source Contract: Effortless On-Chain Interactions
The Etherbase Source contract makes it incredibly easy to read/write events and state, and execute smart contract functions without Solidity or complex libraries.
Key Features:
- KV Store — A simple key-value store for structured, dynamic data. The data can be discovered or subscribed to by anyone.
- Event Emission — Register schemas (e.g., event Transfer(bla)) and emit structured events via an easy call.
- Role-Based Access Control — Restrict write operations as needed.
This entire system runs on-chain, with no Web2 infrastructure required.
You can trivially query any schemas or data, such as:
function getRegisteredEventNames() external view returns (string[] memory) {
return registeredEventNames;
}
mapping(string => EventSchema) public eventSchemas;
...
function getValue(
string[] calldata segments
) external view returns (EtherDatabaseLib.DataType, bytes memory) {
return db.getValue(segments);
}
function setValue(
string[] calldata segments,
EtherDatabaseLib.DataType dataType,
bytes calldata data
) external auth(Role.DBSET) {
db.setValue(segments, dataType, data);
}
Etherbase Web2 Backend with Pub/Sub
We’ve implemented a fast backend for taking the blockchain data and allowing for effortless integration into your applications.
- A proxy layer for high performance execution of Source or custom contracts, enabling any platform with websocket or HTTP support to write to the blockchain.
- A structured websocket pub/sub system for reading and streaming realtime blockchain state and event updates. When used with our own events or Source contracts, supports granular state updates such as subscribing only to users.alice.balance in your Source KV store.
We’ve found these two features significantly simplifies retrieving complete views of data, removing the need for developers to manually poll for updates and reconstruct views manually.
The backend is designed to handle high-performance loads, ensuring smooth operation on chains like Somnia, which are optimized for game-like interactions and can easily reach hundreds of thousands of transactions per second — a scale no existing infrastructure is designed to handle.
Seamless Web2 and Web3 Frontend Support
To make the integration as seamless as possible, we’ve started with some easy-to-use Web2 integrations with Etherbase.
- A React NPM package for seamless integration with web applications with minimal effort, with inspiration from Firestore React hooks.
- A straightforward example Web2 frontend for developers who prefer a UI-driven approach rather than coding smart contract interactions.
We think these simple Web2 additions add a great option alongside the Web3 qualities of Etherbase, making it as easy as possible for anyone to interact and get started.
Built for high performance
Etherbase is designed to scale with high throughput blockchains, which is where we think the future of real-time applications will be built. For this reason, we’ve built Etherbase to work best with Somnia.
Somnia guarantees cheap gas costs, extremely high throughput (1m+ TPS), low latency, sub-second finality times, and great scalability when writing to the same storage slot; something parallelisation like Aptos doesn’t help with, which leads to significantly lower throughput for those parallel chains.
You can use Etherbase with other blockchains, but your gas bill, lag, and sanity may vary.
Technical Approach
Overview
In this overview, we use the example of a real-time 3D voxel world where the player positions and block placements are on-chain. We send the block updates as state updates as the historic state is important for any new user. We send the player positions as events as the precise position is ephemeral. We use an Etherbase Source contract for this example, but a custom contract could also be used for the same result.
First the players register their subscriptions for reading player position event updates and all block state updates:

Now all the players have subscribed, and they have received all the current block positions in the world.
Next, player 1 moves:

Player 1’s position update is sent to the chain as an event, which is then received by both players. Player 1 uses this event to make sure their position was sent correctly. Player 2 applies this update to the rendered player 1, which makes the player move.
Finally, player 2 places a block:

This block is sent as a state update which is then received by both players. Again, player 1 applies this new block, while player 2 uses it to check the block was applied correctly.
If a custom contract is used for this logic, you can see how you could implement anti-cheat: reject a player for placing a block they are not next to, or implementing movement validation such as limiting a player’s movement velocity.
Optimized Granular Updates
Let’s say you want to poll the balances of some users in an ERC-20 contract,
The simplest way to do this is to frequently poll the contract state until the value changes, but this is a significant waste of compute and node API requests, and won’t scale to many users.
The next optimization step is to check the balance whenever an event is fired on the contract — this probably means something changed, so you can check. You can be even better by knowing what event should be fired, in this case:
event Transfer(address indexed from, address indexed to, uint256 value)
You watch for the Transfer event to be fired, either via eth_subscribe or trawling the logs for the event topic of the event.
Finally, the most optimised form is to check the topic of your address being present as well in the event. This means you’ll only ever check the balance if the user sent or received money, which is the optimal way to check.
Doing this repeatedly for many different cases, something games do a lot, is a lot of repetition and unnecessary complexity. We’ve made a simple generic way to do the above on any Source or custom contract — you specify the paths you want to listen to, e.g. balances.0xabcd… and request for updates whenever Transfer fires with the arguments from or to having the address 0xabcd…
In the etherbase-client react hooks, the above looks like this:
const { state, loading, error, update } = useEtherstore([contractAddress, "balances", ["0xabcd...", "0xefff..."]], {
repoll: {
listenEvents: [
{
name: "Transfer",
args: {
from: ["0xabcd...", "0xefff..."],
to: ["0xabcd...", "0xefff..."],
},
},
],
},
});
// state: {"0xabcd...": 13, "0xefff...": 37}
Easy!
We also support the less efficient update mechanisms, but we’ve found the granular updates so easy to write with such great optimisations that it’s worth doing.
We’ve also implemented paths updates for optimised data updates that are natively supported by Etherbase:
interface IEthDBUpdater {
event EthDBPathUpdate(
string[] path,
bytes data,
uint8 dataType
);
event EthDBUpdate();
}
These allow for easy updates if you implement your own solidity contracts and register them with the Etherbase contract — we automatically detect these events in a granular way without requiring you to specify your own custom events and arguments.
View Completeness
Streaming blockchain data can introduce view consistency challenges. For instance, in an on-chain chess game, when a player moves a piece, two updates occur simultaneously: the piece is removed from one square and placed on another. Without careful handling, users might briefly see the piece disappear before it reappears, which disrupts the experience.
While you can re-engineer your contract to bypass these view completeness complexities, this approach does not address cases where view completeness issues are inherent. Therefore, it is crucial to aggregate all updates from each block before sending them to clients.
We have chosen to hold updates and emit them on a per-block basis instead of providing a continuous stream for several reasons:
- Reduced Client Data Load: This approach avoids overwhelming the client with large volumes of data, especially during high transaction periods.
- Minimal Latency: A fast backend ensures that the latency between the first and last log per block is very low, making any delay negligible.
- Backend Processing: By handling the processing on the backend, we eliminate the need for end users to reconstruct and manage view completeness logic. This is particularly beneficial for platforms like Unreal Engine blueprints.
In the future, we may consider offering a lower-latency update stream that allows for manual control of view completeness if it proves to be valuable.
Real-World Use Cases
It’s quite easy to make a fully on-chain 3D game with Etherbase — without it, and without a high performance blockchain like Somnia, it’s extremely difficult.
Guide and Demo: On-Chain Movement in Gaming
First, we need a basic 3D game — I’ve chosen React ThreeJS for its simplicity, and used AI to write the entire thing without any networking yet.
For the networking, we create a new Source in the example frontend:

Add a new private key that can emit events and set it in my codebase:


Set the source and the private key values in the codebase:
export const etherbaseConfig: EtherbaseConfig = {
privateKey:
"0x1f7c04305fd6...",
useBackend: true,
}
export const sourceAddress = "0xc4974fc167FC1E6d0bBa729a1749BcE3eC1C585E"
Add the PlayerUpdate event to the Source contract:

Then let’s add the event emitter logic:
const sourceAddress = "0xabcd..."
const { emitEvent } = useEtherbaseSource({ sourceAddress })
const interval = setInterval(async () => {
const now = Date.now()
const eventName = "PlayerUpdate"
const eventArgs = {
posX: Math.round(positionRef.current.x * FLOAT_PRECISION),
posY: Math.round(positionRef.current.y * FLOAT_PRECISION),
posZ: Math.round(positionRef.current.z * FLOAT_PRECISION),
color: playerColor,
name: playerName,
timestamp: now,
playerId: playerId,
}
await emitEvent({
name: eventName,
args: eventArgs,
})
}, 50) // Send 20x/sec
And now the event reading logic:
useEtherbaseEvents({
sourceAddress,
eventNames: ["PlayerUpdate"],
onEvent: handlePlayerUpdate,
})
const handlePlayerUpdate = useCallback(
(event: any) => {
// Ignore our own updates
if (event.args.playerId === playerId) return
// Decode position
const posX = (event.args.posX as number) / FLOAT_PRECISION
const posY = (evenmaget.args.posY as number) / FLOAT_PRECISION
const posZ = (event.args.posZ as number) / FLOAT_PRECISION
const { color, name, timestamp } = event.args
const now = Date.now()
setRemotePlayers((prev) => {
const newRemotePlayers = { ...prev }
const id = event.args.playerId
if (!newRemotePlayers[id]) {
newRemotePlayers[id] = {
displayPosition: new THREE.Vector3(posX, posY, posZ),
latency: now - timestamp,
color,
name,
}
}
newRemotePlayers[id].latency = now - timestamp
return newRemotePlayers
})
},
[playerId],
)
And then the event reading logic:
useEtherbaseEvents({
sourceAddress,
eventNames: ["PlayerUpdate"],
onEvent: handlePlayerUpdate,
})
const handlePlayerUpdate = useCallback(
(event: any) => {
// Ignore our own updates
if (event.args.playerId === playerId) return
// Decode position
const posX = (event.args.posX as number) / FLOAT_PRECISION
const posY = (evenmaget.args.posY as number) / FLOAT_PRECISION
const posZ = (event.args.posZ as number) / FLOAT_PRECISION
const { color, name, timestamp } = event.args
const now = Date.now()
setRemotePlayers((prev) => {
const newRemotePlayers = { ...prev }
const id = event.args.playerId
if (!newRemotePlayers[id]) {
And voila, suddenly you have a fully networked on-chain game, replicating position at 20Hz!
Showed up to the @MSquared_io protocol team call today and one of our devs is deadass running multiplayer game position updates through @Somnia_Network and it just works. Insanity. A million TPS just redefines what you'd think is feasible to do on-chain. pic.twitter.com/UbflDLJwpm
— Rob Whitehead (@RJFWhite) February 11, 2025
With a couple dozen bots, this demo was able to easily reach thousands of transactions per second on the Somnia devnet

Other ideas
There’s so many other great ideas that we’d love to try; here’s just a few to spark some inspiration:
- On-chain chess with real-time views for anyone wanting to watch with seamless historic playback. Chess logic can be written entirely within solidity, and winners can be rewarded with NFTs. Leaderboards are automatically updated based on calculated ELO.
- Using a blockchain as the permanent store for meaningful data like achievements, inventory, and other player state. Integrating this into existing game engines like Unreal Engine and Unity can be easy with Etherbase, with demos and sample projects available soon.
- Combining MML with Etherbase for a seamlessly interoperable integration with the blockchain. We have a work-in-progress demo, but the potential for interactions are endless here.
For inspiration, here’s a test of MML and Unreal Engine together with the realtime 3D movement demo:
Getting Started
Of course, Etherbase had to be open source: http://github.com/msquared-io/etherbase
Try it now and bring high-performance on-chain interactions to your apps with ease!
Our Next Steps
We’re just getting started. As Etherbase evolves, we’re focused on:
- Security — Audits and optimizations.
- Gas Refunds — Covering fees via Source contract pools.
- Session Keys & Account Abstraction — Enabling seamless, gasless transactions.
If you’ve enjoyed or hated any of what we’ve done, we’d love to hear it! Connect with us on X and let us know what you think!
Join Us at ETH Denver!
We’re excited to be attending ETH Denver alongside Somnia, and we’d love for you to explore Etherbase in its current state. All hackathon participants will have the chance to play, experiment, and build with it!
We’re also sponsoring a track with a $2,000 cash prize for the best product, game, experience, or tool that leverages Etherbase’s event and state system as its primary storage solution.
So bring your ideas, start building, and let’s push the boundaries of what’s possible!