How MUD models data
The MUD framework helps you to model your onchain state in a way that enables building applications with familiar tooling, like relational databases.
In your MUD config, you define data as a set of tables. Like relational databases, these tables have “columns” by way of two MUD concepts: a key schema and a value schema. Each one has a set of fields that map to Solidity types.
Defining tables
Let's say we're making a game where players can move around a map. The definition for a Position
table might look something like:
export default mudConfig({
tables: {
Position: {
keySchema: {
player: "address",
},
valueSchema: {
x: "int32",
y: "int32",
},
},
},
});
Translating the table definition above would look like this in a relational database:
player | x | y |
---|---|---|
0x1234 | -5 | 1 |
0x5678 | 3 | 6 |
Because player
in part of the key schema, we would have a unique/primary key constraint on player
.
Let's add another table for terrain at a given position on the map. MUD allows for multiple keys in the key schema and, like databases, we call these composite keys.
export default mudConfig({
tables: {
Position: {
keySchema: {
player: "address",
},
valueSchema: {
x: "int32",
y: "int32",
},
},
Terrain: {
keySchema: {
x: "int32",
y: "int32",
},
valueSchema: {
terrainType: "string",
},
},
},
});
Similarly, the relational database representation of that table would look like:
x | y | terrainType |
---|---|---|
-1 | 0 | grass |
0 | 1 | tree |
1 | 0 | grass |
Because we have a composite key of x
and y
, we would have a unique/primary key constraint on the tuple of (x, y)
.
Tables on chain
Solidity and the EVM have much more limited data structures, so how can we express a relational database onchain? MUD takes the concept of tables and does a few things with them:
- encodes each table record as a key/value pair before storing onchain
- emits an event for each mutation
- provides a typed Solidity libraries to abstract this away
Field types
Key schema fields can use all of Solidity's static-length primitive types like uint256
, address
, bool
.
Value schema fields can use all of Solidity's static-length primitive types, arrays of those static-length primitive types, as well as string
and bytes
.
Enums and user types are also supported and automatically map down to their Solidity primitive types.
The code and the rest of the documentation call some fields static and others dynamic. In MUD terminology static
means static length (uint16
, int32
, bytes32
, etc.) and dynamic means dynamic length (uint[]
, string
,
bytes
, etc.).
More complex types like structs, string[]
, and bytes[]
are not yet supported. We'll cover the reasons why in our encoding/decoding guide.