diff --git a/examples/minimal/packages/contracts/script/PostDeploy.s.sol b/examples/minimal/packages/contracts/script/PostDeploy.s.sol index 059758821e..f06a6c9661 100644 --- a/examples/minimal/packages/contracts/script/PostDeploy.s.sol +++ b/examples/minimal/packages/contracts/script/PostDeploy.s.sol @@ -3,7 +3,8 @@ pragma solidity >=0.8.0; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; -import { ResourceSelector } from "@latticexyz/world/src/ResourceSelector.sol"; +import { ResourceId } from "@latticexyz/world/src/ResourceId.sol"; +import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol"; import { IWorld } from "../src/codegen/world/IWorld.sol"; import { MessageTable, MessageTableTableId } from "../src/codegen/index.sol"; @@ -19,16 +20,9 @@ contract PostDeploy is Script { // Manually deploy a system with another namespace ChatNamespacedSystem chatNamespacedSystem = new ChatNamespacedSystem(); - IWorld(worldAddress).registerSystem( - ResourceSelector.from("namespace", "ChatNamespaced"), - chatNamespacedSystem, - true - ); - IWorld(worldAddress).registerFunctionSelector( - ResourceSelector.from("namespace", "ChatNamespaced"), - "sendMessage", - "(string)" - ); + bytes32 systemId = ResourceId.encode("namespace", "ChatNamespaced", RESOURCE_SYSTEM); + IWorld(worldAddress).registerSystem(systemId, chatNamespacedSystem, true); + IWorld(worldAddress).registerFunctionSelector(systemId, "sendMessage", "(string)"); // Grant this system access to MessageTable IWorld(worldAddress).grantAccess(MessageTableTableId, address(chatNamespacedSystem)); diff --git a/packages/store/src/ResourceType.sol b/packages/store/src/ResourceType.sol new file mode 100644 index 0000000000..664971e5b4 --- /dev/null +++ b/packages/store/src/ResourceType.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +library ResourceType { + function encode(bytes30 resourceName, bytes2 resourceType) internal pure returns (bytes32) { + return bytes32(resourceName) | (bytes32(resourceType) >> (8 * 30)); + } + + function getType(bytes32 resourceId) internal pure returns (bytes2) { + return bytes2(resourceId << (30 * 8)); + } + + function isType(bytes32 resourceId, bytes2 resourceType) internal pure returns (bool) { + return resourceId & bytes32(resourceType >> (30 * 8)) == bytes32(resourceType >> (30 * 8)); + } +} diff --git a/packages/store/src/storeResourceTypes.sol b/packages/store/src/storeResourceTypes.sol new file mode 100644 index 0000000000..7255f414e6 --- /dev/null +++ b/packages/store/src/storeResourceTypes.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +bytes2 constant RESOURCE_TABLE = "ta"; +bytes2 constant RESOURCE_OFFCHAIN_TABLE = "of"; diff --git a/packages/store/test/ResourceType.t.sol b/packages/store/test/ResourceType.t.sol new file mode 100644 index 0000000000..1bd1d8d602 --- /dev/null +++ b/packages/store/test/ResourceType.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { Test, console } from "forge-std/Test.sol"; +import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; +import { ResourceType } from "../src/ResourceType.sol"; +import { RESOURCE_TABLE } from "../src/storeResourceTypes.sol"; + +contract ResourceTypeTest is Test, GasReporter { + using ResourceType for bytes32; + + function testEncode() public { + startGasReport("encode table ID with name and type"); + bytes32 tableId = ResourceType.encode("name", RESOURCE_TABLE); + endGasReport(); + + assertEq(tableId, bytes32(abi.encodePacked(bytes30("name"), RESOURCE_TABLE))); + } + + function getGetType() public { + bytes32 tableId = ResourceType.encode("name", "tb"); + + startGasReport("get type from a table ID"); + bytes2 resourceType = tableId.getType(); + endGasReport(); + + assertEq(resourceType, "tb"); + } + + function testIsType() public { + bytes32 tableId = ResourceType.encode("name", RESOURCE_TABLE); + + startGasReport("check if a table ID is of type tb"); + bool isType = tableId.isType(RESOURCE_TABLE); + endGasReport(); + + assertTrue(isType); + } + + function testFuzz(bytes30 name, bytes2 resourceType) public { + bytes32 tableId = ResourceType.encode(name, resourceType); + assertEq(tableId.getType(), resourceType); + } +} diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index 1ad535703d..3e28c68b2c 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -21,7 +21,7 @@ export default mudConfig({ }, ResourceAccess: { keySchema: { - resourceSelector: "bytes32", + resourceId: "bytes32", caller: "address", }, valueSchema: { @@ -63,7 +63,7 @@ export default mudConfig({ Systems: { directory: "modules/core/tables", keySchema: { - resourceSelector: "bytes32", + systemId: "bytes32", }, valueSchema: { system: "address", @@ -77,20 +77,20 @@ export default mudConfig({ system: "address", }, valueSchema: { - resourceSelector: "bytes32", + systemId: "bytes32", }, }, SystemHooks: { directory: "modules/core/tables", keySchema: { - resourceSelector: "bytes32", + systemId: "bytes32", }, valueSchema: "bytes21[]", }, ResourceType: { directory: "modules/core/tables", keySchema: { - resourceSelector: "bytes32", + systemId: "bytes32", }, valueSchema: { resourceType: "Resource", @@ -102,7 +102,7 @@ export default mudConfig({ functionSelector: "bytes4", }, valueSchema: { - resourceSelector: "bytes32", + systemId: "bytes32", systemFunctionSelector: "bytes4", }, dataStruct: false, @@ -149,7 +149,7 @@ export default mudConfig({ keySchema: { delegator: "address", delegatee: "address", - resourceSelector: "bytes32", + systemId: "bytes32", callDataHash: "bytes32", }, valueSchema: { diff --git a/packages/world/src/AccessControl.sol b/packages/world/src/AccessControl.sol index d99fd415ef..94a31904eb 100644 --- a/packages/world/src/AccessControl.sol +++ b/packages/world/src/AccessControl.sol @@ -1,43 +1,43 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -import { ResourceSelector } from "./ResourceSelector.sol"; +import { ResourceId } from "./ResourceId.sol"; import { IWorldErrors } from "./interfaces/IWorldErrors.sol"; import { ResourceAccess } from "./tables/ResourceAccess.sol"; import { NamespaceOwner } from "./tables/NamespaceOwner.sol"; library AccessControl { - using ResourceSelector for bytes32; + using ResourceId for bytes32; /** * Returns true if the caller has access to the namespace or name, false otherwise. */ - function hasAccess(bytes32 resourceSelector, address caller) internal view returns (bool) { + function hasAccess(bytes32 resourceId, address caller) internal view returns (bool) { return - address(this) == caller || // First check if the World is calling itself - ResourceAccess._get(resourceSelector.getNamespace(), caller) || // Then check access based on the namespace - ResourceAccess._get(resourceSelector, caller); // If caller has no namespace access, check access on the name + address(this) == caller || // First check if the World is calling itself // TODO: remove this check? + ResourceAccess._get(resourceId.getNamespaceId(), caller) || // Then check access based on the namespace + ResourceAccess._get(resourceId, caller); // If caller has no namespace access, check access on the name } /** * Check for access at the given namespace or name. * Reverts with AccessDenied if the caller has no access. */ - function requireAccess(bytes32 resourceSelector, address caller) internal view { + function requireAccess(bytes32 resourceId, address caller) internal view { // Check if the given caller has access to the given namespace or name - if (!hasAccess(resourceSelector, caller)) { - revert IWorldErrors.AccessDenied(resourceSelector.toString(), caller); + if (!hasAccess(resourceId, caller)) { + revert IWorldErrors.AccessDenied(resourceId.toString(), caller); } } /** - * Check for ownership of the namespace of the given resource selector. + * Check for ownership of the namespace of the given resource ID. * Reverts with AccessDenied if the check fails. */ - function requireOwner(bytes32 resourceSelector, address caller) internal view { - if (NamespaceOwner._get(resourceSelector.getNamespace()) != caller) { - revert IWorldErrors.AccessDenied(resourceSelector.toString(), caller); + function requireOwner(bytes32 resourceId, address caller) internal view { + if (NamespaceOwner._get(resourceId.getNamespace()) != caller) { + revert IWorldErrors.AccessDenied(resourceId.toString(), caller); } } } diff --git a/packages/world/src/Delegation.sol b/packages/world/src/Delegation.sol index 14855a1ae0..852bbb854e 100644 --- a/packages/world/src/Delegation.sol +++ b/packages/world/src/Delegation.sol @@ -43,7 +43,7 @@ library DelegationInstance { // Call the delegation control contract to check if the delegator has granted access to the delegatee (bool success, bytes memory data) = SystemCall.call({ caller: delegatee, - resourceSelector: Delegation.unwrap(self), + systemId: Delegation.unwrap(self), callData: abi.encodeCall(IDelegationControl.verify, (delegator, systemId, callData)), value: 0 }); diff --git a/packages/world/src/ResourceId.sol b/packages/world/src/ResourceId.sol new file mode 100644 index 0000000000..1e5263e626 --- /dev/null +++ b/packages/world/src/ResourceId.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; +import { ROOT_NAMESPACE, ROOT_NAME } from "./constants.sol"; +import { Bytes } from "@latticexyz/store/src/Bytes.sol"; +import { ResourceType } from "@latticexyz/store/src/ResourceType.sol"; +import { RESOURCE_NAMESPACE, MASK_RESOURCE_NAMESPACE } from "./worldResourceTypes.sol"; + +bytes16 constant ROOT_NAMESPACE_STRING = bytes16("ROOT_NAMESPACE"); +bytes16 constant ROOT_NAME_STRING = bytes16("ROOT_NAME"); + +bytes32 constant NAMESPACE_MASK = bytes32(~bytes14("")); + +// TODO: change all namespace functions to namespace id functions (don't use bytes14 but bytes32 for ownership and access control) +// TODO: should resource id be a user type to avoid type errors of eg passing a namespace (bytes14) instead of a namespace id (bytes32) +// (I ran into a bunch of runtime errors while refactoring this where bytes14 was automatically casted to bytes32) + +library ResourceId { + /** + * Create a 32-byte resource ID from a namespace, name and type. + * + * A resource ID is a 32-byte value that uniquely identifies a resource. + * The first 14 bytes represent the namespace, + * the next 16 bytes represent the name, + * the last 2 bytes represent the type. + * + * Note: the location of the resource type needs to stay aligned with `ResourceType` + */ + function encode( + bytes14 resourceNamespace, + bytes16 resourceName, + bytes2 resourceType + ) internal pure returns (bytes32) { + return bytes32(resourceNamespace) | ((bytes32(resourceName) >> (14 * 8)) | (bytes32(resourceType) >> (30 * 8))); + } + + /** + * Create a 32-byte resource ID from a namespace. + */ + function encodeNamespace(bytes14 resourceNamespace) internal pure returns (bytes32) { + return bytes32(resourceNamespace) | (bytes32(RESOURCE_NAMESPACE) >> (30 * 8)); + } + + /** + * Get the namespace of a resource ID. + */ + function getNamespace(bytes32 resourceId) internal pure returns (bytes14) { + return bytes14(resourceId); + } + + /** + * Get the namespace resource ID corresponding to the namespace of a resource ID. + */ + function getNamespaceId(bytes32 resourceId) internal pure returns (bytes32) { + return (resourceId & NAMESPACE_MASK) | MASK_RESOURCE_NAMESPACE; + } + + /** + * Get the name of a resource ID. + */ + function getName(bytes32 resourceId) internal pure returns (bytes16) { + return bytes16(resourceId << (14 * 8)); + } + + /** + * Convert a resource ID to a string for more readable logs + */ + function toString(bytes32 resourceId) internal pure returns (string memory) { + bytes14 resourceNamespace = getNamespace(resourceId); + bytes16 resourceName = getName(resourceId); + bytes2 resourceType = ResourceType.getType(resourceId); + return + string( + abi.encodePacked( + resourceNamespace == ROOT_NAMESPACE ? ROOT_NAMESPACE_STRING : resourceNamespace, + "_", + resourceName == ROOT_NAME ? ROOT_NAME_STRING : resourceName, + ".", + resourceType + ) + ); + } + + /** + * Convert a selector to a trimmed string (no trailing `null` ASCII characters) + */ + function toTrimmedString(bytes16 paddedString) internal pure returns (string memory) { + uint256 length; + for (; length < 16; length++) if (Bytes.slice1(paddedString, length) == 0) break; + bytes memory packedSelector = abi.encodePacked(paddedString); + return string(Bytes.setLength(packedSelector, length)); + } +} diff --git a/packages/world/src/ResourceSelector.sol b/packages/world/src/ResourceSelector.sol deleted file mode 100644 index 8ed6b39326..0000000000 --- a/packages/world/src/ResourceSelector.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; -import { ROOT_NAMESPACE, ROOT_NAME } from "./constants.sol"; -import { Bytes } from "@latticexyz/store/src/Bytes.sol"; - -bytes16 constant ROOT_NAMESPACE_STRING = bytes16("ROOT_NAMESPACE"); -bytes16 constant ROOT_NAME_STRING = bytes16("ROOT_NAME"); - -library ResourceSelector { - /** - * Create a 32-byte resource selector from a namespace and a name. - * - * A ResourceSelector is a 32-byte value that uniquely identifies a resource. - * The first 16 bytes represent the namespace, the last 16 bytes represent the name. - */ - function from(bytes16 namespace, bytes16 name) internal pure returns (bytes32) { - return bytes32(namespace) | (bytes32(name) >> 128); - } - - /** - * Create a 32-byte resource selector from a namespace. The selector points to the namespace's root name. - */ - function from(bytes16 namespace) internal pure returns (bytes32) { - return bytes32(namespace); - } - - /** - * Get the namespace of a ResourceSelector. - */ - function getNamespace(bytes32 resourceSelector) internal pure returns (bytes16) { - return bytes16(resourceSelector); - } - - /** - * Get the name of a ResourceSelector. - */ - function getName(bytes32 resourceSelector) internal pure returns (bytes16) { - return bytes16(resourceSelector << 128); - } - - /** - * Convert a selector to a string for more readable logs - */ - function toString(bytes32 resourceSelector) internal pure returns (string memory) { - bytes16 namespace = getNamespace(resourceSelector); - bytes16 name = getName(resourceSelector); - return - string( - abi.encodePacked( - namespace == ROOT_NAMESPACE ? ROOT_NAMESPACE_STRING : namespace, - "/", - name == ROOT_NAME ? ROOT_NAME_STRING : name - ) - ); - } - - /** - * Convert a selector to a trimmed string (no trailing `null` ASCII characters) - */ - function toTrimmedString(bytes16 selector) internal pure returns (string memory) { - uint256 length; - for (; length < 16; length++) if (Bytes.slice1(selector, length) == 0) break; - bytes memory packedSelector = abi.encodePacked(selector); - return string(Bytes.setLength(packedSelector, length)); - } -} diff --git a/packages/world/src/SystemCall.sol b/packages/world/src/SystemCall.sol index 27241b9a6b..3d9de8f84f 100644 --- a/packages/world/src/SystemCall.sol +++ b/packages/world/src/SystemCall.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.0; import { Hook } from "@latticexyz/store/src/Hook.sol"; -import { ResourceSelector } from "./ResourceSelector.sol"; +import { ResourceId } from "./ResourceId.sol"; import { WorldContextProvider } from "./WorldContext.sol"; import { AccessControl } from "./AccessControl.sol"; -import { ResourceSelector } from "./ResourceSelector.sol"; +import { ResourceId } from "./ResourceId.sol"; import { ROOT_NAMESPACE } from "./constants.sol"; import { WorldContextProvider } from "./WorldContext.sol"; import { revertWithBytes } from "./revertWithBytes.sol"; @@ -21,36 +21,36 @@ import { SystemHooks } from "./modules/core/tables/SystemHooks.sol"; import { Balances } from "./modules/core/tables/Balances.sol"; library SystemCall { - using ResourceSelector for bytes32; + using ResourceId for bytes32; /** - * Calls a system via its resource selector and perform access control checks. + * Calls a system via its ID and perform access control checks. * Does not revert if the call fails, but returns a `success` flag along with the returndata. */ function call( address caller, uint256 value, - bytes32 resourceSelector, + bytes32 systemId, bytes memory callData ) internal returns (bool success, bytes memory data) { // Load the system data - (address systemAddress, bool publicAccess) = Systems._get(resourceSelector); + (address systemAddress, bool publicAccess) = Systems._get(systemId); // Check if the system exists - if (systemAddress == address(0)) revert IWorldErrors.ResourceNotFound(resourceSelector.toString()); + if (systemAddress == address(0)) revert IWorldErrors.ResourceNotFound(systemId.toString()); // Allow access if the system is public or the caller has access to the namespace or name - if (!publicAccess) AccessControl.requireAccess(resourceSelector, caller); + if (!publicAccess) AccessControl.requireAccess(systemId, caller); // If the msg.value is non-zero, update the namespace's balance if (value > 0) { - bytes16 namespace = resourceSelector.getNamespace(); + bytes14 namespace = systemId.getNamespace(); uint256 currentBalance = Balances._get(namespace); Balances._set(namespace, currentBalance + value); } // Call the system and forward any return data - (success, data) = resourceSelector.getNamespace() == ROOT_NAMESPACE // Use delegatecall for root systems (= registered in the root namespace) + (success, data) = systemId.getNamespace() == ROOT_NAMESPACE // Use delegatecall for root systems (= registered in the root namespace) ? WorldContextProvider.delegatecallWithContext({ msgSender: caller, msgValue: value, @@ -66,52 +66,52 @@ library SystemCall { } /** - * Calls a system via its resource selector, perform access control checks and trigger hooks registered for the system. + * Calls a system via its ID, perform access control checks and trigger hooks registered for the system. * Does not revert if the call fails, but returns a `success` flag along with the returndata. */ function callWithHooks( address caller, - bytes32 resourceSelector, + bytes32 systemId, bytes memory callData, uint256 value ) internal returns (bool success, bytes memory data) { // Get system hooks - bytes21[] memory hooks = SystemHooks._get(resourceSelector); + bytes21[] memory hooks = SystemHooks._get(systemId); // Call onBeforeCallSystem hooks (before calling the system) for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); if (hook.isEnabled(BEFORE_CALL_SYSTEM)) { - ISystemHook(hook.getAddress()).onBeforeCallSystem(caller, resourceSelector, callData); + ISystemHook(hook.getAddress()).onBeforeCallSystem(caller, systemId, callData); } } // Call the system and forward any return data - (success, data) = call({ caller: caller, value: value, resourceSelector: resourceSelector, callData: callData }); + (success, data) = call({ caller: caller, value: value, systemId: systemId, callData: callData }); // Call onAfterCallSystem hooks (after calling the system) for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); if (hook.isEnabled(AFTER_CALL_SYSTEM)) { - ISystemHook(hook.getAddress()).onAfterCallSystem(caller, resourceSelector, callData); + ISystemHook(hook.getAddress()).onAfterCallSystem(caller, systemId, callData); } } } /** - * Calls a system via its resource selector, perform access control checks and trigger hooks registered for the system. + * Calls a system via its ID, perform access control checks and trigger hooks registered for the system. * Reverts if the call fails. */ function callWithHooksOrRevert( address caller, - bytes32 resourceSelector, + bytes32 systemId, bytes memory callData, uint256 value ) internal returns (bytes memory data) { (bool success, bytes memory returnData) = callWithHooks({ caller: caller, value: value, - resourceSelector: resourceSelector, + systemId: systemId, callData: callData }); if (!success) revertWithBytes(returnData); diff --git a/packages/world/src/Utils.sol b/packages/world/src/Utils.sol index b54e5d7653..3e77c1f937 100644 --- a/packages/world/src/Utils.sol +++ b/packages/world/src/Utils.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.0; import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; -import { ResourceSelector } from "./ResourceSelector.sol"; +import { ResourceId } from "./ResourceId.sol"; import { SystemRegistry } from "./index.sol"; library Utils { @@ -17,8 +17,8 @@ library Utils { if (StoreSwitch.getStoreAddress() == address(this)) { return ""; } else { - bytes32 resourceSelector = SystemRegistry.get(address(this)); - return ResourceSelector.getNamespace(resourceSelector); + bytes32 systemId = SystemRegistry.get(address(this)); + return ResourceId.getNamespace(systemId); } } } diff --git a/packages/world/src/World.sol b/packages/world/src/World.sol index 73464c011b..9842751350 100644 --- a/packages/world/src/World.sol +++ b/packages/world/src/World.sol @@ -12,8 +12,8 @@ import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; import { WORLD_VERSION } from "./version.sol"; import { System } from "./System.sol"; -import { ResourceSelector } from "./ResourceSelector.sol"; -import { ROOT_NAMESPACE, ROOT_NAME } from "./constants.sol"; +import { ResourceId } from "./ResourceId.sol"; +import { ROOT_NAMESPACE_ID, ROOT_NAMESPACE, ROOT_NAME } from "./constants.sol"; import { AccessControl } from "./AccessControl.sol"; import { SystemCall } from "./SystemCall.sol"; import { WorldContextProvider } from "./WorldContext.sol"; @@ -36,7 +36,7 @@ import { Balances } from "./modules/core/tables/Balances.sol"; import { CORE_MODULE_NAME } from "./modules/core/constants.sol"; contract World is StoreRead, IStoreData, IWorldKernel { - using ResourceSelector for bytes32; + using ResourceId for bytes32; address public immutable creator; function worldVersion() public pure returns (bytes32) { @@ -55,7 +55,7 @@ contract World is StoreRead, IStoreData, IWorldKernel { function initialize(IModule coreModule) public { // Only the initial creator of the World can initialize it if (msg.sender != creator) { - revert AccessDenied(ResourceSelector.from(ROOT_NAMESPACE).toString(), msg.sender); + revert AccessDenied(ROOT_NAMESPACE_ID.toString(), msg.sender); } // The World can only be initialized once @@ -73,7 +73,7 @@ contract World is StoreRead, IStoreData, IWorldKernel { * The module is delegatecalled and installed in the root namespace. */ function installRootModule(IModule module, bytes memory args) public { - AccessControl.requireOwner(ROOT_NAMESPACE, msg.sender); + AccessControl.requireOwner(ROOT_NAMESPACE_ID, msg.sender); _installRootModule(module, args); } @@ -238,40 +238,40 @@ contract World is StoreRead, IStoreData, IWorldKernel { ************************************************************************/ /** - * Call the system at the given resourceSelector. - * If the system is not public, the caller must have access to the namespace or name (encoded in the resourceSelector). + * Call the system at the given system ID. + * If the system is not public, the caller must have access to the namespace or name (encoded in the system ID). */ - function call(bytes32 resourceSelector, bytes memory callData) external payable virtual returns (bytes memory) { - return SystemCall.callWithHooksOrRevert(msg.sender, resourceSelector, callData, msg.value); + function call(bytes32 systemId, bytes memory callData) external payable virtual returns (bytes memory) { + return SystemCall.callWithHooksOrRevert(msg.sender, systemId, callData, msg.value); } /** - * Call the system at the given resourceSelector on behalf of the given delegator. - * If the system is not public, the delegator must have access to the namespace or name (encoded in the resourceSelector). + * Call the system at the given system ID on behalf of the given delegator. + * If the system is not public, the delegator must have access to the namespace or name (encoded in the system ID). */ function callFrom( address delegator, - bytes32 resourceSelector, + bytes32 systemId, bytes memory callData ) external payable virtual returns (bytes memory) { // If the delegator is the caller, call the system directly if (delegator == msg.sender) { - return SystemCall.callWithHooksOrRevert(msg.sender, resourceSelector, callData, msg.value); + return SystemCall.callWithHooksOrRevert(msg.sender, systemId, callData, msg.value); } // Check if there is an explicit authorization for this caller to perform actions on behalf of the delegator Delegation explicitDelegation = Delegation.wrap(Delegations._get({ delegator: delegator, delegatee: msg.sender })); - if (explicitDelegation.verify(delegator, msg.sender, resourceSelector, callData)) { + if (explicitDelegation.verify(delegator, msg.sender, systemId, callData)) { // forward the call as `delegator` - return SystemCall.callWithHooksOrRevert(delegator, resourceSelector, callData, msg.value); + return SystemCall.callWithHooksOrRevert(delegator, systemId, callData, msg.value); } // Check if the delegator has a fallback delegation control set Delegation fallbackDelegation = Delegation.wrap(Delegations._get({ delegator: delegator, delegatee: address(0) })); - if (fallbackDelegation.verify(delegator, msg.sender, resourceSelector, callData)) { + if (fallbackDelegation.verify(delegator, msg.sender, systemId, callData)) { // forward the call with `from` as `msgSender` - return SystemCall.callWithHooksOrRevert(delegator, resourceSelector, callData, msg.value); + return SystemCall.callWithHooksOrRevert(delegator, systemId, callData, msg.value); } revert DelegationNotFound(delegator, msg.sender); @@ -295,15 +295,15 @@ contract World is StoreRead, IStoreData, IWorldKernel { * Fallback function to call registered function selectors */ fallback() external payable { - (bytes32 resourceSelector, bytes4 systemFunctionSelector) = FunctionSelectors._get(msg.sig); + (bytes32 systemId, bytes4 systemFunctionSelector) = FunctionSelectors._get(msg.sig); - if (resourceSelector == 0) revert FunctionSelectorNotFound(msg.sig); + if (systemId == 0) revert FunctionSelectorNotFound(msg.sig); // Replace function selector in the calldata with the system function selector bytes memory callData = Bytes.setBytes4(msg.data, 0, systemFunctionSelector); // Call the function and forward the call data - bytes memory returnData = SystemCall.callWithHooksOrRevert(msg.sender, resourceSelector, callData, msg.value); + bytes memory returnData = SystemCall.callWithHooksOrRevert(msg.sender, systemId, callData, msg.value); // If the call was successful, return the return data assembly { diff --git a/packages/world/src/constants.sol b/packages/world/src/constants.sol index a4a2538803..ddcfd9e6ae 100644 --- a/packages/world/src/constants.sol +++ b/packages/world/src/constants.sol @@ -1,6 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -bytes16 constant ROOT_NAMESPACE = 0; +import { RESOURCE_SYSTEM, RESOURCE_NAMESPACE } from "./worldResourceTypes.sol"; + +bytes14 constant ROOT_NAMESPACE = 0; bytes16 constant ROOT_NAME = 0; -bytes32 constant UNLIMITED_DELEGATION = bytes32(abi.encodePacked(ROOT_NAMESPACE, bytes16("unlimited.d"))); +bytes32 constant ROOT_NAMESPACE_ID = bytes32(abi.encodePacked(ROOT_NAMESPACE, ROOT_NAME, RESOURCE_NAMESPACE)); + +bytes32 constant UNLIMITED_DELEGATION = bytes32( + abi.encodePacked(ROOT_NAMESPACE, bytes16("unlimited"), RESOURCE_SYSTEM) +); diff --git a/packages/world/src/interfaces/IAccessManagementSystem.sol b/packages/world/src/interfaces/IAccessManagementSystem.sol index 8f443689d5..e99360c13c 100644 --- a/packages/world/src/interfaces/IAccessManagementSystem.sol +++ b/packages/world/src/interfaces/IAccessManagementSystem.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.0; /* Autogenerated file. Do not edit manually. */ interface IAccessManagementSystem { - function grantAccess(bytes32 resourceSelector, address grantee) external; + function grantAccess(bytes32 resourceId, address grantee) external; - function revokeAccess(bytes32 resourceSelector, address grantee) external; + function revokeAccess(bytes32 resourceId, address grantee) external; - function transferOwnership(bytes16 namespace, address newOwner) external; + function transferOwnership(bytes14 namespace, address newOwner) external; } diff --git a/packages/world/src/interfaces/IBalanceTransferSystem.sol b/packages/world/src/interfaces/IBalanceTransferSystem.sol index eddb986957..92c3e104dd 100644 --- a/packages/world/src/interfaces/IBalanceTransferSystem.sol +++ b/packages/world/src/interfaces/IBalanceTransferSystem.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.0; /* Autogenerated file. Do not edit manually. */ interface IBalanceTransferSystem { - function transferBalanceToNamespace(bytes16 fromNamespace, bytes16 toNamespace, uint256 amount) external; + function transferBalanceToNamespace(bytes14 fromNamespace, bytes14 toNamespace, uint256 amount) external; - function transferBalanceToAddress(bytes16 fromNamespace, address toAddress, uint256 amount) external; + function transferBalanceToAddress(bytes14 fromNamespace, address toAddress, uint256 amount) external; } diff --git a/packages/world/src/interfaces/IModule.sol b/packages/world/src/interfaces/IModule.sol index a4eb728608..75ffc6e067 100644 --- a/packages/world/src/interfaces/IModule.sol +++ b/packages/world/src/interfaces/IModule.sol @@ -10,7 +10,7 @@ bytes4 constant MODULE_INTERFACE_ID = IModule.getName.selector ^ ERC165_INTERFACE_ID; interface IModule is IERC165 { - error RequiredModuleNotFound(string resourceSelector); + error RequiredModuleNotFound(string moduleId); error RootInstallModeNotSupported(); error NonRootInstallNotSupported(); diff --git a/packages/world/src/interfaces/ISystemHook.sol b/packages/world/src/interfaces/ISystemHook.sol index a09c15f796..955a69f80d 100644 --- a/packages/world/src/interfaces/ISystemHook.sol +++ b/packages/world/src/interfaces/ISystemHook.sol @@ -9,7 +9,7 @@ bytes4 constant SYSTEM_HOOK_INTERFACE_ID = ISystemHook.onBeforeCallSystem.select ERC165_INTERFACE_ID; interface ISystemHook is IERC165 { - function onBeforeCallSystem(address msgSender, bytes32 resourceSelector, bytes memory callData) external; + function onBeforeCallSystem(address msgSender, bytes32 systemId, bytes memory callData) external; - function onAfterCallSystem(address msgSender, bytes32 resourceSelector, bytes memory callData) external; + function onAfterCallSystem(address msgSender, bytes32 systemId, bytes memory callData) external; } diff --git a/packages/world/src/interfaces/IWorldKernel.sol b/packages/world/src/interfaces/IWorldKernel.sol index 72395d553d..00ddde30b4 100644 --- a/packages/world/src/interfaces/IWorldKernel.sol +++ b/packages/world/src/interfaces/IWorldKernel.sol @@ -15,20 +15,16 @@ interface IWorldModuleInstallation { interface IWorldCall { /** - * Call the system at the given resourceSelector. - * If the system is not public, the caller must have access to the namespace or name (encoded in the resourceSelector). + * Call the system at the given system ID. + * If the system is not public, the caller must have access to the namespace or name (encoded in the system ID). */ - function call(bytes32 resourceSelector, bytes memory callData) external payable returns (bytes memory); + function call(bytes32 systemId, bytes memory callData) external payable returns (bytes memory); /** - * Call the system at the given resourceSelector on behalf of the given delegator. - * If the system is not public, the delegator must have access to the namespace or name (encoded in the resourceSelector). + * Call the system at the given system ID on behalf of the given delegator. + * If the system is not public, the delegator must have access to the namespace or name (encoded in the system ID). */ - function callFrom( - address delegator, - bytes32 resourceSelector, - bytes memory callData - ) external payable returns (bytes memory); + function callFrom(address delegator, bytes32 systemId, bytes memory callData) external payable returns (bytes memory); } /** diff --git a/packages/world/src/interfaces/IWorldRegistrationSystem.sol b/packages/world/src/interfaces/IWorldRegistrationSystem.sol index eda464a074..e5e3273f4c 100644 --- a/packages/world/src/interfaces/IWorldRegistrationSystem.sol +++ b/packages/world/src/interfaces/IWorldRegistrationSystem.sol @@ -7,22 +7,22 @@ import { ISystemHook } from "./ISystemHook.sol"; import { WorldContextConsumer } from "./../WorldContext.sol"; interface IWorldRegistrationSystem { - function registerNamespace(bytes16 namespace) external; + function registerNamespace(bytes14 namespace) external; - function registerSystemHook(bytes32 resourceSelector, ISystemHook hookAddress, uint8 enabledHooksBitmap) external; + function registerSystemHook(bytes32 systemId, ISystemHook hookAddress, uint8 enabledHooksBitmap) external; - function unregisterSystemHook(bytes32 resourceSelector, ISystemHook hookAddress) external; + function unregisterSystemHook(bytes32 systemId, ISystemHook hookAddress) external; - function registerSystem(bytes32 resourceSelector, WorldContextConsumer system, bool publicAccess) external; + function registerSystem(bytes32 systemId, WorldContextConsumer system, bool publicAccess) external; function registerFunctionSelector( - bytes32 resourceSelector, + bytes32 systemId, string memory systemFunctionName, string memory systemFunctionArguments ) external returns (bytes4 worldFunctionSelector); function registerRootFunctionSelector( - bytes32 resourceSelector, + bytes32 systemId, bytes4 worldFunctionSelector, bytes4 systemFunctionSelector ) external returns (bytes4); diff --git a/packages/world/src/modules/core/CoreModule.sol b/packages/world/src/modules/core/CoreModule.sol index 9e8698d72a..2100e81b23 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -10,7 +10,8 @@ import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; import { IStoreEphemeral } from "@latticexyz/store/src/IStore.sol"; import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; +import { RESOURCE_SYSTEM } from "../../worldResourceTypes.sol"; import { NamespaceOwner } from "../../tables/NamespaceOwner.sol"; import { ResourceAccess } from "../../tables/ResourceAccess.sol"; @@ -92,7 +93,7 @@ contract CoreModule is Module { target: coreSystem, callData: abi.encodeCall( WorldRegistrationSystem.registerSystem, - (ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), CoreSystem(coreSystem), true) + (ResourceId.encode(ROOT_NAMESPACE, CORE_SYSTEM_NAME, RESOURCE_SYSTEM), CoreSystem(coreSystem), true) ) }); } @@ -136,7 +137,11 @@ contract CoreModule is Module { target: coreSystem, callData: abi.encodeCall( WorldRegistrationSystem.registerRootFunctionSelector, - (ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), functionSelectors[i], functionSelectors[i]) + ( + ResourceId.encode(ROOT_NAMESPACE, CORE_SYSTEM_NAME, RESOURCE_SYSTEM), + functionSelectors[i], + functionSelectors[i] + ) ) }); } diff --git a/packages/world/src/modules/core/implementations/AccessManagementSystem.sol b/packages/world/src/modules/core/implementations/AccessManagementSystem.sol index cff47dd2db..6d6179d21d 100644 --- a/packages/world/src/modules/core/implementations/AccessManagementSystem.sol +++ b/packages/world/src/modules/core/implementations/AccessManagementSystem.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.0; import { IModule } from "../../../interfaces/IModule.sol"; import { System } from "../../../System.sol"; import { AccessControl } from "../../../AccessControl.sol"; -import { ResourceSelector } from "../../../ResourceSelector.sol"; +import { ResourceId } from "../../../ResourceId.sol"; import { ResourceAccess } from "../../../tables/ResourceAccess.sol"; import { InstalledModules } from "../../../tables/InstalledModules.sol"; import { NamespaceOwner } from "../../../tables/NamespaceOwner.sol"; @@ -14,27 +14,27 @@ import { NamespaceOwner } from "../../../tables/NamespaceOwner.sol"; */ contract AccessManagementSystem is System { /** - * Grant access to the resource at the given namespace and name. + * Grant access to the resource at the given resource ID. * Requires the caller to own the namespace. */ - function grantAccess(bytes32 resourceSelector, address grantee) public virtual { + function grantAccess(bytes32 resourceId, address grantee) public virtual { // Require the caller to own the namespace - AccessControl.requireOwner(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceId, _msgSender()); // Grant access to the given resource - ResourceAccess._set(resourceSelector, grantee, true); + ResourceAccess._set(resourceId, grantee, true); } /** - * Revoke access from the resource at the given namespace and name. + * Revoke access from the resource at the given resource ID. * Requires the caller to own the namespace. */ - function revokeAccess(bytes32 resourceSelector, address grantee) public virtual { + function revokeAccess(bytes32 resourceId, address grantee) public virtual { // Require the caller to own the namespace - AccessControl.requireOwner(resourceSelector, _msgSender()); + AccessControl.requireOwner(resourceId, _msgSender()); // Revoke access from the given resource - ResourceAccess._deleteRecord(resourceSelector, grantee); + ResourceAccess._deleteRecord(resourceId, grantee); } /** @@ -42,17 +42,19 @@ contract AccessManagementSystem is System { * Revoke ResourceAccess for previous owner and grant to newOwner. * Requires the caller to own the namespace. */ - function transferOwnership(bytes16 namespace, address newOwner) public virtual { + function transferOwnership(bytes14 namespace, address newOwner) public virtual { + bytes32 namespaceId = ResourceId.encodeNamespace(namespace); + // Require the caller to own the namespace - AccessControl.requireOwner(namespace, _msgSender()); + AccessControl.requireOwner(namespaceId, _msgSender()); // Set namespace new owner NamespaceOwner._set(namespace, newOwner); // Revoke access from old owner - ResourceAccess._deleteRecord(namespace, _msgSender()); + ResourceAccess._deleteRecord(namespaceId, _msgSender()); // Grant access to new owner - ResourceAccess._set(namespace, newOwner, true); + ResourceAccess._set(namespaceId, newOwner, true); } } diff --git a/packages/world/src/modules/core/implementations/BalanceTransferSystem.sol b/packages/world/src/modules/core/implementations/BalanceTransferSystem.sol index 9f0fdde1cd..ff23af0ae4 100644 --- a/packages/world/src/modules/core/implementations/BalanceTransferSystem.sol +++ b/packages/world/src/modules/core/implementations/BalanceTransferSystem.sol @@ -3,21 +3,24 @@ pragma solidity >=0.8.0; import { System } from "../../../System.sol"; import { revertWithBytes } from "../../../revertWithBytes.sol"; -import { ResourceSelector } from "../../../ResourceSelector.sol"; +import { ResourceId } from "../../../ResourceId.sol"; import { AccessControl } from "../../../AccessControl.sol"; import { IWorldErrors } from "../../../interfaces/IWorldErrors.sol"; import { Balances } from "../tables/Balances.sol"; +// TODO: use namespace ID for balance table (bytes32 instead of bytes14) +// TODO: could even use resource ID for balance table, so systems can have their own balance in the table + contract BalanceTransferSystem is System, IWorldErrors { - using ResourceSelector for bytes32; + using ResourceId for bytes32; /** * Transfer balance to another namespace in the World */ - function transferBalanceToNamespace(bytes16 fromNamespace, bytes16 toNamespace, uint256 amount) public virtual { + function transferBalanceToNamespace(bytes14 fromNamespace, bytes14 toNamespace, uint256 amount) public virtual { // Require caller to have access to the namespace - AccessControl.requireAccess(fromNamespace, _msgSender()); + AccessControl.requireAccess(ResourceId.encodeNamespace(fromNamespace), _msgSender()); // Get current namespace balance uint256 balance = Balances._get(fromNamespace); @@ -33,9 +36,9 @@ contract BalanceTransferSystem is System, IWorldErrors { /** * Transfer balance out of the World */ - function transferBalanceToAddress(bytes16 fromNamespace, address toAddress, uint256 amount) public virtual { + function transferBalanceToAddress(bytes14 fromNamespace, address toAddress, uint256 amount) public virtual { // Require caller to have access to the namespace - AccessControl.requireAccess(fromNamespace, _msgSender()); + AccessControl.requireAccess(ResourceId.encodeNamespace(fromNamespace), _msgSender()); // Get current namespace balance uint256 balance = Balances._get(fromNamespace); diff --git a/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol b/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol index 35f2309d8c..f60b7aa1ed 100644 --- a/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol +++ b/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol @@ -6,18 +6,18 @@ import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; import { PackedCounter } from "@latticexyz/store/src/PackedCounter.sol"; import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; import { System } from "../../../System.sol"; -import { ResourceSelector } from "../../../ResourceSelector.sol"; +import { ResourceId } from "../../../ResourceId.sol"; import { AccessControl } from "../../../AccessControl.sol"; contract EphemeralRecordSystem is IStoreEphemeral, System { - using ResourceSelector for bytes32; + using ResourceId for bytes32; /** * Emit the ephemeral event without modifying storage at the given namespace and name. - * Requires the caller to have access to the namespace or name (encoded in the resource selector) + * Requires the caller to have access to the namespace or name (encoded in the table ID) */ function emitEphemeralRecord( - bytes32 resourceSelector, + bytes32 tableId, bytes32[] calldata keyTuple, bytes calldata staticData, PackedCounter encodedLengths, @@ -25,9 +25,9 @@ contract EphemeralRecordSystem is IStoreEphemeral, System { FieldLayout fieldLayout ) public virtual { // Require access to the namespace or name - AccessControl.requireAccess(resourceSelector, msg.sender); + AccessControl.requireAccess(tableId, msg.sender); // Set the record - StoreCore.emitEphemeralRecord(resourceSelector, keyTuple, staticData, encodedLengths, dynamicData, fieldLayout); + StoreCore.emitEphemeralRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData, fieldLayout); } } diff --git a/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol b/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol index f79d328b9c..99dd9830e7 100644 --- a/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol @@ -7,11 +7,12 @@ import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; import { Schema } from "@latticexyz/store/src/Schema.sol"; import { System } from "../../../System.sol"; -import { ResourceSelector } from "../../../ResourceSelector.sol"; +import { ResourceId } from "../../../ResourceId.sol"; import { Resource } from "../../../common.sol"; import { ROOT_NAMESPACE, ROOT_NAME } from "../../../constants.sol"; import { AccessControl } from "../../../AccessControl.sol"; import { requireInterface } from "../../../requireInterface.sol"; +import { revertWithBytes } from "../../../revertWithBytes.sol"; import { WorldContextProvider } from "../../../WorldContext.sol"; import { NamespaceOwner } from "../../../tables/NamespaceOwner.sol"; import { ResourceAccess } from "../../../tables/ResourceAccess.sol"; @@ -31,13 +32,13 @@ import { WorldRegistrationSystem } from "./WorldRegistrationSystem.sol"; * Functions related to registering table resources in the World. */ contract StoreRegistrationSystem is System, IWorldErrors { - using ResourceSelector for bytes32; + using ResourceId for bytes32; /** * Register a table with the given config */ function registerTable( - bytes32 resourceSelector, + bytes32 tableId, FieldLayout fieldLayout, Schema keySchema, Schema valueSchema, @@ -45,35 +46,32 @@ contract StoreRegistrationSystem is System, IWorldErrors { string[] calldata fieldNames ) public virtual { // Require the name to not be the namespace's root name - if (resourceSelector.getName() == ROOT_NAME) revert InvalidSelector(resourceSelector.toString()); + if (tableId.getName() == ROOT_NAME) revert InvalidSelector(tableId.toString()); // If the namespace doesn't exist yet, register it - bytes16 namespace = resourceSelector.getNamespace(); - if (ResourceType._get(namespace) == Resource.NONE) { - // We can't call IBaseWorld(this).registerNamespace directly because it would be handled like - // an external call, so msg.sender would be the address of the World contract - (address systemAddress, ) = Systems._get(ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME)); - WorldContextProvider.delegatecallWithContextOrRevert({ - msgSender: _msgSender(), - msgValue: 0, - target: systemAddress, - callData: abi.encodeCall(WorldRegistrationSystem.registerNamespace, (namespace)) - }); + bytes32 namespaceId = tableId.getNamespaceId(); + if (ResourceType._get(namespaceId) == Resource.NONE) { + // Since this is a root system, we're in the context of the World contract already, + // so we can use delegatecall to register the namespace + (bool success, bytes memory data) = address(this).delegatecall( + abi.encodeCall(WorldRegistrationSystem.registerNamespace, (namespaceId.getNamespace())) + ); + if (!success) revertWithBytes(data); } else { // otherwise require caller to own the namespace - AccessControl.requireOwner(namespace, _msgSender()); + AccessControl.requireOwner(namespaceId, _msgSender()); } // Require no resource to exist at this selector yet - if (ResourceType._get(resourceSelector) != Resource.NONE) { - revert ResourceExists(resourceSelector.toString()); + if (ResourceType._get(tableId) != Resource.NONE) { + revert ResourceExists(tableId.toString()); } // Store the table resource type - ResourceType._set(resourceSelector, Resource.TABLE); + ResourceType._set(tableId, Resource.TABLE); // Register the table - StoreCore.registerTable(resourceSelector, fieldLayout, keySchema, valueSchema, keyNames, fieldNames); + StoreCore.registerTable(tableId, fieldLayout, keySchema, valueSchema, keyNames, fieldNames); } /** diff --git a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol index 58ecdea46f..a3d9cf0c27 100644 --- a/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol @@ -5,10 +5,10 @@ import { Hook, HookLib } from "@latticexyz/store/src/Hook.sol"; import { System } from "../../../System.sol"; import { WorldContextConsumer, WORLD_CONTEXT_CONSUMER_INTERFACE_ID } from "../../../WorldContext.sol"; -import { ResourceSelector } from "../../../ResourceSelector.sol"; +import { ResourceId } from "../../../ResourceId.sol"; import { Resource } from "../../../common.sol"; import { SystemCall } from "../../../SystemCall.sol"; -import { ROOT_NAMESPACE, ROOT_NAME, UNLIMITED_DELEGATION } from "../../../constants.sol"; +import { ROOT_NAMESPACE_ID, ROOT_NAME, UNLIMITED_DELEGATION } from "../../../constants.sol"; import { AccessControl } from "../../../AccessControl.sol"; import { requireInterface } from "../../../requireInterface.sol"; import { NamespaceOwner } from "../../../tables/NamespaceOwner.sol"; @@ -29,54 +29,50 @@ import { FunctionSelectors } from "../tables/FunctionSelectors.sol"; * Registering tables is implemented in StoreRegistrationSystem.sol */ contract WorldRegistrationSystem is System, IWorldErrors { - using ResourceSelector for bytes32; + using ResourceId for bytes32; /** * Register a new namespace */ - function registerNamespace(bytes16 namespace) public virtual { - bytes32 resourceSelector = ResourceSelector.from(namespace); + function registerNamespace(bytes14 namespace) public virtual { + bytes32 namespaceId = ResourceId.encodeNamespace(namespace); // Require namespace to not exist yet - if (ResourceType._get(namespace) != Resource.NONE) revert ResourceExists(resourceSelector.toString()); + if (ResourceType._get(namespaceId) != Resource.NONE) revert ResourceExists(namespaceId.toString()); // Register namespace resource - ResourceType._set(namespace, Resource.NAMESPACE); + ResourceType._set(namespaceId, Resource.NAMESPACE); // Register caller as the namespace owner NamespaceOwner._set(namespace, _msgSender()); // Give caller access to the new namespace - ResourceAccess._set(resourceSelector, _msgSender(), true); + ResourceAccess._set(namespaceId, _msgSender(), true); } /** - * Register a hook for the system at the given resource selector + * Register a hook for the system at the given system ID */ - function registerSystemHook( - bytes32 resourceSelector, - ISystemHook hookAddress, - uint8 enabledHooksBitmap - ) public virtual { + function registerSystemHook(bytes32 systemId, ISystemHook hookAddress, uint8 enabledHooksBitmap) public virtual { // Require the provided address to implement the ISystemHook interface requireInterface(address(hookAddress), SYSTEM_HOOK_INTERFACE_ID); // Require caller to own the namespace - AccessControl.requireOwner(resourceSelector, _msgSender()); + AccessControl.requireOwner(systemId, _msgSender()); // Register the hook - SystemHooks.push(resourceSelector, Hook.unwrap(HookLib.encode(address(hookAddress), enabledHooksBitmap))); + SystemHooks.push(systemId, Hook.unwrap(HookLib.encode(address(hookAddress), enabledHooksBitmap))); } /** - * Unregister the given hook for the system at the given resource selector + * Unregister the given hook for the system at the given system ID */ - function unregisterSystemHook(bytes32 resourceSelector, ISystemHook hookAddress) public virtual { + function unregisterSystemHook(bytes32 systemId, ISystemHook hookAddress) public virtual { // Require caller to own the namespace - AccessControl.requireOwner(resourceSelector, _msgSender()); + AccessControl.requireOwner(systemId, _msgSender()); - // Remove the hook from the list of hooks for this resourceSelector in the system hooks table - HookLib.filterListByAddress(SystemHooksTableId, resourceSelector, address(hookAddress)); + // Remove the hook from the list of hooks for this system in the system hooks table + HookLib.filterListByAddress(SystemHooksTableId, systemId, address(hookAddress)); } /** @@ -88,54 +84,55 @@ contract WorldRegistrationSystem is System, IWorldErrors { * Note: this function doesn't check whether a system already exists at the given selector, * making it possible to upgrade systems. */ - function registerSystem(bytes32 resourceSelector, WorldContextConsumer system, bool publicAccess) public virtual { + function registerSystem(bytes32 systemId, WorldContextConsumer system, bool publicAccess) public virtual { // Require the provided address to implement the WorldContextConsumer interface requireInterface(address(system), WORLD_CONTEXT_CONSUMER_INTERFACE_ID); // Require the name to not be the namespace's root name - if (resourceSelector.getName() == ROOT_NAME) revert InvalidSelector(resourceSelector.toString()); + if (systemId.getName() == ROOT_NAME) revert InvalidSelector(systemId.toString()); - // Require this system to not be registered at a different resource selector yet - bytes32 existingResourceSelector = SystemRegistry._get(address(system)); - if (existingResourceSelector != 0 && existingResourceSelector != resourceSelector) { + // Require this system to not be registered at a different system ID yet + bytes32 existingSystemId = SystemRegistry._get(address(system)); + if (existingSystemId != 0 && existingSystemId != systemId) { revert SystemExists(address(system)); } // If the namespace doesn't exist yet, register it // otherwise require caller to own the namespace - bytes16 namespace = resourceSelector.getNamespace(); - if (ResourceType._get(namespace) == Resource.NONE) registerNamespace(namespace); - else AccessControl.requireOwner(namespace, _msgSender()); + bytes32 namespaceId = systemId.getNamespaceId(); + if (ResourceType._get(namespaceId) == Resource.NONE) registerNamespace(systemId.getNamespace()); + else AccessControl.requireOwner(namespaceId, _msgSender()); + // TODO: this check is unnecessary with resource types, need to replace with a requirement that the system type is encoded correctly // Require no resource other than a system to exist at this selector yet - Resource resourceType = ResourceType._get(resourceSelector); + Resource resourceType = ResourceType._get(systemId); if (resourceType != Resource.NONE && resourceType != Resource.SYSTEM) { - revert ResourceExists(resourceSelector.toString()); + revert ResourceExists(systemId.toString()); } - // Check if a system already exists at this resource selector - address existingSystem = Systems._getSystem(resourceSelector); + // Check if a system already exists at this system ID + address existingSystem = Systems._getSystem(systemId); - // If there is an existing system with this resource selector, remove it + // If there is an existing system with this system ID, remove it if (existingSystem != address(0)) { // Remove the existing system from the system registry SystemRegistry._deleteRecord(existingSystem); // Remove the existing system's access to its namespace - ResourceAccess._deleteRecord(namespace, existingSystem); + ResourceAccess._deleteRecord(namespaceId, existingSystem); } else { // Otherwise, this is a new system, so register its resource type - ResourceType._set(resourceSelector, Resource.SYSTEM); + ResourceType._set(systemId, Resource.SYSTEM); } - // Systems = mapping from resourceSelector to system address and publicAccess - Systems._set(resourceSelector, address(system), publicAccess); + // Systems = mapping from systemId to system address and publicAccess + Systems._set(systemId, address(system), publicAccess); - // SystemRegistry = mapping from system address to resourceSelector - SystemRegistry._set(address(system), resourceSelector); + // SystemRegistry = mapping from system address to systemId + SystemRegistry._set(address(system), systemId); // Grant the system access to its namespace - ResourceAccess._set(namespace, address(system), true); + ResourceAccess._set(namespaceId, address(system), true); } /** @@ -146,31 +143,31 @@ contract WorldRegistrationSystem is System, IWorldErrors { * TODO: replace separate systemFunctionName and systemFunctionArguments with a signature argument */ function registerFunctionSelector( - bytes32 resourceSelector, + bytes32 systemId, string memory systemFunctionName, string memory systemFunctionArguments ) public returns (bytes4 worldFunctionSelector) { // Require the caller to own the namespace - AccessControl.requireOwner(resourceSelector, _msgSender()); + AccessControl.requireOwner(systemId, _msgSender()); // Compute global function selector - string memory namespaceString = ResourceSelector.toTrimmedString(resourceSelector.getNamespace()); - string memory nameString = ResourceSelector.toTrimmedString(resourceSelector.getName()); + string memory namespaceString = ResourceId.toTrimmedString(systemId.getNamespace()); + string memory nameString = ResourceId.toTrimmedString(systemId.getName()); worldFunctionSelector = bytes4( keccak256(abi.encodePacked(namespaceString, "_", nameString, "_", systemFunctionName, systemFunctionArguments)) ); // Require the function selector to be globally unique - bytes32 existingResourceSelector = FunctionSelectors._getResourceSelector(worldFunctionSelector); + bytes32 existingSystemId = FunctionSelectors._getSystemId(worldFunctionSelector); - if (existingResourceSelector != 0) revert FunctionSelectorExists(worldFunctionSelector); + if (existingSystemId != 0) revert FunctionSelectorExists(worldFunctionSelector); // Register the function selector bytes memory systemFunctionSignature = abi.encodePacked(systemFunctionName, systemFunctionArguments); bytes4 systemFunctionSelector = systemFunctionSignature.length == 0 ? bytes4(0) // Save gas by storing 0x0 for empty function signatures (= fallback function) : bytes4(keccak256(systemFunctionSignature)); - FunctionSelectors._set(worldFunctionSelector, resourceSelector, systemFunctionSelector); + FunctionSelectors._set(worldFunctionSelector, systemId, systemFunctionSelector); } /** @@ -181,20 +178,20 @@ contract WorldRegistrationSystem is System, IWorldErrors { * (see https://github.com/latticexyz/mud/issues/444) */ function registerRootFunctionSelector( - bytes32 resourceSelector, + bytes32 systemId, bytes4 worldFunctionSelector, bytes4 systemFunctionSelector ) public returns (bytes4) { // Require the caller to own the root namespace - AccessControl.requireOwner(ROOT_NAMESPACE, _msgSender()); + AccessControl.requireOwner(ROOT_NAMESPACE_ID, _msgSender()); // Require the function selector to be globally unique - bytes32 existingResourceSelector = FunctionSelectors._getResourceSelector(worldFunctionSelector); + bytes32 existingSystemId = FunctionSelectors._getSystemId(worldFunctionSelector); - if (existingResourceSelector != 0) revert FunctionSelectorExists(worldFunctionSelector); + if (existingSystemId != 0) revert FunctionSelectorExists(worldFunctionSelector); // Register the function selector - FunctionSelectors._set(worldFunctionSelector, resourceSelector, systemFunctionSelector); + FunctionSelectors._set(worldFunctionSelector, systemId, systemFunctionSelector); return worldFunctionSelector; } @@ -213,12 +210,7 @@ contract WorldRegistrationSystem is System, IWorldErrors { requireInterface(delegationControl, DELEGATION_CONTROL_INTERFACE_ID); // Call the delegation control contract's init function - SystemCall.call({ - caller: _msgSender(), - resourceSelector: delegationControlId, - callData: initCallData, - value: 0 - }); + SystemCall.call({ caller: _msgSender(), systemId: delegationControlId, callData: initCallData, value: 0 }); } } } diff --git a/packages/world/src/modules/core/tables/FunctionSelectors.sol b/packages/world/src/modules/core/tables/FunctionSelectors.sol index e92a0ff17b..7a278fec78 100644 --- a/packages/world/src/modules/core/tables/FunctionSelectors.sol +++ b/packages/world/src/modules/core/tables/FunctionSelectors.sol @@ -57,7 +57,7 @@ library FunctionSelectors { /** Get the table's field names */ function getFieldNames() internal pure returns (string[] memory fieldNames) { fieldNames = new string[](2); - fieldNames[0] = "resourceSelector"; + fieldNames[0] = "systemId"; fieldNames[1] = "systemFunctionSelector"; } @@ -76,8 +76,8 @@ library FunctionSelectors { _store.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); } - /** Get resourceSelector */ - function getResourceSelector(bytes4 functionSelector) internal view returns (bytes32 resourceSelector) { + /** Get systemId */ + function getSystemId(bytes4 functionSelector) internal view returns (bytes32 systemId) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); @@ -85,8 +85,8 @@ library FunctionSelectors { return (bytes32(_blob)); } - /** Get resourceSelector */ - function _getResourceSelector(bytes4 functionSelector) internal view returns (bytes32 resourceSelector) { + /** Get systemId */ + function _getSystemId(bytes4 functionSelector) internal view returns (bytes32 systemId) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); @@ -94,11 +94,8 @@ library FunctionSelectors { return (bytes32(_blob)); } - /** Get resourceSelector (using the specified store) */ - function getResourceSelector( - IStore _store, - bytes4 functionSelector - ) internal view returns (bytes32 resourceSelector) { + /** Get systemId (using the specified store) */ + function getSystemId(IStore _store, bytes4 functionSelector) internal view returns (bytes32 systemId) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); @@ -106,28 +103,28 @@ library FunctionSelectors { return (bytes32(_blob)); } - /** Set resourceSelector */ - function setResourceSelector(bytes4 functionSelector, bytes32 resourceSelector) internal { + /** Set systemId */ + function setSystemId(bytes4 functionSelector, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); - StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((resourceSelector)), _fieldLayout); + StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((systemId)), _fieldLayout); } - /** Set resourceSelector */ - function _setResourceSelector(bytes4 functionSelector, bytes32 resourceSelector) internal { + /** Set systemId */ + function _setSystemId(bytes4 functionSelector, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); - StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((resourceSelector)), _fieldLayout); + StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((systemId)), _fieldLayout); } - /** Set resourceSelector (using the specified store) */ - function setResourceSelector(IStore _store, bytes4 functionSelector, bytes32 resourceSelector) internal { + /** Set systemId (using the specified store) */ + function setSystemId(IStore _store, bytes4 functionSelector, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); - _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((resourceSelector)), _fieldLayout); + _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((systemId)), _fieldLayout); } /** Get systemFunctionSelector */ @@ -185,9 +182,7 @@ library FunctionSelectors { } /** Get the full data */ - function get( - bytes4 functionSelector - ) internal view returns (bytes32 resourceSelector, bytes4 systemFunctionSelector) { + function get(bytes4 functionSelector) internal view returns (bytes32 systemId, bytes4 systemFunctionSelector) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); @@ -200,9 +195,7 @@ library FunctionSelectors { } /** Get the full data */ - function _get( - bytes4 functionSelector - ) internal view returns (bytes32 resourceSelector, bytes4 systemFunctionSelector) { + function _get(bytes4 functionSelector) internal view returns (bytes32 systemId, bytes4 systemFunctionSelector) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); @@ -218,7 +211,7 @@ library FunctionSelectors { function get( IStore _store, bytes4 functionSelector - ) internal view returns (bytes32 resourceSelector, bytes4 systemFunctionSelector) { + ) internal view returns (bytes32 systemId, bytes4 systemFunctionSelector) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(functionSelector); @@ -231,8 +224,8 @@ library FunctionSelectors { } /** Set the full data using individual values */ - function set(bytes4 functionSelector, bytes32 resourceSelector, bytes4 systemFunctionSelector) internal { - bytes memory _staticData = encodeStatic(resourceSelector, systemFunctionSelector); + function set(bytes4 functionSelector, bytes32 systemId, bytes4 systemFunctionSelector) internal { + bytes memory _staticData = encodeStatic(systemId, systemFunctionSelector); PackedCounter _encodedLengths; bytes memory _dynamicData; @@ -244,8 +237,8 @@ library FunctionSelectors { } /** Set the full data using individual values */ - function _set(bytes4 functionSelector, bytes32 resourceSelector, bytes4 systemFunctionSelector) internal { - bytes memory _staticData = encodeStatic(resourceSelector, systemFunctionSelector); + function _set(bytes4 functionSelector, bytes32 systemId, bytes4 systemFunctionSelector) internal { + bytes memory _staticData = encodeStatic(systemId, systemFunctionSelector); PackedCounter _encodedLengths; bytes memory _dynamicData; @@ -257,13 +250,8 @@ library FunctionSelectors { } /** Set the full data using individual values (using the specified store) */ - function set( - IStore _store, - bytes4 functionSelector, - bytes32 resourceSelector, - bytes4 systemFunctionSelector - ) internal { - bytes memory _staticData = encodeStatic(resourceSelector, systemFunctionSelector); + function set(IStore _store, bytes4 functionSelector, bytes32 systemId, bytes4 systemFunctionSelector) internal { + bytes memory _staticData = encodeStatic(systemId, systemFunctionSelector); PackedCounter _encodedLengths; bytes memory _dynamicData; @@ -278,10 +266,8 @@ library FunctionSelectors { * Decode the tightly packed blob of static data using this table's field layout * Undefined behaviour for invalid blobs */ - function decodeStatic( - bytes memory _blob - ) internal pure returns (bytes32 resourceSelector, bytes4 systemFunctionSelector) { - resourceSelector = (Bytes.slice32(_blob, 0)); + function decodeStatic(bytes memory _blob) internal pure returns (bytes32 systemId, bytes4 systemFunctionSelector) { + systemId = (Bytes.slice32(_blob, 0)); systemFunctionSelector = (Bytes.slice4(_blob, 32)); } @@ -294,21 +280,21 @@ library FunctionSelectors { bytes memory _staticData, PackedCounter, bytes memory - ) internal pure returns (bytes32 resourceSelector, bytes4 systemFunctionSelector) { - (resourceSelector, systemFunctionSelector) = decodeStatic(_staticData); + ) internal pure returns (bytes32 systemId, bytes4 systemFunctionSelector) { + (systemId, systemFunctionSelector) = decodeStatic(_staticData); } /** Tightly pack static data using this table's schema */ - function encodeStatic(bytes32 resourceSelector, bytes4 systemFunctionSelector) internal pure returns (bytes memory) { - return abi.encodePacked(resourceSelector, systemFunctionSelector); + function encodeStatic(bytes32 systemId, bytes4 systemFunctionSelector) internal pure returns (bytes memory) { + return abi.encodePacked(systemId, systemFunctionSelector); } /** Tightly pack full data using this table's field layout */ function encode( - bytes32 resourceSelector, + bytes32 systemId, bytes4 systemFunctionSelector ) internal pure returns (bytes memory, PackedCounter, bytes memory) { - bytes memory _staticData = encodeStatic(resourceSelector, systemFunctionSelector); + bytes memory _staticData = encodeStatic(systemId, systemFunctionSelector); PackedCounter _encodedLengths; bytes memory _dynamicData; diff --git a/packages/world/src/modules/core/tables/ResourceType.sol b/packages/world/src/modules/core/tables/ResourceType.sol index ac9983441a..a5ad9b2dd0 100644 --- a/packages/world/src/modules/core/tables/ResourceType.sol +++ b/packages/world/src/modules/core/tables/ResourceType.sol @@ -53,7 +53,7 @@ library ResourceType { /** Get the table's key names */ function getKeyNames() internal pure returns (string[] memory keyNames) { keyNames = new string[](1); - keyNames[0] = "resourceSelector"; + keyNames[0] = "systemId"; } /** Get the table's field names */ @@ -78,52 +78,52 @@ library ResourceType { } /** Get resourceType */ - function get(bytes32 resourceSelector) internal view returns (Resource resourceType) { + function get(bytes32 systemId) internal view returns (Resource resourceType) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); return Resource(uint8(bytes1(_blob))); } /** Get resourceType */ - function _get(bytes32 resourceSelector) internal view returns (Resource resourceType) { + function _get(bytes32 systemId) internal view returns (Resource resourceType) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); return Resource(uint8(bytes1(_blob))); } /** Get resourceType (using the specified store) */ - function get(IStore _store, bytes32 resourceSelector) internal view returns (Resource resourceType) { + function get(IStore _store, bytes32 systemId) internal view returns (Resource resourceType) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); return Resource(uint8(bytes1(_blob))); } /** Set resourceType */ - function set(bytes32 resourceSelector, Resource resourceType) internal { + function set(bytes32 systemId, Resource resourceType) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(resourceType)), _fieldLayout); } /** Set resourceType */ - function _set(bytes32 resourceSelector, Resource resourceType) internal { + function _set(bytes32 systemId, Resource resourceType) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(resourceType)), _fieldLayout); } /** Set resourceType (using the specified store) */ - function set(IStore _store, bytes32 resourceSelector, Resource resourceType) internal { + function set(IStore _store, bytes32 systemId, Resource resourceType) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.setField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(resourceType)), _fieldLayout); } @@ -144,33 +144,33 @@ library ResourceType { } /** Encode keys as a bytes32 array using this table's field layout */ - function encodeKeyTuple(bytes32 resourceSelector) internal pure returns (bytes32[] memory) { + function encodeKeyTuple(bytes32 systemId) internal pure returns (bytes32[] memory) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; return _keyTuple; } /* Delete all data for given keys */ - function deleteRecord(bytes32 resourceSelector) internal { + function deleteRecord(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys */ - function _deleteRecord(bytes32 resourceSelector) internal { + function _deleteRecord(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys (using the specified store) */ - function deleteRecord(IStore _store, bytes32 resourceSelector) internal { + function deleteRecord(IStore _store, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.deleteRecord(_tableId, _keyTuple, _fieldLayout); } diff --git a/packages/world/src/modules/core/tables/SystemHooks.sol b/packages/world/src/modules/core/tables/SystemHooks.sol index 57bf414ebd..e3285f6347 100644 --- a/packages/world/src/modules/core/tables/SystemHooks.sol +++ b/packages/world/src/modules/core/tables/SystemHooks.sol @@ -50,7 +50,7 @@ library SystemHooks { /** Get the table's key names */ function getKeyNames() internal pure returns (string[] memory keyNames) { keyNames = new string[](1); - keyNames[0] = "resourceSelector"; + keyNames[0] = "systemId"; } /** Get the table's field names */ @@ -75,60 +75,60 @@ library SystemHooks { } /** Get value */ - function get(bytes32 resourceSelector) internal view returns (bytes21[] memory value) { + function get(bytes32 systemId) internal view returns (bytes21[] memory value) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes memory _blob = StoreSwitch.getDynamicField(_tableId, _keyTuple, 0); return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_bytes21()); } /** Get value */ - function _get(bytes32 resourceSelector) internal view returns (bytes21[] memory value) { + function _get(bytes32 systemId) internal view returns (bytes21[] memory value) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes memory _blob = StoreCore.getDynamicField(_tableId, _keyTuple, 0); return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_bytes21()); } /** Get value (using the specified store) */ - function get(IStore _store, bytes32 resourceSelector) internal view returns (bytes21[] memory value) { + function get(IStore _store, bytes32 systemId) internal view returns (bytes21[] memory value) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes memory _blob = _store.getDynamicField(_tableId, _keyTuple, 0); return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_bytes21()); } /** Set value */ - function set(bytes32 resourceSelector, bytes21[] memory value) internal { + function set(bytes32 systemId, bytes21[] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)), _fieldLayout); } /** Set value */ - function _set(bytes32 resourceSelector, bytes21[] memory value) internal { + function _set(bytes32 systemId, bytes21[] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)), _fieldLayout); } /** Set value (using the specified store) */ - function set(IStore _store, bytes32 resourceSelector, bytes21[] memory value) internal { + function set(IStore _store, bytes32 systemId, bytes21[] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)), _fieldLayout); } /** Get the length of value */ - function length(bytes32 resourceSelector) internal view returns (uint256) { + function length(bytes32 systemId) internal view returns (uint256) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; uint256 _byteLength = StoreSwitch.getFieldLength(_tableId, _keyTuple, 0, _fieldLayout); unchecked { @@ -137,9 +137,9 @@ library SystemHooks { } /** Get the length of value */ - function _length(bytes32 resourceSelector) internal view returns (uint256) { + function _length(bytes32 systemId) internal view returns (uint256) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; uint256 _byteLength = StoreCore.getFieldLength(_tableId, _keyTuple, 0, _fieldLayout); unchecked { @@ -148,9 +148,9 @@ library SystemHooks { } /** Get the length of value (using the specified store) */ - function length(IStore _store, bytes32 resourceSelector) internal view returns (uint256) { + function length(IStore _store, bytes32 systemId) internal view returns (uint256) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; uint256 _byteLength = _store.getFieldLength(_tableId, _keyTuple, 0, _fieldLayout); unchecked { @@ -162,9 +162,9 @@ library SystemHooks { * Get an item of value * (unchecked, returns invalid data if index overflows) */ - function getItem(bytes32 resourceSelector, uint256 _index) internal view returns (bytes21) { + function getItem(bytes32 systemId, uint256 _index) internal view returns (bytes21) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; unchecked { bytes memory _blob = StoreSwitch.getFieldSlice( @@ -183,9 +183,9 @@ library SystemHooks { * Get an item of value * (unchecked, returns invalid data if index overflows) */ - function _getItem(bytes32 resourceSelector, uint256 _index) internal view returns (bytes21) { + function _getItem(bytes32 systemId, uint256 _index) internal view returns (bytes21) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; unchecked { bytes memory _blob = StoreCore.getFieldSlice( @@ -204,9 +204,9 @@ library SystemHooks { * Get an item of value (using the specified store) * (unchecked, returns invalid data if index overflows) */ - function getItem(IStore _store, bytes32 resourceSelector, uint256 _index) internal view returns (bytes21) { + function getItem(IStore _store, bytes32 systemId, uint256 _index) internal view returns (bytes21) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; unchecked { bytes memory _blob = _store.getFieldSlice(_tableId, _keyTuple, 0, _fieldLayout, _index * 21, (_index + 1) * 21); @@ -215,49 +215,49 @@ library SystemHooks { } /** Push an element to value */ - function push(bytes32 resourceSelector, bytes21 _element) internal { + function push(bytes32 systemId, bytes21 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)), _fieldLayout); } /** Push an element to value */ - function _push(bytes32 resourceSelector, bytes21 _element) internal { + function _push(bytes32 systemId, bytes21 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)), _fieldLayout); } /** Push an element to value (using the specified store) */ - function push(IStore _store, bytes32 resourceSelector, bytes21 _element) internal { + function push(IStore _store, bytes32 systemId, bytes21 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)), _fieldLayout); } /** Pop an element from value */ - function pop(bytes32 resourceSelector) internal { + function pop(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.popFromField(_tableId, _keyTuple, 0, 21, _fieldLayout); } /** Pop an element from value */ - function _pop(bytes32 resourceSelector) internal { + function _pop(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.popFromField(_tableId, _keyTuple, 0, 21, _fieldLayout); } /** Pop an element from value (using the specified store) */ - function pop(IStore _store, bytes32 resourceSelector) internal { + function pop(IStore _store, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.popFromField(_tableId, _keyTuple, 0, 21, _fieldLayout); } @@ -266,9 +266,9 @@ library SystemHooks { * Update an element of value at `_index` * (checked only to prevent modifying other tables; can corrupt own data if index overflows) */ - function update(bytes32 resourceSelector, uint256 _index, bytes21 _element) internal { + function update(bytes32 systemId, uint256 _index, bytes21 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; unchecked { StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 21, abi.encodePacked((_element)), _fieldLayout); @@ -279,9 +279,9 @@ library SystemHooks { * Update an element of value at `_index` * (checked only to prevent modifying other tables; can corrupt own data if index overflows) */ - function _update(bytes32 resourceSelector, uint256 _index, bytes21 _element) internal { + function _update(bytes32 systemId, uint256 _index, bytes21 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; unchecked { StoreCore.updateInField(_tableId, _keyTuple, 0, _index * 21, abi.encodePacked((_element)), _fieldLayout); @@ -292,9 +292,9 @@ library SystemHooks { * Update an element of value (using the specified store) at `_index` * (checked only to prevent modifying other tables; can corrupt own data if index overflows) */ - function update(IStore _store, bytes32 resourceSelector, uint256 _index, bytes21 _element) internal { + function update(IStore _store, bytes32 systemId, uint256 _index, bytes21 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; unchecked { _store.updateInField(_tableId, _keyTuple, 0, _index * 21, abi.encodePacked((_element)), _fieldLayout); @@ -324,33 +324,33 @@ library SystemHooks { } /** Encode keys as a bytes32 array using this table's field layout */ - function encodeKeyTuple(bytes32 resourceSelector) internal pure returns (bytes32[] memory) { + function encodeKeyTuple(bytes32 systemId) internal pure returns (bytes32[] memory) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; return _keyTuple; } /* Delete all data for given keys */ - function deleteRecord(bytes32 resourceSelector) internal { + function deleteRecord(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys */ - function _deleteRecord(bytes32 resourceSelector) internal { + function _deleteRecord(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys (using the specified store) */ - function deleteRecord(IStore _store, bytes32 resourceSelector) internal { + function deleteRecord(IStore _store, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.deleteRecord(_tableId, _keyTuple, _fieldLayout); } diff --git a/packages/world/src/modules/core/tables/SystemRegistry.sol b/packages/world/src/modules/core/tables/SystemRegistry.sol index 71174911aa..b4dc15a8bd 100644 --- a/packages/world/src/modules/core/tables/SystemRegistry.sol +++ b/packages/world/src/modules/core/tables/SystemRegistry.sol @@ -56,7 +56,7 @@ library SystemRegistry { /** Get the table's field names */ function getFieldNames() internal pure returns (string[] memory fieldNames) { fieldNames = new string[](1); - fieldNames[0] = "resourceSelector"; + fieldNames[0] = "systemId"; } /** Register the table with its config */ @@ -74,8 +74,8 @@ library SystemRegistry { _store.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); } - /** Get resourceSelector */ - function get(address system) internal view returns (bytes32 resourceSelector) { + /** Get systemId */ + function get(address system) internal view returns (bytes32 systemId) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(uint256(uint160(system))); @@ -83,8 +83,8 @@ library SystemRegistry { return (bytes32(_blob)); } - /** Get resourceSelector */ - function _get(address system) internal view returns (bytes32 resourceSelector) { + /** Get systemId */ + function _get(address system) internal view returns (bytes32 systemId) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(uint256(uint160(system))); @@ -92,8 +92,8 @@ library SystemRegistry { return (bytes32(_blob)); } - /** Get resourceSelector (using the specified store) */ - function get(IStore _store, address system) internal view returns (bytes32 resourceSelector) { + /** Get systemId (using the specified store) */ + function get(IStore _store, address system) internal view returns (bytes32 systemId) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(uint256(uint160(system))); @@ -101,38 +101,38 @@ library SystemRegistry { return (bytes32(_blob)); } - /** Set resourceSelector */ - function set(address system, bytes32 resourceSelector) internal { + /** Set systemId */ + function set(address system, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(uint256(uint160(system))); - StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((resourceSelector)), _fieldLayout); + StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((systemId)), _fieldLayout); } - /** Set resourceSelector */ - function _set(address system, bytes32 resourceSelector) internal { + /** Set systemId */ + function _set(address system, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(uint256(uint160(system))); - StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((resourceSelector)), _fieldLayout); + StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((systemId)), _fieldLayout); } - /** Set resourceSelector (using the specified store) */ - function set(IStore _store, address system, bytes32 resourceSelector) internal { + /** Set systemId (using the specified store) */ + function set(IStore _store, address system, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = bytes32(uint256(uint160(system))); - _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((resourceSelector)), _fieldLayout); + _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((systemId)), _fieldLayout); } /** Tightly pack static data using this table's schema */ - function encodeStatic(bytes32 resourceSelector) internal pure returns (bytes memory) { - return abi.encodePacked(resourceSelector); + function encodeStatic(bytes32 systemId) internal pure returns (bytes memory) { + return abi.encodePacked(systemId); } /** Tightly pack full data using this table's field layout */ - function encode(bytes32 resourceSelector) internal pure returns (bytes memory, PackedCounter, bytes memory) { - bytes memory _staticData = encodeStatic(resourceSelector); + function encode(bytes32 systemId) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(systemId); PackedCounter _encodedLengths; bytes memory _dynamicData; diff --git a/packages/world/src/modules/core/tables/Systems.sol b/packages/world/src/modules/core/tables/Systems.sol index 8a60905326..ddd32f0229 100644 --- a/packages/world/src/modules/core/tables/Systems.sol +++ b/packages/world/src/modules/core/tables/Systems.sol @@ -51,7 +51,7 @@ library Systems { /** Get the table's key names */ function getKeyNames() internal pure returns (string[] memory keyNames) { keyNames = new string[](1); - keyNames[0] = "resourceSelector"; + keyNames[0] = "systemId"; } /** Get the table's field names */ @@ -77,111 +77,111 @@ library Systems { } /** Get system */ - function getSystem(bytes32 resourceSelector) internal view returns (address system) { + function getSystem(bytes32 systemId) internal view returns (address system) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); return (address(bytes20(_blob))); } /** Get system */ - function _getSystem(bytes32 resourceSelector) internal view returns (address system) { + function _getSystem(bytes32 systemId) internal view returns (address system) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); return (address(bytes20(_blob))); } /** Get system (using the specified store) */ - function getSystem(IStore _store, bytes32 resourceSelector) internal view returns (address system) { + function getSystem(IStore _store, bytes32 systemId) internal view returns (address system) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); return (address(bytes20(_blob))); } /** Set system */ - function setSystem(bytes32 resourceSelector, address system) internal { + function setSystem(bytes32 systemId, address system) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((system)), _fieldLayout); } /** Set system */ - function _setSystem(bytes32 resourceSelector, address system) internal { + function _setSystem(bytes32 systemId, address system) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((system)), _fieldLayout); } /** Set system (using the specified store) */ - function setSystem(IStore _store, bytes32 resourceSelector, address system) internal { + function setSystem(IStore _store, bytes32 systemId, address system) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((system)), _fieldLayout); } /** Get publicAccess */ - function getPublicAccess(bytes32 resourceSelector) internal view returns (bool publicAccess) { + function getPublicAccess(bytes32 systemId) internal view returns (bool publicAccess) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); return (_toBool(uint8(bytes1(_blob)))); } /** Get publicAccess */ - function _getPublicAccess(bytes32 resourceSelector) internal view returns (bool publicAccess) { + function _getPublicAccess(bytes32 systemId) internal view returns (bool publicAccess) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); return (_toBool(uint8(bytes1(_blob)))); } /** Get publicAccess (using the specified store) */ - function getPublicAccess(IStore _store, bytes32 resourceSelector) internal view returns (bool publicAccess) { + function getPublicAccess(IStore _store, bytes32 systemId) internal view returns (bool publicAccess) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); return (_toBool(uint8(bytes1(_blob)))); } /** Set publicAccess */ - function setPublicAccess(bytes32 resourceSelector, bool publicAccess) internal { + function setPublicAccess(bytes32 systemId, bool publicAccess) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.setField(_tableId, _keyTuple, 1, abi.encodePacked((publicAccess)), _fieldLayout); } /** Set publicAccess */ - function _setPublicAccess(bytes32 resourceSelector, bool publicAccess) internal { + function _setPublicAccess(bytes32 systemId, bool publicAccess) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.setField(_tableId, _keyTuple, 1, abi.encodePacked((publicAccess)), _fieldLayout); } /** Set publicAccess (using the specified store) */ - function setPublicAccess(IStore _store, bytes32 resourceSelector, bool publicAccess) internal { + function setPublicAccess(IStore _store, bytes32 systemId, bool publicAccess) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.setField(_tableId, _keyTuple, 1, abi.encodePacked((publicAccess)), _fieldLayout); } /** Get the full data */ - function get(bytes32 resourceSelector) internal view returns (address system, bool publicAccess) { + function get(bytes32 systemId) internal view returns (address system, bool publicAccess) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; (bytes memory _staticData, PackedCounter _encodedLengths, bytes memory _dynamicData) = StoreSwitch.getRecord( _tableId, @@ -192,9 +192,9 @@ library Systems { } /** Get the full data */ - function _get(bytes32 resourceSelector) internal view returns (address system, bool publicAccess) { + function _get(bytes32 systemId) internal view returns (address system, bool publicAccess) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; (bytes memory _staticData, PackedCounter _encodedLengths, bytes memory _dynamicData) = StoreCore.getRecord( _tableId, @@ -205,9 +205,9 @@ library Systems { } /** Get the full data (using the specified store) */ - function get(IStore _store, bytes32 resourceSelector) internal view returns (address system, bool publicAccess) { + function get(IStore _store, bytes32 systemId) internal view returns (address system, bool publicAccess) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; (bytes memory _staticData, PackedCounter _encodedLengths, bytes memory _dynamicData) = _store.getRecord( _tableId, @@ -218,40 +218,40 @@ library Systems { } /** Set the full data using individual values */ - function set(bytes32 resourceSelector, address system, bool publicAccess) internal { + function set(bytes32 systemId, address system, bool publicAccess) internal { bytes memory _staticData = encodeStatic(system, publicAccess); PackedCounter _encodedLengths; bytes memory _dynamicData; bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); } /** Set the full data using individual values */ - function _set(bytes32 resourceSelector, address system, bool publicAccess) internal { + function _set(bytes32 systemId, address system, bool publicAccess) internal { bytes memory _staticData = encodeStatic(system, publicAccess); PackedCounter _encodedLengths; bytes memory _dynamicData; bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); } /** Set the full data using individual values (using the specified store) */ - function set(IStore _store, bytes32 resourceSelector, address system, bool publicAccess) internal { + function set(IStore _store, bytes32 systemId, address system, bool publicAccess) internal { bytes memory _staticData = encodeStatic(system, publicAccess); PackedCounter _encodedLengths; bytes memory _dynamicData; bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); } @@ -294,33 +294,33 @@ library Systems { } /** Encode keys as a bytes32 array using this table's field layout */ - function encodeKeyTuple(bytes32 resourceSelector) internal pure returns (bytes32[] memory) { + function encodeKeyTuple(bytes32 systemId) internal pure returns (bytes32[] memory) { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; return _keyTuple; } /* Delete all data for given keys */ - function deleteRecord(bytes32 resourceSelector) internal { + function deleteRecord(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreSwitch.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys */ - function _deleteRecord(bytes32 resourceSelector) internal { + function _deleteRecord(bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys (using the specified store) */ - function deleteRecord(IStore _store, bytes32 resourceSelector) internal { + function deleteRecord(IStore _store, bytes32 systemId) internal { bytes32[] memory _keyTuple = new bytes32[](1); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = systemId; _store.deleteRecord(_tableId, _keyTuple, _fieldLayout); } diff --git a/packages/world/src/modules/keysintable/KeysInTableModule.sol b/packages/world/src/modules/keysintable/KeysInTableModule.sol index cd6d0b9f7d..b1777c14de 100644 --- a/packages/world/src/modules/keysintable/KeysInTableModule.sol +++ b/packages/world/src/modules/keysintable/KeysInTableModule.sol @@ -9,7 +9,7 @@ import { Module } from "../../Module.sol"; import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; import { revertWithBytes } from "../../revertWithBytes.sol"; import { KeysInTableHook } from "./KeysInTableHook.sol"; @@ -27,7 +27,7 @@ import { UsedKeysIndex, UsedKeysIndexTableId } from "./tables/UsedKeysIndex.sol" * TODO: add support for `install` (via `World.installModule`) by using `callFrom` with the `msgSender()` */ contract KeysInTableModule is Module { - using ResourceSelector for bytes32; + using ResourceId for bytes32; // The KeysInTableHook is deployed once and infers the target table id // from the source table id (passed as argument to the hook methods) diff --git a/packages/world/src/modules/keyswithvalue/KeysWithValueHook.sol b/packages/world/src/modules/keyswithvalue/KeysWithValueHook.sol index d666a3f4fa..fb21234177 100644 --- a/packages/world/src/modules/keyswithvalue/KeysWithValueHook.sol +++ b/packages/world/src/modules/keyswithvalue/KeysWithValueHook.sol @@ -9,12 +9,12 @@ import { PackedCounter } from "@latticexyz/store/src/PackedCounter.sol"; import { Tables } from "@latticexyz/store/src/codegen/tables/Tables.sol"; import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; import { MODULE_NAMESPACE } from "./constants.sol"; import { KeysWithValue } from "./tables/KeysWithValue.sol"; import { ArrayLib } from "../utils/ArrayLib.sol"; -import { getTargetTableSelector } from "../utils/getTargetTableSelector.sol"; +import { getTargetTableId } from "./getTargetTableId.sol"; /** * This is a very naive and inefficient implementation for now. @@ -25,7 +25,7 @@ import { getTargetTableSelector } from "../utils/getTargetTableSelector.sol"; */ contract KeysWithValueHook is StoreHook { using ArrayLib for bytes32[]; - using ResourceSelector for bytes32; + using ResourceId for bytes32; function _world() internal view returns (IBaseWorld) { return IBaseWorld(StoreSwitch.getStoreAddress()); @@ -39,7 +39,7 @@ contract KeysWithValueHook is StoreHook { bytes memory dynamicData, FieldLayout fieldLayout ) public override { - bytes32 targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); // Get the previous value bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout); @@ -67,7 +67,7 @@ contract KeysWithValueHook is StoreHook { // Remove the key from the list of keys with the previous value FieldLayout fieldLayout = FieldLayout.wrap(Tables.getFieldLayout(sourceTableId)); bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout); - bytes32 targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); _removeKeyFromList(targetTableId, keyTuple[0], previousValue); } @@ -81,7 +81,7 @@ contract KeysWithValueHook is StoreHook { // Add the key to the list of keys with the new value FieldLayout fieldLayout = FieldLayout.wrap(Tables.getFieldLayout(sourceTableId)); bytes32 newValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout); - bytes32 targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); KeysWithValue.push(targetTableId, newValue, keyTuple[0]); } @@ -97,7 +97,7 @@ contract KeysWithValueHook is StoreHook { // Remove the key from the list of keys with the previous value FieldLayout fieldLayout = FieldLayout.wrap(Tables.getFieldLayout(sourceTableId)); bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout); - bytes32 targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); _removeKeyFromList(targetTableId, keyTuple[0], previousValue); } @@ -113,7 +113,7 @@ contract KeysWithValueHook is StoreHook { // Add the key to the list of keys with the new value FieldLayout fieldLayout = FieldLayout.wrap(Tables.getFieldLayout(sourceTableId)); bytes32 newValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout); - bytes32 targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); KeysWithValue.push(targetTableId, newValue, keyTuple[0]); } @@ -124,7 +124,7 @@ contract KeysWithValueHook is StoreHook { ) public override { // Remove the key from the list of keys with the previous value bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout); - bytes32 targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); _removeKeyFromList(targetTableId, keyTuple[0], previousValue); } diff --git a/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol b/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol index 65774a0093..dca859bd84 100644 --- a/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol +++ b/packages/world/src/modules/keyswithvalue/KeysWithValueModule.sol @@ -8,13 +8,13 @@ import { Module } from "../../Module.sol"; import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; import { WorldContextConsumer } from "../../WorldContext.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; import { revertWithBytes } from "../../revertWithBytes.sol"; import { MODULE_NAMESPACE } from "./constants.sol"; import { KeysWithValueHook } from "./KeysWithValueHook.sol"; import { KeysWithValue } from "./tables/KeysWithValue.sol"; -import { getTargetTableSelector } from "../utils/getTargetTableSelector.sol"; +import { getTargetTableId } from "./getTargetTableId.sol"; /** * This module deploys a hook that is called when a value is set in the `sourceTableId` @@ -28,7 +28,7 @@ import { getTargetTableSelector } from "../utils/getTargetTableSelector.sol"; * TODO: add support for `install` (via `World.installModule`) by using `callFrom` with the `msgSender()` */ contract KeysWithValueModule is Module { - using ResourceSelector for bytes32; + using ResourceId for bytes32; // The KeysWithValueHook is deployed once and infers the target table id // from the source table id (passed as argument to the hook methods) @@ -41,7 +41,7 @@ contract KeysWithValueModule is Module { function installRoot(bytes memory args) public { // Extract source table id from args bytes32 sourceTableId = abi.decode(args, (bytes32)); - bytes32 targetTableSelector = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableSelector = getTargetTableId(MODULE_NAMESPACE, sourceTableId); IBaseWorld world = IBaseWorld(_world()); diff --git a/packages/world/src/modules/keyswithvalue/constants.sol b/packages/world/src/modules/keyswithvalue/constants.sol index 17528e1ec8..3238b56ae8 100644 --- a/packages/world/src/modules/keyswithvalue/constants.sol +++ b/packages/world/src/modules/keyswithvalue/constants.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -// Limiting the module namespace to 8 bytes so the last 8 bytes +// Limiting the module namespace to 7 bytes so the remaining 7 bytes // can be used for an identifier of the source table namespace to avoid // collisions between tables with the same name in different namespaces -bytes8 constant MODULE_NAMESPACE = "keyswval"; +bytes7 constant MODULE_NAMESPACE = "kyswval"; diff --git a/packages/world/src/modules/keyswithvalue/getKeysWithValue.sol b/packages/world/src/modules/keyswithvalue/getKeysWithValue.sol index e47fba0d10..6a19178aa0 100644 --- a/packages/world/src/modules/keyswithvalue/getKeysWithValue.sol +++ b/packages/world/src/modules/keyswithvalue/getKeysWithValue.sol @@ -6,7 +6,7 @@ import { PackedCounter } from "@latticexyz/store/src/PackedCounter.sol"; import { MODULE_NAMESPACE } from "./constants.sol"; import { KeysWithValue } from "./tables/KeysWithValue.sol"; -import { getTargetTableSelector } from "../utils/getTargetTableSelector.sol"; +import { getTargetTableId } from "./getTargetTableId.sol"; /** * Get a list of keys with the given value. @@ -21,7 +21,7 @@ function getKeysWithValue( bytes memory dynamicData ) view returns (bytes32[] memory keysWithValue) { // Get the corresponding reverse mapping table - bytes32 keysWithValueTableId = getTargetTableSelector(MODULE_NAMESPACE, tableId); + bytes32 keysWithValueTableId = getTargetTableId(MODULE_NAMESPACE, tableId); // Get the keys with the given value bytes memory value; @@ -44,7 +44,7 @@ function getKeysWithValue( bytes memory dynamicData ) view returns (bytes32[] memory keysWithValue) { // Get the corresponding reverse mapping table - bytes32 keysWithValueTableId = getTargetTableSelector(MODULE_NAMESPACE, tableId); + bytes32 keysWithValueTableId = getTargetTableId(MODULE_NAMESPACE, tableId); // Get the keys with the given value bytes memory value; diff --git a/packages/world/src/modules/keyswithvalue/getTargetTableId.sol b/packages/world/src/modules/keyswithvalue/getTargetTableId.sol new file mode 100644 index 0000000000..852ffd4823 --- /dev/null +++ b/packages/world/src/modules/keyswithvalue/getTargetTableId.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; +import { ResourceId } from "../../ResourceId.sol"; +import { RESOURCE_TABLE } from "../../worldResourceTypes.sol"; + +/** + * Get a deterministic selector for the reverse mapping table for the given source table. + * The selector is constructed as follows: + * - The first 7 bytes are the module namespace + * - The next 7 bytes are the first 8 bytes of the source table namespace + * -- This is to avoid collisions between tables with the same name in different namespaces + * (Note that collisions are still possible if the first 8 bytes of the namespace are the same, in which case installing the module fails) + * - The last 16 bytes are the source table name + */ +function getTargetTableId(bytes7 moduleNamespace, bytes32 sourceTableId) pure returns (bytes32) { + bytes16 tableName = ResourceId.getName(sourceTableId); + bytes7 sourceTableNamespace = bytes7(bytes32(sourceTableId)); + return + bytes32(moduleNamespace) | + (bytes32(sourceTableNamespace) >> (7 * 8)) | + (bytes32(tableName) >> (14 * 8)) | + (bytes32(RESOURCE_TABLE) >> (30 * 8)); +} diff --git a/packages/world/src/modules/std-delegations/CallboundDelegationControl.sol b/packages/world/src/modules/std-delegations/CallboundDelegationControl.sol index fbb62081ee..2ec57dabab 100644 --- a/packages/world/src/modules/std-delegations/CallboundDelegationControl.sol +++ b/packages/world/src/modules/std-delegations/CallboundDelegationControl.sol @@ -8,14 +8,14 @@ contract CallboundDelegationControl is DelegationControl { /** * Verify a delegation by checking if the delegator has any available calls left in the CallboundDelegations table and decrementing the available calls if so. */ - function verify(address delegator, bytes32 resourceSelector, bytes memory callData) public returns (bool) { + function verify(address delegator, bytes32 systemId, bytes memory callData) public returns (bool) { bytes32 callDataHash = keccak256(callData); - // Get the number of available calls for the given delegator, resourceSelector and callData + // Get the number of available calls for the given delegator, systemId and callData uint256 availableCalls = CallboundDelegations.get({ delegator: delegator, delegatee: _msgSender(), - resourceSelector: resourceSelector, + systemId: systemId, callDataHash: callDataHash }); @@ -24,7 +24,7 @@ contract CallboundDelegationControl is DelegationControl { CallboundDelegations.deleteRecord({ delegator: delegator, delegatee: _msgSender(), - resourceSelector: resourceSelector, + systemId: systemId, callDataHash: callDataHash }); return true; @@ -38,7 +38,7 @@ contract CallboundDelegationControl is DelegationControl { CallboundDelegations.set({ delegator: delegator, delegatee: _msgSender(), - resourceSelector: resourceSelector, + systemId: systemId, callDataHash: callDataHash, availableCalls: availableCalls }); @@ -51,11 +51,11 @@ contract CallboundDelegationControl is DelegationControl { /** * Initialize a delegation by setting the number of available calls in the CallboundDelegations table */ - function initDelegation(address delegatee, bytes32 resourceSelector, bytes memory callData, uint256 numCalls) public { + function initDelegation(address delegatee, bytes32 systemId, bytes memory callData, uint256 numCalls) public { CallboundDelegations.set({ delegator: _msgSender(), delegatee: delegatee, - resourceSelector: resourceSelector, + systemId: systemId, callDataHash: keccak256(callData), availableCalls: numCalls }); diff --git a/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol b/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol index d1ba02718d..5228ed4bc3 100644 --- a/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol +++ b/packages/world/src/modules/std-delegations/StandardDelegationsModule.sol @@ -5,7 +5,7 @@ import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; import { Module } from "../../Module.sol"; import { WorldContextConsumer } from "../../WorldContext.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; import { revertWithBytes } from "../../revertWithBytes.sol"; import { CallboundDelegationControl } from "./CallboundDelegationControl.sol"; diff --git a/packages/world/src/modules/std-delegations/TimeboundDelegationControl.sol b/packages/world/src/modules/std-delegations/TimeboundDelegationControl.sol index efeb00663e..e4c96915d1 100644 --- a/packages/world/src/modules/std-delegations/TimeboundDelegationControl.sol +++ b/packages/world/src/modules/std-delegations/TimeboundDelegationControl.sol @@ -7,7 +7,7 @@ import { TimeboundDelegations } from "./tables/TimeboundDelegations.sol"; contract TimeboundDelegationControl is DelegationControl { /** * Verify a delegation by checking if the current block timestamp is not larger than the max valid timestamp for the delegation. - * Note: the delegation control check ignores the resourceSelector and callData parameters. + * Note: the delegation control check ignores the systemId and callData parameters. */ function verify(address delegator, bytes32, bytes memory) public view returns (bool) { // Get the max valid timestamp for the given delegator diff --git a/packages/world/src/modules/std-delegations/constants.sol b/packages/world/src/modules/std-delegations/constants.sol index dfe282a288..450f08235f 100644 --- a/packages/world/src/modules/std-delegations/constants.sol +++ b/packages/world/src/modules/std-delegations/constants.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; import { ROOT_NAMESPACE } from "../../constants.sol"; bytes16 constant MODULE_NAME = bytes16("stddelegations.m"); diff --git a/packages/world/src/modules/std-delegations/tables/CallboundDelegations.sol b/packages/world/src/modules/std-delegations/tables/CallboundDelegations.sol index e0dae09e55..6cc5e4602f 100644 --- a/packages/world/src/modules/std-delegations/tables/CallboundDelegations.sol +++ b/packages/world/src/modules/std-delegations/tables/CallboundDelegations.sol @@ -55,7 +55,7 @@ library CallboundDelegations { keyNames = new string[](4); keyNames[0] = "delegator"; keyNames[1] = "delegatee"; - keyNames[2] = "resourceSelector"; + keyNames[2] = "systemId"; keyNames[3] = "callDataHash"; } @@ -84,13 +84,13 @@ library CallboundDelegations { function get( address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash ) internal view returns (uint256 availableCalls) { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -101,13 +101,13 @@ library CallboundDelegations { function _get( address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash ) internal view returns (uint256 availableCalls) { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -119,13 +119,13 @@ library CallboundDelegations { IStore _store, address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash ) internal view returns (uint256 availableCalls) { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -136,14 +136,14 @@ library CallboundDelegations { function set( address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash, uint256 availableCalls ) internal { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); @@ -153,14 +153,14 @@ library CallboundDelegations { function _set( address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash, uint256 availableCalls ) internal { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); @@ -171,14 +171,14 @@ library CallboundDelegations { IStore _store, address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash, uint256 availableCalls ) internal { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); @@ -203,40 +203,35 @@ library CallboundDelegations { function encodeKeyTuple( address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash ) internal pure returns (bytes32[] memory) { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; return _keyTuple; } /* Delete all data for given keys */ - function deleteRecord(address delegator, address delegatee, bytes32 resourceSelector, bytes32 callDataHash) internal { + function deleteRecord(address delegator, address delegatee, bytes32 systemId, bytes32 callDataHash) internal { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; StoreSwitch.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys */ - function _deleteRecord( - address delegator, - address delegatee, - bytes32 resourceSelector, - bytes32 callDataHash - ) internal { + function _deleteRecord(address delegator, address delegatee, bytes32 systemId, bytes32 callDataHash) internal { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); @@ -247,13 +242,13 @@ library CallboundDelegations { IStore _store, address delegator, address delegatee, - bytes32 resourceSelector, + bytes32 systemId, bytes32 callDataHash ) internal { bytes32[] memory _keyTuple = new bytes32[](4); _keyTuple[0] = bytes32(uint256(uint160(delegator))); _keyTuple[1] = bytes32(uint256(uint160(delegatee))); - _keyTuple[2] = resourceSelector; + _keyTuple[2] = systemId; _keyTuple[3] = callDataHash; _store.deleteRecord(_tableId, _keyTuple, _fieldLayout); diff --git a/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol b/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol index f404c4b50a..4266170053 100644 --- a/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol +++ b/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol @@ -5,12 +5,13 @@ import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; import { Module } from "../../Module.sol"; import { WorldContextConsumer } from "../../WorldContext.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { ResourceId } from "../../ResourceId.sol"; +import { RESOURCE_TABLE, RESOURCE_SYSTEM } from "../../worldResourceTypes.sol"; import { UniqueEntity } from "./tables/UniqueEntity.sol"; import { UniqueEntitySystem } from "./UniqueEntitySystem.sol"; -import { NAMESPACE, MODULE_NAME, SYSTEM_NAME, TABLE_NAME } from "./constants.sol"; +import { MODULE_NAME, TABLE_ID, SYSTEM_ID } from "./constants.sol"; /** * This module creates a table that stores a nonce, and @@ -33,12 +34,12 @@ contract UniqueEntityModule is Module { IBaseWorld world = IBaseWorld(_world()); // Register table - UniqueEntity.register(world, ResourceSelector.from(NAMESPACE, TABLE_NAME)); + UniqueEntity.register(world, TABLE_ID); // Register system - world.registerSystem(ResourceSelector.from(NAMESPACE, SYSTEM_NAME), uniqueEntitySystem, true); + world.registerSystem(SYSTEM_ID, uniqueEntitySystem, true); // Register system's functions - world.registerFunctionSelector(ResourceSelector.from(NAMESPACE, SYSTEM_NAME), "getUniqueEntity", "()"); + world.registerFunctionSelector(SYSTEM_ID, "getUniqueEntity", "()"); } } diff --git a/packages/world/src/modules/uniqueentity/UniqueEntitySystem.sol b/packages/world/src/modules/uniqueentity/UniqueEntitySystem.sol index 3ef850f25e..89c515aa85 100644 --- a/packages/world/src/modules/uniqueentity/UniqueEntitySystem.sol +++ b/packages/world/src/modules/uniqueentity/UniqueEntitySystem.sol @@ -5,17 +5,16 @@ import { System } from "../../System.sol"; import { UniqueEntity } from "./tables/UniqueEntity.sol"; -import { NAMESPACE, TABLE_NAME } from "./constants.sol"; -import { ResourceSelector } from "../../ResourceSelector.sol"; +import { TABLE_ID } from "./constants.sol"; +import { ResourceId } from "../../ResourceId.sol"; contract UniqueEntitySystem is System { /** * Increment and get an entity nonce. */ function getUniqueEntity() public virtual returns (bytes32) { - bytes32 tableId = ResourceSelector.from(NAMESPACE, TABLE_NAME); - uint256 uniqueEntity = UniqueEntity.get(tableId) + 1; - UniqueEntity.set(tableId, uniqueEntity); + uint256 uniqueEntity = UniqueEntity.get(TABLE_ID) + 1; + UniqueEntity.set(TABLE_ID, uniqueEntity); return bytes32(uniqueEntity); } diff --git a/packages/world/src/modules/uniqueentity/constants.sol b/packages/world/src/modules/uniqueentity/constants.sol index 772f4742e2..ba69e6572f 100644 --- a/packages/world/src/modules/uniqueentity/constants.sol +++ b/packages/world/src/modules/uniqueentity/constants.sol @@ -1,7 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -bytes16 constant NAMESPACE = bytes16("uniqueEntity"); -bytes16 constant MODULE_NAME = bytes16("uniqueEntity.m"); +import { RESOURCE_TABLE, RESOURCE_SYSTEM } from "../../worldResourceTypes.sol"; + +bytes14 constant NAMESPACE = bytes14("uniqueEntity"); +bytes16 constant MODULE_NAME = bytes16("uniqueEntity"); bytes16 constant SYSTEM_NAME = bytes16("system"); bytes16 constant TABLE_NAME = bytes16("table"); + +bytes32 constant TABLE_ID = bytes32(abi.encodePacked(NAMESPACE, TABLE_NAME, RESOURCE_TABLE)); +bytes32 constant SYSTEM_ID = bytes32(abi.encodePacked(NAMESPACE, SYSTEM_NAME, RESOURCE_SYSTEM)); diff --git a/packages/world/src/modules/utils/getTargetTableSelector.sol b/packages/world/src/modules/utils/getTargetTableSelector.sol deleted file mode 100644 index 84ff1035f0..0000000000 --- a/packages/world/src/modules/utils/getTargetTableSelector.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; -import { ResourceSelector } from "../../ResourceSelector.sol"; - -/** - * Get a deterministic selector for the reverse mapping table for the given source table. - * The selector is constructed as follows: - * - The first 8 bytes are the module namespace - * - The next 8 bytes are the first 8 bytes of the source table namespace - * -- This is to avoid collisions between tables with the same name in different namespaces - * (Note that collisions are still possible if the first 8 bytes of the namespace are the same, in which case installing the module fails) - * - The last 16 bytes are the source table name - */ -function getTargetTableSelector(bytes8 moduleNamespace, bytes32 sourceTableId) pure returns (bytes32) { - bytes16 tableName = ResourceSelector.getName(sourceTableId); - bytes8 sourceTableNamespace = bytes8(bytes32(sourceTableId)); - return bytes32(moduleNamespace) | (bytes32(sourceTableNamespace) >> 64) | (bytes32(tableName) >> 128); -} diff --git a/packages/world/src/tables/ResourceAccess.sol b/packages/world/src/tables/ResourceAccess.sol index 553447e59f..e3b2ded402 100644 --- a/packages/world/src/tables/ResourceAccess.sol +++ b/packages/world/src/tables/ResourceAccess.sol @@ -51,7 +51,7 @@ library ResourceAccess { /** Get the table's key names */ function getKeyNames() internal pure returns (string[] memory keyNames) { keyNames = new string[](2); - keyNames[0] = "resourceSelector"; + keyNames[0] = "resourceId"; keyNames[1] = "caller"; } @@ -77,9 +77,9 @@ library ResourceAccess { } /** Get access */ - function get(bytes32 resourceSelector, address caller) internal view returns (bool access) { + function get(bytes32 resourceId, address caller) internal view returns (bool access) { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -87,9 +87,9 @@ library ResourceAccess { } /** Get access */ - function _get(bytes32 resourceSelector, address caller) internal view returns (bool access) { + function _get(bytes32 resourceId, address caller) internal view returns (bool access) { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -97,9 +97,9 @@ library ResourceAccess { } /** Get access (using the specified store) */ - function get(IStore _store, bytes32 resourceSelector, address caller) internal view returns (bool access) { + function get(IStore _store, bytes32 resourceId, address caller) internal view returns (bool access) { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -107,27 +107,27 @@ library ResourceAccess { } /** Set access */ - function set(bytes32 resourceSelector, address caller, bool access) internal { + function set(bytes32 resourceId, address caller, bool access) internal { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((access)), _fieldLayout); } /** Set access */ - function _set(bytes32 resourceSelector, address caller, bool access) internal { + function _set(bytes32 resourceId, address caller, bool access) internal { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); StoreCore.setField(_tableId, _keyTuple, 0, abi.encodePacked((access)), _fieldLayout); } /** Set access (using the specified store) */ - function set(IStore _store, bytes32 resourceSelector, address caller, bool access) internal { + function set(IStore _store, bytes32 resourceId, address caller, bool access) internal { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((access)), _fieldLayout); @@ -149,36 +149,36 @@ library ResourceAccess { } /** Encode keys as a bytes32 array using this table's field layout */ - function encodeKeyTuple(bytes32 resourceSelector, address caller) internal pure returns (bytes32[] memory) { + function encodeKeyTuple(bytes32 resourceId, address caller) internal pure returns (bytes32[] memory) { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); return _keyTuple; } /* Delete all data for given keys */ - function deleteRecord(bytes32 resourceSelector, address caller) internal { + function deleteRecord(bytes32 resourceId, address caller) internal { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); StoreSwitch.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys */ - function _deleteRecord(bytes32 resourceSelector, address caller) internal { + function _deleteRecord(bytes32 resourceId, address caller) internal { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); } /* Delete all data for given keys (using the specified store) */ - function deleteRecord(IStore _store, bytes32 resourceSelector, address caller) internal { + function deleteRecord(IStore _store, bytes32 resourceId, address caller) internal { bytes32[] memory _keyTuple = new bytes32[](2); - _keyTuple[0] = resourceSelector; + _keyTuple[0] = resourceId; _keyTuple[1] = bytes32(uint256(uint160(caller))); _store.deleteRecord(_tableId, _keyTuple, _fieldLayout); diff --git a/packages/world/src/worldResourceTypes.sol b/packages/world/src/worldResourceTypes.sol new file mode 100644 index 0000000000..0461e55d8b --- /dev/null +++ b/packages/world/src/worldResourceTypes.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "@latticexyz/store/src/storeResourceTypes.sol"; + +bytes2 constant RESOURCE_NAMESPACE = "na"; +bytes2 constant RESOURCE_MODULE = "mo"; +bytes2 constant RESOURCE_SYSTEM = "sy"; + +// First 30 bytes are 0, last 2 bytes are the resource type +bytes32 constant MASK_RESOURCE_NAMESPACE = bytes32(RESOURCE_NAMESPACE) >> (30 * 8); +bytes32 constant MASK_RESOURCE_MODULE = bytes32(RESOURCE_MODULE) >> (30 * 8); +bytes32 constant MASK_RESOURCE_SYSTEM = bytes32(RESOURCE_SYSTEM) >> (30 * 8); diff --git a/packages/world/test/AccessControl.t.sol b/packages/world/test/AccessControl.t.sol index feddf64c67..2e8da2682a 100644 --- a/packages/world/test/AccessControl.t.sol +++ b/packages/world/test/AccessControl.t.sol @@ -8,23 +8,29 @@ import { StoreMock } from "@latticexyz/store/test/StoreMock.sol"; import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; import { World } from "../src/World.sol"; import { AccessControl } from "../src/AccessControl.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; +import { RESOURCE_TABLE, RESOURCE_NAMESPACE } from "../src/worldResourceTypes.sol"; import { ResourceAccess } from "../src/tables/ResourceAccess.sol"; import { NamespaceOwner } from "../src/tables/NamespaceOwner.sol"; contract AccessControlTest is Test, GasReporter, StoreMock { - bytes16 constant namespace = "namespace"; - bytes16 constant name = "name"; - address constant presetCaller = address(0x0123); - address constant caller = address(0x01); + bytes14 private constant namespace = "namespace"; + bytes16 private constant name = "name"; + address private constant presetCaller = address(0x0123); + address private constant caller = address(0x01); + + bytes32 private tableId; + bytes32 private namespaceId; function setUp() public { ResourceAccess.register(); NamespaceOwner.register(); + tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); + namespaceId = ResourceId.encodeNamespace(namespace); NamespaceOwner.set(namespace, address(this)); - ResourceAccess.set(ResourceSelector.from(namespace, name), presetCaller, true); + ResourceAccess.set(tableId, presetCaller, true); } function testAccessControl() public { @@ -32,61 +38,57 @@ contract AccessControlTest is Test, GasReporter, StoreMock { // Check that the caller has no access to the namespace or name startGasReport("AccessControl: hasAccess (cold)"); - hasAccess = AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller); + hasAccess = AccessControl.hasAccess(tableId, caller); endGasReport(); - assertFalse(hasAccess); + assertFalse(hasAccess, "caller should not have access to the table"); // Grant access to the namespace - ResourceAccess.set(ResourceSelector.from(namespace, 0), caller, true); + ResourceAccess.set(namespaceId, caller, true); // Check that the caller has access to the namespace or name startGasReport("AccessControl: hasAccess (warm, namespace only)"); - hasAccess = AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller); + hasAccess = AccessControl.hasAccess(tableId, caller); endGasReport(); - assertTrue(hasAccess); + assertTrue(hasAccess, "caller should have access to the namespace"); // Revoke access to the namespace - ResourceAccess.set(ResourceSelector.from(namespace, 0), caller, false); + ResourceAccess.set(namespaceId, caller, false); // Check that the caller has no access to the namespace or name startGasReport("AccessControl: hasAccess (warm)"); - hasAccess = AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller); + hasAccess = AccessControl.hasAccess(tableId, caller); endGasReport(); - assertFalse(hasAccess); + assertFalse(hasAccess, "access to the namespace should have been revoked"); // Grant access to the name - ResourceAccess.set(ResourceSelector.from(namespace, name), caller, true); + ResourceAccess.set(tableId, caller, true); // Check that the caller has access to the name - assertTrue(AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller)); + assertTrue(AccessControl.hasAccess(tableId, caller), "access to the table should have been granted"); // Revoke access to the name - ResourceAccess.set(ResourceSelector.from(namespace, name), caller, false); + ResourceAccess.set(tableId, caller, false); // Check that the caller has no access to the namespace or name - assertFalse(AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller)); + assertFalse(AccessControl.hasAccess(tableId, caller), "access to the table should have been revoked"); } function testRequireAccess() public { - bytes32 resourceSelector = ResourceSelector.from(namespace, name); startGasReport("AccessControl: requireAccess (cold)"); - AccessControl.requireAccess(resourceSelector, presetCaller); + AccessControl.requireAccess(tableId, presetCaller); endGasReport(); startGasReport("AccessControl: requireAccess (warm)"); - AccessControl.requireAccess(resourceSelector, presetCaller); + AccessControl.requireAccess(tableId, presetCaller); endGasReport(); startGasReport("AccessControl: requireAccess (this address)"); - AccessControl.requireAccess(resourceSelector, address(this)); + AccessControl.requireAccess(tableId, address(this)); endGasReport(); } function testRequireAccessRevert() public { - bytes32 resourceSelector = ResourceSelector.from(namespace, name); - vm.expectRevert( - abi.encodeWithSelector(IWorldErrors.AccessDenied.selector, ResourceSelector.toString(resourceSelector), caller) - ); - AccessControl.requireAccess(resourceSelector, caller); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.AccessDenied.selector, ResourceId.toString(tableId), caller)); + AccessControl.requireAccess(tableId, caller); } } diff --git a/packages/world/test/KeysInTableModule.t.sol b/packages/world/test/KeysInTableModule.t.sol index 7789e33740..6c08f827ee 100644 --- a/packages/world/test/KeysInTableModule.t.sol +++ b/packages/world/test/KeysInTableModule.t.sol @@ -13,8 +13,9 @@ import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol" import { World } from "../src/World.sol"; import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; import { ROOT_NAMESPACE } from "../src/constants.sol"; +import { RESOURCE_TABLE } from "../src/worldResourceTypes.sol"; import { CoreModule } from "../src/modules/core/CoreModule.sol"; import { KeysInTableModule } from "../src/modules/keysintable/KeysInTableModule.sol"; @@ -22,11 +23,12 @@ import { getKeysInTable } from "../src/modules/keysintable/getKeysInTable.sol"; import { hasKey } from "../src/modules/keysintable/hasKey.sol"; contract KeysInTableModuleTest is Test, GasReporter { - using ResourceSelector for bytes32; + using ResourceId for bytes32; + IBaseWorld private world; KeysInTableModule private keysInTableModule = new KeysInTableModule(); // Modules can be deployed once and installed multiple times - bytes16 private namespace = ROOT_NAMESPACE; + bytes14 private namespace = ROOT_NAMESPACE; bytes16 private name = bytes16("source"); bytes16 private singletonName = bytes16("singleton"); bytes16 private compositeName = bytes16("composite"); @@ -42,9 +44,9 @@ contract KeysInTableModuleTest is Test, GasReporter { Schema private tableKeySchema; Schema private singletonKeySchema; Schema private compositeKeySchema; - bytes32 private tableId = ResourceSelector.from(namespace, name); - bytes32 private singletonTableId = ResourceSelector.from(namespace, singletonName); - bytes32 private compositeTableId = ResourceSelector.from(namespace, compositeName); + bytes32 private tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); + bytes32 private singletonTableId = ResourceId.encode(namespace, singletonName, RESOURCE_TABLE); + bytes32 private compositeTableId = ResourceId.encode(namespace, compositeName, RESOURCE_TABLE); uint256 private val1 = 123; uint256 private val2 = 42; @@ -205,7 +207,7 @@ contract KeysInTableModuleTest is Test, GasReporter { // Install the hook on the second table bytes16 sourceFile2 = bytes16("source2"); - bytes32 sourceTableId2 = ResourceSelector.from(namespace, sourceFile2); + bytes32 sourceTableId2 = ResourceId.encode(namespace, sourceFile2, RESOURCE_TABLE); world.registerTable( sourceTableId2, tableFieldLayout, diff --git a/packages/world/test/KeysWithValueModule.t.sol b/packages/world/test/KeysWithValueModule.t.sol index fa8e8e83d5..94496317e1 100644 --- a/packages/world/test/KeysWithValueModule.t.sol +++ b/packages/world/test/KeysWithValueModule.t.sol @@ -10,26 +10,30 @@ import { SchemaEncodeHelper } from "@latticexyz/store/test/SchemaEncodeHelper.so import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { ResourceType } from "@latticexyz/store/src/ResourceType.sol"; import { FieldLayoutEncodeHelper } from "@latticexyz/store/test/FieldLayoutEncodeHelper.sol"; import { World } from "../src/World.sol"; import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; import { ROOT_NAMESPACE } from "../src/constants.sol"; +import { RESOURCE_TABLE } from "../src/worldResourceTypes.sol"; import { CoreModule } from "../src/modules/core/CoreModule.sol"; import { KeysWithValueModule } from "../src/modules/keyswithvalue/KeysWithValueModule.sol"; import { MODULE_NAMESPACE } from "../src/modules/keyswithvalue/constants.sol"; import { KeysWithValue } from "../src/modules/keyswithvalue/tables/KeysWithValue.sol"; import { getKeysWithValue } from "../src/modules/keyswithvalue/getKeysWithValue.sol"; -import { getTargetTableSelector } from "../src/modules/utils/getTargetTableSelector.sol"; +import { getTargetTableId } from "../src/modules/keyswithvalue/getTargetTableId.sol"; contract KeysWithValueModuleTest is Test, GasReporter { - using ResourceSelector for bytes32; + using ResourceId for bytes32; + using ResourceType for bytes32; + IBaseWorld world; KeysWithValueModule private keysWithValueModule = new KeysWithValueModule(); // Modules can be deployed once and installed multiple times - bytes16 private namespace = ROOT_NAMESPACE; + bytes14 private namespace = ROOT_NAMESPACE; bytes16 private sourceName = bytes16("source"); bytes32 private key1 = keccak256("test"); bytes32[] private keyTuple1; @@ -52,8 +56,8 @@ contract KeysWithValueModuleTest is Test, GasReporter { keyTuple1[0] = key1; keyTuple2 = new bytes32[](1); keyTuple2[0] = key2; - sourceTableId = ResourceSelector.from(namespace, sourceName); - targetTableId = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + sourceTableId = ResourceId.encode(namespace, sourceName, RESOURCE_TABLE); + targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId); } function _installKeysWithValueModule() internal { @@ -219,17 +223,20 @@ contract KeysWithValueModuleTest is Test, GasReporter { function testGetTargetTableSelector() public { startGasReport("compute the target table selector"); - bytes32 targetTableSelector = getTargetTableSelector(MODULE_NAMESPACE, sourceTableId); + bytes32 targetTableSelector = getTargetTableId(MODULE_NAMESPACE, sourceTableId); endGasReport(); - // The first 8 bytes are the module namespace - assertEq(bytes8(targetTableSelector), MODULE_NAMESPACE); + // The first 7 bytes are the module namespace + assertEq(bytes7(targetTableSelector), MODULE_NAMESPACE, "module namespace does not match"); + + // followed by the first 7 bytes of the source table namespace + assertEq(bytes7(targetTableSelector << (7 * 8)), bytes7(namespace), "table namespace does not match"); - // followed by the first 4 bytes of the source table namespace - assertEq(bytes8(targetTableSelector << 64), bytes8(namespace)); + // The next 16 bytes are the source name + assertEq(targetTableSelector.getName(), sourceName, "table name does not match"); - // The last 16 bytes are the source name - assertEq(targetTableSelector.getName(), sourceName); + // The last 2 bytes are the table resource type + assertEq(targetTableSelector.getType(), RESOURCE_TABLE, "target table resource type does not match"); } function testGetKeysWithValueGas() public { diff --git a/packages/world/test/ResourceId.t.sol b/packages/world/test/ResourceId.t.sol new file mode 100644 index 0000000000..ba45e13a05 --- /dev/null +++ b/packages/world/test/ResourceId.t.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { Test, console } from "forge-std/Test.sol"; +import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; +import { ResourceType } from "@latticexyz/store/src/ResourceType.sol"; + +import { ResourceId } from "../src/ResourceId.sol"; +import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; + +contract ResourceIdTest is Test, GasReporter { + using ResourceId for bytes32; + using ResourceType for bytes32; + + function testGetNamespace() public { + bytes32 resourceId = ResourceId.encode("namespace", "name", RESOURCE_SYSTEM); + + startGasReport("encode namespace, name and type"); + bytes14 namespace = resourceId.getNamespace(); + endGasReport(); + + assertEq(namespace, "namespace"); + } + + function testGetNamespaceId() public { + bytes32 resourceId = ResourceId.encode("namespace", "name", RESOURCE_SYSTEM); + + startGasReport("get namespace ID from a resource ID"); + bytes32 namespaceId = resourceId.getNamespaceId(); + endGasReport(); + + assertEq(namespaceId, ResourceId.encodeNamespace("namespace")); + } + + function testGetType() public { + bytes32 resourceId = ResourceId.encode("namespace", "name", RESOURCE_SYSTEM); + + startGasReport("get type from a resource ID"); + bytes2 resourceType = resourceId.getType(); + endGasReport(); + + assertEq(resourceType, "sy"); + } + + function testIsType() public { + bytes32 resourceId = ResourceId.encode("namespace", "name", RESOURCE_SYSTEM); + + startGasReport("check if a resource ID has a given type"); + bool isType = resourceId.isType(RESOURCE_SYSTEM); + endGasReport(); + + assertTrue(isType); + } + + function testMatchResourceTypeEncoding() public { + bytes32 resourceId = ResourceId.encode("namespace", "name", RESOURCE_SYSTEM); + bytes30 resourceIdWithoutType = bytes30(resourceId); + assertEq(resourceId, ResourceType.encode(resourceIdWithoutType, RESOURCE_SYSTEM)); + } + + function testFuzz(bytes14 namespace, bytes16 name, bytes2 resourceType) public { + bytes32 resourceId = ResourceId.encode(namespace, name, resourceType); + assertEq(resourceId.getNamespace(), namespace); + assertEq(resourceId.getNamespaceId(), ResourceId.encodeNamespace(namespace)); + assertEq(resourceId.getNamespaceId().getNamespace(), namespace); + assertEq(resourceId.getName(), name); + assertEq(resourceId.getType(), resourceType); + } +} diff --git a/packages/world/test/StandardDelegationsModule.t.sol b/packages/world/test/StandardDelegationsModule.t.sol index 28006e43c4..16c9245a84 100644 --- a/packages/world/test/StandardDelegationsModule.t.sol +++ b/packages/world/test/StandardDelegationsModule.t.sol @@ -5,13 +5,17 @@ import { Test } from "forge-std/Test.sol"; import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; import { World } from "../src/World.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; -import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; +import { ResourceId } from "../src/ResourceId.sol"; import { System } from "../src/System.sol"; +import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; + +import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; import { DELEGATION_CONTROL_INTERFACE_ID } from "../src/interfaces/IDelegationControl.sol"; + import { CoreModule } from "../src/modules/core/CoreModule.sol"; import { Systems } from "../src/modules/core/tables/Systems.sol"; + import { StandardDelegationsModule } from "../src/modules/std-delegations/StandardDelegationsModule.sol"; import { CallboundDelegationControl } from "../src/modules/std-delegations/CallboundDelegationControl.sol"; import { TimeboundDelegationControl } from "../src/modules/std-delegations/TimeboundDelegationControl.sol"; @@ -21,7 +25,7 @@ import { WorldTestSystem } from "./World.t.sol"; contract StandardDelegationsModuleTest is Test, GasReporter { IBaseWorld private world; - bytes32 private systemResourceSelector = ResourceSelector.from("namespace", "testSystem"); + bytes32 private systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); address private delegator = address(1); address private delegatee = address(2); @@ -32,7 +36,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { // Register a new system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(systemResourceSelector, system, true); + world.registerSystem(systemId, system, true); } function testCallFromCallboundDelegation() public { @@ -44,7 +48,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { CALLBOUND_DELEGATION, abi.encodeCall( CallboundDelegationControl.initDelegation, - (delegatee, systemResourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ()), 1) + (delegatee, systemId, abi.encodeCall(WorldTestSystem.msgSender, ()), 1) ) ); endGasReport(); @@ -54,7 +58,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { startGasReport("call a system via a callbound delegation"); bytes memory returnData = world.callFrom( delegator, - systemResourceSelector, + systemId, abi.encodeCall(WorldTestSystem.msgSender, ()) ); endGasReport(); @@ -66,7 +70,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { // Expect the delegation to have been used up vm.prank(delegatee); vm.expectRevert(abi.encodeWithSelector(IWorldErrors.DelegationNotFound.selector, delegator, delegatee)); - world.callFrom(delegator, systemResourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); } function testCallFromTimeboundDelegation() public { @@ -90,7 +94,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { startGasReport("call a system via a timebound delegation"); bytes memory returnData = world.callFrom( delegator, - systemResourceSelector, + systemId, abi.encodeCall(WorldTestSystem.msgSender, ()) ); endGasReport(); @@ -102,19 +106,19 @@ contract StandardDelegationsModuleTest is Test, GasReporter { // Set the timestamp to maxTimestamp and expect the delegation to still be valid vm.warp(maxTimestamp); vm.prank(delegatee); - world.callFrom(delegator, systemResourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); // Set the timestamp to maxTimestamp+1 and expect the delegation to be expired vm.warp(maxTimestamp + 1); vm.prank(delegatee); vm.expectRevert(abi.encodeWithSelector(IWorldErrors.DelegationNotFound.selector, delegator, delegatee)); - world.callFrom(delegator, systemResourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); } function testRegisterDelegationRevertInterfaceNotSupported() public { // Register a system that is not a delegation control system System noDelegationControlSystem = new System(); - bytes32 noDelegationControlId = ResourceSelector.from("namespace", "noDelegation"); + bytes32 noDelegationControlId = ResourceId.encode("namespace", "noDelegation", RESOURCE_SYSTEM); world.registerSystem(noDelegationControlId, noDelegationControlSystem, true); // Expect the registration to revert if the system does not implement the delegation control interface diff --git a/packages/world/test/UniqueEntityModule.t.sol b/packages/world/test/UniqueEntityModule.t.sol index 22db658279..258e902e6f 100644 --- a/packages/world/test/UniqueEntityModule.t.sol +++ b/packages/world/test/UniqueEntityModule.t.sol @@ -14,14 +14,15 @@ import { UniqueEntity } from "../src/modules/uniqueentity/tables/UniqueEntity.so import { getUniqueEntity } from "../src/modules/uniqueentity/getUniqueEntity.sol"; import { NAMESPACE, TABLE_NAME } from "../src/modules/uniqueentity/constants.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; +import { RESOURCE_TABLE } from "../src/worldResourceTypes.sol"; contract UniqueEntityModuleTest is Test, GasReporter { - using ResourceSelector for bytes32; + using ResourceId for bytes32; IBaseWorld world; UniqueEntityModule uniqueEntityModule = new UniqueEntityModule(); - bytes32 tableId = ResourceSelector.from(NAMESPACE, TABLE_NAME); + bytes32 tableId = ResourceId.encode(NAMESPACE, TABLE_NAME, RESOURCE_TABLE); function setUp() public { world = IBaseWorld(address(new World())); @@ -78,7 +79,7 @@ contract UniqueEntityModuleTest is Test, GasReporter { vm.expectRevert( abi.encodeWithSelector( IWorldErrors.AccessDenied.selector, - ResourceSelector.from(NAMESPACE, TABLE_NAME).toString(), + ResourceId.encode(NAMESPACE, TABLE_NAME, RESOURCE_TABLE).toString(), alice ) ); diff --git a/packages/world/test/Utils.t.sol b/packages/world/test/Utils.t.sol index d3def80af0..1fb78bf5b6 100644 --- a/packages/world/test/Utils.t.sol +++ b/packages/world/test/Utils.t.sol @@ -7,7 +7,8 @@ import { Utils } from "../src/Utils.sol"; import { System } from "../src/System.sol"; import { World } from "../src/World.sol"; import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; +import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; import { CoreModule } from "../src/modules/core/CoreModule.sol"; @@ -18,7 +19,7 @@ contract UtilsTestSystem is System { } contract UtilsTest is Test { - using ResourceSelector for bytes32; + using ResourceId for bytes32; IBaseWorld internal world; error SomeError(uint256 someValue, string someString); @@ -28,20 +29,19 @@ contract UtilsTest is Test { world.initialize(new CoreModule()); } - function _registerAndGetNamespace(bytes16 namespace) internal returns (bytes16 returnedNamespace) { + function _registerAndGetNamespace(bytes14 namespace) internal returns (bytes16 returnedNamespace) { UtilsTestSystem testSystem = new UtilsTestSystem(); bytes16 name = "testSystem"; - world.registerSystem(ResourceSelector.from(namespace, name), testSystem, true); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); + world.registerSystem(systemId, testSystem, true); + + bytes memory data = world.call(systemId, abi.encodeCall(UtilsTestSystem.systemNamespace, ())); - bytes memory data = world.call( - ResourceSelector.from(namespace, name), - abi.encodeCall(UtilsTestSystem.systemNamespace, ()) - ); returnedNamespace = abi.decode(data, (bytes16)); } function testSystemNamespace() public { - bytes16 namespace; + bytes14 namespace; bytes16 returnedNamespace; namespace = ""; @@ -52,7 +52,7 @@ contract UtilsTest is Test { returnedNamespace = _registerAndGetNamespace(namespace); assertEq(returnedNamespace, namespace); - namespace = "maxlen_namespace"; + namespace = "max_len_nmspce"; returnedNamespace = _registerAndGetNamespace(namespace); assertEq(returnedNamespace, namespace); } diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index 9194959b2d..3a3e2acb57 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -import { Test } from "forge-std/Test.sol"; +import { Test, console } from "forge-std/Test.sol"; import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; @@ -23,8 +23,9 @@ import { EchoSubscriber } from "@latticexyz/store/test/EchoSubscriber.sol"; import { WORLD_VERSION } from "../src/version.sol"; import { World } from "../src/World.sol"; import { System } from "../src/System.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; import { ROOT_NAMESPACE, ROOT_NAME, UNLIMITED_DELEGATION } from "../src/constants.sol"; +import { RESOURCE_TABLE, RESOURCE_SYSTEM, RESOURCE_NAMESPACE } from "../src/worldResourceTypes.sol"; import { Resource } from "../src/common.sol"; import { WorldContextProvider, WORLD_CONTEXT_CONSUMER_INTERFACE_ID } from "../src/WorldContext.sol"; import { SystemHook } from "../src/SystemHook.sol"; @@ -88,9 +89,9 @@ contract WorldTestSystem is System { return returndata; } - function writeData(bytes16 namespace, bytes16 name, bool data) public { + function writeData(bytes14 namespace, bytes16 name, bool data) public { bytes32[] memory keyTuple = new bytes32[](0); - bytes32 tableId = ResourceSelector.from(namespace, name); + bytes32 tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); FieldLayout fieldLayout = StoreSwitch.getFieldLayout(tableId); if (StoreSwitch.getStoreAddress() == address(this)) { @@ -136,12 +137,12 @@ contract PayableFallbackSystem is System { contract EchoSystemHook is SystemHook { event SystemHookCalled(bytes data); - function onBeforeCallSystem(address msgSender, bytes32 resourceSelector, bytes memory callData) public { - emit SystemHookCalled(abi.encode("before", msgSender, resourceSelector, callData)); + function onBeforeCallSystem(address msgSender, bytes32 systemId, bytes memory callData) public { + emit SystemHookCalled(abi.encode("before", msgSender, systemId, callData)); } - function onAfterCallSystem(address msgSender, bytes32 resourceSelector, bytes memory callData) public { - emit SystemHookCalled(abi.encode("after", msgSender, resourceSelector, callData)); + function onAfterCallSystem(address msgSender, bytes32 systemId, bytes memory callData) public { + emit SystemHookCalled(abi.encode("after", msgSender, systemId, callData)); } } @@ -158,7 +159,7 @@ contract RevertSystemHook is SystemHook { } contract WorldTest is Test, GasReporter { - using ResourceSelector for bytes32; + using ResourceId for bytes32; event HelloWorld(bytes32 indexed worldVersion); event HookCalled(bytes data); @@ -183,12 +184,12 @@ contract WorldTest is Test, GasReporter { } // Expect an error when trying to write from an address that doesn't have access - function _expectAccessDenied(address caller, bytes16 namespace, bytes16 name) internal { + function _expectAccessDenied(address caller, bytes14 namespace, bytes16 name, bytes2 resourceType) internal { vm.prank(caller); vm.expectRevert( abi.encodeWithSelector( IWorldErrors.AccessDenied.selector, - ResourceSelector.from(namespace, name).toString(), + ResourceId.encode(namespace, name, resourceType).toString(), caller ) ); @@ -209,7 +210,7 @@ contract WorldTest is Test, GasReporter { vm.expectRevert( abi.encodeWithSelector( IWorldErrors.AccessDenied.selector, - ResourceSelector.from(ROOT_NAMESPACE).toString(), + ResourceId.encodeNamespace(ROOT_NAMESPACE).toString(), address(0x4242) ) ); @@ -273,70 +274,80 @@ contract WorldTest is Test, GasReporter { function testStoreAddress() public { // Register a system and use it to get storeAddress WorldTestSystem system = new WorldTestSystem(); - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); - world.registerSystem(resourceSelector, system, false); - bytes memory result = world.call(resourceSelector, abi.encodeCall(WorldTestSystem.getStoreAddress, ())); + world.registerSystem(systemId, system, false); + bytes memory result = world.call(systemId, abi.encodeCall(WorldTestSystem.getStoreAddress, ())); assertEq(abi.decode(result, (address)), address(world)); } function testRegisterNamespace() public { + bytes14 namespace = "testNamespace"; startGasReport("Register a new namespace"); - world.registerNamespace("test"); + world.registerNamespace(namespace); endGasReport(); // Expect the caller to be the namespace owner - assertEq(NamespaceOwner.get(world, "test"), address(this), "caller should be namespace owner"); + assertEq(NamespaceOwner.get(world, namespace), address(this), "caller should be namespace owner"); // Expect the caller to have access - assertEq(ResourceAccess.get(world, "test", address(this)), true, "caller should have access"); + assertEq( + ResourceAccess.get(world, ResourceId.encodeNamespace(namespace), address(this)), + true, + "caller should have access" + ); // Expect an error when registering an existing namespace vm.expectRevert( - abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, ResourceSelector.toString(bytes16("test"))) + abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, ResourceId.encodeNamespace(namespace).toString()) ); - world.registerNamespace("test"); + world.registerNamespace(namespace); } function testTransferNamespace() public { - world.registerNamespace("testTransfer"); + bytes14 namespace = "testTransfer"; + bytes32 namespaceId = ResourceId.encodeNamespace(namespace); + + world.registerNamespace(namespace); // Expect the new owner to not be namespace owner before transfer assertFalse( - (NamespaceOwner.get(world, "testTransfer") == address(1)), + (NamespaceOwner.get(world, namespace) == address(1)), "new owner should not be namespace owner before transfer" ); // Expect the new owner to not have access before transfer assertEq( - ResourceAccess.get(world, "testTransfer", address(1)), + ResourceAccess.get(world, namespaceId, address(1)), false, "new owner should not have access before transfer" ); - world.transferOwnership("testTransfer", address(1)); + world.transferOwnership(namespace, address(1)); + // Expect the new owner to be namespace owner - assertEq(NamespaceOwner.get(world, "testTransfer"), address(1), "new owner should be namespace owner"); + assertEq(NamespaceOwner.get(world, namespace), address(1), "new owner should be namespace owner"); + // Expect the new owner to have access - assertEq(ResourceAccess.get(world, "testTransfer", address(1)), true, "new owner should have access"); + assertEq(ResourceAccess.get(world, namespaceId, address(1)), true, "new owner should have access"); + // Expect previous owner to no longer be owner - assertFalse( - (NamespaceOwner.get(world, "testTransfer") == address(this)), - "caller should no longer be namespace owner" - ); + assertFalse((NamespaceOwner.get(world, namespace) == address(this)), "caller should no longer be namespace owner"); + // Expect previous owner to no longer have access - assertEq(ResourceAccess.get(world, "testTransfer", address(this)), false, "caller should no longer have access"); + assertEq(ResourceAccess.get(world, namespaceId, address(this)), false, "caller should no longer have access"); + // Expect revert if caller is not the owner - _expectAccessDenied(address(this), "testTransfer", 0); - world.transferOwnership("testTransfer", address(1)); + _expectAccessDenied(address(this), namespace, 0, RESOURCE_NAMESPACE); + world.transferOwnership(namespace, address(1)); } function testRegisterTable() public { FieldLayout fieldLayout = FieldLayoutEncodeHelper.encode(1, 32, 1); Schema valueSchema = SchemaEncodeHelper.encode(SchemaType.BOOL, SchemaType.UINT256, SchemaType.STRING); - bytes16 namespace = "testNamespace"; + bytes14 namespace = "testNamespace"; bytes16 tableName = "testTable"; - bytes32 tableSelector = ResourceSelector.from(namespace, tableName); + bytes32 tableId = ResourceId.encode(namespace, tableName, RESOURCE_TABLE); string[] memory keyNames = new string[](1); keyNames[0] = "key1"; string[] memory fieldNames = new string[](3); @@ -345,79 +356,80 @@ contract WorldTest is Test, GasReporter { fieldNames[2] = "value3"; startGasReport("Register a new table in the namespace"); - world.registerTable(tableSelector, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); + world.registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); endGasReport(); // Expect the namespace to be created and owned by the caller assertEq(NamespaceOwner.get(world, namespace), address(this), "namespace should be created by caller"); // Expect the table to be registered - assertEq(world.getFieldLayout(tableSelector).unwrap(), fieldLayout.unwrap(), "value schema should be registered"); + assertEq(world.getFieldLayout(tableId).unwrap(), fieldLayout.unwrap(), "value schema should be registered"); - bytes memory loadedKeyNames = Tables.getAbiEncodedKeyNames(world, tableSelector); + bytes memory loadedKeyNames = Tables.getAbiEncodedKeyNames(world, tableId); assertEq(loadedKeyNames, abi.encode(keyNames), "key names should be registered"); - bytes memory loadedfieldNames = Tables.getAbiEncodedFieldNames(world, tableSelector); + bytes memory loadedfieldNames = Tables.getAbiEncodedFieldNames(world, tableId); assertEq(loadedfieldNames, abi.encode(fieldNames), "value names should be registered"); // Expect an error when registering an existing table - vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, tableSelector.toString())); - world.registerTable(tableSelector, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, tableId.toString())); + world.registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); // Expect an error when registering a table in a namespace that is not owned by the caller - bytes32 otherTableSelector = ResourceSelector.from(namespace, "otherTable"); - _expectAccessDenied(address(0x01), namespace, ""); - world.registerTable(otherTableSelector, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); + bytes32 otherTableId = ResourceId.encode(namespace, "otherTable", RESOURCE_TABLE); + _expectAccessDenied(address(0x01), namespace, "", RESOURCE_NAMESPACE); + world.registerTable(otherTableId, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); // Expect the World to not be allowed to call registerTable via an external call - _expectAccessDenied(address(world), namespace, ""); - world.registerTable(otherTableSelector, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); + _expectAccessDenied(address(world), namespace, "", RESOURCE_NAMESPACE); + world.registerTable(otherTableId, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); } function testRegisterSystem() public { System system = new System(); - bytes16 namespace = ""; + bytes14 namespace = ""; + bytes32 namespaceId = ResourceId.encodeNamespace(namespace); bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); // !gasrepot Register a new system - world.registerSystem(resourceSelector, system, false); + world.registerSystem(systemId, system, false); // Expect the system to be registered - (address registeredAddress, bool publicAccess) = Systems.get(world, resourceSelector); + (address registeredAddress, bool publicAccess) = Systems.get(world, systemId); assertEq(registeredAddress, address(system)); // Expect the system namespace to be owned by the caller - address routeOwner = NamespaceOwner.get(world, ""); + address routeOwner = NamespaceOwner.get(world, namespace); assertEq(routeOwner, address(this)); // Expect the system to not be publicly accessible assertFalse(publicAccess); // Expect the system to be accessible by the caller - assertTrue(ResourceAccess.get({ _store: world, resourceSelector: "", caller: address(this) })); + assertTrue(ResourceAccess.get({ _store: world, resourceId: namespaceId, caller: address(this) })); // Expect the system to not be accessible by another address - assertFalse(ResourceAccess.get({ _store: world, resourceSelector: "", caller: address(0x1) })); + assertFalse(ResourceAccess.get({ _store: world, resourceId: namespaceId, caller: address(0x1) })); // Expect the system to have access to its own namespace - assertTrue(ResourceAccess.get({ _store: world, resourceSelector: "", caller: address(system) })); + assertTrue(ResourceAccess.get({ _store: world, resourceId: namespaceId, caller: address(system) })); // Expect the namespace to be created if it doesn't exist yet assertEq(NamespaceOwner.get(world, "newNamespace"), address(0)); - world.registerSystem(ResourceSelector.from("newNamespace", "testSystem"), new System(), false); + world.registerSystem(ResourceId.encode("newNamespace", "testSystem", RESOURCE_SYSTEM), new System(), false); assertEq(NamespaceOwner.get(world, "newNamespace"), address(this)); - // Expect an error when registering an existing system at a new resource selector + // Expect an error when registering an existing system at a new system ID vm.expectRevert(abi.encodeWithSelector(IWorldErrors.SystemExists.selector, address(system))); - world.registerSystem(ResourceSelector.from("", "newSystem"), system, true); + world.registerSystem(ResourceId.encode("", "newSystem", RESOURCE_SYSTEM), system, true); // Don't expect an error when updating the public access of an existing system - world.registerSystem(resourceSelector, system, true); + world.registerSystem(systemId, system, true); - // Expect an error when registering a system at an existing resource selector of a different type + // Expect an error when registering a system at an existing resource ID of a different type System newSystem = new System(); - bytes32 tableId = ResourceSelector.from("", "testTable"); + bytes32 tableId = ResourceId.encode("", "testTable", RESOURCE_TABLE); world.registerTable( tableId, Bool.getFieldLayout(), @@ -429,14 +441,14 @@ contract WorldTest is Test, GasReporter { vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, tableId.toString())); world.registerSystem(tableId, newSystem, true); - // Expect an error when registering a system in a namespace is not owned by the caller + // Expect an error when registering a system in a namespace that is not owned by the caller System yetAnotherSystem = new System(); - _expectAccessDenied(address(0x01), "", ""); - world.registerSystem(ResourceSelector.from("", "rootSystem"), yetAnotherSystem, true); + _expectAccessDenied(address(0x01), "", "", RESOURCE_NAMESPACE); + world.registerSystem(ResourceId.encode("", "rootSystem", RESOURCE_SYSTEM), yetAnotherSystem, true); // Expect the registration to fail when coming from the World (since the World address doesn't have access) - _expectAccessDenied(address(world), "", ""); - world.registerSystem(ResourceSelector.from("", "rootSystem"), yetAnotherSystem, true); + _expectAccessDenied(address(world), "", "", RESOURCE_NAMESPACE); + world.registerSystem(ResourceId.encode("", "rootSystem", RESOURCE_SYSTEM), yetAnotherSystem, true); // Expect the registration to fail if the provided address does not implement the WorldContextConsumer interface vm.expectRevert( @@ -446,13 +458,18 @@ contract WorldTest is Test, GasReporter { WORLD_CONTEXT_CONSUMER_INTERFACE_ID ) ); - world.registerSystem(ResourceSelector.from("someNamespace", "invalidSystem"), System(address(world)), true); + world.registerSystem( + ResourceId.encode("someNamespace", "invalidSystem", RESOURCE_SYSTEM), + System(address(world)), + true + ); } function testUpgradeSystem() public { - bytes16 namespace = "testNamespace"; + bytes14 namespace = "testNamespace"; + bytes32 namespaceId = ResourceId.encodeNamespace(namespace); bytes16 systemName = "testSystem"; - bytes32 systemId = ResourceSelector.from(namespace, systemName); + bytes32 systemId = ResourceId.encode(namespace, systemName, RESOURCE_SYSTEM); // Register a system System oldSystem = new System(); @@ -464,32 +481,38 @@ contract WorldTest is Test, GasReporter { // Expect the system address and public access to be updated in the System table (address registeredAddress, bool publicAccess) = Systems.get(world, systemId); - assertEq(registeredAddress, address(newSystem)); - assertEq(publicAccess, false); + assertEq(registeredAddress, address(newSystem), "system address should be updated"); + assertEq(publicAccess, false, "public access should be updated"); // Expect the SystemRegistry table to not have a reference to the old system anymore bytes32 registeredSystemId = SystemRegistry.get(world, address(oldSystem)); - assertEq(registeredSystemId, bytes32(0)); + assertEq(registeredSystemId, bytes32(0), "old system should be removed from SystemRegistry"); // Expect the SystemRegistry table to have a reference to the new system registeredSystemId = SystemRegistry.get(world, address(newSystem)); - assertEq(registeredSystemId, systemId); + assertEq(registeredSystemId, systemId, "new system should be added to SystemRegistry"); // Expect the old system to not have access to the namespace anymore - assertFalse(ResourceAccess.get(world, namespace, address(oldSystem))); + assertFalse( + ResourceAccess.get(world, namespaceId, address(oldSystem)), + "old system should not have access to the namespace" + ); // Expect the new system to have access to the namespace - assertTrue(ResourceAccess.get(world, namespace, address(newSystem))); + assertTrue( + ResourceAccess.get(world, namespaceId, address(newSystem)), + "new system should have access to the namespace" + ); // Expect the resource type to still be SYSTEM - assertEq(uint8(ResourceType.get(world, systemId)), uint8(Resource.SYSTEM)); + assertEq(uint8(ResourceType.get(world, systemId)), uint8(Resource.SYSTEM), "resource type should still be SYSTEM"); } function testDuplicateSelectors() public { // Register a new table - bytes32 resourceSelector = ResourceSelector.from("namespace", "name"); + bytes32 tableId = ResourceId.encode("namespace", "name", RESOURCE_TABLE); world.registerTable( - resourceSelector, + tableId, Bool.getFieldLayout(), defaultKeySchema, Bool.getValueSchema(), @@ -501,17 +524,17 @@ contract WorldTest is Test, GasReporter { System system = new System(); // Expect an error when trying to register a system at the same selector - vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, resourceSelector.toString())); - world.registerSystem(resourceSelector, system, false); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, tableId.toString())); + world.registerSystem(tableId, system, false); // Register a new system - bytes32 resourceSelector2 = ResourceSelector.from("namespace2", "name"); - world.registerSystem(resourceSelector2, new System(), false); + bytes32 systemId = ResourceId.encode("namespace2", "name", RESOURCE_SYSTEM); + world.registerSystem(systemId, new System(), false); // Expect an error when trying to register a table at the same selector - vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, resourceSelector2.toString())); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.ResourceExists.selector, systemId.toString())); world.registerTable( - resourceSelector2, + systemId, Bool.getFieldLayout(), defaultKeySchema, Bool.getValueSchema(), @@ -529,7 +552,7 @@ contract WorldTest is Test, GasReporter { } function testSetRecord() public { - bytes32 tableId = ResourceSelector.from("testSetRecord", "testTable"); + bytes32 tableId = ResourceId.encode("testSetRecord", "testTable", RESOURCE_TABLE); // Register a new table world.registerTable( tableId, @@ -548,7 +571,7 @@ contract WorldTest is Test, GasReporter { assertTrue(Bool.get(world, tableId)); // Expect an error when trying to write from an address that doesn't have access - _expectAccessDenied(address(0x01), "testSetRecord", "testTable"); + _expectAccessDenied(address(0x01), "testSetRecord", "testTable", RESOURCE_TABLE); Bool.set(world, tableId, true); // Expect the World to have access @@ -557,9 +580,9 @@ contract WorldTest is Test, GasReporter { } function testSetField() public { - bytes16 namespace = "testSetField"; + bytes14 namespace = "testSetField"; bytes16 name = "testTable"; - bytes32 tableId = ResourceSelector.from(namespace, name); + bytes32 tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); FieldLayout fieldLayout = Bool.getFieldLayout(); Schema valueSchema = Bool.getValueSchema(); @@ -574,7 +597,7 @@ contract WorldTest is Test, GasReporter { assertTrue(Bool.get(world, tableId)); // Expect an error when trying to write from an address that doesn't have access - _expectAccessDenied(address(0x01), "testSetField", "testTable"); + _expectAccessDenied(address(0x01), "testSetField", "testTable", RESOURCE_TABLE); world.setField(tableId, singletonKey, 0, abi.encodePacked(true), fieldLayout); // Expect the World to have access @@ -583,9 +606,9 @@ contract WorldTest is Test, GasReporter { } function testPushToField() public { - bytes16 namespace = "testPushToField"; + bytes14 namespace = "testPushField"; bytes16 name = "testTable"; - bytes32 tableId = ResourceSelector.from(namespace, name); + bytes32 tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); FieldLayout fieldLayout = AddressArray.getFieldLayout(); Schema valueSchema = AddressArray.getValueSchema(); @@ -616,7 +639,7 @@ contract WorldTest is Test, GasReporter { assertEq(AddressArray.get(world, tableId, key), dataToPush); // Expect an error when trying to write from an address that doesn't have access - _expectAccessDenied(address(0x01), namespace, name); + _expectAccessDenied(address(0x01), namespace, name, RESOURCE_TABLE); world.pushToField(tableId, keyTuple, 0, encodedData, fieldLayout); // Expect the World to have access @@ -625,9 +648,9 @@ contract WorldTest is Test, GasReporter { } function testDeleteRecord() public { - bytes16 namespace = "testDeleteRecord"; + bytes14 namespace = "testDeleteReco"; bytes16 name = "testTable"; - bytes32 tableId = ResourceSelector.from(namespace, name); + bytes32 tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); FieldLayout fieldLayout = Bool.getFieldLayout(); Schema valueSchema = Bool.getValueSchema(); @@ -665,7 +688,7 @@ contract WorldTest is Test, GasReporter { assertTrue(Bool.get(world, tableId)); // Expect an error when trying to delete from an address that doesn't have access - _expectAccessDenied(address(0x02), "testDeleteRecord", "testTable"); + _expectAccessDenied(address(0x02), namespace, name, RESOURCE_TABLE); world.deleteRecord(tableId, singletonKey, fieldLayout); // Expect the World to have access @@ -676,19 +699,19 @@ contract WorldTest is Test, GasReporter { function testCall() public { // Register a new system WorldTestSystem system = new WorldTestSystem(); - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); - world.registerSystem(resourceSelector, system, false); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); + world.registerSystem(systemId, system, false); // Call a system function without arguments via the World startGasReport("call a system via the World"); - bytes memory result = world.call(resourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + bytes memory result = world.call(systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); endGasReport(); // Expect the system to have received the caller's address assertEq(address(uint160(uint256(bytes32(result)))), address(this)); // Call a system function with arguments via the World - result = world.call(resourceSelector, abi.encodeCall(WorldTestSystem.echo, (bytes32(uint256(0x123))))); + result = world.call(systemId, abi.encodeCall(WorldTestSystem.echo, (bytes32(uint256(0x123))))); // Expect the return data to be decodeable as a tuple (address returnedAddress, bytes32 returnedBytes32) = abi.decode(result, (address, bytes32)); @@ -701,33 +724,30 @@ contract WorldTest is Test, GasReporter { assertEq(returnStruct.input, bytes32(uint256(0x123))); // Expect an error when trying to call a private system from an address that doesn't have access - _expectAccessDenied(address(0x01), "namespace", "testSystem"); - world.call(resourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + _expectAccessDenied(address(0x01), "namespace", "testSystem", RESOURCE_SYSTEM); + world.call(systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); // Expect the World to have access vm.prank(address(world)); - world.call(resourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + world.call(systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); // Expect errors from the system to be forwarded vm.expectRevert(abi.encodeWithSelector(WorldTestSystem.WorldTestSystemError.selector, "test error")); - world.call(resourceSelector, abi.encodeCall(WorldTestSystem.err, ("test error"))); + world.call(systemId, abi.encodeCall(WorldTestSystem.err, ("test error"))); // Register another system in the same namespace WorldTestSystem subSystem = new WorldTestSystem(); - bytes32 subsystemResourceSelector = ResourceSelector.from("namespace", "testSubSystem"); - world.registerSystem(subsystemResourceSelector, subSystem, false); + bytes32 subsystemId = ResourceId.encode("namespace", "testSubSystem", RESOURCE_SYSTEM); + world.registerSystem(subsystemId, subSystem, false); // Call the subsystem via the World (with access to the base route) - returnedAddress = abi.decode( - world.call(subsystemResourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())), - (address) - ); + returnedAddress = abi.decode(world.call(subsystemId, abi.encodeCall(WorldTestSystem.msgSender, ())), (address)); assertEq(returnedAddress, address(this)); // Call the subsystem via delegatecall from the system // (Note: just for testing purposes, in reality systems can call subsystems directly instead of via two indirections like here) bytes memory nestedReturndata = world.call( - resourceSelector, + systemId, abi.encodeCall( WorldTestSystem.delegateCallSubSystem, // Function in system ( @@ -748,14 +768,14 @@ contract WorldTest is Test, GasReporter { function testCallFromSelf() public { // Register a new system WorldTestSystem system = new WorldTestSystem(); - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); - world.registerSystem(resourceSelector, system, true); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); address caller = address(1); // Call a system via callFrom with the own address vm.prank(caller); - bytes memory returnData = world.callFrom(caller, resourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + bytes memory returnData = world.callFrom(caller, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); address returnedAddress = abi.decode(returnData, (address)); // Expect the system to have received the delegator's address @@ -765,8 +785,8 @@ contract WorldTest is Test, GasReporter { function testCallFromUnlimitedDelegation() public { // Register a new system WorldTestSystem system = new WorldTestSystem(); - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); - world.registerSystem(resourceSelector, system, true); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); // Register an unlimited delegation address delegator = address(1); @@ -779,11 +799,7 @@ contract WorldTest is Test, GasReporter { // Call a system from the delegatee on behalf of the delegator vm.prank(delegatee); startGasReport("call a system via an unlimited delegation"); - bytes memory returnData = world.callFrom( - delegator, - resourceSelector, - abi.encodeCall(WorldTestSystem.msgSender, ()) - ); + bytes memory returnData = world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); endGasReport(); address returnedAddress = abi.decode(returnData, (address)); @@ -794,8 +810,8 @@ contract WorldTest is Test, GasReporter { function testCallFromFailDelegationNotFound() public { // Register a new system WorldTestSystem system = new WorldTestSystem(); - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); - world.registerSystem(resourceSelector, system, true); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); // Expect a revert when attempting to perform a call on behalf of an address that doesn't have a delegation vm.expectRevert( @@ -806,14 +822,14 @@ contract WorldTest is Test, GasReporter { ) ); vm.prank(address(1)); - world.callFrom(address(2), resourceSelector, abi.encodeCall(WorldTestSystem.msgSender, ())); + world.callFrom(address(2), systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); } function testCallFromLimitedDelegation() public { // Register a new system WorldTestSystem system = new WorldTestSystem(); - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); - world.registerSystem(resourceSelector, system, true); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); // Register a limited delegation address delegator = address(1); @@ -825,7 +841,7 @@ contract WorldTest is Test, GasReporter { function testRegisterStoreHook() public { FieldLayout fieldLayout = Bool.getFieldLayout(); Schema valueSchema = Bool.getValueSchema(); - bytes32 tableId = ResourceSelector.from("", "testTable"); + bytes32 tableId = ResourceId.encode("", "testTable", RESOURCE_TABLE); // Register a new table world.registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](1)); @@ -898,7 +914,7 @@ contract WorldTest is Test, GasReporter { function testUnregisterStoreHook() public { FieldLayout fieldLayout = Bool.getFieldLayout(); Schema valueSchema = Bool.getValueSchema(); - bytes32 tableId = ResourceSelector.from("", "testTable"); + bytes32 tableId = ResourceId.encode("", "testTable", RESOURCE_TABLE); // Register a new table world.registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](1)); @@ -977,11 +993,11 @@ contract WorldTest is Test, GasReporter { } function testRegisterSystemHook() public { - bytes32 systemId = ResourceSelector.from("namespace", "testTable"); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); // Register a new system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(systemId, system, false); + world.registerSystem(systemId, system, true); // Expect the registration to fail if the contract does not implement the system hook interface vm.expectRevert( @@ -1014,7 +1030,7 @@ contract WorldTest is Test, GasReporter { } function testUnregisterSystemHook() public { - bytes32 systemId = ResourceSelector.from("namespace", "testTable"); + bytes32 systemId = ResourceId.encode("namespace", "testTable", RESOURCE_SYSTEM); // Register a new system WorldTestSystem system = new WorldTestSystem(); @@ -1052,7 +1068,7 @@ contract WorldTest is Test, GasReporter { } function testWriteRootSystem() public { - bytes32 tableId = ResourceSelector.from("namespace", "testTable"); + bytes32 tableId = ResourceId.encode("namespace", "testTable", RESOURCE_TABLE); // Register a new table world.registerTable( tableId, @@ -1064,22 +1080,19 @@ contract WorldTest is Test, GasReporter { ); // Register a new system - bytes32 rootSystemId = ResourceSelector.from("", "testSystem"); + bytes32 rootSystemId = ResourceId.encode("", "testSystem", RESOURCE_SYSTEM); WorldTestSystem system = new WorldTestSystem(); world.registerSystem(rootSystemId, system, false); // Call a system function that writes data to the World - world.call( - rootSystemId, - abi.encodeCall(WorldTestSystem.writeData, (bytes16("namespace"), bytes16("testTable"), true)) - ); + world.call(rootSystemId, abi.encodeCall(WorldTestSystem.writeData, ("namespace", "testTable", true))); // Expect the data to be written assertTrue(Bool.get(world, tableId)); } function testWriteAutonomousSystem() public { - bytes32 tableId = ResourceSelector.from("namespace", "testTable"); + bytes32 tableId = ResourceId.encode("namespace", "testTable", RESOURCE_TABLE); // Register a new table world.registerTable( tableId, @@ -1091,52 +1104,52 @@ contract WorldTest is Test, GasReporter { ); // Register a new system - bytes32 systemId = ResourceSelector.from("namespace", "testSystem"); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_TABLE); WorldTestSystem system = new WorldTestSystem(); world.registerSystem(systemId, system, false); // Call a system function that writes data to the World - world.call(systemId, abi.encodeCall(WorldTestSystem.writeData, (bytes16("namespace"), bytes16("testTable"), true))); + world.call(systemId, abi.encodeCall(WorldTestSystem.writeData, ("namespace", "testTable", true))); // Expect the data to be written assertTrue(Bool.get(world, tableId)); } function testDelegatecallRootSystem() public { - bytes32 resourceSelector = ResourceSelector.from("", "testSystem"); + bytes32 systemId = ResourceId.encode("", "testSystem", RESOURCE_SYSTEM); // Register a new root system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(resourceSelector, system, false); + world.registerSystem(systemId, system, false); // Call the root sysyem vm.expectEmit(true, true, true, true); emit WorldTestSystemLog("delegatecall"); - world.call(resourceSelector, abi.encodeCall(WorldTestSystem.emitCallType, ())); + world.call(systemId, abi.encodeCall(WorldTestSystem.emitCallType, ())); } function testCallAutonomousSystem() public { - bytes32 resourceSelector = ResourceSelector.from("namespace", "testSystem"); + bytes32 systemId = ResourceId.encode("namespace", "testSystem", RESOURCE_SYSTEM); // Register a new non-root system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(resourceSelector, system, false); + world.registerSystem(systemId, system, false); // Call the sysyem vm.expectEmit(true, true, true, true); emit WorldTestSystemLog("call"); - world.call(resourceSelector, abi.encodeCall(WorldTestSystem.emitCallType, ())); + world.call(systemId, abi.encodeCall(WorldTestSystem.emitCallType, ())); } function testRegisterFunctionSelector() public { - bytes16 namespace = "testNamespace"; + bytes14 namespace = "testNamespace"; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); // Register a new system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(resourceSelector, system, true); + world.registerSystem(systemId, system, true); startGasReport("Register a function selector"); - bytes4 functionSelector = world.registerFunctionSelector(resourceSelector, "msgSender", "()"); + bytes4 functionSelector = world.registerFunctionSelector(systemId, "msgSender", "()"); endGasReport(); string memory expectedWorldFunctionSignature = "testNamespace_testSystem_msgSender()"; @@ -1150,7 +1163,7 @@ contract WorldTest is Test, GasReporter { assertEq(abi.decode(data, (address)), address(this), "wrong address returned"); // Register a function selector to the error function - functionSelector = world.registerFunctionSelector(resourceSelector, "err", "(string)"); + functionSelector = world.registerFunctionSelector(systemId, "err", "(string)"); // Expect errors to be passed through vm.expectRevert(abi.encodeWithSelector(WorldTestSystem.WorldTestSystemError.selector, "test error")); @@ -1158,27 +1171,27 @@ contract WorldTest is Test, GasReporter { } function testRegisterRootFunctionSelector() public { - bytes16 namespace = "testNamespace"; + bytes14 namespace = "testNamespace"; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); // Register a new system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(resourceSelector, system, true); + world.registerSystem(systemId, system, true); bytes4 worldFunc = bytes4(abi.encodeWithSignature("testSelector()")); bytes4 sysFunc = WorldTestSystem.msgSender.selector; // Expect an error when trying to register a root function selector from an account without access - _expectAccessDenied(address(0x01), "", ""); - world.registerRootFunctionSelector(resourceSelector, worldFunc, sysFunc); + _expectAccessDenied(address(0x01), "", "", RESOURCE_NAMESPACE); + world.registerRootFunctionSelector(systemId, worldFunc, sysFunc); // Expect the World to not be able to register a root function selector when calling the function externally - _expectAccessDenied(address(world), "", ""); - world.registerRootFunctionSelector(resourceSelector, "smth", "smth"); + _expectAccessDenied(address(world), "", "", RESOURCE_NAMESPACE); + world.registerRootFunctionSelector(systemId, "smth", "smth"); startGasReport("Register a root function selector"); - bytes4 functionSelector = world.registerRootFunctionSelector(resourceSelector, worldFunc, sysFunc); + bytes4 functionSelector = world.registerRootFunctionSelector(systemId, worldFunc, sysFunc); endGasReport(); assertEq(functionSelector, worldFunc, "wrong function selector returned"); @@ -1191,7 +1204,7 @@ contract WorldTest is Test, GasReporter { // Register a function selector to the error function functionSelector = world.registerRootFunctionSelector( - resourceSelector, + systemId, WorldTestSystem.err.selector, WorldTestSystem.err.selector ); @@ -1202,16 +1215,16 @@ contract WorldTest is Test, GasReporter { } function testRegisterFallbackSystem() public { - bytes16 namespace = "testNamespace"; + bytes14 namespace = "testNamespace"; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); // Register a new system WorldTestSystem system = new WorldTestSystem(); - world.registerSystem(resourceSelector, system, true); + world.registerSystem(systemId, system, true); startGasReport("Register a fallback system"); - bytes4 funcSelector1 = world.registerFunctionSelector(resourceSelector, "", ""); + bytes4 funcSelector1 = world.registerFunctionSelector(systemId, "", ""); endGasReport(); // Call the system's fallback function @@ -1223,7 +1236,7 @@ contract WorldTest is Test, GasReporter { bytes4 worldFunc = bytes4(abi.encodeWithSignature("testSelector()")); startGasReport("Register a root fallback system"); - bytes4 funcSelector2 = world.registerRootFunctionSelector(resourceSelector, worldFunc, 0); + bytes4 funcSelector2 = world.registerRootFunctionSelector(systemId, worldFunc, 0); endGasReport(); assertEq(funcSelector2, worldFunc, "wrong function selector returned"); @@ -1259,13 +1272,13 @@ contract WorldTest is Test, GasReporter { function testPayableSystem() public { // Register a root system with a payable function in the world WorldTestSystem system = new WorldTestSystem(); - bytes16 namespace = "noroot"; + bytes14 namespace = "noroot"; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); - world.registerSystem(resourceSelector, system, true); + world.registerSystem(systemId, system, true); world.registerRootFunctionSelector( - resourceSelector, + systemId, WorldTestSystem.receiveEther.selector, WorldTestSystem.receiveEther.selector ); @@ -1290,12 +1303,12 @@ contract WorldTest is Test, GasReporter { function testNonPayableSystem() public { // Register a non-root system with a non-payable function in the world WorldTestSystem system = new WorldTestSystem(); - bytes16 namespace = "noroot"; + bytes14 namespace = "noroot"; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); - world.registerSystem(resourceSelector, system, true); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); world.registerRootFunctionSelector( - resourceSelector, + systemId, WorldTestSystem.msgSender.selector, WorldTestSystem.msgSender.selector ); @@ -1321,15 +1334,11 @@ contract WorldTest is Test, GasReporter { function testNonPayableFallbackSystem() public { // Register a root system with a non-payable function in the world WorldTestSystem system = new WorldTestSystem(); - bytes16 namespace = ROOT_NAMESPACE; + bytes14 namespace = ROOT_NAMESPACE; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); - world.registerSystem(resourceSelector, system, true); - world.registerRootFunctionSelector( - resourceSelector, - bytes4(abi.encodeWithSignature("systemFallback()")), - bytes4("") - ); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); + world.registerRootFunctionSelector(systemId, bytes4(abi.encodeWithSignature("systemFallback()")), bytes4("")); // create new funded address and impersonate address alice = makeAddr("alice"); @@ -1351,15 +1360,11 @@ contract WorldTest is Test, GasReporter { function testPayableFallbackSystem() public { // Register a root system with a payable function in the world PayableFallbackSystem system = new PayableFallbackSystem(); - bytes16 namespace = ROOT_NAMESPACE; + bytes14 namespace = ROOT_NAMESPACE; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); - world.registerSystem(resourceSelector, system, true); - world.registerRootFunctionSelector( - resourceSelector, - bytes4(abi.encodeWithSignature("systemFallback()")), - bytes4("") - ); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); + world.registerRootFunctionSelector(systemId, bytes4(abi.encodeWithSignature("systemFallback()")), bytes4("")); // create new funded address and impersonate address alice = makeAddr("alice"); @@ -1381,12 +1386,12 @@ contract WorldTest is Test, GasReporter { function testPayableRootSystem() public { // Register a root system with a payable function in the world WorldTestSystem system = new WorldTestSystem(); - bytes16 namespace = ROOT_NAMESPACE; + bytes14 namespace = ROOT_NAMESPACE; bytes16 name = "testSystem"; - bytes32 resourceSelector = ResourceSelector.from(namespace, name); - world.registerSystem(resourceSelector, system, true); + bytes32 systemId = ResourceId.encode(namespace, name, RESOURCE_SYSTEM); + world.registerSystem(systemId, system, true); world.registerRootFunctionSelector( - resourceSelector, + systemId, WorldTestSystem.receiveEther.selector, WorldTestSystem.receiveEther.selector ); diff --git a/packages/world/test/WorldBalance.t.sol b/packages/world/test/WorldBalance.t.sol index f7225afde6..c102a18f10 100644 --- a/packages/world/test/WorldBalance.t.sol +++ b/packages/world/test/WorldBalance.t.sol @@ -6,13 +6,14 @@ import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; import { World } from "../src/World.sol"; import { System } from "../src/System.sol"; import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; import { ROOT_NAMESPACE } from "../src/constants.sol"; import { CoreModule } from "../src/modules/core/CoreModule.sol"; import { Balances } from "../src/modules/core/tables/Balances.sol"; import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; +import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; -using ResourceSelector for bytes32; +using ResourceId for bytes32; contract WorldBalanceTestSystem is System { function echoValue() public payable returns (uint256) { @@ -24,9 +25,9 @@ contract WorldBalanceTest is Test, GasReporter { IBaseWorld public world; WorldBalanceTestSystem public rootSystem = new WorldBalanceTestSystem(); WorldBalanceTestSystem public nonRootSystem = new WorldBalanceTestSystem(); - bytes16 public namespace = "namespace"; - bytes32 public rootSystemId = ResourceSelector.from(ROOT_NAMESPACE, "testSystem"); - bytes32 public nonRootSystemId = ResourceSelector.from(namespace, "testSystem"); + bytes14 public namespace = "namespace"; + bytes32 public rootSystemId = ResourceId.encode(ROOT_NAMESPACE, "testSystem", RESOURCE_SYSTEM); + bytes32 public nonRootSystemId = ResourceId.encode(namespace, "testSystem", RESOURCE_SYSTEM); address public caller = address(4242); function setUp() public { @@ -222,7 +223,7 @@ contract WorldBalanceTest is Test, GasReporter { vm.expectRevert( abi.encodeWithSelector( IWorldErrors.AccessDenied.selector, - ResourceSelector.from(ROOT_NAMESPACE).toString(), + ResourceId.encodeNamespace(ROOT_NAMESPACE).toString(), caller ) ); @@ -324,7 +325,7 @@ contract WorldBalanceTest is Test, GasReporter { vm.expectRevert( abi.encodeWithSelector( IWorldErrors.AccessDenied.selector, - ResourceSelector.from(ROOT_NAMESPACE).toString(), + ResourceId.encodeNamespace(ROOT_NAMESPACE).toString(), caller ) ); diff --git a/packages/world/test/WorldDynamicUpdate.t.sol b/packages/world/test/WorldDynamicUpdate.t.sol index e2bea13264..dc795a4fb1 100644 --- a/packages/world/test/WorldDynamicUpdate.t.sol +++ b/packages/world/test/WorldDynamicUpdate.t.sol @@ -16,7 +16,8 @@ import { SchemaEncodeHelper } from "@latticexyz/store/test/SchemaEncodeHelper.so import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; import { World } from "../src/World.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; +import { RESOURCE_TABLE } from "../src/worldResourceTypes.sol"; import { NamespaceOwner } from "../src/tables/NamespaceOwner.sol"; import { ResourceAccess } from "../src/tables/ResourceAccess.sol"; @@ -28,7 +29,7 @@ import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; contract UpdateInFieldTest is Test, GasReporter { - using ResourceSelector for bytes32; + using ResourceId for bytes32; event HookCalled(bytes data); event WorldTestSystemLog(string log); @@ -40,7 +41,7 @@ contract UpdateInFieldTest is Test, GasReporter { bytes32[] internal keyTuple; bytes32[] internal singletonKey; - bytes16 namespace; + bytes14 namespace; bytes16 name; bytes32 internal tableId; address[] internal initData; @@ -61,7 +62,7 @@ contract UpdateInFieldTest is Test, GasReporter { namespace = "DynamicUpdTest"; name = "testTable"; - tableId = ResourceSelector.from(namespace, name); + tableId = ResourceId.encode(namespace, name, RESOURCE_TABLE); // Register a new table world.registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](1)); diff --git a/packages/world/test/query.t.sol b/packages/world/test/query.t.sol index 27f8621b9a..dd7d946094 100644 --- a/packages/world/test/query.t.sol +++ b/packages/world/test/query.t.sol @@ -13,8 +13,9 @@ import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol" import { World } from "../src/World.sol"; import { IBaseWorld } from "../src/interfaces/IBaseWorld.sol"; -import { ResourceSelector } from "../src/ResourceSelector.sol"; +import { ResourceId } from "../src/ResourceId.sol"; import { ROOT_NAMESPACE } from "../src/constants.sol"; +import { RESOURCE_TABLE } from "../src/worldResourceTypes.sol"; import { CoreModule } from "../src/modules/core/CoreModule.sol"; import { KeysInTableModule } from "../src/modules/keysintable/KeysInTableModule.sol"; @@ -22,12 +23,12 @@ import { KeysWithValueModule } from "../src/modules/keyswithvalue/KeysWithValueM import { query, QueryFragment, QueryType } from "../src/modules/keysintable/query.sol"; contract QueryTest is Test, GasReporter { - using ResourceSelector for bytes32; + using ResourceId for bytes32; IBaseWorld private world; KeysInTableModule private keysInTableModule = new KeysInTableModule(); // Modules can be deployed once and installed multiple times KeysWithValueModule private keysWithValueModule = new KeysWithValueModule(); - bytes16 private namespace = ROOT_NAMESPACE; + bytes14 private namespace = ROOT_NAMESPACE; bytes16 private name1 = bytes16("source1"); bytes16 private name2 = bytes16("source2"); bytes16 private name3 = bytes16("source3"); @@ -35,9 +36,9 @@ contract QueryTest is Test, GasReporter { FieldLayout private tableFieldLayout; Schema private tableKeySchema; Schema private tableValueSchema; - bytes32 private table1 = ResourceSelector.from(namespace, name1); - bytes32 private table2 = ResourceSelector.from(namespace, name2); - bytes32 private table3 = ResourceSelector.from(namespace, name3); + bytes32 private table1 = ResourceId.encode(namespace, name1, RESOURCE_TABLE); + bytes32 private table2 = ResourceId.encode(namespace, name2, RESOURCE_TABLE); + bytes32 private table3 = ResourceId.encode(namespace, name3, RESOURCE_TABLE); uint256 private value = 1; bytes32[] private key1 = new bytes32[](1);