diff --git a/.changeset/bright-kangaroos-battle.md b/.changeset/bright-kangaroos-battle.md new file mode 100644 index 0000000000..bbbc1880c1 --- /dev/null +++ b/.changeset/bright-kangaroos-battle.md @@ -0,0 +1,8 @@ +--- +"@latticexyz/world-modules": patch +"@latticexyz/world": major +--- + +World function signatures for namespaced systems have changed from `{namespace}_{systemName}_{functionName}` to `{namespace}__{functionName}` (double underscore, no system name). This is more ergonomic and is more consistent with namespaced resources in other parts of the codebase (e.g. MUD config types, table names in the schemaful indexer). + +If you have a project using the `namespace` key in your `mud.config.ts` or are manually registering systems and function selectors on a namespace, you will likely need to codegen your system interfaces (`pnpm build`) and update any calls to these systems through the world's namespaced function signatures. diff --git a/examples/minimal/packages/contracts/src/interfaces/IChatNamespacedSystem.sol b/examples/minimal/packages/contracts/src/interfaces/IChatNamespacedSystem.sol index ab8bd76b81..54a19f0379 100644 --- a/examples/minimal/packages/contracts/src/interfaces/IChatNamespacedSystem.sol +++ b/examples/minimal/packages/contracts/src/interfaces/IChatNamespacedSystem.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.21; -// TODO allow overriding namespace per-system interface IChatNamespacedSystem { - function namespace_ChatNamespaced_sendMessage(string memory message) external; + function namespace__sendMessage(string memory message) external; } diff --git a/examples/minimal/packages/contracts/test/ChatNamespaced.t.sol b/examples/minimal/packages/contracts/test/ChatNamespaced.t.sol index c87c3e4304..7c033b99d0 100644 --- a/examples/minimal/packages/contracts/test/ChatNamespaced.t.sol +++ b/examples/minimal/packages/contracts/test/ChatNamespaced.t.sol @@ -22,6 +22,6 @@ contract ChatNamespacedTest is MudTest { MessageTable.encodeLengths(value), MessageTable.encodeDynamic(value) ); - IChatNamespacedSystem(worldAddress).namespace_ChatNamespaced_sendMessage(value); + IChatNamespacedSystem(worldAddress).namespace__sendMessage(value); } } diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index d951032107..a330ba3498 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -303,7 +303,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 703658 + "gasUsed": 701756 }, { "file": "test/UniqueEntityModule.t.sol", @@ -315,7 +315,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 672525 + "gasUsed": 670623 }, { "file": "test/UniqueEntityModule.t.sol", diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 54b497614b..3d135987cd 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -105,7 +105,7 @@ "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 84542 + "gasUsed": 81992 }, { "file": "test/World.t.sol", diff --git a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol index 616da52738..f88a6faf68 100644 --- a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol @@ -195,14 +195,7 @@ contract WorldRegistrationSystem is System, IWorldErrors, LimitedCallContext { // Compute global function selector string memory namespaceString = WorldResourceIdLib.toTrimmedString(systemId.getNamespace()); - string memory nameString = WorldResourceIdLib.toTrimmedString(systemId.getName()); - bytes memory worldFunctionSignature = abi.encodePacked( - namespaceString, - "_", - nameString, - "_", - systemFunctionSignature - ); + bytes memory worldFunctionSignature = abi.encodePacked(namespaceString, "__", systemFunctionSignature); worldFunctionSelector = bytes4(keccak256(worldFunctionSignature)); // Require the function selector to be globally unique diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index 83afa4b809..9078a01e79 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -57,7 +57,7 @@ import { DelegationControlMock } from "./DelegationControlMock.sol"; import { createCoreModule } from "./createCoreModule.sol"; interface IWorldTestSystem { - function testNamespace_testSystem_err(string memory input) external pure; + function testNamespace__err(string memory input) external pure; } struct WorldTestSystemReturn { @@ -1580,7 +1580,7 @@ contract WorldTest is Test, GasReporter { bytes4 functionSelector = world.registerFunctionSelector(systemId, "msgSender()"); endGasReport(); - string memory expectedWorldFunctionSignature = "testNamespace_testSystem_msgSender()"; + string memory expectedWorldFunctionSignature = "testNamespace__msgSender()"; bytes4 expectedWorldFunctionSelector = bytes4(keccak256(abi.encodePacked(expectedWorldFunctionSignature))); assertEq(functionSelector, expectedWorldFunctionSelector, "wrong function selector returned"); @@ -1595,7 +1595,7 @@ contract WorldTest is Test, GasReporter { // Expect errors to be passed through vm.expectRevert(abi.encodeWithSelector(WorldTestSystem.WorldTestSystemError.selector, "test error")); - IWorldTestSystem(address(world)).testNamespace_testSystem_err("test error"); + IWorldTestSystem(address(world)).testNamespace__err("test error"); } function testRegisterRootFunctionSelector() public { diff --git a/packages/world/test/WorldBalance.t.sol b/packages/world/test/WorldBalance.t.sol index 65a6c84500..30f494fe87 100644 --- a/packages/world/test/WorldBalance.t.sol +++ b/packages/world/test/WorldBalance.t.sol @@ -126,7 +126,7 @@ contract WorldBalanceTest is Test, GasReporter { // Call a function on a non-root system with value vm.deal(caller, value); vm.prank(caller); - (success, data) = address(world).call{ value: value }(abi.encodeWithSignature("namespace_testSystem_echoValue()")); + (success, data) = address(world).call{ value: value }(abi.encodeWithSignature("namespace__echoValue()")); assertTrue(success); assertEq(abi.decode(data, (uint256)), value); diff --git a/packages/world/ts/node/render-solidity/worldgen.ts b/packages/world/ts/node/render-solidity/worldgen.ts index a65d63ed8e..f9dbf77d37 100644 --- a/packages/world/ts/node/render-solidity/worldgen.ts +++ b/packages/world/ts/node/render-solidity/worldgen.ts @@ -42,11 +42,9 @@ export async function worldgen( } }); const systemInterfaceName = `I${system.basename}`; - // create an interface using the external functions and imports - const { name } = resolvedConfig.systems[system.basename]; const output = renderSystemInterface({ name: systemInterfaceName, - functionPrefix: config.namespace === "" ? "" : `${config.namespace}_${name}_`, + functionPrefix: config.namespace === "" ? "" : `${config.namespace}__`, functions, errors, imports,