Skip to content

Commit

Permalink
Merge branch 'main' into yonadaaa/byte-to-bits-magic-number
Browse files Browse the repository at this point in the history
  • Loading branch information
holic authored Jan 12, 2024
2 parents c32553e + c6c13f2 commit 7820ce2
Show file tree
Hide file tree
Showing 172 changed files with 7,186 additions and 469 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-ads-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/store": patch
---

Storage events are now emitted after "before" hooks, so that the resulting logs are now correctly ordered and reflect onchain logic. This resolves issues with store writes and event emissions happening in "before" hooks.
25 changes: 25 additions & 0 deletions .changeset/modern-brooms-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@latticexyz/cli": patch
"@latticexyz/world-modules": patch
"@latticexyz/world": major
---

Previously `registerSystem` and `registerTable` had a side effect of registering namespaces if the system or table's namespace didn't exist yet.
This caused a possible frontrunning issue, where an attacker could detect a `registerSystem`/`registerTable` transaction in the mempool,
insert a `registerNamespace` transaction before it, grant themselves access to the namespace, transfer ownership of the namespace to the victim,
so that the `registerSystem`/`registerTable` transactions still went through successfully.
To mitigate this issue, the side effect of registering a namespace in `registerSystem` and `registerTable` has been removed.
Calls to these functions now expect the respective namespace to exist and the caller to own the namespace, otherwise they revert.

Changes in consuming projects are only necessary if tables or systems are registered manually.
If only the MUD deployer is used to register tables and systems, no changes are necessary, as the MUD deployer has been updated accordingly.

```diff
+ world.registerNamespace(namespaceId);
world.registerSystem(systemId, system, true);
```

```diff
+ world.registerNamespace(namespaceId);
MyTable.register();
```
12 changes: 12 additions & 0 deletions .changeset/pretty-toys-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@latticexyz/store": patch
---

Aligned the order of function arguments in the `Storage` library.

```solidity
store(uint256 storagePointer, uint256 offset, bytes memory data)
store(uint256 storagePointer, uint256 offset, uint256 length, uint256 memoryPointer)
load(uint256 storagePointer, uint256 offset, uint256 length)
load(uint256 storagePointer, uint256 offset, uint256 length, uint256 memoryPointer)
```
5 changes: 5 additions & 0 deletions .changeset/seven-carpets-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/world": patch
---

Namespace balances can no longer be transferred to non-existent namespaces.
12 changes: 12 additions & 0 deletions .changeset/young-poets-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@latticexyz/store": minor
---

Improved error messages for invalid `FieldLayout`s

```diff
-error FieldLayoutLib_InvalidLength(uint256 length);
+error FieldLayoutLib_TooManyFields(uint256 numFields, uint256 maxFields);
+error FieldLayoutLib_TooManyDynamicFields(uint256 numFields, uint256 maxFields);
+error FieldLayoutLib_Empty();
```
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
- main
pull_request:

env:
FOUNDRY_VERBOSITY: 5

jobs:
test:
name: Run tests
Expand Down
127 changes: 126 additions & 1 deletion docs/pages/cli/config.mdx
Original file line number Diff line number Diff line change
@@ -1 +1,126 @@
# Config
# The World config

Certain CLI commands, such as [`mud tablegen`](/cli/tablegen) and [`mud worldgen`](/cli/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 in the `tables` object of your configuration.
- The [namespace](/world/namespaces-access-control) the [`System`s](/world/systems) and tables will be deployed in.
- The `System`s 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](/world/modules) that will be installed in the `World`.

The is an example of a `World` config:

```tsx
import { mudConfig } from "@latticexyz/world/register";
import { resolveTableId } from "@latticexyz/config";

export default mudConfig({
excludeSystems: ["System3", "System2"],
worldContractName: "CustomWorld",
namespace: "mud",
systems: {
IncrementSystem: {
name: "increment",
openAccess: true,
},
},
tables: {
CounterTable: {
valueSchema: {
value: "uint32",
},
},
},
deploysDirectory: "./mud-deploys",
modules: [
{
name: "KeysWithValueModule",
root: true,
args: [resolveTableId("CounterTable")],
},
],
});
```

