diff --git a/packages/world/src/interfaces/IAccessManagementSystem.sol b/packages/world/src/interfaces/IAccessManagementSystem.sol index 640de4ed61..ea754bd2f5 100644 --- a/packages/world/src/interfaces/IAccessManagementSystem.sol +++ b/packages/world/src/interfaces/IAccessManagementSystem.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.0; /* Autogenerated file. Do not edit manually. */ interface IAccessManagementSystem { - function grantAccess(bytes16 namespace, bytes16 name, address grantee) external; + function grantAccess(bytes32 resourceSelector, address grantee) external; - function revokeAccess(bytes16 namespace, bytes16 name, address grantee) external; + function revokeAccess(bytes32 resourceSelector, address grantee) external; } diff --git a/packages/world/src/interfaces/IBaseWorld.sol b/packages/world/src/interfaces/IBaseWorld.sol index 3682f23ac3..88806d4364 100644 --- a/packages/world/src/interfaces/IBaseWorld.sol +++ b/packages/world/src/interfaces/IBaseWorld.sol @@ -5,12 +5,11 @@ pragma solidity >=0.8.0; import { IStore } from "@latticexyz/store/src/IStore.sol"; import { IWorldKernel } from "../interfaces/IWorldKernel.sol"; -import { IWorldEphemeral } from "../interfaces/IWorldEphemeral.sol"; import { ICoreSystem } from "./ICoreSystem.sol"; import { IAccessManagementSystem } from "./IAccessManagementSystem.sol"; import { IModuleInstallationSystem } from "./IModuleInstallationSystem.sol"; -import { IRegistrationSystem } from "./IRegistrationSystem.sol"; +import { IWorldRegistrationSystem } from "./IWorldRegistrationSystem.sol"; /** * The IBaseWorld interface includes all systems dynamically added to the World @@ -19,11 +18,10 @@ import { IRegistrationSystem } from "./IRegistrationSystem.sol"; interface IBaseWorld is IStore, IWorldKernel, - IWorldEphemeral, ICoreSystem, IAccessManagementSystem, IModuleInstallationSystem, - IRegistrationSystem + IWorldRegistrationSystem { } diff --git a/packages/world/src/interfaces/IWorldEphemeral.sol b/packages/world/src/interfaces/IWorldEphemeral.sol deleted file mode 100644 index 7616962411..0000000000 --- a/packages/world/src/interfaces/IWorldEphemeral.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; - -import { Schema } from "@latticexyz/store/src/Schema.sol"; - -/** - * Necessary in addition to `IStoreEphemeral` - * because 2 functions with the same name need 2 separate interfaces to allow referencing their selector - */ -interface IWorldEphemeral { - /** - * Emit the ephemeral event without modifying storage at the given namespace and name. - * Requires the caller to have access to the namespace or name. - */ - function emitEphemeralRecord( - bytes16 namespace, - bytes16 name, - bytes32[] calldata key, - bytes calldata data, - Schema valueSchema - ) external; -} diff --git a/packages/world/src/interfaces/IWorldRegistrationSystem.sol b/packages/world/src/interfaces/IWorldRegistrationSystem.sol new file mode 100644 index 0000000000..bed728265a --- /dev/null +++ b/packages/world/src/interfaces/IWorldRegistrationSystem.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/* Autogenerated file. Do not edit manually. */ + +import { ISystemHook } from "./ISystemHook.sol"; +import { System } from "./../System.sol"; + +interface IWorldRegistrationSystem { + function registerNamespace(bytes16 namespace) external; + + function registerSystemHook(bytes32 resourceSelector, ISystemHook hook) external; + + function registerSystem(bytes32 resourceSelector, System system, bool publicAccess) external; + + function registerFunctionSelector( + bytes32 resourceSelector, + string memory systemFunctionName, + string memory systemFunctionArguments + ) external returns (bytes4 worldFunctionSelector); + + function registerRootFunctionSelector( + bytes32 resourceSelector, + 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 f87d77ebbe..cd3937a679 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -10,7 +10,6 @@ import { IBaseWorld } from "../../interfaces/IBaseWorld.sol"; import { IModule } from "../../interfaces/IModule.sol"; import { IStoreEphemeral } from "@latticexyz/store/src/IStore.sol"; -import { IWorldEphemeral } from "../../interfaces/IWorldEphemeral.sol"; import { ResourceSelector } from "../../ResourceSelector.sol"; import { NamespaceOwner } from "../../tables/NamespaceOwner.sol"; @@ -26,7 +25,8 @@ import { ResourceType } from "./tables/ResourceType.sol"; import { SystemHooks } from "./tables/SystemHooks.sol"; import { SystemRegistry } from "./tables/SystemRegistry.sol"; -import { RegistrationSystem } from "./implementations/RegistrationSystem.sol"; +import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; +import { StoreRegistrationSystem } from "./implementations/StoreRegistrationSystem.sol"; import { ModuleInstallationSystem } from "./implementations/ModuleInstallationSystem.sol"; import { AccessManagementSystem } from "./implementations/AccessManagementSystem.sol"; import { EphemeralRecordSystem } from "./implementations/EphemeralRecordSystem.sol"; @@ -80,7 +80,7 @@ contract CoreModule is IModule, WorldContext { delegate: true, value: 0, funcSelectorAndArgs: abi.encodeWithSelector( - RegistrationSystem.registerSystem.selector, + WorldRegistrationSystem.registerSystem.selector, ROOT_NAMESPACE, CORE_SYSTEM_NAME, coreSystem, @@ -93,24 +93,23 @@ contract CoreModule is IModule, WorldContext { * Register function selectors for all CoreSystem functions in the World */ function _registerFunctionSelectors() internal { - bytes4[13] memory functionSelectors = [ - // --- RegistrationSystem --- - RegistrationSystem.registerNamespace.selector, - RegistrationSystem.registerTable.selector, - RegistrationSystem.registerHook.selector, - RegistrationSystem.registerStoreHook.selector, - RegistrationSystem.registerSystemHook.selector, - RegistrationSystem.registerSystem.selector, - RegistrationSystem.registerFunctionSelector.selector, - RegistrationSystem.registerRootFunctionSelector.selector, + bytes4[11] memory functionSelectors = [ + // --- WorldRegistrationSystem --- + WorldRegistrationSystem.registerNamespace.selector, + WorldRegistrationSystem.registerSystemHook.selector, + WorldRegistrationSystem.registerSystem.selector, + WorldRegistrationSystem.registerFunctionSelector.selector, + WorldRegistrationSystem.registerRootFunctionSelector.selector, + // --- StoreRegistrationSystem --- + StoreRegistrationSystem.registerTable.selector, + StoreRegistrationSystem.registerStoreHook.selector, // --- ModuleInstallationSystem --- ModuleInstallationSystem.installModule.selector, // --- AccessManagementSystem --- AccessManagementSystem.grantAccess.selector, AccessManagementSystem.revokeAccess.selector, // --- EphemeralRecordSystem --- - IStoreEphemeral.emitEphemeralRecord.selector, - IWorldEphemeral.emitEphemeralRecord.selector + IStoreEphemeral.emitEphemeralRecord.selector ]; for (uint256 i = 0; i < functionSelectors.length; i++) { @@ -122,7 +121,7 @@ contract CoreModule is IModule, WorldContext { delegate: true, value: 0, funcSelectorAndArgs: abi.encodeWithSelector( - RegistrationSystem.registerRootFunctionSelector.selector, + WorldRegistrationSystem.registerRootFunctionSelector.selector, ResourceSelector.from(ROOT_NAMESPACE, CORE_SYSTEM_NAME), functionSelectors[i], functionSelectors[i] diff --git a/packages/world/src/modules/core/CoreSystem.sol b/packages/world/src/modules/core/CoreSystem.sol index af48796c0b..368558f929 100644 --- a/packages/world/src/modules/core/CoreSystem.sol +++ b/packages/world/src/modules/core/CoreSystem.sol @@ -3,7 +3,8 @@ pragma solidity >=0.8.0; import { IWorldErrors } from "../../interfaces/IWorldErrors.sol"; -import { RegistrationSystem } from "./implementations/RegistrationSystem.sol"; +import { StoreRegistrationSystem } from "./implementations/StoreRegistrationSystem.sol"; +import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; import { ModuleInstallationSystem } from "./implementations/ModuleInstallationSystem.sol"; import { AccessManagementSystem } from "./implementations/AccessManagementSystem.sol"; import { EphemeralRecordSystem } from "./implementations/EphemeralRecordSystem.sol"; @@ -14,7 +15,8 @@ import { EphemeralRecordSystem } from "./implementations/EphemeralRecordSystem.s */ contract CoreSystem is IWorldErrors, - RegistrationSystem, + StoreRegistrationSystem, + WorldRegistrationSystem, ModuleInstallationSystem, AccessManagementSystem, EphemeralRecordSystem diff --git a/packages/world/src/modules/core/implementations/AccessManagementSystem.sol b/packages/world/src/modules/core/implementations/AccessManagementSystem.sol index aece45d441..df10f158e0 100644 --- a/packages/world/src/modules/core/implementations/AccessManagementSystem.sol +++ b/packages/world/src/modules/core/implementations/AccessManagementSystem.sol @@ -4,6 +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 { Call } from "../../../Call.sol"; import { ResourceAccess } from "../../../tables/ResourceAccess.sol"; import { InstalledModules } from "../../../tables/InstalledModules.sol"; @@ -16,9 +17,9 @@ contract AccessManagementSystem is System { * Grant access to the resource at the given namespace and name. * Requires the caller to own the namespace. */ - function grantAccess(bytes16 namespace, bytes16 name, address grantee) public virtual { + function grantAccess(bytes32 resourceSelector, address grantee) public virtual { // Require the caller to own the namespace - bytes32 resourceSelector = AccessControl.requireOwnerOrSelf(namespace, name, _msgSender()); + AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); // Grant access to the given resource ResourceAccess.set(resourceSelector, grantee, true); @@ -28,9 +29,9 @@ contract AccessManagementSystem is System { * Revoke access from the resource at the given namespace and name. * Requires the caller to own the namespace. */ - function revokeAccess(bytes16 namespace, bytes16 name, address grantee) public virtual { + function revokeAccess(bytes32 resourceSelector, address grantee) public virtual { // Require the caller to own the namespace - bytes32 resourceSelector = AccessControl.requireOwnerOrSelf(namespace, name, _msgSender()); + AccessControl.requireOwnerOrSelf(resourceSelector, _msgSender()); // Revoke access from the given resource ResourceAccess.deleteRecord(resourceSelector, grantee); diff --git a/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol b/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol index b20fe81f57..f49bb8996b 100644 --- a/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol +++ b/packages/world/src/modules/core/implementations/EphemeralRecordSystem.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.0; import { IStoreEphemeral } from "@latticexyz/store/src/IStore.sol"; import { Schema } from "@latticexyz/store/src/Schema.sol"; import { IModule } from "../../../interfaces/IModule.sol"; -import { IWorldEphemeral } from "../../../interfaces/IWorldEphemeral.sol"; import { System } from "../../../System.sol"; import { ResourceSelector } from "../../../ResourceSelector.sol"; import { AccessControl } from "../../../AccessControl.sol"; @@ -13,38 +12,23 @@ import { ResourceAccess } from "../../../tables/ResourceAccess.sol"; import { InstalledModules } from "../../../tables/InstalledModules.sol"; import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; -contract EphemeralRecordSystem is IStoreEphemeral, IWorldEphemeral, System { +contract EphemeralRecordSystem is IStoreEphemeral, System { using ResourceSelector 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. + * Requires the caller to have access to the namespace or name (encoded in the resource selector) */ function emitEphemeralRecord( - bytes16 namespace, - bytes16 name, + bytes32 resourceSelector, bytes32[] calldata key, bytes calldata data, Schema valueSchema ) public virtual { // Require access to the namespace or name - bytes32 resourceSelector = AccessControl.requireAccess(namespace, name, msg.sender); + AccessControl.requireAccess(resourceSelector, msg.sender); // Set the record StoreCore.emitEphemeralRecord(resourceSelector, key, data, valueSchema); } - - /** - * Emit the ephemeral event without modifying storage at the given tableId. - * This overload exists to conform with the `IStore` interface. - * Access is checked based on the namespace or name (encoded in the tableId). - */ - function emitEphemeralRecord( - bytes32 tableId, - bytes32[] calldata key, - bytes calldata data, - Schema valueSchema - ) public virtual { - emitEphemeralRecord(tableId.getNamespace(), tableId.getName(), key, data, valueSchema); - } } diff --git a/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol b/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol new file mode 100644 index 0000000000..7486549f6a --- /dev/null +++ b/packages/world/src/modules/core/implementations/StoreRegistrationSystem.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { IStoreHook } from "@latticexyz/store/src/IStore.sol"; +import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; + +import { System } from "../../../System.sol"; +import { ResourceSelector } from "../../../ResourceSelector.sol"; +import { Resource } from "../../../Types.sol"; +import { ROOT_NAMESPACE, ROOT_NAME } from "../../../constants.sol"; +import { AccessControl } from "../../../AccessControl.sol"; +import { Call } from "../../../Call.sol"; +import { NamespaceOwner } from "../../../tables/NamespaceOwner.sol"; +import { ResourceAccess } from "../../../tables/ResourceAccess.sol"; +import { ISystemHook } from "../../../interfaces/ISystemHook.sol"; +import { IWorldErrors } from "../../../interfaces/IWorldErrors.sol"; + +import { ResourceType } from "../tables/ResourceType.sol"; +import { SystemHooks } from "../tables/SystemHooks.sol"; +import { SystemRegistry } from "../tables/SystemRegistry.sol"; +import { Systems } from "../tables/Systems.sol"; +import { FunctionSelectors } from "../tables/FunctionSelectors.sol"; + +import { CORE_SYSTEM_NAME } from "../constants.sol"; + +import { WorldRegistrationSystem } from "./WorldRegistrationSystem.sol"; + +/** + * Functions related to registering table resources in the World. + */ +contract StoreRegistrationSystem is System, IWorldErrors { + using ResourceSelector for bytes32; + + /** + * Register a table with given schema in the given namespace + */ + function registerTable( + bytes32 resourceSelector, + Schema keySchema, + Schema valueSchema, + string[] calldata keyNames, + 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 the namespace doesn't exist yet, register it + bytes16 namespace = resourceSelector.getNamespace(); + if (ResourceType.get(namespace) == Resource.NONE) { + // We can't call IBaseWorld(this).registerSchema 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)); + Call.withSender({ + msgSender: _msgSender(), + target: systemAddress, + funcSelectorAndArgs: abi.encodeWithSelector(WorldRegistrationSystem.registerNamespace.selector, namespace), + delegate: true, + value: 0 + }); + } else { + // otherwise require caller to own the namespace + AccessControl.requireOwnerOrSelf(namespace, _msgSender()); + } + + // Require no resource to exist at this selector yet + if (ResourceType.get(resourceSelector) != Resource.NONE) { + revert ResourceExists(resourceSelector.toString()); + } + + // Store the table resource type + ResourceType.set(resourceSelector, Resource.TABLE); + + // Register the table's schema + StoreCore.registerTable(resourceSelector, keySchema, valueSchema, keyNames, fieldNames); + } + + /** + * Register a hook for the table at the given namepace and name. + * Requires the caller to own the namespace. + */ + function registerStoreHook(bytes32 tableId, IStoreHook hook) public virtual { + // Require caller to own the namespace + AccessControl.requireOwnerOrSelf(tableId, _msgSender()); + + // Register the hook + StoreCore.registerStoreHook(tableId, hook); + } +} diff --git a/packages/world/src/modules/core/implementations/RegistrationSystem.sol b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol similarity index 72% rename from packages/world/src/modules/core/implementations/RegistrationSystem.sol rename to packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol index bb70ae1ade..af57701497 100644 --- a/packages/world/src/modules/core/implementations/RegistrationSystem.sol +++ b/packages/world/src/modules/core/implementations/WorldRegistrationSystem.sol @@ -1,10 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -import { IStoreHook } from "@latticexyz/store/src/IStore.sol"; -import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; -import { Schema } from "@latticexyz/store/src/Schema.sol"; - import { System } from "../../../System.sol"; import { ResourceSelector } from "../../../ResourceSelector.sol"; import { Resource } from "../../../Types.sol"; @@ -22,9 +18,10 @@ import { Systems } from "../tables/Systems.sol"; import { FunctionSelectors } from "../tables/FunctionSelectors.sol"; /** - * Functions related to registering resources in the World. + * Functions related to registering resources other than tables in the World. + * Registering tables is implemented in StoreRegistrationSystem.sol */ -contract RegistrationSystem is System, IWorldErrors { +contract WorldRegistrationSystem is System, IWorldErrors { using ResourceSelector for bytes32; /** @@ -46,68 +43,6 @@ contract RegistrationSystem is System, IWorldErrors { ResourceAccess.set(resourceSelector, _msgSender(), true); } - /** - * Register a table with given schema in the given namespace - */ - function registerTable( - bytes32 resourceSelector, - Schema keySchema, - Schema valueSchema, - string[] calldata keyNames, - 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 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.requireOwnerOrSelf(namespace, _msgSender()); - - // Require no resource to exist at this selector yet - if (ResourceType.get(resourceSelector) != Resource.NONE) { - revert ResourceExists(resourceSelector.toString()); - } - - // Store the table resource type - ResourceType.set(resourceSelector, Resource.TABLE); - - // Register the table's schema - StoreCore.registerTable(resourceSelector, keySchema, valueSchema, keyNames, fieldNames); - } - - /** - * Register the given store hook for the table at the given namespace and name. - * Hooks on table names must implement the IStoreHook interface, - * and hooks on system names must implement the ISystemHook interface. - */ - function registerHook(bytes32 resourceSelector, address hook) public virtual { - Resource resourceType = ResourceType.get(resourceSelector); - - if (resourceType == Resource.TABLE) { - return registerStoreHook(resourceSelector, IStoreHook(hook)); - } - - if (resourceType == Resource.SYSTEM) { - return registerSystemHook(resourceSelector, ISystemHook(hook)); - } - - revert InvalidSelector(resourceSelector.toString()); - } - - /** - * Register a hook for the table at the given namepace and name. - * Requires the caller to own the namespace. - */ - function registerStoreHook(bytes32 tableId, IStoreHook hook) public virtual { - // Require caller to own the namespace - AccessControl.requireOwnerOrSelf(tableId, _msgSender()); - - // Register the hook - StoreCore.registerStoreHook(tableId, hook); - } - /** * Register a hook for the system at the given namespace and name */ diff --git a/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol b/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol index 05ffefa7dc..b817e4a531 100644 --- a/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol +++ b/packages/world/src/modules/uniqueentity/UniqueEntityModule.sol @@ -32,9 +32,9 @@ contract UniqueEntityModule is IModule, WorldContext { UniqueEntity.register(world, ResourceSelector.from(NAMESPACE, TABLE_NAME)); // Register system - world.registerSystem(NAMESPACE, SYSTEM_NAME, uniqueEntitySystem, true); + world.registerSystem(ResourceSelector.from(NAMESPACE, SYSTEM_NAME), uniqueEntitySystem, true); // Register system's functions - world.registerFunctionSelector(NAMESPACE, SYSTEM_NAME, "getUniqueEntity", "()"); + world.registerFunctionSelector(ResourceSelector.from(NAMESPACE, SYSTEM_NAME), "getUniqueEntity", "()"); } } diff --git a/packages/world/ts/node/render-solidity/renderWorld.ts b/packages/world/ts/node/render-solidity/renderWorld.ts index 4c80e9e614..f6eb71b818 100644 --- a/packages/world/ts/node/render-solidity/renderWorld.ts +++ b/packages/world/ts/node/render-solidity/renderWorld.ts @@ -14,7 +14,6 @@ export function renderWorld(options: RenderWorldOptions) { ? [ { symbol: "IStore", path: `${storeImportPath}IStore.sol` }, { symbol: "IWorldKernel", path: `${worldImportPath}interfaces/IWorldKernel.sol` }, - { symbol: "IWorldEphemeral", path: `${worldImportPath}interfaces/IWorldEphemeral.sol` }, ] : [ {