From 5741d53d0a39990a0d7b2842f1f012973655e060 Mon Sep 17 00:00:00 2001 From: alvarius Date: Mon, 25 Sep 2023 01:25:14 +0100 Subject: [PATCH] feat(world): add `batchCallFrom` (#1594) --- .changeset/serious-plants-itch.md | 22 +++ packages/world-modules/gas-report.json | 26 +-- packages/world/gas-report.json | 26 ++- .../src/codegen/interfaces/IBaseWorld.sol | 4 +- .../codegen/interfaces/IBatchCallSystem.sol | 12 ++ .../codegen/interfaces/ICallBatchSystem.sol | 10 - .../world/src/modules/core/CoreModule.sol | 9 +- .../world/src/modules/core/CoreSystem.sol | 4 +- .../core/implementations/BatchCallSystem.sol | 44 +++++ .../core/implementations/CallBatchSystem.sol | 27 --- packages/world/src/modules/core/types.sol | 6 + packages/world/test/BatchCall.t.sol | 175 ++++++++++++++++++ packages/world/test/CallBatch.t.sol | 109 ----------- packages/world/test/World.t.sol | 7 +- 14 files changed, 301 insertions(+), 180 deletions(-) create mode 100644 .changeset/serious-plants-itch.md create mode 100644 packages/world/src/codegen/interfaces/IBatchCallSystem.sol delete mode 100644 packages/world/src/codegen/interfaces/ICallBatchSystem.sol create mode 100644 packages/world/src/modules/core/implementations/BatchCallSystem.sol delete mode 100644 packages/world/src/modules/core/implementations/CallBatchSystem.sol create mode 100644 packages/world/test/BatchCall.t.sol delete mode 100644 packages/world/test/CallBatch.t.sol diff --git a/.changeset/serious-plants-itch.md b/.changeset/serious-plants-itch.md new file mode 100644 index 0000000000..b6fbe7134b --- /dev/null +++ b/.changeset/serious-plants-itch.md @@ -0,0 +1,22 @@ +--- +"@latticexyz/world": major +--- + +- `IBaseWorld` now has a `batchCallFrom` method, which allows system calls via `callFrom` to be executed in batch. + +```solidity +import { SystemCallFromData } from "@latticexyz/world/modules/core/types.sol"; + +interface IBaseWorld { + function batchCallFrom(SystemCallFromData[] calldata systemCalls) external returns (bytes[] memory returnDatas); +} +``` + +- The `callBatch` method of `IBaseWorld` has been renamed to `batchCall` to align better with the `batchCallFrom` method. + +```diff +interface IBaseWorld { +- function callBatch(SystemCallData[] calldata systemCalls) external returns (bytes[] memory returnDatas); ++ function batchCall(SystemCallData[] calldata systemCalls) external returns (bytes[] memory returnDatas); +} +``` diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index 3e5655abe5..1dd64dfa2b 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -3,13 +3,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1408400 + "gasUsed": 1408533 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1408400 + "gasUsed": 1408533 }, { "file": "test/KeysInTableModule.t.sol", @@ -21,13 +21,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1408400 + "gasUsed": 1408533 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1408400 + "gasUsed": 1408533 }, { "file": "test/KeysInTableModule.t.sol", @@ -45,7 +45,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1408400 + "gasUsed": 1408533 }, { "file": "test/KeysInTableModule.t.sol", @@ -63,7 +63,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 649560 + "gasUsed": 649692 }, { "file": "test/KeysWithValueModule.t.sol", @@ -81,7 +81,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 649560 + "gasUsed": 649692 }, { "file": "test/KeysWithValueModule.t.sol", @@ -93,7 +93,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 649560 + "gasUsed": 649692 }, { "file": "test/KeysWithValueModule.t.sol", @@ -111,7 +111,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 649560 + "gasUsed": 649692 }, { "file": "test/KeysWithValueModule.t.sol", @@ -195,7 +195,7 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "register a callbound delegation", - "gasUsed": 117579 + "gasUsed": 117623 }, { "file": "test/StandardDelegationsModule.t.sol", @@ -207,7 +207,7 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "register a timebound delegation", - "gasUsed": 112073 + "gasUsed": 112117 }, { "file": "test/StandardDelegationsModule.t.sol", @@ -219,7 +219,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 676208 + "gasUsed": 676231 }, { "file": "test/UniqueEntityModule.t.sol", @@ -231,7 +231,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 643472 + "gasUsed": 643428 }, { "file": "test/UniqueEntityModule.t.sol", diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index d08185a933..3243c97e71 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -42,10 +42,16 @@ "gasUsed": 1326 }, { - "file": "test/CallBatch.t.sol", - "test": "testCallBatchReturnData", - "name": "call systems with callBatch", - "gasUsed": 45264 + "file": "test/BatchCall.t.sol", + "test": "testBatchCallFromReturnData", + "name": "call systems with batchCallFrom", + "gasUsed": 46608 + }, + { + "file": "test/BatchCall.t.sol", + "test": "testBatchCallReturnData", + "name": "call systems with batchCall", + "gasUsed": 45405 }, { "file": "test/World.t.sol", @@ -63,7 +69,7 @@ "file": "test/World.t.sol", "test": "testCallFromUnlimitedDelegation", "name": "register an unlimited delegation", - "gasUsed": 47695 + "gasUsed": 47739 }, { "file": "test/World.t.sol", @@ -87,31 +93,31 @@ "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 83287 + "gasUsed": 83265 }, { "file": "test/World.t.sol", "test": "testRegisterNamespace", "name": "Register a new namespace", - "gasUsed": 121072 + "gasUsed": 121116 }, { "file": "test/World.t.sol", "test": "testRegisterRootFunctionSelector", "name": "Register a root function selector", - "gasUsed": 80571 + "gasUsed": 80549 }, { "file": "test/World.t.sol", "test": "testRegisterSystem", "name": "register a system", - "gasUsed": 162954 + "gasUsed": 162932 }, { "file": "test/World.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 637709 + "gasUsed": 637753 }, { "file": "test/World.t.sol", diff --git a/packages/world/src/codegen/interfaces/IBaseWorld.sol b/packages/world/src/codegen/interfaces/IBaseWorld.sol index 53c74f4c5b..a8112b5dc0 100644 --- a/packages/world/src/codegen/interfaces/IBaseWorld.sol +++ b/packages/world/src/codegen/interfaces/IBaseWorld.sol @@ -9,7 +9,7 @@ import { IWorldKernel } from "../../interfaces/IWorldKernel.sol"; import { ICoreSystem } from "./ICoreSystem.sol"; import { IAccessManagementSystem } from "./IAccessManagementSystem.sol"; import { IBalanceTransferSystem } from "./IBalanceTransferSystem.sol"; -import { ICallBatchSystem } from "./ICallBatchSystem.sol"; +import { IBatchCallSystem } from "./IBatchCallSystem.sol"; import { IModuleInstallationSystem } from "./IModuleInstallationSystem.sol"; import { IWorldRegistrationSystem } from "./IWorldRegistrationSystem.sol"; @@ -23,7 +23,7 @@ interface IBaseWorld is ICoreSystem, IAccessManagementSystem, IBalanceTransferSystem, - ICallBatchSystem, + IBatchCallSystem, IModuleInstallationSystem, IWorldRegistrationSystem { diff --git a/packages/world/src/codegen/interfaces/IBatchCallSystem.sol b/packages/world/src/codegen/interfaces/IBatchCallSystem.sol new file mode 100644 index 0000000000..aa957a321d --- /dev/null +++ b/packages/world/src/codegen/interfaces/IBatchCallSystem.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.21; + +/* Autogenerated file. Do not edit manually. */ + +import { SystemCallData, SystemCallFromData } from "./../../modules/core/types.sol"; + +interface IBatchCallSystem { + function batchCall(SystemCallData[] calldata systemCalls) external returns (bytes[] memory returnDatas); + + function batchCallFrom(SystemCallFromData[] calldata systemCalls) external returns (bytes[] memory returnDatas); +} diff --git a/packages/world/src/codegen/interfaces/ICallBatchSystem.sol b/packages/world/src/codegen/interfaces/ICallBatchSystem.sol deleted file mode 100644 index b164789391..0000000000 --- a/packages/world/src/codegen/interfaces/ICallBatchSystem.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.21; - -/* Autogenerated file. Do not edit manually. */ - -import { SystemCallData } from "./../../modules/core/types.sol"; - -interface ICallBatchSystem { - function callBatch(SystemCallData[] calldata systemCalls) external returns (bytes[] memory returnDatas); -} diff --git a/packages/world/src/modules/core/CoreModule.sol b/packages/world/src/modules/core/CoreModule.sol index e2213b77f8..62d3e35723 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -29,7 +29,7 @@ import { Balances } from "../../codegen/tables/Balances.sol"; import { AccessManagementSystem } from "./implementations/AccessManagementSystem.sol"; import { BalanceTransferSystem } from "./implementations/BalanceTransferSystem.sol"; -import { CallBatchSystem } from "./implementations/CallBatchSystem.sol"; +import { BatchCallSystem } from "./implementations/BatchCallSystem.sol"; import { ModuleInstallationSystem } from "./implementations/ModuleInstallationSystem.sol"; import { StoreRegistrationSystem } from "./implementations/StoreRegistrationSystem.sol"; import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; @@ -98,7 +98,7 @@ contract CoreModule is Module { * Register function selectors for all CoreSystem functions in the World */ function _registerFunctionSelectors() internal { - string[18] memory functionSignatures = [ + string[19] memory functionSignatures = [ // --- AccessManagementSystem --- "grantAccess(bytes32,address)", "revokeAccess(bytes32,address)", @@ -106,8 +106,9 @@ contract CoreModule is Module { // --- BalanceTransferSystem --- "transferBalanceToNamespace(bytes32,bytes32,uint256)", "transferBalanceToAddress(bytes32,address,uint256)", - // --- CallBatchSystem --- - "callBatch((bytes32,bytes)[])", + // --- BatchCallSystem --- + "batchCall((bytes32,bytes)[])", + "batchCallFrom((address,bytes32,bytes)[])", // --- ModuleInstallationSystem --- "installModule(address,bytes)", // --- StoreRegistrationSystem --- diff --git a/packages/world/src/modules/core/CoreSystem.sol b/packages/world/src/modules/core/CoreSystem.sol index 61f56f26d7..875145cc47 100644 --- a/packages/world/src/modules/core/CoreSystem.sol +++ b/packages/world/src/modules/core/CoreSystem.sol @@ -5,7 +5,7 @@ import { IWorldErrors } from "../../interfaces/IWorldErrors.sol"; import { AccessManagementSystem } from "./implementations/AccessManagementSystem.sol"; import { BalanceTransferSystem } from "./implementations/BalanceTransferSystem.sol"; -import { CallBatchSystem } from "./implementations/CallBatchSystem.sol"; +import { BatchCallSystem } from "./implementations/BatchCallSystem.sol"; import { ModuleInstallationSystem } from "./implementations/ModuleInstallationSystem.sol"; import { StoreRegistrationSystem } from "./implementations/StoreRegistrationSystem.sol"; import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; @@ -18,7 +18,7 @@ contract CoreSystem is IWorldErrors, AccessManagementSystem, BalanceTransferSystem, - CallBatchSystem, + BatchCallSystem, ModuleInstallationSystem, StoreRegistrationSystem, WorldRegistrationSystem diff --git a/packages/world/src/modules/core/implementations/BatchCallSystem.sol b/packages/world/src/modules/core/implementations/BatchCallSystem.sol new file mode 100644 index 0000000000..e7bc1d0141 --- /dev/null +++ b/packages/world/src/modules/core/implementations/BatchCallSystem.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { System } from "../../../System.sol"; +import { IBaseWorld } from "../../../codegen/interfaces/IBaseWorld.sol"; +import { revertWithBytes } from "../../../revertWithBytes.sol"; + +import { SystemCallData, SystemCallFromData } from "../types.sol"; + +contract BatchCallSystem is System { + /** + * Batch calls to multiple systems into a single transaction, return the array of return data. + */ + function batchCall(SystemCallData[] calldata systemCalls) public returns (bytes[] memory returnDatas) { + IBaseWorld world = IBaseWorld(_world()); + returnDatas = new bytes[](systemCalls.length); + + for (uint256 i; i < systemCalls.length; i++) { + (bool success, bytes memory returnData) = address(world).delegatecall( + abi.encodeCall(world.call, (systemCalls[i].systemId, systemCalls[i].callData)) + ); + if (!success) revertWithBytes(returnData); + + returnDatas[i] = abi.decode(returnData, (bytes)); + } + } + + /** + * Batch calls to multiple systems into a single transaction, return the array of return data. + */ + function batchCallFrom(SystemCallFromData[] calldata systemCalls) public returns (bytes[] memory returnDatas) { + IBaseWorld world = IBaseWorld(_world()); + returnDatas = new bytes[](systemCalls.length); + + for (uint256 i; i < systemCalls.length; i++) { + (bool success, bytes memory returnData) = address(world).delegatecall( + abi.encodeCall(world.callFrom, (systemCalls[i].from, systemCalls[i].systemId, systemCalls[i].callData)) + ); + if (!success) revertWithBytes(returnData); + + returnDatas[i] = abi.decode(returnData, (bytes)); + } + } +} diff --git a/packages/world/src/modules/core/implementations/CallBatchSystem.sol b/packages/world/src/modules/core/implementations/CallBatchSystem.sol deleted file mode 100644 index 8cabb6ea90..0000000000 --- a/packages/world/src/modules/core/implementations/CallBatchSystem.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; - -import { System } from "../../../System.sol"; -import { IBaseWorld } from "../../../codegen/interfaces/IBaseWorld.sol"; -import { revertWithBytes } from "../../../revertWithBytes.sol"; - -import { SystemCallData } from "../types.sol"; - -contract CallBatchSystem is System { - /** - * Batch calls to multiple systems into a single transaction, return the array of return data. - */ - function callBatch(SystemCallData[] calldata systemCalls) public returns (bytes[] memory returnDatas) { - IBaseWorld world = IBaseWorld(_world()); - returnDatas = new bytes[](systemCalls.length); - - for (uint256 i; i < systemCalls.length; i++) { - (bool success, bytes memory returnData) = address(world).delegatecall( - abi.encodeCall(world.call, (systemCalls[i].systemId, systemCalls[i].callData)) - ); - if (!success) revertWithBytes(returnData); - - returnDatas[i] = abi.decode(returnData, (bytes)); - } - } -} diff --git a/packages/world/src/modules/core/types.sol b/packages/world/src/modules/core/types.sol index d7061059c7..8cb71ef19f 100644 --- a/packages/world/src/modules/core/types.sol +++ b/packages/world/src/modules/core/types.sol @@ -7,3 +7,9 @@ struct SystemCallData { ResourceId systemId; bytes callData; } + +struct SystemCallFromData { + address from; + ResourceId systemId; + bytes callData; +} diff --git a/packages/world/test/BatchCall.t.sol b/packages/world/test/BatchCall.t.sol new file mode 100644 index 0000000000..2380a18c25 --- /dev/null +++ b/packages/world/test/BatchCall.t.sol @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { Test } from "forge-std/Test.sol"; +import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; + +import { World } from "../src/World.sol"; +import { System } from "../src/System.sol"; +import { UNLIMITED_DELEGATION } from "../src/constants.sol"; +import { ResourceId, WorldResourceIdLib } from "../src/WorldResourceId.sol"; +import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; + +import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; +import { IBaseWorld } from "../src/codegen/interfaces/IBaseWorld.sol"; +import { CoreModule } from "../src/modules/core/CoreModule.sol"; +import { SystemCallData, SystemCallFromData } from "../src/modules/core/types.sol"; + +address constant caller = address(1); +address constant delegator = address(2); +address constant delegatee = address(3); + +contract TestSystem is System { + address public admin; + uint256 public counter; + + function getStoreAddress() public view returns (address) { + return StoreSwitch.getStoreAddress(); + } + + function msgSender() public view returns (address) { + return _msgSender(); + } + + function setAdmin(address newAdmin) public { + if (admin != address(0) && _msgSender() != admin) { + revert("sender is not admin"); + } + admin = newAdmin; + } + + function increment() public { + require(_msgSender() == admin, "sender is not admin"); + + counter++; + } +} + +contract BatchCallTest is Test, GasReporter { + IBaseWorld world; + bytes14 namespace = "namespace"; + bytes16 name = "testSystem"; + + ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); + + function setUp() public { + world = IBaseWorld(address(new World())); + world.initialize(new CoreModule()); + } + + function testBatchCall() public { + // Register a new system + TestSystem system = new TestSystem(); + world.registerSystem(systemId, system, true); + + // Try to increment the counter without setting the admin + SystemCallData[] memory systemCalls = new SystemCallData[](1); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.expectRevert("sender is not admin"); + world.batchCall(systemCalls); + + // Set the admin and increment the counter twice + systemCalls = new SystemCallData[](3); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.setAdmin, (caller))); + systemCalls[1] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + systemCalls[2] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.expectRevert("sender is not admin"); + world.batchCall(systemCalls); + + vm.prank(caller); + world.batchCall(systemCalls); + + assertEq(system.counter(), 2, "wrong counter value"); + + // Increment the counter again + systemCalls = new SystemCallData[](1); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(caller); + world.batchCall(systemCalls); + + assertEq(system.counter(), 3, "wrong counter value"); + } + + function testBatchCallReturnData() public { + // Register a new system + TestSystem system = new TestSystem(); + world.registerSystem(systemId, system, true); + + // Batch call functions on the system + SystemCallData[] memory systemCalls = new SystemCallData[](2); + + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.msgSender, ())); + systemCalls[1] = SystemCallData(systemId, abi.encodeCall(TestSystem.getStoreAddress, ())); + + vm.prank(caller); + startGasReport("call systems with batchCall"); + bytes[] memory returnDatas = world.batchCall(systemCalls); + endGasReport(); + + assertEq(abi.decode(returnDatas[0], (address)), caller, "wrong address returned"); + assertEq(abi.decode(returnDatas[1], (address)), address(world), "wrong store returned"); + } + + function testBatchCallFrom() public { + // Register a new system + TestSystem system = new TestSystem(); + world.registerSystem(systemId, system, true); + + // Try to increment the counter without creating a delegation + SystemCallFromData[] memory systemCalls = new SystemCallFromData[](1); + systemCalls[0] = SystemCallFromData(delegator, systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(delegatee); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.World_DelegationNotFound.selector, delegator, delegatee)); + world.batchCallFrom(systemCalls); + + // Create an unlimited delegation + vm.prank(delegator); + world.registerDelegation(delegatee, UNLIMITED_DELEGATION, new bytes(0)); + + // Try to increment the counter without setting the admin + vm.prank(delegatee); + vm.expectRevert("sender is not admin"); + world.batchCallFrom(systemCalls); + + // Set the admin and increment the counter twice + systemCalls = new SystemCallFromData[](4); + systemCalls[0] = SystemCallFromData(delegatee, systemId, abi.encodeCall(TestSystem.setAdmin, (delegator))); + systemCalls[1] = SystemCallFromData(delegator, systemId, abi.encodeCall(TestSystem.increment, ())); + systemCalls[2] = SystemCallFromData(delegator, systemId, abi.encodeCall(TestSystem.setAdmin, (delegatee))); + systemCalls[3] = SystemCallFromData(delegatee, systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(delegatee); + world.batchCallFrom(systemCalls); + + assertEq(system.counter(), 2, "wrong counter value"); + } + + function testBatchCallFromReturnData() public { + // Register a new system + TestSystem system = new TestSystem(); + world.registerSystem(systemId, system, true); + + // Create an unlimited delegation + vm.prank(delegator); + world.registerDelegation(delegatee, UNLIMITED_DELEGATION, new bytes(0)); + + // Batch call functions on the system + SystemCallFromData[] memory systemCalls = new SystemCallFromData[](2); + + systemCalls[0] = SystemCallFromData(delegatee, systemId, abi.encodeCall(TestSystem.msgSender, ())); + systemCalls[1] = SystemCallFromData(delegator, systemId, abi.encodeCall(TestSystem.msgSender, ())); + + vm.prank(delegatee); + startGasReport("call systems with batchCallFrom"); + bytes[] memory returnDatas = world.batchCallFrom(systemCalls); + endGasReport(); + + assertEq(abi.decode(returnDatas[0], (address)), delegatee, "wrong delegatee returned"); + assertEq(abi.decode(returnDatas[1], (address)), delegator, "wrong delegator returned"); + } +} diff --git a/packages/world/test/CallBatch.t.sol b/packages/world/test/CallBatch.t.sol deleted file mode 100644 index 8fab0a1baf..0000000000 --- a/packages/world/test/CallBatch.t.sol +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; - -import { Test } from "forge-std/Test.sol"; -import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; -import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; - -import { World } from "../src/World.sol"; -import { System } from "../src/System.sol"; -import { ResourceId, WorldResourceIdLib } from "../src/WorldResourceId.sol"; -import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; - -import { IBaseWorld } from "../src/codegen/interfaces/IBaseWorld.sol"; -import { CoreModule } from "../src/modules/core/CoreModule.sol"; -import { SystemCallData } from "../src/modules/core/types.sol"; - -address constant caller = address(1); - -contract TestSystem is System { - address public admin; - uint256 public counter; - - function getStoreAddress() public view returns (address) { - return StoreSwitch.getStoreAddress(); - } - - function msgSender() public view returns (address) { - return _msgSender(); - } - - function setAdmin(address newAdmin) public { - admin = newAdmin; - } - - function increment() public { - require(_msgSender() == admin, "sender is not admin"); - - counter++; - } -} - -contract CallBatchTest is Test, GasReporter { - IBaseWorld world; - bytes14 namespace = "namespace"; - bytes16 name = "testSystem"; - - ResourceId systemId = WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: namespace, name: name }); - - function setUp() public { - world = IBaseWorld(address(new World())); - world.initialize(new CoreModule()); - } - - function testCallBatch() public { - // Register a new system - TestSystem system = new TestSystem(); - world.registerSystem(systemId, system, true); - - // Try to increment the counter without setting the admin - SystemCallData[] memory systemCalls = new SystemCallData[](1); - systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); - - vm.expectRevert("sender is not admin"); - world.callBatch(systemCalls); - - // Set the admin and increment the counter twice - systemCalls = new SystemCallData[](3); - systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.setAdmin, (caller))); - systemCalls[1] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); - systemCalls[2] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); - - vm.expectRevert("sender is not admin"); - world.callBatch(systemCalls); - - vm.prank(caller); - world.callBatch(systemCalls); - - assertEq(system.counter(), 2, "wrong counter value"); - - // Increment the counter again - systemCalls = new SystemCallData[](1); - systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); - - vm.prank(caller); - world.callBatch(systemCalls); - - assertEq(system.counter(), 3, "wrong counter value"); - } - - function testCallBatchReturnData() public { - // Register a new system - TestSystem system = new TestSystem(); - world.registerSystem(systemId, system, true); - - // Batch call functions on the system - SystemCallData[] memory systemCalls = new SystemCallData[](2); - - systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.msgSender, ())); - systemCalls[1] = SystemCallData(systemId, abi.encodeCall(TestSystem.getStoreAddress, ())); - - vm.prank(caller); - startGasReport("call systems with callBatch"); - bytes[] memory returnDatas = world.callBatch(systemCalls); - endGasReport(); - - assertEq(abi.decode(returnDatas[0], (address)), caller, "wrong address returned"); - assertEq(abi.decode(returnDatas[1], (address)), address(world), "wrong store returned"); - } -} diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index 684d54f896..68cd479fd3 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -216,7 +216,7 @@ contract WorldTest is Test, GasReporter { // Should have registered the core system function selectors CoreSystem coreSystem = CoreSystem(Systems.getSystem(world, CORE_SYSTEM_ID)); - bytes4[18] memory coreFunctionSignatures = [ + bytes4[19] memory coreFunctionSignatures = [ // --- AccessManagementSystem --- coreSystem.grantAccess.selector, coreSystem.revokeAccess.selector, @@ -224,8 +224,9 @@ contract WorldTest is Test, GasReporter { // --- BalanceTransferSystem --- coreSystem.transferBalanceToNamespace.selector, coreSystem.transferBalanceToAddress.selector, - // --- CallBatchSystem --- - coreSystem.callBatch.selector, + // --- BatchCallSystem --- + coreSystem.batchCall.selector, + coreSystem.batchCallFrom.selector, // --- ModuleInstallationSystem --- coreSystem.installModule.selector, // --- StoreRegistrationSystem ---