## Global configuration keys

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.

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

- **`worldContractName`**: a `string`: the name of a contract in your project implementing the `IWorld` interface.
Useful if you want to modify the default World implementation, but potentially dangerous.
- **`deploysDirectory`** a `string`: which folder to put the deployment artifacts into after deployment.

- **`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.

- **`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:

- `fileSelector` (optional): a `string`: the file selector for the system.
- `openAccess` (optional, default `true`): a `bool`: if set to `false`, only the systems in the same namespace and the addresses or systems listed in the the `accessList` array have access.

- `accessList` (required if openAccess is `false`): an array of `string`. Each address in the array will be granted access to this system, allowing them to call it.

- **`tables`**: a record of tables. The keys in the record are table names.
The value is a record of [table properties](https://github.com/latticexyz/mud/blob/main/packages/store/ts/config/storeConfig.ts#L110-L135).

- **`valueSchema`** (record):
The keys of this record are the field names of the value (which should 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.

- **`keySchema`** (record):
The keys of this record are the field names of the key (which should start with a lowercase letter).
The values are strings that contain the data types of the fields.

The default value is:

```json
{ "key": "bytes32" }
```

For a singleton table (one that contains a single row), use `{}` as the key schema.

- **`directory`** (string):
Directory in which to create the table.
The default is `tables`, so by default tables are created in `src/codegen/tables`.

- **`tableIdArgument`** (bool):
Make methods accept `tableId` argument instead of it being a hardcoded constant.
The default is `false` because you can achieve the same result using [`StoreSwitch`](/store/table-libraries#storeswitch).

- **`storeArgument`** (bool):
Include methods that accept a manual `IStore` argument.
The default is `true`.

- **`offchainOnly`**: (bool):
Table's information is available offchain (using [events](https://docs.soliditylang.org/en/latest/contracts.html#events)), but don't store in onchain.
These tables require a lot less gas.

- **`dataStruct`**: (bool):
Include a [data struct](https://docs.soliditylang.org/en/v0.8.23/types.html#structs) and methods for it.
Default is false for 1-column tables; true for multi-column tables.

Sample code for using a table library with `dataStruct`:

```solidity
// no data struct
MyTable.set(keccak256("some.key"), 1, 12, "foo");
// data struct
MyTable.set(keccak256("some.key"), { field1: 1, field2: 12, stringField: "foo" });
```
114 changes: 113 additions & 1 deletion docs/pages/cli/test.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,115 @@
# mud test

**Coming soon**
This command runs the tests in a MUD project. Internally, it runs the following steps:

1. Starts an [`anvil`](https://book.getfoundry.sh/reference/anvil/) instance.
{/* This could be either an empty blockchain, or one that can be forked for a [fork test](https://book.getfoundry.sh/forge/fork-testing). */}
1. Deploys the `World` and all related `System`s using [`mud deploy`](./deploy).
1. Runs tests using [`forge test`](https://book.getfoundry.sh/forge/tests) and passes the deployed world address to the tests via the `WORLD_ADDRESS` environment variable.

## Command line options

| Option | Meaning | Type | Default value |
| ----------------------- | ---------------------------------------------- | ------- | ---------------------------------------------------------- |
| `--version` | Show version number | boolean | `false` |
| `--configPath` | Path to the config file | string | `mud.config.ts` |
| `--printConfig` | Print the resolved config | boolean | `false` |
| `--saveDeployment` | Save the deployment info to a file | boolean | `true` |
| `--profile` | The foundry profile to use | string | `local` |
| `--srcDir` | Source directory | string | Foundry `src` directory |
| `--skipBuild` | Skip rebuilding the contracts before deploying | boolean | `false` |
| `--alwaysRunPostDeploy` | Run `PostDeploy.s.sol` after each deploy | boolean | `false` (run the script only when deploying a new `World`) |
| `--port` | Port for the testing `anvil` instance | number | 4242 |
| `--help` | Show help | boolean | `false` |

## Examples

```sh copy
pnpm mud test
```

## Writing MUD tests

MUD test contracts inherit from [`MudTest`](https://github.com/latticexyz/mud/blob/main/packages/world/test/MudTest.t.sol).
This contract gets the `World` address from the `$WORLD_ADDRESS` environment variable and sets it as the `Store` address.

<details>

<summary>Line by line explanation of a test</summary>

This is an explanation of [the test](https://github.com/latticexyz/mud/blob/main/templates/react/packages/contracts/test/TasksTest.t.sol) for the [React template](https://github.com/latticexyz/mud/tree/main/templates/react) contracts.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;
import "forge-std/Test.sol";
import { MudTest } from "@latticexyz/world/test/MudTest.t.sol";
```

Import the general definitions required in all MUD tests.

```solidity
import { IWorld } from "../src/codegen/world/IWorld.sol";
import { Tasks, TasksData } from "../src/codegen/index.sol";
```

Import the definitions required for this test, the `World` we can access and the tables we'll use.

```solidity
contract TasksTest is MudTest {
function testWorldExists() public {
```

MUD tests are [Foundry tests](https://book.getfoundry.sh/forge/tests).
Any public function that starts with `test` is a test that gets executed.

```solidity
uint256 codeSize;
address addr = worldAddress;
```

The `World` address comes from the [`MudTest`](https://github.com/latticexyz/mud/blob/main/packages/world/test/MudTest.t.sol#L11).

```solidity
assembly {
codeSize := extcodesize(addr)
}
assertTrue(codeSize > 0);
}
```

Use [`extcodesize`](https://www.evm.codes/#3b?fork=shanghai) to get the size of the `World` contract.
If the deploy process failed, there wouldn't be any code there.

```solidity
function testTasks() public {
// Expect task to exist that we created during PostDeploy script
TasksData memory task = Tasks.get("1");
```

Use the structure for a table entry's values that is created as part of code generation.

```solidity
assertEq(task.description, "Walk the dog");
assertEq(task.completedAt, 0);
```

Verify the information that is prepopulated by [the `PostDeploy.s.sol` script](https://github.com/latticexyz/mud/blob/main/templates/react/packages/contracts/script/PostDeploy.s.sol).

```solidity
// Expect the task to be completed after calling completeTask from our TasksSystem
IWorld(worldAddress).completeTask("1");
```

Call a `System` to modify the table data.

```solidity
assertEq(Tasks.getCompletedAt("1"), block.timestamp);
}
}
```

Verify that the call changed the data correctly.

</details>
17 changes: 14 additions & 3 deletions docs/pages/contribute.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
## Contribute
# Contribute

We'd love your support in improving MUD! [The MUD monorepo](https://github.com/latticexyz/mud) includes all of MUD's source code, and pull requests are always welcome.
To discuss new features or changes [join our Discord](https://lattice.xyz/discord).

You can find a list of good first issues (that don't require a lot of context on the full system) at [contribute.mud.dev](https://contribute.mud.dev).

### Local development setup
## Local development setup

The following steps are only necessary if you want to contribute to MUD. To use MUD in your project, [set up a new project with the MUD CLI](/quick-start).

Expand All @@ -32,7 +32,18 @@ The following steps are only necessary if you want to contribute to MUD. To use
pnpm build
```

### Pull requests
### Using your repository in an application

To check the changes in an application, run these commands at the application's root.

```sh copy
pnpm mud set-version --link <link to MUD repository>
pnpm install
```

While the application's `pnpm dev` is running, any time you `pnpm build` the MUD repository the application gets updated automatically.

## Pull requests

MUD follows the [conventional commit specification](https://www.conventionalcommits.org/en/v1.0.0/) for PR titles.
Please keep the scope of your PR small (rather open multiple small PRs than one huge PR).
Binary file added docs/pages/guides/extend-ui-with-msgs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 7820ce2

Please sign in to comment.