Skip to content

Commit 2522c4e

Browse files
committed
feat: optional system hooks feature; function that gets triggered on unregister of a delegation
1 parent 07338f1 commit 2522c4e

19 files changed

+1316
-5
lines changed

packages/cli/src/deploy/getWorldContracts.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import accessManagementSystemBuild from "@latticexyz/world/out/AccessManagementS
22
import balanceTransferSystemBuild from "@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json" assert { type: "json" };
33
import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json" assert { type: "json" };
44
import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" };
5+
import extendedRegistrationSystemBuild from "@latticexyz/world/out/ExtendedRegistrationSystem.sol/ExtendedRegistrationSystem.json" assert { type: "json" };
56
import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" };
67
import initModuleAbi from "@latticexyz/world/out/InitModule.sol/InitModule.abi.json" assert { type: "json" };
78
import { Hex, encodeDeployData, size } from "viem";
@@ -33,11 +34,18 @@ export function getWorldContracts(deployerAddress: Hex) {
3334
bytecode: registrationBytecode,
3435
});
3536

37+
const extendedRegistrationDeployedBytecodeSize = size(extendedRegistrationSystemBuild.deployedBytecode.object as Hex);
38+
const extendedRegistrationBytecode = extendedRegistrationSystemBuild.bytecode.object as Hex;
39+
const extendedRegistration = getContractAddress({
40+
deployerAddress,
41+
bytecode: extendedRegistrationBytecode,
42+
});
43+
3644
const initModuleDeployedBytecodeSize = size(initModuleBuild.deployedBytecode.object as Hex);
3745
const initModuleBytecode = encodeDeployData({
3846
bytecode: initModuleBuild.bytecode.object as Hex,
3947
abi: initModuleAbi,
40-
args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration],
48+
args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration, extendedRegistration],
4149
});
4250
const initModule = getContractAddress({ deployerAddress, bytecode: initModuleBytecode });
4351

