Skip to content

Commit

Permalink
feat(world): add SystemCall.staticcall (#3381)
Browse files Browse the repository at this point in the history
  • Loading branch information
vdrg authored Nov 25, 2024
1 parent c9da6ec commit 275c867
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 4 deletions.
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
52 changes: 52 additions & 0 deletions packages/world/src/SystemCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,58 @@ 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 yet, as it would require a runtime check
// that we are in the context of a staticcall before performing the delegatecall
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

0 comments on commit 275c867

Please sign in to comment.