diff --git a/.changeset/honest-months-boil.md b/.changeset/honest-months-boil.md new file mode 100644 index 0000000000..613cd6e4e2 --- /dev/null +++ b/.changeset/honest-months-boil.md @@ -0,0 +1,18 @@ +--- +"@latticexyz/cli": major +"@latticexyz/world": major +--- + +The `registerRootFunctionSelector` function's signature was changed to accept a `string functionSignature` parameter instead of a `bytes4 functionSelector` parameter. +This change enables the `World` to store the function signatures of all registered functions in a `FunctionSignatures` offchain table, which will allow for the automatic generation of interfaces for a given `World` address in the future. + +```diff +IBaseWorld { + function registerRootFunctionSelector( + ResourceId systemId, +- bytes4 worldFunctionSelector, ++ string memory worldFunctionSignature, + bytes4 systemFunctionSelector + ) external returns (bytes4 worldFunctionSelector); +} +``` diff --git a/packages/cli/src/utils/systems/getRegisterFunctionSelectorsCallData.ts b/packages/cli/src/utils/systems/getRegisterFunctionSelectorsCallData.ts index 057522ad33..027714eb55 100644 --- a/packages/cli/src/utils/systems/getRegisterFunctionSelectorsCallData.ts +++ b/packages/cli/src/utils/systems/getRegisterFunctionSelectorsCallData.ts @@ -46,7 +46,7 @@ function getRegisterFunctionSelectorCallData(input: { const functionSelector = toFunctionSelector(systemFunctionSignature); return { func: "registerRootFunctionSelector", - args: [resourceIdToHex({ type: "system", namespace, name }), functionSelector, functionSelector], + args: [resourceIdToHex({ type: "system", namespace, name }), systemFunctionSignature, functionSelector], }; } else { return { diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 7a8c0036af..8318a79df6 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -99,7 +99,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 654836 + "gasUsed": 654858 }, { "file": "test/KeysWithValueModule.t.sol", @@ -117,7 +117,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 654836 + "gasUsed": 654858 }, { "file": "test/KeysWithValueModule.t.sol", @@ -129,7 +129,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 654836 + "gasUsed": 654858 }, { "file": "test/KeysWithValueModule.t.sol", @@ -147,7 +147,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 654836 + "gasUsed": 654858 }, { "file": "test/KeysWithValueModule.t.sol", @@ -255,7 +255,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 676985 + "gasUsed": 682963 }, { "file": "test/UniqueEntityModule.t.sol", @@ -267,7 +267,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 644325 + "gasUsed": 650259 }, { "file": "test/UniqueEntityModule.t.sol", @@ -309,19 +309,19 @@ "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 77897 + "gasUsed": 83885 }, { "file": "test/World.t.sol", "test": "testRegisterNamespace", "name": "Register a new namespace", - "gasUsed": 123141 + "gasUsed": 123163 }, { "file": "test/World.t.sol", "test": "testRegisterRootFunctionSelector", "name": "Register a root function selector", - "gasUsed": 74651 + "gasUsed": 81147 }, { "file": "test/World.t.sol", @@ -333,7 +333,7 @@ "file": "test/World.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 640825 + "gasUsed": 640821 }, { "file": "test/World.t.sol", diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index 2add7cfb72..9ce2191b4b 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -98,6 +98,16 @@ export default mudConfig({ }, dataStruct: false, }, + FunctionSignatures: { + directory: "modules/core/tables", + keySchema: { + functionSelector: "bytes4", + }, + valueSchema: { + functionSignature: "string", + }, + offchainOnly: true, + }, KeysWithValue: { directory: "modules/keyswithvalue/tables", keySchema: { diff --git a/packages/world/src/index.sol b/packages/world/src/index.sol index 5ca62f57e7..d42101c41c 100644 --- a/packages/world/src/index.sol +++ b/packages/world/src/index.sol @@ -12,6 +12,7 @@ import { Systems, SystemsTableId } from "./modules/core/tables/Systems.sol"; import { SystemRegistry, SystemRegistryTableId } from "./modules/core/tables/SystemRegistry.sol"; import { SystemHooks, SystemHooksTableId } from "./modules/core/tables/SystemHooks.sol"; import { FunctionSelectors, FunctionSelectorsTableId } from "./modules/core/tables/FunctionSelectors.sol"; +import { FunctionSignatures, FunctionSignaturesTableId } from "./modules/core/tables/FunctionSignatures.sol"; import { KeysWithValue } from "./modules/keyswithvalue/tables/KeysWithValue.sol"; import { KeysInTable, KeysInTableData, KeysInTableTableId } from "./modules/keysintable/tables/KeysInTable.sol"; import { UsedKeysIndex, UsedKeysIndexTableId } from "./modules/keysintable/tables/UsedKeysIndex.sol"; diff --git a/packages/world/src/interfaces/IWorldRegistrationSystem.sol b/packages/world/src/interfaces/IWorldRegistrationSystem.sol index 1fc03c8a45..5880071b4b 100644 --- a/packages/world/src/interfaces/IWorldRegistrationSystem.sol +++ b/packages/world/src/interfaces/IWorldRegistrationSystem.sol @@ -23,9 +23,9 @@ interface IWorldRegistrationSystem { function registerRootFunctionSelector( ResourceId systemId, - bytes4 worldFunctionSelector, + string memory worldFunctionSignature, bytes4 systemFunctionSelector - ) external returns (bytes4); + ) external returns (bytes4 worldFunctionSelector); function registerDelegation(address delegatee, ResourceId delegationControlId, bytes memory initCallData) external; } diff --git a/packages/world/src/modules/core/CoreModule.sol b/packages/world/src/modules/core/CoreModule.sol index 0a63273cf7..a2dc4333ea 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -96,33 +96,33 @@ contract CoreModule is Module { * Register function selectors for all CoreSystem functions in the World */ function _registerFunctionSelectors() internal { - bytes4[17] memory functionSelectors = [ + string[17] memory functionSignatures = [ // --- AccessManagementSystem --- - AccessManagementSystem.grantAccess.selector, - AccessManagementSystem.revokeAccess.selector, - AccessManagementSystem.transferOwnership.selector, + "grantAccess(bytes32,address)", + "revokeAccess(bytes32,address)", + "transferOwnership(bytes32,address)", // --- BalanceTransferSystem --- - BalanceTransferSystem.transferBalanceToNamespace.selector, - BalanceTransferSystem.transferBalanceToAddress.selector, + "transferBalanceToNamespace(bytes32,bytes32,uint256)", + "transferBalanceToAddress(bytes32,address,uint256)", // --- CallBatchSystem --- - CallBatchSystem.callBatch.selector, + "callBatch((bytes32,bytes)[])", // --- ModuleInstallationSystem --- - ModuleInstallationSystem.installModule.selector, + "installModule(address,bytes)", // --- StoreRegistrationSystem --- - StoreRegistrationSystem.registerTable.selector, - StoreRegistrationSystem.registerStoreHook.selector, - StoreRegistrationSystem.unregisterStoreHook.selector, + "registerTable(bytes32,bytes32,bytes32,bytes32,string[],string[])", + "registerStoreHook(bytes32,address,uint8)", + "unregisterStoreHook(bytes32,address)", // --- WorldRegistrationSystem --- - WorldRegistrationSystem.registerNamespace.selector, - WorldRegistrationSystem.registerSystemHook.selector, - WorldRegistrationSystem.unregisterSystemHook.selector, - WorldRegistrationSystem.registerSystem.selector, - WorldRegistrationSystem.registerFunctionSelector.selector, - WorldRegistrationSystem.registerRootFunctionSelector.selector, - WorldRegistrationSystem.registerDelegation.selector + "registerNamespace(bytes32)", + "registerSystemHook(bytes32,address,uint8)", + "unregisterSystemHook(bytes32,address)", + "registerSystem(bytes32,address,bool)", + "registerFunctionSelector(bytes32,string)", + "registerRootFunctionSelector(bytes32,string,bytes4)", + "registerDelegation(address,bytes32,bytes)" ]; - for (uint256 i = 0; i < functionSelectors.length; i++) { + for (uint256 i = 0; i < functionSignatures.length; i++) { // Use the CoreSystem's `registerRootFunctionSelector` to register the // root function selectors in the World. WorldContextProvider.delegatecallWithContextOrRevert({ @@ -131,7 +131,7 @@ contract CoreModule is Module { target: coreSystem, callData: abi.encodeCall( WorldRegistrationSystem.registerRootFunctionSelector, - (CORE_SYSTEM_ID, functionSelectors[i], functionSelectors[i]) + (CORE_SYSTEM_ID, functionSignatures[i], bytes4(keccak256(bytes(functionSignatures[i])))) ) }); } diff --git a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol index 54a25e97b1..30e40316ea 100644 --- a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol @@ -24,6 +24,7 @@ import { SystemHooks, SystemHooksTableId } from "../tables/SystemHooks.sol"; import { SystemRegistry } from "../tables/SystemRegistry.sol"; import { Systems } from "../tables/Systems.sol"; import { FunctionSelectors } from "../tables/FunctionSelectors.sol"; +import { FunctionSignatures } from "../tables/FunctionSignatures.sol"; /** * Functions related to registering resources other than tables in the World. @@ -159,9 +160,14 @@ contract WorldRegistrationSystem is System, IWorldErrors { // Compute global function selector string memory namespaceString = WorldResourceIdLib.toTrimmedString(systemId.getNamespace()); string memory nameString = WorldResourceIdLib.toTrimmedString(systemId.getName()); - worldFunctionSelector = bytes4( - keccak256(abi.encodePacked(namespaceString, "_", nameString, "_", systemFunctionSignature)) + bytes memory worldFunctionSignature = abi.encodePacked( + namespaceString, + "_", + nameString, + "_", + systemFunctionSignature ); + worldFunctionSelector = bytes4(keccak256(worldFunctionSignature)); // Require the function selector to be globally unique bytes32 existingSystemId = FunctionSelectors._getSystemId(worldFunctionSelector); @@ -171,6 +177,9 @@ contract WorldRegistrationSystem is System, IWorldErrors { // Register the function selector bytes4 systemFunctionSelector = bytes4(keccak256(bytes(systemFunctionSignature))); FunctionSelectors._set(worldFunctionSelector, ResourceId.unwrap(systemId), systemFunctionSelector); + + // Register the function signature for offchain use + FunctionSignatures._set(worldFunctionSelector, string(worldFunctionSignature)); } /** @@ -179,12 +188,15 @@ contract WorldRegistrationSystem is System, IWorldErrors { */ function registerRootFunctionSelector( ResourceId systemId, - bytes4 worldFunctionSelector, + string memory worldFunctionSignature, bytes4 systemFunctionSelector - ) public returns (bytes4) { + ) public returns (bytes4 worldFunctionSelector) { // Require the caller to own the root namespace AccessControl.requireOwner(ROOT_NAMESPACE_ID, _msgSender()); + // Compute the function selector from the provided signature + worldFunctionSelector = bytes4(keccak256(bytes(worldFunctionSignature))); + // Require the function selector to be globally unique bytes32 existingSystemId = FunctionSelectors._getSystemId(worldFunctionSelector); @@ -193,7 +205,8 @@ contract WorldRegistrationSystem is System, IWorldErrors { // Register the function selector FunctionSelectors._set(worldFunctionSelector, ResourceId.unwrap(systemId), systemFunctionSelector); - return worldFunctionSelector; + // Register the function signature for offchain use + FunctionSignatures._set(worldFunctionSelector, worldFunctionSignature); } /** diff --git a/packages/world/src/modules/core/tables/FunctionSignatures.sol b/packages/world/src/modules/core/tables/FunctionSignatures.sol new file mode 100644 index 0000000000..263809abaa --- /dev/null +++ b/packages/world/src/modules/core/tables/FunctionSignatures.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.21; + +/* Autogenerated file. Do not edit manually. */ + +// Import schema type +import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; + +// Import store internals +import { IStore } from "@latticexyz/store/src/IStore.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; +import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; +import { Bytes } from "@latticexyz/store/src/Bytes.sol"; +import { Memory } from "@latticexyz/store/src/Memory.sol"; +import { SliceLib } from "@latticexyz/store/src/Slice.sol"; +import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; +import { FieldLayout, FieldLayoutLib } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; +import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "@latticexyz/store/src/storeResourceTypes.sol"; + +ResourceId constant _tableId = ResourceId.wrap( + bytes32(abi.encodePacked(RESOURCE_OFFCHAIN_TABLE, bytes14(""), bytes16("FunctionSignatur"))) +); +ResourceId constant FunctionSignaturesTableId = _tableId; + +FieldLayout constant _fieldLayout = FieldLayout.wrap( + 0x0000000100000000000000000000000000000000000000000000000000000000 +); + +library FunctionSignatures { + /** Get the table values' field layout */ + function getFieldLayout() internal pure returns (FieldLayout) { + return _fieldLayout; + } + + /** Get the table's key schema */ + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _keySchema = new SchemaType[](1); + _keySchema[0] = SchemaType.BYTES4; + + return SchemaLib.encode(_keySchema); + } + + /** Get the table's value schema */ + function getValueSchema() internal pure returns (Schema) { + SchemaType[] memory _valueSchema = new SchemaType[](1); + _valueSchema[0] = SchemaType.STRING; + + return SchemaLib.encode(_valueSchema); + } + + /** Get the table's key names */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](1); + keyNames[0] = "functionSelector"; + } + + /** Get the table's field names */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "functionSignature"; + } + + /** Register the table with its config */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** Register the table with its config */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** Register the table with its config (using the specified store) */ + function register(IStore _store) internal { + _store.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** Set the full data using individual values */ + function set(bytes4 functionSelector, string memory functionSignature) internal { + bytes memory _staticData; + PackedCounter _encodedLengths = encodeLengths(functionSignature); + bytes memory _dynamicData = encodeDynamic(functionSignature); + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** Set the full data using individual values */ + function _set(bytes4 functionSelector, string memory functionSignature) internal { + bytes memory _staticData; + PackedCounter _encodedLengths = encodeLengths(functionSignature); + bytes memory _dynamicData = encodeDynamic(functionSignature); + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** Set the full data using individual values (using the specified store) */ + function set(IStore _store, bytes4 functionSelector, string memory functionSignature) internal { + bytes memory _staticData; + PackedCounter _encodedLengths = encodeLengths(functionSignature); + bytes memory _dynamicData = encodeDynamic(functionSignature); + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + _store.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** + * Decode the tightly packed blob of static data using this table's field layout + * Undefined behaviour for invalid blobs + */ + function decodeDynamic( + PackedCounter _encodedLengths, + bytes memory _blob + ) internal pure returns (string memory functionSignature) { + uint256 _start; + uint256 _end; + unchecked { + _end = _encodedLengths.atIndex(0); + } + functionSignature = (string(SliceLib.getSubslice(_blob, _start, _end).toBytes())); + } + + /** + * Decode the tightly packed blob using this table's field layout. + * Undefined behaviour for invalid blobs. + */ + function decode( + bytes memory, + PackedCounter _encodedLengths, + bytes memory _dynamicData + ) internal pure returns (string memory functionSignature) { + (functionSignature) = decodeDynamic(_encodedLengths, _dynamicData); + } + + /** Delete all data for given keys */ + function deleteRecord(bytes4 functionSelector) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + StoreSwitch.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** Delete all data for given keys */ + function _deleteRecord(bytes4 functionSelector) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** Delete all data for given keys (using the specified store) */ + function deleteRecord(IStore _store, bytes4 functionSelector) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + _store.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** Tightly pack dynamic data using this table's schema */ + function encodeLengths(string memory functionSignature) internal pure returns (PackedCounter _encodedLengths) { + // Lengths are effectively checked during copy by 2**40 bytes exceeding gas limits + unchecked { + _encodedLengths = PackedCounterLib.pack(bytes(functionSignature).length); + } + } + + /** Tightly pack dynamic data using this table's schema */ + function encodeDynamic(string memory functionSignature) internal pure returns (bytes memory) { + return abi.encodePacked(bytes((functionSignature))); + } + + /** Tightly pack full data using this table's field layout */ + function encode(string memory functionSignature) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData; + PackedCounter _encodedLengths = encodeLengths(functionSignature); + bytes memory _dynamicData = encodeDynamic(functionSignature); + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** Encode keys as a bytes32 array using this table's field layout */ + function encodeKeyTuple(bytes4 functionSelector) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(functionSelector); + + return _keyTuple; + } +} diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index d80dbdc52a..50abcff526 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -36,8 +36,11 @@ import { NamespaceOwner, NamespaceOwnerTableId } from "../src/tables/NamespaceOw import { ResourceAccess } from "../src/tables/ResourceAccess.sol"; import { CoreModule } from "../src/modules/core/CoreModule.sol"; +import { CoreSystem } from "../src/modules/core/CoreSystem.sol"; +import { CORE_SYSTEM_ID } from "../src/modules/core/constants.sol"; import { Systems } from "../src/modules/core/tables/Systems.sol"; import { SystemRegistry } from "../src/modules/core/tables/SystemRegistry.sol"; +import { FunctionSelectors } from "../src/modules/core/tables/FunctionSelectors.sol"; import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; @@ -219,6 +222,41 @@ contract WorldTest is Test, GasReporter { // Expect the creator to be able to initialize the World newWorld.initialize(coreModule); + // Should have registered the core system function selectors + CoreSystem coreSystem = CoreSystem(Systems.getSystem(world, ResourceId.unwrap(CORE_SYSTEM_ID))); + bytes4[17] memory coreFunctionSignatures = [ + // --- AccessManagementSystem --- + coreSystem.grantAccess.selector, + coreSystem.revokeAccess.selector, + coreSystem.transferOwnership.selector, + // --- BalanceTransferSystem --- + coreSystem.transferBalanceToNamespace.selector, + coreSystem.transferBalanceToAddress.selector, + // --- CallBatchSystem --- + coreSystem.callBatch.selector, + // --- ModuleInstallationSystem --- + coreSystem.installModule.selector, + // --- StoreRegistrationSystem --- + coreSystem.registerTable.selector, + coreSystem.registerStoreHook.selector, + coreSystem.unregisterStoreHook.selector, + // --- WorldRegistrationSystem --- + coreSystem.registerNamespace.selector, + coreSystem.registerSystemHook.selector, + coreSystem.unregisterSystemHook.selector, + coreSystem.registerSystem.selector, + coreSystem.registerFunctionSelector.selector, + coreSystem.registerRootFunctionSelector.selector, + coreSystem.registerDelegation.selector + ]; + + for (uint256 i; i < coreFunctionSignatures.length; i++) { + assertEq( + FunctionSelectors.getSystemFunctionSelector(world, coreFunctionSignatures[i]), + coreFunctionSignatures[i] + ); + } + // Should have registered the table data table (fka schema table) assertEq( Tables.getFieldLayout(newWorld, ResourceId.unwrap(TablesTableId)), @@ -1392,7 +1430,7 @@ contract WorldTest is Test, GasReporter { WorldTestSystem system = new WorldTestSystem(); world.registerSystem(systemId, system, true); - bytes4 worldFunc = bytes4(abi.encodeWithSignature("testSelector()")); + string memory worldFunc = "testSelector()"; bytes4 sysFunc = WorldTestSystem.msgSender.selector; // Expect an error when trying to register a root function selector from an account without access @@ -1413,20 +1451,16 @@ contract WorldTest is Test, GasReporter { bytes4 functionSelector = world.registerRootFunctionSelector(systemId, worldFunc, sysFunc); endGasReport(); - assertEq(functionSelector, worldFunc, "wrong function selector returned"); + assertEq(functionSelector, bytes4(keccak256(bytes(worldFunc))), "wrong function selector returned"); // Call the system via the World with the registered function selector - (bool success, bytes memory data) = address(world).call(abi.encodePacked(worldFunc)); + (bool success, bytes memory data) = address(world).call(abi.encodeWithSignature(worldFunc)); assertTrue(success, "call failed"); assertEq(abi.decode(data, (address)), address(this), "wrong address returned"); // Register a function selector to the error function - functionSelector = world.registerRootFunctionSelector( - systemId, - WorldTestSystem.err.selector, - WorldTestSystem.err.selector - ); + functionSelector = world.registerRootFunctionSelector(systemId, "err(string)", WorldTestSystem.err.selector); // Expect errors to be passed through vm.expectRevert(abi.encodeWithSelector(WorldTestSystem.WorldTestSystemError.selector, "test error")); @@ -1462,11 +1496,7 @@ contract WorldTest is Test, GasReporter { ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); world.registerSystem(systemId, system, true); - world.registerRootFunctionSelector( - systemId, - WorldTestSystem.receiveEther.selector, - WorldTestSystem.receiveEther.selector - ); + world.registerRootFunctionSelector(systemId, "receiveEther()", WorldTestSystem.receiveEther.selector); // create new funded address and impersonate address alice = makeAddr("alice"); @@ -1492,11 +1522,7 @@ contract WorldTest is Test, GasReporter { bytes16 name = "testSystem"; ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); world.registerSystem(systemId, system, true); - world.registerRootFunctionSelector( - systemId, - WorldTestSystem.msgSender.selector, - WorldTestSystem.msgSender.selector - ); + world.registerRootFunctionSelector(systemId, "msgSender()", WorldTestSystem.msgSender.selector); // create new funded address and impersonate address alice = makeAddr("alice"); @@ -1523,7 +1549,7 @@ contract WorldTest is Test, GasReporter { bytes16 name = "testSystem"; ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); world.registerSystem(systemId, system, true); - world.registerRootFunctionSelector(systemId, bytes4(abi.encodeWithSignature("systemFallback()")), bytes4("")); + world.registerRootFunctionSelector(systemId, "systemFallback()", bytes4("")); // create new funded address and impersonate address alice = makeAddr("alice"); @@ -1549,7 +1575,7 @@ contract WorldTest is Test, GasReporter { bytes16 name = "testSystem"; ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); world.registerSystem(systemId, system, true); - world.registerRootFunctionSelector(systemId, bytes4(abi.encodeWithSignature("systemFallback()")), bytes4("")); + world.registerRootFunctionSelector(systemId, "systemFallback()", bytes4("")); // create new funded address and impersonate address alice = makeAddr("alice"); @@ -1575,11 +1601,7 @@ contract WorldTest is Test, GasReporter { bytes16 name = "testSystem"; ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); world.registerSystem(systemId, system, true); - world.registerRootFunctionSelector( - systemId, - WorldTestSystem.receiveEther.selector, - WorldTestSystem.receiveEther.selector - ); + world.registerRootFunctionSelector(systemId, "receiveEther()", WorldTestSystem.receiveEther.selector); // create new funded address and impersonate address alice = makeAddr("alice"); diff --git a/packages/world/test/WorldBalance.t.sol b/packages/world/test/WorldBalance.t.sol index 2cd288bdc2..ca36645905 100644 --- a/packages/world/test/WorldBalance.t.sol +++ b/packages/world/test/WorldBalance.t.sol @@ -39,7 +39,7 @@ contract WorldBalanceTest is Test, GasReporter { world.registerSystem(rootSystemId, rootSystem, true); world.registerSystem(nonRootSystemId, nonRootSystem, true); - world.registerRootFunctionSelector(rootSystemId, rootSystem.echoValue.selector, rootSystem.echoValue.selector); + world.registerRootFunctionSelector(rootSystemId, "echoValue()", rootSystem.echoValue.selector); world.registerFunctionSelector(nonRootSystemId, "echoValue()"); }