New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

MUD 101 how to build your first AW - Alvarius

ETHGlobalMon, Oct 9, 2023, 12:00 AM

Join Alvarius from Lattice for a workshop titled "MUD 101: how to build your first AW". We invite you to join the first virtual Autonomous Worlds hackathon, where participants will explore the potential of multi-author Worlds by developing onchain games, worlds, and art projects. Leverage the power of MUD, a new framework designed for ambitious Ethereum applications, and follow in the footsteps of dozens of teams that have already built unique projects with it, including OPCraft — an onchain voxel world, EVM Factorio, real-time strategy games, and more. By working with the MUD framework, participants will not only contribute to the growth of these worlds but also deepen the understanding of the concept of Autonomous Worlds and its implications in technology and digital collaboration. ----------------- Follow us: https://twitter.com/ETHGlobal​ Check us out: https://ethglobal.co​m Email us at: hello@ethglobal.com

Transcript

foreign [Music] app to demonstrate how to get started with the framework build something real and then deploy to production but before we jump into the codes let me give you a very brief overview of a couple of important Concepts in mud so that everything else clicks into place much faster let's start with a quick reminder of how unchain development used to work without mud so in the old world let's say we want to create a contract where we want to store a mapping of the owners of a given address we store a mapping we call it owned by from address to address and then we create a function set owner which allows us to set the owner of a given address that function emits an event and then we set the owner in our own by mapping the data is going to be stored in storage and the location of the data in storage depends on the hash of the key that we use to index the mapping that means if we have access to a full node we can read all the values in storage but we can never recover the key because the key was hashed to find the storage location and everyone other contracts to be able to get the owner of a given address we have to remember to implement a custom getter function because without this function another contract really has no way of accessing this value in the storage in upfront ends we most likely also want to know which addresses have an owner so what are all the keys that have been set in this mapping and this is why we had to remember to emit our custom event in our set function set owner which also includes the key so that a custom indexer can now Index this event and then our clients can ask the indexer to get a list of all the keys that have been set in this mapping doing all of this for every state variable we need in our contracts is very cumbersome and this is why we created math store with Mod store you don't need any custom getter functions you don't need any custom events you don't need any custom indexers and you don't need any custom networking code because all of this comes by default so how does this work we start with a standard data model that is based on tables and then we provide an optimized call library that is used to interact with the standard data model with these tables and because the user doesn't interact with storage directly but rather through this Library the library can take care of optimizing the storage layout and so in some cases even can achieve more efficient data packing than native solidity and then this core Library also emits events by default for every state change which then can be picked up by a default indexer which can be used by clients to get the state very quickly the standard data model is very simple all the data is stored in tables and every table has a schema that describes the types of values that are stored in this table and then every record that means a row in the table has a key which is used to Index this Row in the table here is an example of an owner table that has a schema with a single field called owner and the value that is stored in this field is an address and then each row is indexed by a bytes 32 key which is implicit in the schema because we didn't provide any override for a key schema here is an example of another table called the position table and this table has a schema with two Fields One X and one y and both of them have type in 32 and again we didn't provide a key schema so we're using an implicit byte 32 as a key and lastly here is an example for a balance table this time we do provide a key scheme app which means the key has two pieces the first one is owner and is of type address the second one is item and is of Type U and 32 and then our value schema has a single field called amount and is of Type U and 256 and this means every Row in this table is indexed by the Tuple of owner and item and then the value of this row is the amount the data in these tables is modified through the optimized core library but you as a developer never have to actually touch this core Library directly but rather we generate typed wrapper libraries for you based on the table schema and another thing that you as a developer never have to worry about is emitting events for when data changes because the core Library does it automatically and then based on these events the default indexes can index the data and make it available in an SQL database to any client so as a quick recap mud store gives you structured schemas storage optimization tight encoding and default indexers and it's compatible with any contract as a plug-in replacement for a native solidity storage the second piece of the mud protocol that I quickly want to give you an intro about is the mud World which gives you permissionlessly extendable contracts and here's how it works at first a single World contract is deployed inside of this world contract anyone can register a new namespace and then inside of the namespace the owner of the namespace can register new tables that contain the data of this namespace this is powered by mudstore and this is a major difference to vanilla solidity because in vanilla solidity you would Define the data types at the time when you write your contract and then you deploy that contract and the data types are fixed here we're registering a new table inside of an existing contract at runtime to extend the functionality of the world the owner of a namespace can reduce the new systems in their namespace and for each system a function selector is going to be registered in the world contract so that the system can be called through the world contract by default systems can read data from all the tables but they can only write to tables in their own namespace and they can write to tables where the owner of the namespace gave explicit approval to the system to write to this table mud store and mud world are two important lower level pieces of the mud protocol but now we're going to focus on the mud framework which is the thing that glues all of this together into an engine for ambitious on-chain applications and it comes with batteries included it comes with the CLI it comes with the development server and dashboard and it comes with templates and this is what we're going to have a look at now so let's create a new mod project we can do so by running pnpm create mud at Canary and then we put the name of our project that we want to set up in this case it's mod 101 and we put at Canary because we want to use the latest Alpha version of mud so now we're asked to choose between the react version and the vanilla version of the template and for the sake of this video I'm going to choose the react version here so now that's gonna download all the packages install all the dependencies and gonna set up our project and once that's done we can CD into our project and run pmpm run Dev to start the local development server what this is doing is setting up a local ethereum node deploying all the contracts to that local ethereum node and also starting a local web development server alright so this is done it's saying mud watching for changes because later when we change our files it's gonna automatically redeploy and recompile everything but for now let's just head over to the browser and have a look at our app we can go to localhost 3000 which is where the Local web server is running to have a look at the app that was just created for us here on the right side we can see the mud Dev tools on the very top you see a couple of General stats about the current chain that we're running on in this case our local founder chain we can see that the block number is increasing because we're connected to our local RPC node and we can also see a burner wallet that was created for us when we loaded this page for the first time we see our balance which is zero eat which is fine because we're on a local development chain and then we can see a couple of store events that were emitted when we set up the app for the first time and then on the left side we see the app that was just created for us if we press the button here we see there's a new action coming through and we see one new store event at the bottom the counter value which got increased to two What's Happening Here in the background is that if we press the button a transaction is sent to the chain and then mud synchronizes the state of the chain in the background automatically to the UI and to the client and to show you how that works let's jump into the code our project is split up into two packages we have one client package and we have one contract package and the first thing we're going to have a look at is the mud config which we find inside of the contract package under mat.config.ts and in here we see that we currently have a single table set up the counter table and we see that this table has a schema with a single field which is a un32 and then we also see a key schema that has no keys inside of it and the reason for this is that our counter table has only a single row we call this a Singleton table and we don't need any keys for it because it only has a single row now this is our config and based on this config Matt code generated a library to interact with this table and we can find this library in code gen tables and then counter.sol and here we see okay this is a code generated an audio generated file we should not edit this manually and we see a bunch of methods that were generated for us but we don't have to look at this in detail um we can just close this again and interact with it as a black box now the next thing we're going to have a look at is the client for this we switch to the client package and we go into source and open app.tsx which includes the source code of the page we just saw here we see the counter with the counter value behind it and we see the increment button that we just saw on the page that we opened and we also see that when we press this increment button the increment function is called which comes from system calls so let's look at where this comes from this is coming from create system calls which is a function inside of source mud and then create system calls.

