Skip to content

Commit

Permalink
feat(world): use ResourceId namespaceId for all methods acting on the…
Browse files Browse the repository at this point in the history
… namespace as a resource
  • Loading branch information
alvrs committed Sep 20, 2023
1 parent 202c042 commit c64ac48
Show file tree
Hide file tree
Showing 23 changed files with 244 additions and 211 deletions.
25 changes: 25 additions & 0 deletions .changeset/real-students-exercise.md
@@ -0,0 +1,25 @@
---
"@latticexyz/world": major
---

All `World` methods acting on namespaces as resources have been updated to use `ResourceId namespaceId` as parameter instead of `bytes14 namespace`.
The reason for this change is to make it clearer when a namespace is used as resource, as opposed to being part of another resource's ID.

```diff
+ import { ResourceId } from "@latticexyz/store/src/ResourceId.sol";

IBaseWorld {
- function registerNamespace(bytes14 namespace) external;
+ function registerNamespace(ResourceId namespaceId) external;

- function transferOwnership(bytes14 namespace, address newOwner) external;
+ function transferOwnership(ResourceId namespaceId, address newOwner) external;

- function transferBalanceToNamespace(bytes14 fromNamespace, bytes14 toNamespace, uint256 amount) external;
+ function transferBalanceToNamespace(ResourceId fromNamespaceId, ResourceId toNamespaceId, uint256 amount) external;

- function transferBalanceToAddress(bytes14 fromNamespace, address toAddress, uint256 amount) external;
+ function transferBalanceToAddress(ResourceId fromNamespaceId, address toAddress, uint256 amount) external;
}

```
2 changes: 1 addition & 1 deletion packages/store/src/ResourceId.sol
Expand Up @@ -20,7 +20,7 @@ library ResourceIdInstance {
return bytes2(ResourceId.unwrap(resourceId) << (NAME_BYTES * BYTES_TO_BITS));
}

