Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prototype new MUD config #1668

Closed
alvrs opened this issue Sep 29, 2023 · 4 comments
Closed

prototype new MUD config #1668

alvrs opened this issue Sep 29, 2023 · 4 comments
Assignees

Comments

@alvrs
Copy link
Member

alvrs commented Sep 29, 2023

What is the MUD config

The MUD config includes information about tables, systems, modules, and other things in the World.
It is used by different tools. Store's tablegen script generates Solidity table libraries from the tables config, World's worldgen script generates interfaces for all Systems and combines them in a World interface. The deploy script reads the tables, systems, and modules from the config and registers them in the World.

Current approach for config parsing

We currently use zod to parse, validate and expand the mud.config.ts. The config defined by users can include shorthand definitions, which the zod parser turns into the full definitions.

Example: zod turns a shorthand table definition into the full config:

const zShorthandSchemaConfig = zFieldData.transform((fieldData) => {
return zFullSchemaConfig.parse({
value: fieldData,
});
});

// Shorthand schema
const table = "uint256"

// Full schema
const table = {
  value: "uint256"
}

Unfortunately zod does not propagate strong types through the parsing function. (For example, { value: "uint256" } becomes { value: string }). This is a problem for us, because we want to infer types of MUD client libraries directly from the MUD config. This is why currently we have to define all of our types (and also the expanding logic) twice - once in zod, and once in typescript types.

Example: typescript types corresponding to the zod schema:

export type FullSchemaConfig<UserTypes extends StringForUnion = StringForUnion> = Record<string, FieldData<UserTypes>>;
export type ShorthandSchemaConfig<UserTypes extends StringForUnion = StringForUnion> = FieldData<UserTypes>;
export type SchemaConfig<UserTypes extends StringForUnion = StringForUnion> =
| FullSchemaConfig<UserTypes>
| ShorthandSchemaConfig<UserTypes>;
export type ExpandSchemaConfig<TSchemaConfig extends SchemaConfig<string>> =
TSchemaConfig extends ShorthandSchemaConfig<string> ? { value: TSchemaConfig } : TSchemaConfig;

Solution draft

Our config parsing approach has been pretty complex and hard to extend and we'd like to rethink it from scratch. On a related note, we're planning to add plugin support to the MUD config, which is something we should keep in mind when designing the new config parsing approach.

Conceptually, the config has an input type, and an output type. The input type allows shorthands, the output type is the fully extended version of the config, including default values etc.

A resolve function can turn an input type into an output type. The resolve function needs to maintain strong types! (The current mudConfig parser function is a resolve function in this sense, but it unfortunately doesn't maintain strong types.

Here is an example of a resolve function that does maintain strong types: https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgJIgA4FczIN4BQyxyMwEANgCYCCAXMgM5hSgDmA3AQL4EGiRYiFAHkc2MAB4AKugnIIAD0ggqjNJhwA+fERJQIjAPYUAbhCoAxctXrIABgBI8szWADaAIjKVangLrcALQGxmYW9jx8MFggCGDARiDIoSbmMnI4CsoQquqZYFoAFKASDK4SAJQMYmASGW46hCQpEGBYUMl4rWHmVja0DE54pTgAdD62wanhVPbIvLwECEnMPWkWAMJJZGzIALzr4UXdk4PIngAWlBRGnguVXAQzfdsgu2MvFta+NFwA9P8WsDgQA9AD8QA

As a next step built on top of the resolve functions with strong types, we want to find an elegant way to extend the config with plugins.

One idea is to define the general Input and Output<Input> types, as well as a general resolve<TInput extends Input>(input: TInput): Output<TOutput> function in a common package, and then let plugins extend the types via "Typescript interface merging" (which is why we'd have to define these types as interfaces as opposed to type). The Input type could have an array for plugins, each plugin defines its resolve function and extends the top level Input as well as Output types, and the resolve function iterates through the array of plugins to resolve the config of each of them. The plugin's resolve functions could technically use zod internally, but could also rely on much simpler plain typescript operations.

A couple related issues with more (partially outdated) context: #746 #994 #700

@alvrs alvrs added this to the MUD stable milestone Sep 29, 2023
@alvrs alvrs self-assigned this Oct 2, 2023
@holic
Copy link
Member

holic commented Oct 4, 2023

See also my WIP #1561

@holic
Copy link
Member

holic commented Oct 4, 2023

While working on #1611, I spotted some inconsistencies with our system config and APIs:

Our system config has openAccess: boolean and accessList: string[] (which can be addresses or system names) and then our registerSystem contract method uses publicAccess: boolean

I am wondering if it'd be clearer to have something like:

{
  allowAll: true;
} | {
  allowAll: false;
  allowedAddresses: Hex[];
  allowedSystemIds: Hex[];
}

and also update the system registration method to allowAll: boolean

@holic
Copy link
Member

holic commented Nov 1, 2023

Related: #1819

@holic
Copy link
Member

holic commented Mar 20, 2024

this has landed in #2483! see also #2435

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Status: Blocked
Development

No branches or pull requests

2 participants