@@ -66,6 +74,12 @@ export function getWorldContracts(deployerAddress: Hex) {
6674
debugLabel: "core registration system",
6775
address: registration,
6876
},
77+
ExtendedRegistrationSystem: {
78+
bytecode: extendedRegistrationBytecode,
79+
deployedBytecodeSize: extendedRegistrationDeployedBytecodeSize,
80+
debugLabel: "extended core registration system",
81+
address: extendedRegistration,
82+
},
6983
InitModule: {
7084
bytecode: initModuleBytecode,
7185
deployedBytecodeSize: initModuleDeployedBytecodeSize,

packages/world/mud.config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export const configInput = {
4444
delegationControlId: "ResourceId",
4545
},
4646
key: ["delegator", "delegatee"],
47+
codegen: {
48+
storeArgument: true,
49+
},
4750
},
4851
NamespaceDelegationControl: {
4952
schema: {
@@ -84,6 +87,18 @@ export const configInput = {
8487
},
8588
key: ["systemId"],
8689
},
90+
OptionalSystemHooks: {
91+
schema: {
92+
player: "address",
93+
systemId: "ResourceId",
94+
callDataHash: "bytes32",
95+
hooks: "bytes21[]",
96+
},
97+
key: ["player", "systemId", "callDataHash"],
98+
codegen: {
99+
storeArgument: true,
100+
},
101+
},
87102
FunctionSelectors: {
88103
schema: {
89104
worldFunctionSelector: "bytes4",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.24;
3+
4+
import { IERC165 } from "./IERC165.sol";
5+
6+
interface ICustomUnregisterDelegation is IERC165 {
7+
function canUnregister(address delegator) external returns (bool);
8+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.24;
3+
4+
import { ResourceId } from "@latticexyz/store/src/ResourceId.sol";
5+
import { ISystemHook } from "./ISystemHook.sol";
6+
7+
/**
8+
* @title IOptionalSystemHook
9+
* @dev Interface defining optional hooks for external functionality.
10+
* Provides pre and post hooks that can be triggered before and after a system call respectively.
11+
* This interface adheres to the ERC-165 standard for determining interface support.
12+
*/
13+
interface IOptionalSystemHook is ISystemHook {
14+
/**
15+
* @notice Executes when a system hook is registered by the user.
16+
* @dev Provides the ability to add custom logic or checks when a system hook is registered.
17+
* @param msgSender The original sender of the system call.
18+
* @param systemId The ID of the system
19+
* @param enabledHooksBitmap Bitmap indicating which hooks are enabled
20+
* @param callDataHash The hash of the call data for the system hook
21+
*/
22+
function onRegisterHook(
23+
address msgSender,
24+
ResourceId systemId,
25+
uint8 enabledHooksBitmap,
26+
bytes32 callDataHash
27+
) external;
28+
29+
/**
30+
* @notice Executes when a system hook is unregistered by the user.
31+
* @dev Provides the ability to add custom logic or checks when a system hook is unregistered.
32+
* @param msgSender The original sender of the system call.
33+
* @param systemId The ID of the system
34+
* @param enabledHooksBitmap Bitmap indicating which hooks are enabled
35+
* @param callDataHash The hash of the call data for the system hook
36+
*/
37+
function onUnregisterHook(
38+
address msgSender,
39+
ResourceId systemId,
40+
uint8 enabledHooksBitmap,
41+
bytes32 callDataHash
42+
) external;
43+
}

packages/world/src/IWorldErrors.sol

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ interface IWorldErrors {
8080
*/
8181
error World_UnlimitedDelegationNotAllowed();
8282

83+
/**
84+
* @notice Raised when unregister delegation is called but a custom unregister delegation blocks it
85+
* e.g. if the delegation agreement wanted to enforce some conditions before allowing the delegation to be removed
86+
*/
87+
error World_CustomUnregisterDelegationNotAllowed();
88+
8389
/**
8490
* @notice Raised when there's an insufficient balance for a particular operation.
8591
* @param balance The current balance.
@@ -107,4 +113,12 @@ interface IWorldErrors {
107113
* @param functionSelector The function selector of the disallowed callback.
108114
*/
109115
error World_CallbackNotAllowed(bytes4 functionSelector);
116+
117+
/**
118+
* @notice Raised when trying to register an optional system hook that is already registered.
119+
* @param systemId The ID of the system.
120+
* @param hookAddress The address of the hook.
121+
* @param callDataHash The hash of the call data.
122+
*/
123+
error World_OptionalHookAlreadyRegistered(ResourceId systemId, address hookAddress, bytes32 callDataHash);
110124
}

packages/world/src/SystemCall.sol

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import { BEFORE_CALL_SYSTEM, AFTER_CALL_SYSTEM } from "./systemHookTypes.sol";
1212

1313
import { IWorldErrors } from "./IWorldErrors.sol";
1414
import { ISystemHook } from "./ISystemHook.sol";
15+
import { IOptionalSystemHook } from "./IOptionalSystemHook.sol";
1516

1617
import { Systems } from "./codegen/tables/Systems.sol";
1718
import { SystemHooks } from "./codegen/tables/SystemHooks.sol";
19+
import { OptionalSystemHooks } from "./codegen/tables/OptionalSystemHooks.sol";
1820
import { Balances } from "./codegen/tables/Balances.sol";
1921

2022
/**
@@ -145,6 +147,10 @@ library SystemCall {
145147
// Get system hooks
146148
bytes21[] memory hooks = SystemHooks._get(systemId);
147149

150+
// Get optional hooks specified by the caller
151+
bytes21[] memory optionalSystemHooks = OptionalSystemHooks._get(caller, systemId, bytes32(0));
152+
bytes21[] memory optionalSystemHooksWithCallData = OptionalSystemHooks._get(caller, systemId, keccak256(callData));
153+
148154
// Call onBeforeCallSystem hooks (before calling the system)
149155
for (uint256 i; i < hooks.length; i++) {
150156
Hook hook = Hook.wrap(hooks[i]);
@@ -153,6 +159,21 @@ library SystemCall {
153159
}
154160
}
155161

162+
// Call optional onBeforeCallSystem hooks (before calling the system)
163+
for (uint256 i; i < optionalSystemHooks.length; i++) {
164+
Hook hook = Hook.wrap(optionalSystemHooks[i]);
165+
if (hook.isEnabled(BEFORE_CALL_SYSTEM)) {
166+
IOptionalSystemHook(hook.getAddress()).onBeforeCallSystem(caller, systemId, callData);
167+
}
168+
}
169+
170+
for (uint256 i; i < optionalSystemHooksWithCallData.length; i++) {
171+
Hook hook = Hook.wrap(optionalSystemHooksWithCallData[i]);
172+
if (hook.isEnabled(BEFORE_CALL_SYSTEM)) {
173+
IOptionalSystemHook(hook.getAddress()).onBeforeCallSystem(caller, systemId, callData);
174+
}
175+
}
176+
156177
// Call the system and forward any return data
157178
(success, data) = call({ caller: caller, value: value, systemId: systemId, callData: callData });
158179

@@ -163,6 +184,20 @@ library SystemCall {
163184
ISystemHook(hook.getAddress()).onAfterCallSystem(caller, systemId, callData);
164185
}
165186
}
187+
188+
// Call optional onAfterCallSystem hooks (after calling the system)
189+
for (uint256 i; i < optionalSystemHooks.length; i++) {
190+
Hook hook = Hook.wrap(optionalSystemHooks[i]);
191+
if (hook.isEnabled(AFTER_CALL_SYSTEM)) {
192+
IOptionalSystemHook(hook.getAddress()).onAfterCallSystem(caller, systemId, callData);
193+
}
194+
}
195+
for (uint256 i; i < optionalSystemHooksWithCallData.length; i++) {
196+
Hook hook = Hook.wrap(optionalSystemHooksWithCallData[i]);
197+
if (hook.isEnabled(AFTER_CALL_SYSTEM)) {
198+
IOptionalSystemHook(hook.getAddress()).onAfterCallSystem(caller, systemId, callData);
199+
}
200+
}
166201
}
167202

168203
/**

packages/world/src/codegen/index.sol

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/world/src/codegen/interfaces/IBaseWorld.sol

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/world/src/codegen/interfaces/IExtendedRegistrationSystem.sol

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/world/src/codegen/interfaces/IExtendedWorldRegistrationSystem.sol

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)