Config

MUD config

Certain CLI commands, such as mud tablegen and mud worldgen require the MUD configuration file. This file needs to be named mud.config.ts and be in the same folder as your foundry.toml file.

The config is used to define:

  • The tables in your project.
  • The namespace(s) that Systems and tables will be deployed in.
  • The Systems in your project. By default, the deployer will find all Solidity matching *System.sol (so any file ending in System.sol, in any folder) and deploy them as public System. If you want greater control over your systems (to change their public access or their name), you can use the systems object in the config.
  • The modules that will be installed in the World.
  • The enumerations in your World.
  • Deployment and code generation options.

Multiple namespaces

Starting with version 2.1 you can put multiple namespaces in the same config file, you create a namespaces record and within it a record for every namespace. For example:

Sample mud.config.ts files

A namespace

This is an extremely simple configuration file with a single namespace that contains a single table. The Systems are defined implicitly, as all the contracts that match src/namespaces/app/systems/*System.sol.

mud.config.ts
import { defineWorld } from "@latticexyz/world";
 
export default defineWorld({
  namespaces: {
    app: {
      tables: {
        Tasks: {
          schema: {
            id: "bytes32",
            createdAt: "uint256",
            completedAt: "uint256",
            description: "string",
          },
          key: ["id"],
        },
      },
    },
  },
});

Source files

  • src/namespaces/app/systems - Systems that belong to the app namespace.

Generated files

  • src/namespaces/app/codegen/tables/Tasks.sol - the generated code for app__Tasks table.
  • src/namespaces/app/codegen/index.sol - a single file that imports all the table definitions of the namespace (in this case, only Tasks.sol).
  • src/codegen/world/I*System.sol - interfaces for all the Systems.
  • src/codegen/world/IWorld.sol - the IWorld interface that inherits from all the I*System.sol files.

A namespace with an explicit System definition

By default Systems are publicly accessible. In this configuration, we explicitly specify RootSystem so we can specify that access to it is limited to authorized addresses.

mud.config.ts
import { defineWorld } from "@latticexyz/world";
 
export default defineWorld({
  namespaces: {
    app: {
      tables: {
        Tasks: {
          schema: {
            id: "bytes32",
            createdAt: "uint256",
            completedAt: "uint256",
            description: "string",
          },
          key: ["id"],
        },
      },
      systems: {
        RootSystem: {
          openAccess: false,
        },
      },
    },
  },
});

Source files

  • src/namespaces/app/systems - Systems that belong to the app namespace.
  • src/namespaces/app/systems/RootSystem.sol - The System specified in mud.config.ts.

Generated files

  • src/namespaces/app/codegen/tables/Tasks.sol - the generated code for app__Tasks.
  • src/namespaces/app/codegen/index.sol - a single file that imports all the table definitions (in this case, only Tasks.sol).
  • src/codegen/world/I*System.sol - interfaces for all the Systems, including IRootSystem.sol
  • src/codegen/world/IWorld.sol - the IWorld interface that inherits from all the I*System.sol files.

Two namespaces

In this example there are two namespaces, app and config. Each namespace contains a single table: app__Tasks and config__Configuration.

mud.config.ts
import { defineWorld } from "@latticexyz/world";
 
export default defineWorld({
  namespaces: {
    app: {
      tables: {
        Tasks: {
          schema: {
            id: "bytes32",
            createdAt: "uint256",
            completedAt: "uint256",
            description: "string",
          },
          key: ["id"],
        },
      },
    },
    config: {
      tables: {
        Configuration: {
          schema: {
            deployer: "address",
            tokenAddress: "address",
            ipAddress: "bytes4",
            url: "string",
          },
          key: [],
        },
      },
    },
  },
});

Source files

  • src/namespaces/app/systems - Systems that belong to the app namespace.
  • src/namespaces/config/systems - Systems that belong to the app namespace.

Generated files

  • src/namespaces/app/codegen/tables/Tasks.sol - the generated code for app__Tasks table.
  • src/namespaces/app/codegen/index.sol - a single file that imports all the table definitions of the namespace (in this case, only Tasks.sol).
  • src/namespaces/config/systems - Systems that belong to the config namespace.
  • src/namespaces/config/codegen/tables/Tasks.sol - the generated code for config__Configuration table.
  • src/namespaces/config/codegen/index.sol - a single file that imports all the table definitions of the namespace (in this case, only Configuration.sol).
  • src/codegen/world/I*System.sol - interfaces for all the Systems.
  • src/codegen/world/IWorld.sol - the IWorld interface that inherits from all the I*System.sol files.

Enumerations

mud.config.ts
import { defineWorld } from "@latticexyz/world";
 
export default defineWorld({
  enums: {
    Direction: ["Up", "Down", "Left", "Right"],
    MapDirection: ["North", "East", "South", "West"],
  },
  namespaces: {
    app: {
      tables: {
        Heading: {
          schema: {
            id: "bytes32",
            direction: "Direction",
            name: "string",
          },
          key: ["id"],
        },
        MapCursor: {
          schema: {
            id: "bytes32",
            direction: "MapDirection",
            name: "string",
          },
          key: ["id"],
        },
      },
    },
  },
});

Source files

  • src/namespaces/app/systems - Systems that belong to the app namespace.

Generated files

  • src/namespaces/app/codegen/tables/Heading.sol - the generated code for app__Heading table.
  • src/namespaces/app/codegen/tables/MapCursor.sol - the generated code for app__MapCursor table.
  • src/namespaces/app/codegen/index.sol - a single file that imports all the table definitions of the namespace (in this case, Heading.sol and MapCursor.sol).
  • src/codegn/common.sol - the enumerations in the config file.
  • src/codegen/world/I*.sol - interfaces for all the Systems.
  • src/codegen/world/IWorld.sol - the IWorld interface that inherits from all the I*System.sol files.

Fields within a namespace

  • tables: a record of tables. The keys in the record are table names. The value is a record of table properties (opens in a new tab).

    • schema (record): The keys of this record are the field names in the data, which includes both the key fields and the value fields. By convention, these keys start with a lowercase letter. The values are strings that contain the data types of the fields. Note that this is the sole required field, all the others are optional.

    • key (list): A list of the schema fields that are the key for that table. If you want a singleton table, use an empty list (as in Counter table above).

    • type (either table or offchainTable): The table type. The default is table, which is a table stored onchain. If you specify offchainTable, the table's data is only available offchain through events.

  • systems: a record of system definitions. The keys in the record are file names without the .sol extension. For example, if your system is named TestSystem.sol, use TestSystem as the key.

    The value is a record of system configuration properties:

    • registerFunctionSelectors (optional, default true): a bool. Whether we want to automatically register the public functions of the System as function selectors
    • openAccess (optional, default true): a bool. If set to false, access is limited to:
    • accessList: an array of string. Each address in the array will be granted access to this system, allowing them to call it.
  • excludeSystems: an array of string: which systems to not deploy, even if their name ends with “System”.

Global configuration keys (for multi-namespace config files)

In addition to namespaces, these fields are also supported.

  • enums: a record of enumerations (opens in a new tab). The keys are the names of the enumerations. The values are arrays of the strings for the values the enumeration can take.

  • modules an array of module definitions: each module definition has a name, root (optional), and args key.

    • name: Name of the module to install. The same module can be installed multiple times. This should be the name of the contract file without .sol (eg: if the file is named DopeModule.sol, the name of the module is DopeModule)

    • root: whether to create a root module or not. root modules have access to all tables and are not bound to namespace restrictions.

    • args: a list of arguments to be sent to the install function of the module. In this array, you can use the function resolveTableId. This function will turn a table name from your config into its low-level ID in the World. It is useful to pass references of a table to a module.

  • codegen: a record of code generation options.

    • worldInterfaceName a string: The name of the interface for the World. The default value is IWorld.
    • worldgenDirectory a string: The directory for system and world interfaces. The default value is world.
  • deploy: a record of deployment options.

    • postDeployScript a string: Script to execute after the deployment is complete. This script must be placed in the forge scripts directory (see foundry.toml) and have a .s.sol extension. The default is PostDeploy.

    • deploysDirectory a string: Which folder to put the deployment artifacts into after deployment. The default is ./deploys.

    • worldsFile a string: JSON file for the chain to World deploy address mapping. The default is ./worlds.json.

    • upgradeableWorldImplementation a bool: Whether the World is to be deployed behind a proxy to enable upgrades of the core World implementation. The default is false.

Single namespace

This is an older config file format which is still supported.

import { defineWorld } from "@latticexyz/world";
 
export default defineWorld({
  enums: {
    TerrainType: ["None", "TallGrass", "Boulder"],
  },
  excludeSystems: ["System3", "System2"],
  worldContractName: "CustomWorld",
  namespace: "mud",
  systems: {
    IncrementSystem: {
      name: "increment",
      openAccess: true,
    },
  },
  tables: {
    Counter: {
      schema: {
        value: "uint32",
      },
      key: [],
    },
    Tasks: {
      schema: {
        id: "bytes32",
        createdAt: "uint256",
        completedAt: "uint256",
        description: "string",
      },
      key: ["id"],
    },
  },
});

Global configuration keys (for single namespace config files)

The global configuration keys are all optional.

  • namespace: a string: which namespace to deploy the resources defined in the config into. The default value is the ROOT namespace, which is highly discouraged.

  • tables: a record of tables. The keys in the record are table names. The value is a record of table properties (opens in a new tab).

    • schema (record): The keys of this record are the field names in the data, which includes both the key fields and the value fields. By convention, these keys start with a lowercase letter. The values are strings that contain the data types of the fields. Note that this is the sole required field, all the others are optional.

    • key (list): A list of the schema fields that are the key for that table. If you want a singleton table, use an empty list (as in Counter table above).

    • type (either table or offchainTable): The table type. The default is table, which is a table stored onchain. If you specify offchainTable, the table's data is only available offchain through events.

  • systems: a record of system definitions. The keys in the record are file names without the .sol extension. For example, if your system is named TestSystem.sol, use TestSystem as the key.

    The value is a record of system configuration properties:

    • registerFunctionSelectors (optional, default true): a bool. Whether we want to automatically register the public functions of the System as function selectors
    • openAccess (optional, default true): a bool. If set to false, access is limited to:
    • accessList: an array of string. Each address in the array will be granted access to this system, allowing them to call it.
  • enums: a record of enumerations (opens in a new tab). The keys are the names of the enumerations. The values are arrays of the strings for the values the enumeration can take.

  • excludeSystems: an array of string: which systems to not deploy, even if their name ends with “System”.

  • modules an array of module definitions: each module definition has a name, root (optional), and args key.

    • name: Name of the module to install. The same module can be installed multiple times. This should be the name of the contract file without .sol (eg: if the file is named DopeModule.sol, the name of the module is DopeModule)

    • root: whether to create a root module or not. root modules have access to all tables and are not bound to namespace restrictions.

    • args: a list of arguments to be sent to the install function of the module. In this array, you can use the function resolveTableId. This function will turn a table name from your config into its low-level ID in the World. It is useful to pass references of a table to a module.

  • codegen: a record of code generation options.

    • worldInterfaceName a string: The name of the interface for the World. The default value is IWorld.
    • worldgenDirectory a string: The directory for system and world interfaces. The default value is world.
  • deploy: a record of deployment options.

    • postDeployScript a string: Script to execute after the deployment is complete. This script must be placed in the forge scripts directory (see foundry.toml) and have a .s.sol extension. The default is PostDeploy.

    • deploysDirectory a string: Which folder to put the deployment artifacts into after deployment. The default is ./deploys.

    • worldsFile a string: JSON file for the chain to World deploy address mapping. The default is ./worlds.json.

    • upgradeableWorldImplementation a bool: Whether the World is to be deployed behind a proxy to enable upgrades of the core World implementation. The default is false.