World
Namespaces & Access Control

Namespaces and Access Control

Access control in a World is based on namespaces. Every resource is part of a namespace (a blank namespace refers to the root namespace). Access to resources is managed by the owner of the namespace.

Resource identifiers

A ResourceId is a 32-byte value that uniquely identifies a resource in a World. It is two bytes of resource type followed by 14 bytes of namespace and then 16 bytes of the name of the actual resource.

Currently, MUD supports these resource types:

Access control can be attached to any resource.

Access control levels

There are three access levels in MUD.

"No" access

This is the level that most users of a MUD application have for all resources. Users on this level are allowed to do the following:

  • Read data from tables. Any information posted or created on the blockchain is public, so this information is available anyway.
  • Call functions on public Systems.

Access

This level of access is often required for software that is part of the application. Access can be granted either on a namespace basis (access to the namespace gives access to all the resources inside it) or on an individual resource.

Entities with this level of access can do anything that "no" access allows, and also:

  • Write directly to tables. This is as opposed to users with no access, who can only modify table information by going through a public System (by default, a System has access to its own namespace, which includes all of the namespace's tables).
  • Call functions on private Systems.
  • In the case of access to a namespace, withdraw from the ETH balance of the namespace. To avoid giving this permission, you can give an address access to every resource in the namespace, rather than to the namespace itself.

Ownership

Namespace is the only resource type that has an owner. The owner is a single account (but by using multi-sig accounts ownership can be shared).

The owner is an administrative account, a superuser. When you change ownership, the new owner gets access to the namespace, and the old owner loses it. Therefore, owners can do anything an address with access can. Additionally, owners can also:

Owners can modify which contract a World uses for each System. Note: once ownership of a namespace is burned (i.e. transferred to address(0)), no new access can be granted or revoked, ownership can't be transferred again, and Systems can't be added, removed, or upgraded (unless the System is itself a proxy (opens in a new tab)).

Modifying access control

By default access to a namespace is granted to:

  • The namespace owner
  • The Systems of that namespace

Namespace access provides access to all the resources within the namespace, so there is no need, by default, for access to the resources within the namespace.

If that is insufficient, AccessManagementSystem (opens in a new tab) lets you grantAccess (opens in a new tab), revokeAccess (opens in a new tab), and transferOwnership (opens in a new tab) of a namespace.

For example, here is a script that grants access to the Counter table to one address and revokes it for another.

Permissions.s.sol
pragma solidity >=0.8.21;
 
import { Script } from "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol";
 
import { IWorld } from "../src/codegen/world/IWorld.sol";
import { CounterTableId } from "../src/codegen/index.sol";
 
contract Permissions is Script {
  function run() external {
    address worldAddress = 0x6E9474e9c83676B9A71133FF96Db43E7AA0a4342;
 
    // Load the private key from the `PRIVATE_KEY` environment variable (in .env)
    uint256 namespaceOwnerPrivateKey = vm.envUint("PRIVATE_KEY");
 
    // Start broadcasting transactions from the account owning the namespace
    vm.startBroadcast(namespaceOwnerPrivateKey);
 
    IWorld(worldAddress).grantAccess(CounterTableId, address(0));
    IWorld(worldAddress).revokeAccess(CounterTableId, address(1));
 
    vm.stopBroadcast();
  }
}