Skip to content

Commit

Permalink
feat(world): add batchCallFrom (#1594)
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs authored Sep 25, 2023
1 parent c07fa02 commit 5741d53
Show file tree
Hide file tree
Showing 14 changed files with 301 additions and 180 deletions.
22 changes: 22 additions & 0 deletions .changeset/serious-plants-itch.md
Original file line number Diff line number Diff line change
@@ -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);
}
```
26 changes: 13 additions & 13 deletions packages/world-modules/gas-report.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down
26 changes: 16 additions & 10 deletions packages/world/gas-report.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/codegen/interfaces/IBaseWorld.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions packages/world/src/codegen/interfaces/IBatchCallSystem.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 0 additions & 10 deletions packages/world/src/codegen/interfaces/ICallBatchSystem.sol

This file was deleted.

9 changes: 5 additions & 4 deletions packages/world/src/modules/core/CoreModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -98,16 +98,17 @@ 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)",
"transferOwnership(bytes32,address)",
// --- 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 ---
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/modules/core/CoreSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -18,7 +18,7 @@ contract CoreSystem is
IWorldErrors,
AccessManagementSystem,
BalanceTransferSystem,
CallBatchSystem,
BatchCallSystem,
ModuleInstallationSystem,
StoreRegistrationSystem,
WorldRegistrationSystem
Expand Down
Original file line number Diff line number Diff line change
@@ -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));
}
}
}

This file was deleted.

6 changes: 6 additions & 0 deletions packages/world/src/modules/core/types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ struct SystemCallData {
ResourceId systemId;
bytes callData;
}

struct SystemCallFromData {
address from;
ResourceId systemId;
bytes callData;
}
Loading

0 comments on commit 5741d53

Please sign in to comment.