ts and in here we set up our functions that we want to call on the world contract so what actually happens here is we call a function on the world contract via World send and the function that we're calling is the increment function and we don't provide any arguments here so let's switch back to the contract package to see where this function is coming from I'm closing the clients package going back to contracts and then I'm going inside of source and I'm opening the systems folder and I see a single system the increment system every contract whose name ends in system is automatically considered a system by mud and it's going to be registered in the world contract during the deploy process of mud and then for every function selector inside of that system this function selector is also going to be registered on the world contract so that people can call this function directly through the world contract and then the world contact forwards the call to our system contract so in this case we have a single increment function and this function is registered on the world contract which is why we were able to call the increment function directly on the world contract from the client now what this function does is it reads the current value from the counter table and remember this is a Singleton cable so we don't have to provide a key and then it increases that value by one and it sets the new value on the counter table again so if we go back to our app we can now read the value from the counter table through this hook called the use component value and then this is the value that we display in the app now the reason why this is called use component value is because this is coming from a pattern called ECS or entity component systems for the sake of this tutorial we're not going to go into ECS though and so I'm gonna quickly replace this with a lower level hook called use row which also allows us to read rows from a table and doesn't have the ECS abstraction around it you use this hook I have to provide the Store Cache which is where mod synchronizes all the contracts stay to and I can get this from the network here and then I provide that as the first argument and the second argument is going to include the table that we want to filter for which in this case is the counter and then we also have to provide an argument for the key that we're interested in but in this case since it's a Singleton cable the key can be empty and because our return value is slightly different we have to fix this up here and provide the key of the value which in our case is also called value and then just to confirm everything still works I'm going back to the browser pressing the increment button I see the transaction going through and I see the state being synchronized and updated in the UI we don't need these Imports anymore so let me just real quick clean this up removing this import removing the components and we also don't need the Singleton entity anymore all right now let's create a new feature I want to create a balance table which stores the balance of a certain item that a certain address has and I want to create an admin system which allows people to Mint a certain amount of a certain item so the first thing that we're going to do is go back to our mod config and add the configuration for that new table we're going to call this table the balance table and we're going to give it a schema of a single un32 and this time we want to have multiple rows in our table and we want each row to be indexable by a composite key of the owner which is an address and the type of item which is going to be a un32 as well once we save this file the mod development server is going to pick up the change to our config and then Auto generate the new table that we just defined here which we can find in code gen and then in table so we see there's a new auto generated table Library called balance table alright so let's create a new system to interact with this new table for this we go into systems and we create a new file that we call the Min system and I'm just going to copy the code from the increment system for now I'm going to paste it into a new file and then I'm gonna clean up everything that we don't need so we're going to rename this to Min system and I'm going to remove everything that is in here and we don't want to interact with the counter table but rather the balance table so I'm going to put balance here and of course I named this table not just balance but balance table and this is why I have to import from balance table here foreign next we're going to create our Min function which we just call Mint and we take one argument as an input which is going to be our item that we want to Mint and this is a public function and then we want to grab the current balance of the column of this function to be able to increase it and for this we're gonna do balancedable dot get and now we have to provide the two keys that we use to index each row in this table and so the first index the first key is going to be the address of the call and the second index is going to be the item and one thing to note here is that we don't use message dot sender here but rather we use underscore message sender which is a function that's implemented on the system based contract and the reason for this is that this system contract is not called directly but rather it's called through the world contract and so the world contract is forwarding the original caller of the system through through this function and now that we have the balance we want to increase the balance and set the increased balance on the balance table so I want to set the balance of the message sender of the current item with the new balance plus five and that's all we need to do for now now once I save this file the mud development server is going to pick up the change recompile all the contracts and redeploy the world with a new contract but we don't have any way to interact with it yet from the front end and so we quickly set up a connection to the front end by going back into our client and into Source into Mutt and into create system calls and in here we're just going to create a little wrapper function to call our contract this is really just for our convenience to not have to call the contract directly in app.tsx so we call this function mint and in here all we have to do is call worlds and with the new mint function which is not available on world sent because everything was recompiled in the background and it tells us we need one more argument the item so we're going to provide an item here and then we're just going to put one for now and then we return this function to make it available on the context that we use in app.tsx now let's go back to app.tsx and let's clean up all the things that we don't need anymore in here so we don't need the counter anymore we don't need to stiff anymore and we also don't need the button anymore and instead I'm going to create a new button which will be our mint button and on click of this button we are going to call the mint function which we can get from the system calls object up here and then we want to call this when we click the mint button all right this is all we need now let's go back to our browser and we see the mint button and we see that if we click this mint button A Min transaction is sent to the contracts and it's confirmed and then here in the recent store events we can see a new event that came in which is an event an update to the balance table where we see it now has value 5 for some key but the new value is not displayed in the UI yet because we didn't set up that connection yet so let's go back to our code and let's set up a connection in the UI so I want to get all the balances from our balance table so in this case I'm going to use a different hook I'm going to use the use rows hook and it behaves very similar to the use row hook we also provide the Store Cache as the first argument and then as the second argument I provide a filter object which will include the table that I want to filter on which in this case is the balance table and then we're going to set up a very simple UI for this by looping over every element of the balances array every Row in the balance table and we map each of these rows to a paragraph element so that we can see it in our browser and here we've just put balance Dot K dot owner has and then we want to have the number of items it has so balances dot value dot value this is because the the only value in our schema is called value right now and now the type of item this is part of the key so we do we do balance dot key dots item and then we can save this and head back to our browser and see the result well you can confirm that this is my address by looking at my address in the mud Dev tools but this is way too long so I'm just quickly going to shorten this to 10 characters and then when we go back to our browser this is much more readable and you can see in my address has five items of type one and if we press the Min button again you see that your eye is updating you see the transaction on the right and you see the event in the dev tools all right process and and I'll be going through a quick contract enter and let's go into the contracts directory from where we're gonna deploy our contracts to an actual chain the first thing we have to do here is create a new wallet so I'm just going to use the cast utility to create a new random wallet and I'm gonna copy my private key and I'm gonna head back over to the code into the contracts package where I can find a DOT end file which includes the environment variables and I'm gonna paste my private key there so far this included the default envelope private key and I'm going to override it with the newly created private key from cast then I head back to the console and I copy the address and because this is a fresh private key and fresh address um it's it's not going to have any funds on the test net and so because we want to deploy to the lattice test net I can just say pnpm mud faucet dash dash address and then I paste the address here and the mod faucet is gonna drip me some eth to this new address so that we can deploy to the test net and now the last thing that I have to do to deploy to the test net is type pnpm deploy test net which refers to a script that you can find in the package.json in the contracts package and now this is running the mod deployer again but this time we're deploying to an actual chain so this time it's going to take slightly longer than the the def Runner which just deploys to the local chain because now we have to wait for every transaction to be actually confirmed by the real chain and there we go the contracts have been deployed to the chain and we see the world address that it got deployed to and now to interact with this production deployment we we're going to start our development server again but just to have the development client running because we don't have our client deployed yet so I'm going back to the product route running a pmpm Dev to start the development server again and it's starting both the development client as well as the development contracts but in this case we just care about the development client the error that you see here is the contracts complaining that we're trying to deploy to the local development chain with the private key that doesn't have any funds on the local test chain but again this doesn't matter because we're only interested in the client here and if we scroll up a little we can see that the client is running fine so this is all we care about so we can go back to our browser and to connect to the production chain we just have to append the chain ID param through the URL so we type question mark chain ID equals 4242 which is the chain ID of the lattice tested that we just deployed to and we press enter and now you see it's connected to the letters test net it you see the block number increasing because it's connected to the test and RPC and you see our new burner wallet that was created for us here and we see the balance that we have on this test net which is quite a bunch and if we press the mint button you can see the transaction being executed and being confirmed and you can see the balance value being updated and the I being updated as well this is a very simple app of course but it should give you an idea of how to get started with the framework and how to build something much more complex than this if you want to dive deeper you can find the documentation at Matlab and we're going to follow up with a bunch of videos that go deeper into specific topics like ECS and building games with mud all right cheers thank you various um and we have this few maybe like a minute or so but I don't know if there are other any remaining questions that that uh participants house how could we browse games already created a month that's a great question um there's a website for that I'm gonna post the link um in the chat it's community.

