From 3da3cd3c0dde693ffb1c0e05f069f28e817ac43b Mon Sep 17 00:00:00 2001 From: alvarius Date: Mon, 17 Mar 2025 22:08:41 +0100 Subject: [PATCH 1/5] pin foundry version --- .github/actions/setup-prerequisites/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-prerequisites/action.yml b/.github/actions/setup-prerequisites/action.yml index b4d6534721..2a8d93b223 100644 --- a/.github/actions/setup-prerequisites/action.yml +++ b/.github/actions/setup-prerequisites/action.yml @@ -16,4 +16,4 @@ runs: - name: Setup foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly + version: nightly-f47d7e0c29a36372908b917cd74aa589d5888f8e From 45a77684c3b8fc8e425d745c4845d5484b84f210 Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Fri, 24 Jan 2025 11:42:41 +0000 Subject: [PATCH 2/5] add failing test --- packages/world/test/BatchCall.t.sol | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/packages/world/test/BatchCall.t.sol b/packages/world/test/BatchCall.t.sol index 0af2b6b434..d9cb3710aa 100644 --- a/packages/world/test/BatchCall.t.sol +++ b/packages/world/test/BatchCall.t.sol @@ -14,6 +14,8 @@ import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; import { IWorldErrors } from "../src/IWorldErrors.sol"; import { IBaseWorld } from "../src/codegen/interfaces/IBaseWorld.sol"; import { SystemCallData, SystemCallFromData } from "../src/modules/init/types.sol"; +import { BATCH_CALL_SYSTEM_ID } from "../src/modules/init/constants.sol"; +import { BatchCallSystem } from "../src/modules/init/implementations/BatchCallSystem.sol"; import { createWorld } from "./createWorld.sol"; @@ -175,4 +177,45 @@ contract BatchCallTest is Test, GasReporter { assertEq(abi.decode(returnDatas[0], (address)), delegatee, "wrong delegatee returned"); assertEq(abi.decode(returnDatas[1], (address)), delegator, "wrong delegator returned"); } + + /** + * If all calls come from the same delegation, it should be simpler and cheaper to compose + * calls via `callFrom(batchCall(...))` instead of `batchCallFrom(...)`. + */ + function testCallFromBatchCall() public { + // Register a new system + TestSystem system = new TestSystem(); + world.registerSystem(systemId, system, true); + + // Try to increment the counter without creating a delegation + SystemCallData[] memory systemCalls = new SystemCallData[](1); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(delegatee); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.World_DelegationNotFound.selector, delegator, delegatee)); + world.callFrom(delegator, BATCH_CALL_SYSTEM_ID, abi.encodeCall(BatchCallSystem.batchCall, (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.callFrom(delegator, BATCH_CALL_SYSTEM_ID, abi.encodeCall(BatchCallSystem.batchCall, (systemCalls))); + + assertEq(system.admin(), address(0)); + + // Set the admin and increment the counter twice + systemCalls = new SystemCallData[](3); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.setAdmin, (delegator))); + systemCalls[1] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + systemCalls[2] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(delegatee); + world.callFrom(delegator, BATCH_CALL_SYSTEM_ID, abi.encodeCall(BatchCallSystem.batchCall, (systemCalls))); + + assertEq(system.admin(), delegator); + assertEq(system.counter(), 2, "wrong counter value"); + } } From 15f07c34f03cce6ce6808895837b6eca3fb54227 Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Fri, 24 Jan 2025 11:58:49 +0000 Subject: [PATCH 3/5] use SystemCall lib --- .../modules/init/implementations/BatchCallSystem.sol | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/world/src/modules/init/implementations/BatchCallSystem.sol b/packages/world/src/modules/init/implementations/BatchCallSystem.sol index 9a62614193..aaa7e00a3a 100644 --- a/packages/world/src/modules/init/implementations/BatchCallSystem.sol +++ b/packages/world/src/modules/init/implementations/BatchCallSystem.sol @@ -6,6 +6,7 @@ import { IBaseWorld } from "../../../codegen/interfaces/IBaseWorld.sol"; import { revertWithBytes } from "../../../revertWithBytes.sol"; import { SystemCallData, SystemCallFromData } from "../types.sol"; import { LimitedCallContext } from "../LimitedCallContext.sol"; +import { SystemCall } from "../../../SystemCall.sol"; /** * @title Batch Call System @@ -26,11 +27,12 @@ contract BatchCallSystem is System, LimitedCallContext { 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)) + bytes memory returnData = SystemCall.callWithHooksOrRevert( + address(world), + systemCalls[i].systemId, + systemCalls[i].callData, + 0 ); - if (!success) revertWithBytes(returnData); - returnDatas[i] = abi.decode(returnData, (bytes)); } } From fae4ad59ff32c9596340c85b37876db78429dc21 Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Fri, 24 Jan 2025 12:03:21 +0000 Subject: [PATCH 4/5] _msgSender() --- .../world/src/modules/init/implementations/BatchCallSystem.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/world/src/modules/init/implementations/BatchCallSystem.sol b/packages/world/src/modules/init/implementations/BatchCallSystem.sol index aaa7e00a3a..e7bd897556 100644 --- a/packages/world/src/modules/init/implementations/BatchCallSystem.sol +++ b/packages/world/src/modules/init/implementations/BatchCallSystem.sol @@ -23,12 +23,11 @@ contract BatchCallSystem is System, LimitedCallContext { function batchCall( SystemCallData[] calldata systemCalls ) public onlyDelegatecall returns (bytes[] memory returnDatas) { - IBaseWorld world = IBaseWorld(_world()); returnDatas = new bytes[](systemCalls.length); for (uint256 i; i < systemCalls.length; i++) { bytes memory returnData = SystemCall.callWithHooksOrRevert( - address(world), + _msgSender(), systemCalls[i].systemId, systemCalls[i].callData, 0 From 248301f7654814b8b1b0eeb630dfdcd4dfa3b444 Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Fri, 24 Jan 2025 13:03:59 +0000 Subject: [PATCH 5/5] fix --- .../src/modules/init/implementations/BatchCallSystem.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/world/src/modules/init/implementations/BatchCallSystem.sol b/packages/world/src/modules/init/implementations/BatchCallSystem.sol index e7bd897556..71450d2cc5 100644 --- a/packages/world/src/modules/init/implementations/BatchCallSystem.sol +++ b/packages/world/src/modules/init/implementations/BatchCallSystem.sol @@ -26,13 +26,12 @@ contract BatchCallSystem is System, LimitedCallContext { returnDatas = new bytes[](systemCalls.length); for (uint256 i; i < systemCalls.length; i++) { - bytes memory returnData = SystemCall.callWithHooksOrRevert( + returnDatas[i] = SystemCall.callWithHooksOrRevert( _msgSender(), systemCalls[i].systemId, systemCalls[i].callData, 0 ); - returnDatas[i] = abi.decode(returnData, (bytes)); } } @@ -49,11 +48,11 @@ contract BatchCallSystem is System, LimitedCallContext { returnDatas = new bytes[](systemCalls.length); for (uint256 i; i < systemCalls.length; i++) { + // TODO: swap this with SystemCall.callFromWithHooksOrRevert once available (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)); } }