# MUD - How we built an EVM application framework from the ground up by Alvarius | Devcon SEA

- Channel: [Devcon](https://streameth.org/devcon)
- Date: 2025-10-07
- Duration: 19:28
- Watch: https://streameth.org/watch/yt-w02aI1S7gcc
- YouTube: https://www.youtube.com/watch?v=w02aI1S7gcc

## Description

We wanted to accomplish one simple task: put a game—with all its data and logic—on a blockchain. What followed were countless technical challenges, years of efforts, and learnings that are applicable to anyone building complex onchain apps.

How should data be structured? How can complex world state stay up-to-date on the client? How do we allow multiple teams to build on one single world, without it all breaking apart? Join us as we share the pitfalls and learnings.

Speaker(s): Alvarius
Skill level: Intermediate
Track: Developer Experience
Keywords: DevEx, Frameworks, Gaming, Autonomous World, onchain

Follow us: https://twitter.com/efdevcon, https://twitter.com/ethereum, https://warpcast.com/devcon
Learn more about devcon: https://www.devcon.org/
Learn more about ethereum: https://ethereum.org/ 

Visit the https://archive.devcon.org/ to gain access to the entire library of Devcon talks with the ease of filtering, playlists, personalized suggestions, decentralized access on Swarm, IPFS and more.

Devcon is the Ethereum conference for developers, researchers, thinkers, and makers. 
Devcon SEA was held in Bangkok, Thailand on Nov 12 - Nov 15, 2024.
Devcon is organized and presented by the Ethereum Foundation. To find out more, please visit https://ethereum.foundation/

## Transcript

[Music] hello everybody my name is alvarius I'm an onchain developer mostly focusing on fully onchain games and today I'm going to tell you a story about how we built our first fully onchain game and made a big mess and then build a framework that now allows us to build full onchain game prototypes in a matter of a couple of days but first let me take you back to around three and a half years ago um three and a half years ago my friend Justin and I we discovered Dark Forest and we got really inspired by it dark forest was one of the first fully onchain games and that means basically all the game mechanics all the physics of your game are deployed or are living in a um in smart contracts on a public blockchain and then the client is essentially just a window in to this onchain world and now you suddenly have something where um the world will essentially live on as long as the chain will live on which makes it feel very real and then also the other thing is you're deploying to a public Global computer where also everybody else can deploy to the same computer and extend the world so there's a lot of potential for um emergent Behavior here and we had this feeling that we there's this potential to create something that can be more meaningful than existing Virtual Worlds of course just a potential you still have to build a fun game and so we got started building we get started with the default patterns that everybody was using at the time so the first thing we wanted to add was positions for our entities in the game and so we added a mapping on the contract and then also a mapping on the client because of course we want to render the entities the position of our entities in our client and then we had to add a couple of getter functions so that our client when the Cent loads can basically hydrate the initial State on the client and then we added the first physics of our game the move function um and in here we have to make sure to both modify the state but then also emit an event that the client can listen to to keep the state in sync so this is a lot of boilerplate just for having um one type of State synchronized between contracts and clients and of course we don't only want position but but a lot more on chain state so the next thing we added was health our entities but now we had to add the exact same baller plate again mappings G functions custom events custom sync stack on the client and then the same thing for energy and for skills and for inventory and you get the idea it's the same baller plate over and over again and at some point we were at the point where we couldn't really iterate on the actual game mechanics anymore because every time we wanted to change anything we basically had to drill that change through the entire s stack just to keep the contract and client state in sync and so at some point we decided to trash everything we have and change something um we decided to build a framework to solve our own problems so that for the next project we could basically skip all the boilerplate and just focus on the fun stuff on the game mechanics of our game and that framework over the last three and a half years turned into mud and now we're not the only ones using it now it's used by a bunch of teams um from small teams to Big teams who all ran into the same problems that we ran into and now they use muds to ship faster so in the next 15 minutes I'm going to talk about three problems that we ran into back then and how we solved them in mud the first one I already told you about onchain games have a lot of state and you need to synchronize that state to the client to render a game and I also already told you about the fact that the default approach of using gter functions events and so on doesn't scale well and so here's what we did the first thing we did was standardize the way we basically shape our our state and so now we just use tables for everything um a table you can kind of think of it as a mapping in solidity you can implement it as a mapping in solidity um but we like to think of it as tables and tables can have multiple rows we call those records and then each record is uniquely identified by one or more keys and now the important thing is what happens when a record in our table changes well instead of emitting a different event for each different type of table like position changed Health changed and so on WE emit one default event one generic event for all the tables and on that event we have enough information um to know which table changed which record changed and which value in that record changed and then with this generic event we can then build a syn stack that understands this generic event and then takes care of updating the same value on the client and now we don't need any you know we don't need a custom syn stack adapter for every different type of table but we can reuse the same code for all the different state that we have and then we generate some libraries for the contracts that basically just take care of setting the state and then also emitting this event so we don't have to think about that every time and now we essentially eliminated all the boiler plate because now adding a new type of state is just one line of code on the contracts it's automatically synced to the client and then one line on the cont on the client to access the state there and then once we have this automatic syn stck we can do more fun stuff with it like we can also pipe the state into a relational database from which then the clients can use it to sync the state quicker so we now also have an automatic indexer and because now all the state lives in an in a relational database we can also use SQL to basically query all of our onchain state now some of you might might have noticed that solidity doesn't actually have generic events so we have to use a little trick here what we do is on the contracts we basically encode the state as tightly as possible and then um we store the and then we emit that encoded data as as bites on the event so our event signature is just bites everywhere and then on the contract also we have a a special table which stores the schema of all the other tables and this table is also synced through the through the default sync stack and that means now the clients and indexers have the information that they need to then decode this state update and all of that is encapsulated in this automatic sync stack um so it all happens automatically um I have a little demo for how this looks in practice and I think I have to yep all right so here we see um a client on the on the left side we see a default app of M counter every time we click the button a transaction is sent on the right side you see the world Explorer you can see the transactions and then what happens is in the background the sync stack basically synchronizes the state from the contracts back to the client and that's when the UI updates and the other thing you can see here is in the world Explorer there's also a view to um basically inspect all the all the data in your app because it's all standardized in tables and then we can look at another quick demo which is um a slightly more complex table a task list and here we can use SQL input on the world Explorer as well um to basically fill tilter down the task list to only display the tasks that have been completed or or not completed yet and obviously you could also use more complex SQL here all right so that's the core of it but that's it doesn't end here the next problem we ran into is logic onchain games also besides a lot of State they also have a lot of logic so the next issue we ran into is the you know 24 kilobytes bite code limit on contracts um here's how we solve it the General approach is very similar to the diamond pattern so we have one Central entry point which we call the world contract and then into that contract we register stateless system contracts that basically implement the functionality and then when a user calls the W contract they only need to know the address of this one world contract and then the call is forwarded to the system contract so far pretty standard Diamond um but now we can add the store to it in the store we have a table for the systems so now when we register a new system in the world information about the system is also stored in the systems table and now the automatic syn stack can take over and basically you know mirror that information into a database and then from that database we can generate an an API which is always up to date so when we redist a new system that also gets reded into the systems table and then the ABI immediately updates now I told told you that systems are stateless which is true but they can still interact with State they can read from tables and they can also ride to tables and then that data is also again automatically synced to the client but because the system contract itself doesn't contain any state we can very easily upgraded it's really trivial we literally just swap out the implementation address and we don't have to um take care of you know storage slots ordering or whatever because the system contracts themselves totally stateless all the state lives in the store in the world and then when new tables are registered at runtime later those are also picked up by the by the automatic sync stack immediately um and each table has its own storage position in this contract so there's no state overlaps or storage slots overlaps and with that we can we can then take it one step further and introduce the concept of name spaces which basically means a system that is registered in a nam space can read from all the tables but can only write to the tables that are in the same name space and with that we can now really lean into extendability because we can basically allow anybody to register new functionality in our world contract all right another quick demo we see again the counter table and now we see the interact tab in the world Explorer which basically shows all the functions available on the world including the one um that increments the counter and we can also interact with the world through this uh Explorer and now when we we add a new function the another increment function that adds two to the counter we save that file in the background it's immediately upgraded through the def tool um and then the the new AI function immediately shows up on the world Explorer and we can again use the world Explorer to interact with the app all right last one for today is higher level logic you may be familiar with ec20 and the approve and transfer from functionality which basically among other things oh well it allows you to um give somebody permission to transfer on your behalf which among other things um enables Atomic swaps so pretty cool now let's say we want to add that to our game we want to allow somebody we want to give somebody permission to move our unit um on our behalf um now we could add an approved move function and a move from function and then when we want to do the same for attacking we could add an approve attack and then attack from function but that would again be a lot of voiler plate and now let's say we wanted to add something very similar but slightly different um we want to allow somebody to sign a piece of data that then allows us to um attack or move on somebody's behalf so should we add move with signature attack with signature because we have a framework now we can move that logic one level higher to the level of the framework and then we don't have to implement it in each of the systems so in our case we can add a new entry point to the world which is which is called call from and it takes another argument in addition to the system arguments which is the address that you want to call on whose behalf you want to call and then this entry point can implement the the functionality for checking that this delegation is actually valid and then if it's valid it forwards the call to the system with this new address that you're calling on whose behalf you're calling and then with that we don't have to implement that for every system again but rather it just implemented once at the framework level and works for all the systems and same with the the signature example we we have a call with signature end point entry point here where you can call it with a signature from somebody that allows you to call a function on their behalf and then if it's valid it's forwarded to the system as them basically this is useful for a bunch of different things but one example is session wallets so in our game we don't want uh an approval pop up every time we do anything um oh not not d a time yet um we don't want an approval popup when we do anything but rather we want to create a a scope to delegation once at the beginning and then um the user should be able to for the for the duration of the session to just do moves in in the game without additionally approve approving and in our case now we can connect the main account we can create the scope delegation through this entry point function and then um yeah user doesn't have to click approve every time again and we have again another quick quick demo of this um this is using some UI that ships with with M um here we the user can create an account um or connect an existing account in this example we're creating a pasy account then a delegation is set up um and then once that is set up the user can basically move in the game without Additionally you know clicking approve every time again this is an a demo app we built to demo this this onboarding flow but then also some latency stuff that we that we walked um you can try it out if you want on your phone on eat thefly.com um and yeah this was just a tiny glimpse into mud um which we built in the beginning to solve our own problems but now is used by many people to who had the same problems um many of them are going to present to tomorrow at mday here in this venue at classroom a um so I would recommend to to uh come check that out if this was interesting to you and then if you can't make it tomorrow or just in general you can also learn more about mud on m.de and with that thank you and hopefully see you tomorrow good stuff I don't know if I'm a Frog or if I'm if it's lunchtime because that made me hungry cool so the first question uh from the Q&amp;A is that in your demo transactions are happening instantly in redstone block time is two seconds what's going on there yes so that's the that's some some new um instant confirmation stuff we worked on um we're going to talk more about that tomorrow at mday um so yeah I don't want to I don't want to reveal too much so I would recommend to come to mday tomorrow very interesting next question how do you handle a table growing beyond the size of one storage slot okay that that might have been unclear in the way I explained it tables can grow indefinitely big um you can basically one table the the table um can have multiple records and the records can span multiple storage slots so there's no there's no one storage slot limitation um you can have a the schema has some limitation in the the number of fields you can have I think it's 28 Fields um and then one table can have multiple records as many as you want and that just you know is is linear in storage so so you can go on as as as as much as you want okay so how does Mud sync table schema changes for Rel relational databases and ensure that there are no issues what happen happens if that schema migration does not work that's a that's a great question um you can't currently change a schema so it's basically you register a table once and then that's the schema that you will have um if you if you need to change the schema you can create a new table um in theory it should it it would be like doable to add fields to your schema but yeah like the with the mentioned complications you would have to do a database migration as well and that's um that's not not trivial so we decided to just make schema immutable cool um how were namespaces implemented in evm um I don't know into how much detail I can go here but it's basically just like contract logic like we um have access control logic in the wall contract that makes sure that you can only um write to tables uh uh that you that you have access to oh maybe maybe one thing that I didn't mention that that might make this more clear um if a system is registered in a nam space then what happens if the user calls the the World entry point is the world doesn't do a delegate call to the system which a normal like default Diamond would do um but rather it does a call and then when the system wants to read or write from the table then it basically does a call back to the world and at that point we can do access control um on the name spaces okay I think this is the last question in the queue uh what do you think about the possibility of building real-time multiplayer games using new existing infrastructure projects that provide tees trusted execution environments while using mud to store the incremental changes to save costs yeah this is also a great question um again I would recommend you all to come to mday Tomorrow there's there's some demos there um that kind of do something in this direction it's a real-time game um slightly different approach but yeah definitely definitely possible to do real- Time games at this point this is the same talk tomorrow right it's uh in classroom a uh tomorrow I'm not sure what time exactly I think 1 11: until 5: or something okay classroom May if you want to hear about when they do immediate stuff with tees okay we got one more question Game Dev is often on the tech Frontier what lessons for the do you have for the rest of the industry yeah so we started this framework as a as a way to build our games more efficiently but as we built this framework we at some point we realize there's nothing in this framework that's specific to to game def actually um so yeah if you're if you're building an onchain app that's not a game I would recommend you to just try it out as well um and it might just make it easier okay and I think we got time for one more question um why do we need to bring everything on chain and how does this scale moving forward for FPS games yeah this is almost a philosophical question like why do we need to bring stuff on chain um there's a lot of advantages or like a lot of things that that are interesting about it what I mentioned in the beginning um you have something that can potentially live on forever um you have the potential to for other people to extend it in in more interesting ways because they can deploy code to basically the same computer that this game is running on um in terms of skat ability that's kind of what we're working on and also a lot of lot of other people are working on um I think it's interesting to try to push the um the you know like try to put more ambitious things on chain to basically extend what we can uh do on chain um to kind of remove those limitations