mat.dev oh there we go okay someone posted already uh Sam that you have a question yeah I'm adventurous it was great um and uh you know pulled down and set up a template app and then run it locally and just trying to better understand this burner wallet stuff you know like gray ux I love it I love running stuff through a burger wallet like that so you know get the wallet pop-ups but I'm I'm a little bit confused about like transaction fees and you know more of a production you know mean mean that sort of deployment here right like is the suggestion that that users should fund that burner wallet or is that something that should sort of get replaced in this stack to to make something more serious it's not just like a sort of demo thing yeah so if you'd apply to the lattice test net we have a faucet so you can automatically fund the burner wallet whenever somebody um like visits your app and I think for the for the optimism tester we're also going to have a faucet available which can be which can autofund the the burner wallets alternatively you can also just connect any external wallet to your app um the the only downside to that is that you now have to um like ask users to confirm transactions right without doing that well yeah so okay yeah depending on your use case that might be I I I have another tool that I use for burner wallets and uh also Implement meta transactions so it's like I feel like that's probably the direction I want to maybe take my hack so yeah totally okay all right that's only compatible you can just connect it to the ethers or VM executor that's connected um to your client okay okay um all right great uh I'll probably have tons more questions as I work through this but but awesome excited to back around in the states cool yeah and there were a few other questions um uh just an FY for for if people were looking for the link to that video this this all will be recorded and shared with you later so if you're looking for that exact video that Avery's presented and don't worry about it we'll just share this link let me do this presentation the recording uh ET at s is easy to integrate contracts that weren't written within the same mud project um yeah sure I mean so it depends on what you want to do if you just want to interact with an external contract from your contract um you can just call it like like before essentially and if you want to register an external contract as a system in your wall in your world um that might be slightly more involved but technically also possible if you have specific questions we can dive into it later the MDS can we deploy to uh lattice test note during this hackathon I think that might have been answered yeah I mean I think you can if you want to but also optimism is providing a test that is probably better maintained and uh could 4337 be a solution here like account abstraction yeah I think that was related to the um discussion and mudb used to create just a single contract or a few that can be used in a bigger mud project like using a predefined interface I'm not quite sure if I understand this question can not be used to create just a single contract or a view that can be used in a bigger mod project like used using prudent um yeah I'm not sure I understand maybe you can elaborate oh yeah okay cool we'll chat about it in Discord uh if Guinea you had a question your other hand raised I am that's ET guys me the question is the same and um like suppose I I'd like to well be able to extend a project we could stand on a running project with something provided by other people so that's um should I use just uh rigid interface I Define beforehand and just take addresses or the did anyone compose different mod projects so far oh I see so essentially different different mod worlds is your question because so it did have one world then it's very easy for people to extend it by registering your systems because that's a measurement so people can register their own namespace and their own system in your world and if you want to integrate different worlds together that's also theoretic theoretically possible but would require some some more custom code because now you have to um like you can't assume anymore that the um the color of your system will always be this one world but maybe you have different worlds now um so it's it's totally possible like you can just write custom solidity code for it but it's not um the original intention essentially yep so to add systems to a running product what do this will do they download they they make the Clone the code they add a system and then what yeah so you can deploy systems to an existing world as well by um just providing the world address parameter to the CLI and then essentially it doesn't deploy a a raw world anymore in the beginning in the deployer but rather just deploys your systems to the existing world I believe this is covered somewhere in uh in the dock streets yeah yeah shadow thank you so much anyway I have two more questions uh how can nfts be integrated and be compliant with the ERC 720 spec yeah this is a this is a mode so there's a couple of different approaches there's a couple of proposals up on the mod Discord if you want to read them in detail and one of our team members actually wants to to hack on this during this hackathon as well um dj1a in our discourse so um we can chat about it later as well can you explain how to create packages I'm not sure I understand this one uh Mick are installing you wanna become a spirit and yeah um I think the question is just related to I guess like if I wanna automate I think I was reading some of the docs in V2 and they explained something about it it is possible to like like I just want to understand like the packaging system currently I see we have like a different tracks yeah do you mean modules maybe like oh yeah essentially yeah yeah cool all right so so modules are essentially contracts that include some logic that install um tables and systems in an existing world so and you can basically install a module on the world and then what happens is the world is going to call that module contract and then the module contract is gonna call back to the wall then register the systems and the tables and that you want to um or like that that the module needs to install there and we have a couple of basically built-in modules so you can have a look at as examples and I think we also might have a Doc Page and if not we're working on it and we'll have one shortly what's one example of like a module I should look into and you can for example you can have a look at the core module of the world um which it actually implements some of the the core wealth functionality in in a module essentially so basically we we have a very minimal set of functions that are actually on the world contract and then during the world deploy contract process we install this core module which then extends the functionality by a bunch of more things um and yeah I can if you're on Discord I can send you I can point you to the specific links um we we have other module we have the keys and table module which basically installs an um like an on-chain indexer for your tables by default keys with value is another one yeah I can send some links later all right thanks yeah this was a like a classification earlier question are systems and names space enter name space is interchangeable um not quite so the namespace is um kind of it's so a namespace wraps around the system in a sense so a system is a contract that you deploy and you deploy the system into a namespace and you also deploy tables into a namespace and access control is based on namespaces so namespaces are more of a concept than an actual like contract or anything so the the data inside of the world contract if you will and this is a follow-up to you I think Guinness question can systems interact with each other across worlds um you can definitely call other worlds from your systems and I guess so basically you would call systems always through the world contract as an entry point and so if you want to call a system in another world you would call that Otherworld and then that other world would forward the call to its to its system okay it's uh file coordination sponsor I haven't been screwed uh flower coin no I think it was a sponsor or another brain if all coin is uh should be just optimism Xerox Park lattice and the NXT storage I don't think file coins isn't sponsor for here um okay maybe this uh well there's maybe just like one more question um and this is the last question is there a preference for Acton whether we develop on mud or mud tune or is mud to not out yet and materials out you can install it with the add Cannery flag so if you do pnpm create mod at Canary then you get the latest version which is smart too also on on GitHub on Main that's Alma 2. I would strongly recommend using mod 2 if you want to use mod um open mod 1 because there's a bunch of improvements and not really many if if anything like basically everything you can do in mod 1 you can also do in mod 2 but better and cheaper awesome well cheers with uh thank you everybody for attending thank you alvarius for presenting uh today and if anybody has any other further questions please feel free to reach out to them on their partner Channel and Discord and uh yeah that'll be it so thank you all for attending cheers

Automatic transcript — names and jargon may be misspelled.