function isType(ResourceId resourceId, bytes2 resourceType) internal view returns (bool) {
function isType(ResourceId resourceId, bytes2 resourceType) internal pure returns (bool) {
return ResourceId.unwrap(resourceId) & TYPE_MASK == bytes32(resourceType) >> (NAME_BYTES * BYTES_TO_BITS);
}
}
38 changes: 19 additions & 19 deletions packages/world/gas-report.json
Expand Up @@ -39,13 +39,13 @@
"file": "test/KeysInTableModule.t.sol",
"test": "testInstallComposite",
"name": "install keys in table module",
"gasUsed": 1414829
"gasUsed": 1414689
},
{
"file": "test/KeysInTableModule.t.sol",
"test": "testInstallGas",
"name": "install keys in table module",
"gasUsed": 1414829
"gasUsed": 1414689
},
{
"file": "test/KeysInTableModule.t.sol",
Expand All @@ -57,13 +57,13 @@
"file": "test/KeysInTableModule.t.sol",
"test": "testInstallSingleton",
"name": "install keys in table module",
"gasUsed": 1414829
"gasUsed": 1414689
},
{
"file": "test/KeysInTableModule.t.sol",
"test": "testSetAndDeleteRecordHookCompositeGas",
"name": "install keys in table module",
"gasUsed": 1414829
"gasUsed": 1414689
},
{
"file": "test/KeysInTableModule.t.sol",
Expand All @@ -81,7 +81,7 @@
"file": "test/KeysInTableModule.t.sol",
"test": "testSetAndDeleteRecordHookGas",
"name": "install keys in table module",
"gasUsed": 1414829
"gasUsed": 1414689
},
{
"file": "test/KeysInTableModule.t.sol",
Expand All @@ -99,7 +99,7 @@
"file": "test/KeysWithValueModule.t.sol",
"test": "testGetKeysWithValueGas",
"name": "install keys with value module",
"gasUsed": 664865
"gasUsed": 664413
},
{
"file": "test/KeysWithValueModule.t.sol",
Expand All @@ -117,7 +117,7 @@
"file": "test/KeysWithValueModule.t.sol",
"test": "testInstall",
"name": "install keys with value module",
"gasUsed": 664865
"gasUsed": 664413
},
{
"file": "test/KeysWithValueModule.t.sol",
Expand All @@ -129,7 +129,7 @@
"file": "test/KeysWithValueModule.t.sol",
"test": "testSetAndDeleteRecordHook",
"name": "install keys with value module",
"gasUsed": 664865
"gasUsed": 664413
},
{
"file": "test/KeysWithValueModule.t.sol",
Expand All @@ -147,7 +147,7 @@
"file": "test/KeysWithValueModule.t.sol",
"test": "testSetField",
"name": "install keys with value module",
"gasUsed": 664865
"gasUsed": 664413
},
{
"file": "test/KeysWithValueModule.t.sol",
Expand Down Expand Up @@ -231,7 +231,7 @@
"file": "test/StandardDelegationsModule.t.sol",
"test": "testCallFromCallboundDelegation",
"name": "register a callbound delegation",
"gasUsed": 114173
"gasUsed": 114161
},
{
"file": "test/StandardDelegationsModule.t.sol",
Expand All @@ -243,7 +243,7 @@
"file": "test/StandardDelegationsModule.t.sol",
"test": "testCallFromTimeboundDelegation",
"name": "register a timebound delegation",
"gasUsed": 108625
"gasUsed": 108613
},
{
"file": "test/StandardDelegationsModule.t.sol",
Expand All @@ -255,7 +255,7 @@
"file": "test/UniqueEntityModule.t.sol",
"test": "testInstall",
"name": "install unique entity module",
"gasUsed": 690879
"gasUsed": 690445
},
{
"file": "test/UniqueEntityModule.t.sol",
Expand All @@ -267,7 +267,7 @@
"file": "test/UniqueEntityModule.t.sol",
"test": "testInstallRoot",
"name": "installRoot unique entity module",
"gasUsed": 681148
"gasUsed": 680717
},
{
"file": "test/UniqueEntityModule.t.sol",
Expand Down Expand Up @@ -309,37 +309,37 @@
"file": "test/World.t.sol",
"test": "testRegisterFallbackSystem",
"name": "Register a fallback system",
"gasUsed": 58802
"gasUsed": 58798
},
{
"file": "test/World.t.sol",
"test": "testRegisterFallbackSystem",
"name": "Register a root fallback system",
"gasUsed": 52544
"gasUsed": 52551
},
{
"file": "test/World.t.sol",
"test": "testRegisterFunctionSelector",
"name": "Register a function selector",
"gasUsed": 79396
"gasUsed": 79392
},
{
"file": "test/World.t.sol",
"test": "testRegisterNamespace",
"name": "Register a new namespace",
"gasUsed": 123284
"gasUsed": 122878
},
{
"file": "test/World.t.sol",
"test": "testRegisterRootFunctionSelector",
"name": "Register a root function selector",
"gasUsed": 74457
"gasUsed": 74464
},
{
"file": "test/World.t.sol",
"test": "testRegisterTable",
"name": "Register a new table in the namespace",
"gasUsed": 652534
"gasUsed": 652093
},
{
"file": "test/World.t.sol",
Expand Down
4 changes: 2 additions & 2 deletions packages/world/mud.config.ts
Expand Up @@ -13,7 +13,7 @@ export default mudConfig({
************************************************************************/
NamespaceOwner: {
keySchema: {
namespace: "bytes16",
namespaceId: "bytes32",
},
valueSchema: {
owner: "address",
Expand Down Expand Up @@ -54,7 +54,7 @@ export default mudConfig({
Balances: {
directory: "modules/core/tables",
keySchema: {
namespace: "bytes16",
namespaceId: "bytes32",
},
valueSchema: {
balance: "uint256",
Expand Down
2 changes: 1 addition & 1 deletion packages/world/src/AccessControl.sol
Expand Up @@ -36,7 +36,7 @@ library AccessControl {
* Reverts with AccessDenied if the check fails.
*/
function requireOwner(ResourceId resourceId, address caller) internal view {
if (NamespaceOwner._get(resourceId.getNamespace()) != caller) {
if (NamespaceOwner._get(ResourceId.unwrap(resourceId.getNamespaceId())) != caller) {
revert IWorldErrors.AccessDenied(resourceId.toString(), caller);
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/world/src/SystemCall.sol
Expand Up @@ -43,9 +43,9 @@ library SystemCall {

// If the msg.value is non-zero, update the namespace's balance
if (value > 0) {
bytes14 namespace = systemId.getNamespace();
uint256 currentBalance = Balances._get(namespace);
Balances._set(namespace, currentBalance + value);
ResourceId namespaceId = systemId.getNamespaceId();
uint256 currentBalance = Balances._get(ResourceId.unwrap(namespaceId));
Balances._set(ResourceId.unwrap(namespaceId), currentBalance + value);
}

// Call the system and forward any return data
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/World.sol
Expand Up @@ -287,8 +287,8 @@ contract World is StoreRead, IStoreData, IWorldKernel {
* ETH sent to the World without calldata is added to the root namespace's balance
*/
receive() external payable {
uint256 rootBalance = Balances._get(ROOT_NAMESPACE);
Balances._set(ROOT_NAMESPACE, rootBalance + msg.value);
uint256 rootBalance = Balances._get(ResourceId.unwrap(ROOT_NAMESPACE_ID));
Balances._set(ResourceId.unwrap(ROOT_NAMESPACE_ID), rootBalance + msg.value);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/WorldResourceId.sol
Expand Up @@ -92,9 +92,9 @@ library WorldResourceIdInstance {
string(
abi.encodePacked(
resourceNamespace == ROOT_NAMESPACE ? ROOT_NAMESPACE_STRING : resourceNamespace,
"_",
":",
resourceName == ROOT_NAME ? ROOT_NAME_STRING : resourceName,
".",
":",
resourceType
)
);
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/factories/WorldFactory.sol
Expand Up @@ -6,7 +6,7 @@ import { World } from "../World.sol";
import { IWorldFactory } from "./IWorldFactory.sol";
import { IBaseWorld } from "../interfaces/IBaseWorld.sol";
import { IModule } from "../interfaces/IModule.sol";
import { ROOT_NAMESPACE } from "../constants.sol";
import { ROOT_NAMESPACE_ID } from "../constants.sol";

contract WorldFactory is IWorldFactory {
IModule public coreModule;
Expand All @@ -27,7 +27,7 @@ contract WorldFactory is IWorldFactory {

// Initialize the World and transfer ownership to the caller
world.initialize(coreModule);
world.transferOwnership(ROOT_NAMESPACE, msg.sender);
world.transferOwnership(ROOT_NAMESPACE_ID, msg.sender);

emit WorldDeployed(worldAddress);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/world/src/interfaces/IAccessManagementSystem.sol
Expand Up @@ -10,5 +10,5 @@ interface IAccessManagementSystem {

function revokeAccess(ResourceId resourceId, address grantee) external;

function transferOwnership(bytes14 namespace, address newOwner) external;
function transferOwnership(ResourceId namespaceId, address newOwner) external;
}
6 changes: 4 additions & 2 deletions packages/world/src/interfaces/IBalanceTransferSystem.sol
Expand Up @@ -3,8 +3,10 @@ pragma solidity >=0.8.0;

/* Autogenerated file. Do not edit manually. */

import { ResourceId } from "./../WorldResourceId.sol";

interface IBalanceTransferSystem {
function transferBalanceToNamespace(bytes14 fromNamespace, bytes14 toNamespace, uint256 amount) external;
function transferBalanceToNamespace(ResourceId fromNamespaceId, ResourceId toNamespaceId, uint256 amount) external;

function transferBalanceToAddress(bytes14 fromNamespace, address toAddress, uint256 amount) external;
function transferBalanceToAddress(ResourceId fromNamespaceId, address toAddress, uint256 amount) external;
}
2 changes: 1 addition & 1 deletion packages/world/src/interfaces/IWorldRegistrationSystem.sol
Expand Up @@ -8,7 +8,7 @@ import { ISystemHook } from "./ISystemHook.sol";
import { WorldContextConsumer } from "./../WorldContext.sol";

interface IWorldRegistrationSystem {
function registerNamespace(bytes14 namespace) external;
function registerNamespace(ResourceId namespaceId) external;

function registerSystemHook(ResourceId systemId, ISystemHook hookAddress, uint8 enabledHooksBitmap) external;

Expand Down
8 changes: 4 additions & 4 deletions packages/world/src/modules/core/CoreModule.sol
Expand Up @@ -2,7 +2,7 @@
pragma solidity >=0.8.0;

import { WorldContextProvider } from "../../WorldContext.sol";
import { ROOT_NAMESPACE } from "../../constants.sol";
import { ROOT_NAMESPACE, ROOT_NAMESPACE_ID } from "../../constants.sol";
import { Resource } from "../../common.sol";
import { Module } from "../../Module.sol";

Expand Down Expand Up @@ -77,9 +77,9 @@ contract CoreModule is Module {
SystemRegistry.register();
ResourceType.register();

NamespaceOwner._set(ROOT_NAMESPACE, _msgSender());
ResourceAccess._set(ROOT_NAMESPACE, _msgSender(), true);
ResourceType._set(ROOT_NAMESPACE, Resource.NAMESPACE);
NamespaceOwner._set(ResourceId.unwrap(ROOT_NAMESPACE_ID), _msgSender());
ResourceAccess._set(ResourceId.unwrap(ROOT_NAMESPACE_ID), _msgSender(), true);
ResourceType._set(ResourceId.unwrap(ROOT_NAMESPACE_ID), Resource.NAMESPACE);
}

/**
Expand Down
Expand Up @@ -42,14 +42,12 @@ contract AccessManagementSystem is System {
* Revoke ResourceAccess for previous owner and grant to newOwner.
* Requires the caller to own the namespace.
*/
function transferOwnership(bytes14 namespace, address newOwner) public virtual {
ResourceId namespaceId = WorldResourceIdLib.encodeNamespace(namespace);

function transferOwnership(ResourceId namespaceId, address newOwner) public virtual {
// Require the caller to own the namespace
AccessControl.requireOwner(namespaceId, _msgSender());

// Set namespace new owner
NamespaceOwner._set(namespace, newOwner);
NamespaceOwner._set(ResourceId.unwrap(namespaceId), newOwner);

// Revoke access from old owner
ResourceAccess._deleteRecord(ResourceId.unwrap(namespaceId), _msgSender());
Expand Down
Expand Up @@ -15,36 +15,40 @@ contract BalanceTransferSystem is System, IWorldErrors {
/**
* Transfer balance to another namespace in the World
*/
function transferBalanceToNamespace(bytes14 fromNamespace, bytes14 toNamespace, uint256 amount) public virtual {
function transferBalanceToNamespace(
ResourceId fromNamespaceId,
ResourceId toNamespaceId,
uint256 amount
) public virtual {
// Require caller to have access to the namespace
AccessControl.requireAccess(WorldResourceIdLib.encodeNamespace(fromNamespace), _msgSender());
AccessControl.requireAccess(fromNamespaceId, _msgSender());

// Get current namespace balance
uint256 balance = Balances._get(fromNamespace);
uint256 balance = Balances._get(ResourceId.unwrap(fromNamespaceId));

// Require the balance balance to be greater or equal to the amount to transfer
if (amount > balance) revert InsufficientBalance(balance, amount);

// Update the balances
Balances._set(fromNamespace, balance - amount);
Balances._set(toNamespace, Balances._get(toNamespace) + amount);
Balances._set(ResourceId.unwrap(fromNamespaceId), balance - amount);
Balances._set(ResourceId.unwrap(toNamespaceId), Balances._get(ResourceId.unwrap(toNamespaceId)) + amount);
}

/**
* Transfer balance out of the World
*/
function transferBalanceToAddress(bytes14 fromNamespace, address toAddress, uint256 amount) public virtual {
function transferBalanceToAddress(ResourceId fromNamespaceId, address toAddress, uint256 amount) public virtual {
// Require caller to have access to the namespace
AccessControl.requireAccess(WorldResourceIdLib.encodeNamespace(fromNamespace), _msgSender());
AccessControl.requireAccess(fromNamespaceId, _msgSender());

// Get current namespace balance
uint256 balance = Balances._get(fromNamespace);
uint256 balance = Balances._get(ResourceId.unwrap(fromNamespaceId));

// Require the balance balance to be greater or equal to the amount to transfer
if (amount > balance) revert InsufficientBalance(balance, amount);

// Update the balances
Balances._set(fromNamespace, balance - amount);
Balances._set(ResourceId.unwrap(fromNamespaceId), balance - amount);

// Transfer the balance to the given address, revert on failure
(bool success, bytes memory data) = payable(toAddress).call{ value: amount }("");
Expand Down
Expand Up @@ -54,7 +54,7 @@ contract StoreRegistrationSystem is System, IWorldErrors {
// 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()))
abi.encodeCall(WorldRegistrationSystem.registerNamespace, (namespaceId))
);
if (!success) revertWithBytes(data);
} else {
Expand Down

0 comments on commit c64ac48

Please sign in to comment.