Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(world): add SystemCall.staticcall #3381

Merged
merged 10 commits into from
Nov 25, 2024
Merged
5 changes: 5 additions & 0 deletions .changeset/yellow-trains-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/world": patch
---

Add a SystemCall.staticcall function that performs a staticcall without executing hooks.
55 changes: 55 additions & 0 deletions docs/pages/world/reference/internal/systemcall.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,61 @@ function call(
| `success` | `bool` | A flag indicating whether the system call was successful. |
| `data` | `bytes` | The return data from the system call. |

#### staticcall

Makes a staticcall to a system identified by its Resource ID while ensuring necessary access controls.

_This function does not revert if the system staticcall fails. Instead, it returns a success flag._

```solidity
function staticcall(
address caller,
ResourceId systemId,
bytes memory callData
) internal view returns (bool success, bytes memory data);
```

**Parameters**

| Name | Type | Description |
| ---------- | ------------ | -------------------------------------------------- |
| `caller` | `address` | The address initiating the system staticcall. |
| `systemId` | `ResourceId` | The unique Resource ID of the system being called. |
| `callData` | `bytes` | The calldata to be executed in the system. |

**Returns**

| Name | Type | Description |
| --------- | ------- | --------------------------------------------------------------- |
| `success` | `bool` | A flag indicating whether the system staticcall was successful. |
| `data` | `bytes` | The return data from the system staticcall. |

#### staticcallOrRevert

Makes a staticcall to a system identified by its Resource ID, ensures access controls, and reverts on failure.

```solidity
function staticcallOrRevert(
address caller,
ResourceId systemId,
bytes memory callData
) internal view returns (bytes memory data);
```

**Parameters**

| Name | Type | Description |
| ---------- | ------------ | -------------------------------------------------- |
| `caller` | `address` | The address initiating the system staticcall. |
| `systemId` | `ResourceId` | The unique Resource ID of the system being called. |
| `callData` | `bytes` | The calldata to be executed in the system. |

**Returns**

| Name | Type | Description |
| ------ | ------- | ------------------------------------------- |
| `data` | `bytes` | The return data from the system staticcall. |

#### callWithHooks

Calls a system identified by its Resource ID, ensuring access controls, and triggers associated system hooks.
Expand Down
27 changes: 27 additions & 0 deletions docs/pages/world/reference/world-context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,33 @@ function callWithContext(
| `success` | `bool` | A boolean indicating whether the call was successful or not. |
| `data` | `bytes` | The abi encoded return data from the call. |

#### staticcallWithContext

Makes a staticcall to the target contract with context values appended to the calldata.

```solidity
function staticcallWithContext(
address msgSender,
address target,
bytes memory callData
) internal view returns (bool success, bytes memory data);
```

**Parameters**

| Name | Type | Description |
| ----------- | --------- | -------------------------------------- |
| `msgSender` | `address` | The address of the transaction sender. |
| `target` | `address` | The address of the contract to call. |
| `callData` | `bytes` | The calldata for the staticcall. |

**Returns**

| Name | Type | Description |
| --------- | ------- | ------------------------------------------------------------------ |
| `success` | `bool` | A boolean indicating whether the staticcall was successful or not. |
| `data` | `bytes` | The abi encoded return data from the staticcall. |

#### delegatecallWithContext

Makes a delegatecall to the target contract with context values appended to the calldata.
Expand Down
4 changes: 2 additions & 2 deletions packages/store/ts/flattenStoreLogs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ describe("flattenStoreLogs", async () => {
"Store_SetRecord store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)",
"Store_SetRecord store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)",
"Store_SetRecord world__Systems (0x737900000000000000000000000000004d6f766553797374656d000000000000)",
"Store_SetRecord world__SystemRegistry (0x000000000000000000000000c3082aa42cf81d515c45c3c2c59775f71dfe987c)",
"Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000c3082aa42cf81d515c45c3c2c59775f71dfe987c)",
"Store_SetRecord world__SystemRegistry (0x00000000000000000000000008f2b45d8787be8a81869d9968f25323861352b0)",
"Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000008f2b45d8787be8a81869d9968f25323861352b0)",
"Store_SetRecord world__FunctionSelector (0xb591186e00000000000000000000000000000000000000000000000000000000)",
"Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)",
"Store_SetRecord store__Tables (0x7462000000000000000000000000000043616c6c576974685369676e61747572)",
Expand Down
4 changes: 2 additions & 2 deletions packages/store/ts/getStoreLogs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ describe("getStoreLogs", async () => {
"Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)",
"Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)",
"Store_SetRecord world__Systems (0x737900000000000000000000000000004d6f766553797374656d000000000000)",
"Store_SpliceStaticData world__SystemRegistry (0x000000000000000000000000c3082aa42cf81d515c45c3c2c59775f71dfe987c)",
"Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000c3082aa42cf81d515c45c3c2c59775f71dfe987c)",
"Store_SpliceStaticData world__SystemRegistry (0x00000000000000000000000008f2b45d8787be8a81869d9968f25323861352b0)",
"Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000008f2b45d8787be8a81869d9968f25323861352b0)",
"Store_SetRecord world__FunctionSelector (0xb591186e00000000000000000000000000000000000000000000000000000000)",
"Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)",
"Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)",
Expand Down
51 changes: 51 additions & 0 deletions packages/world/src/SystemCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,57 @@ library SystemCall {
});
}

/**
* @notice Makes a staticcall to a system identified by its Resource ID while ensuring necessary access controls.
* @dev This function does not revert if the system staticcall fails. Instead, it returns a success flag.
* @param caller The address initiating the system staticcall.
* @param systemId The unique Resource ID of the system being called.
* @param callData The calldata to be executed in the system.
* @return success A flag indicating whether the system staticcall was successful.
* @return data The return data from the system staticcall.
*/
function staticcall(
address caller,
ResourceId systemId,
bytes memory callData
) internal view returns (bool success, bytes memory data) {
// Load the system data
(address systemAddress, bool publicAccess) = Systems._get(systemId);

// Check if the system exists
if (systemAddress == address(0)) revert IWorldErrors.World_ResourceNotFound(systemId, systemId.toString());

// Staticcalls are not supported for root systems
vdrg marked this conversation as resolved.
Show resolved Hide resolved
if (systemId.getNamespace() == ROOT_NAMESPACE) revert IWorldErrors.World_InvalidNamespace(ROOT_NAMESPACE);

// Allow access if the system is public or the caller has access to the namespace or name
if (!publicAccess) AccessControl._requireAccess(systemId, caller);

// Call the system and forward any return data
(success, data) = WorldContextProviderLib.staticcallWithContext({
msgSender: caller,
target: systemAddress,
callData: callData
});
}

/**
* @notice Makes a staticcall to a system identified by its Resource ID, ensures access controls, and reverts on failure.
* @param caller The address initiating the system staticcall.
* @param systemId The unique Resource ID of the system being called.
* @param callData The calldata to be executed in the system.
* @return data The return data from the system staticcall.
*/
function staticcallOrRevert(
address caller,
ResourceId systemId,
bytes memory callData
) internal view returns (bytes memory data) {
(bool success, bytes memory returnData) = staticcall({ caller: caller, systemId: systemId, callData: callData });
if (!success) revertWithBytes(returnData);
return returnData;
}

/**
* @notice Calls a system identified by its Resource ID, ensuring access controls, and triggers associated system hooks.
* @dev This function does not revert if the system call fails. Instead, it returns a success flag.
Expand Down
16 changes: 16 additions & 0 deletions packages/world/src/WorldContext.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,22 @@ library WorldContextProviderLib {
);
}

/**
* @notice Makes a staticcall to the target contract with context values appended to the calldata.
* @param msgSender The address of the transaction sender.
* @param target The address of the contract to call.
* @param callData The calldata for the staticcall.
* @return success A boolean indicating whether the staticcall was successful or not.
* @return data The abi encoded return data from the staticcall.
*/
function staticcallWithContext(
address msgSender,
address target,
bytes memory callData
) internal view returns (bool success, bytes memory data) {
(success, data) = target.staticcall(appendContext({ callData: callData, msgSender: msgSender, msgValue: 0 }));
}

/**
* @notice Makes a delegatecall to the target contract with context values appended to the calldata.
* @param msgSender The address of the transaction sender.
Expand Down
Loading