World
System Hooks

System hooks

This page is about hooks that are called before or after a System call. You can also use store hooks that are called whenever information in a table is modified, regardless of the source of the change.

The namespace owner can register (opens in a new tab) hooks that are called before and/or after calls to a specific System.

System hook contracts

A system hook contract is a contract that implements the ISystemHook (opens in a new tab) interface. This interface requires the implementation of two functions.

  • onBeforeCallSystem, which is called before the actual call.
  • onAfterCallSystem, which is called afterward.
  • supportsInterface, which is part of IEP-165 (opens in a new tab) used to specify which interfaces are supported by a contract.

To have the correct supportsInterface you can inherit from SystemHook (opens in a new tab).

Sample code

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;
 
import { Script } from "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
 
import { IWorld } from "../src/codegen/world/IWorld.sol";
 
import { SystemHook } from "@latticexyz/world/src/SystemHook.sol";
 
import { ResourceId, WorldResourceIdLib, WorldResourceIdInstance } from "@latticexyz/world/src/WorldResourceId.sol";
import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol";
import { BEFORE_CALL_SYSTEM, AFTER_CALL_SYSTEM } from "@latticexyz/world/src/systemHookTypes.sol";
 
contract JustSayNo is SystemHook {
  function onBeforeCallSystem(address msgSender, ResourceId systemId, bytes memory callData) external {
    return;
  }
 
  function onAfterCallSystem(address msgSender, ResourceId systemId, bytes memory callData) external {
    revert("Just say no");
  }
}
 
contract SystemHookDeploy is Script {
  function run() external {
    address worldAddress = 0xC14fBdb7808D9e2a37c1a45b635C8C3fF64a1cc1;
 
    // Load the private key from the `PRIVATE_KEY` environment variable (in .env)
    uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
 
    // Start broadcasting transactions from the deployer account
    vm.startBroadcast(deployerPrivateKey);
 
    // Deploy JustSayNo
    JustSayNo justSayNo = new JustSayNo();
    console.log(address(justSayNo));
 
    ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: "", name: "TasksSystem" });
 
    IWorld(worldAddress).registerSystemHook(systemId, justSayNo, AFTER_CALL_SYSTEM);
 
    vm.stopBroadcast();
  }
}
Explanation
import { SystemHook } from "@latticexyz/world/src/SystemHook.sol";

The system hook contract inherits from SystemHook.

import { ResourceId, WorldResourceIdLib, WorldResourceIdInstance } from "@latticexyz/world/src/WorldResourceId.sol";
import { RESOURCE_SYSTEM } from "@latticexyz/world/src/worldResourceTypes.sol";

We need to create the resource of the System for which we register a hook.

import { BEFORE_CALL_SYSTEM, AFTER_CALL_SYSTEM } from "@latticexyz/world/src/systemHookTypes.sol";

We need these constants to specify when the hook applies.

contract JustSayNo is SystemHook {
 
  function onBeforeCallSystem(address msgSender, ResourceId systemId, bytes memory callData) external {
    return ;
  }
 
  function onAfterCallSystem(address msgSender, ResourceId systemId, bytes memory callData) external {

This is the system hook contract. It has two functions:

  • onBeforeCallSystem, which is executed before the call
  • onAfterCallSystem, which is executed after the call

Both functions get the sender, the system being called, and the call data it receives.

    revert("Just say no");
  }
}

This hook disables the System by causing all calls to revert.

contract SystemHookDeploy is Script {
  function run() external {
   ...

This is the function that the script executes.

    // Deploy JustSayNo
    JustSayNo justSayNo = new JustSayNo();

Deploy the system hook contract.

    ResourceId systemId = WorldResourceIdLib.encode(
      { typeId: RESOURCE_SYSTEM,
        namespace: "",
        name: "TasksSystem"
      });

Create the resource ID for the System we are disabling.

    IWorld(worldAddress)
        .registerSystemHook(systemId, justSayNo, AFTER_CALL_SYSTEM);
  }
}

Register the system hook.