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

refactor(world): expose library for WorldContextConsumer #1624

Merged
merged 6 commits into from
Sep 30, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/olive-foxes-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@latticexyz/world-modules": patch
"@latticexyz/world": minor
alvrs marked this conversation as resolved.
Show resolved Hide resolved
---

We now expose a `WorldContextConsumerLib` library with the same functionality as the `WorldContextConsumer` contract, but the ability to be used inside of internal libraries.
We also renamed the `WorldContextProvider` library to `WorldContextProviderLib` for consistency.
30 changes: 15 additions & 15 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": 1407523
"gasUsed": 1407698
},
{
"file": "test/KeysInTableModule.t.sol",
"test": "testInstallGas",
"name": "install keys in table module",
"gasUsed": 1407523
"gasUsed": 1407698
},
{
"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": 1407523
"gasUsed": 1407698
},
{
"file": "test/KeysInTableModule.t.sol",
"test": "testSetAndDeleteRecordHookCompositeGas",
"name": "install keys in table module",
"gasUsed": 1407523
"gasUsed": 1407698
},
{
"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": 1407523
"gasUsed": 1407698
},
{
"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": 648854
"gasUsed": 648994
},
{
"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": 648854
"gasUsed": 648994
},
{
"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": 648854
"gasUsed": 648994
},
{
"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": 648854
"gasUsed": 648994
},
{
"file": "test/KeysWithValueModule.t.sol",
Expand Down Expand Up @@ -195,31 +195,31 @@
"file": "test/StandardDelegationsModule.t.sol",
"test": "testCallFromCallboundDelegation",
"name": "register a callbound delegation",
"gasUsed": 117315
"gasUsed": 117420
},
{
"file": "test/StandardDelegationsModule.t.sol",
"test": "testCallFromCallboundDelegation",
"name": "call a system via a callbound delegation",
"gasUsed": 36583
"gasUsed": 36688
},
{
"file": "test/StandardDelegationsModule.t.sol",
"test": "testCallFromTimeboundDelegation",
"name": "register a timebound delegation",
"gasUsed": 111809
"gasUsed": 111914
},
{
"file": "test/StandardDelegationsModule.t.sol",
"test": "testCallFromTimeboundDelegation",
"name": "call a system via a timebound delegation",
"gasUsed": 26745
"gasUsed": 26815
},
{
"file": "test/UniqueEntityModule.t.sol",
"test": "testInstall",
"name": "install unique entity module",
"gasUsed": 675100
"gasUsed": 675275
},
{
"file": "test/UniqueEntityModule.t.sol",
Expand All @@ -231,7 +231,7 @@
"file": "test/UniqueEntityModule.t.sol",
"test": "testInstallRoot",
"name": "installRoot unique entity module",
"gasUsed": 642496
"gasUsed": 642601
},
{
"file": "test/UniqueEntityModule.t.sol",
Expand Down
22 changes: 11 additions & 11 deletions packages/world/gas-report.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,37 +45,37 @@
"file": "test/BatchCall.t.sol",
"test": "testBatchCallFromReturnData",
"name": "call systems with batchCallFrom",
"gasUsed": 46377
"gasUsed": 46444
},
{
"file": "test/BatchCall.t.sol",
"test": "testBatchCallReturnData",
"name": "call systems with batchCall",
"gasUsed": 45171
"gasUsed": 45206
},
{
"file": "test/World.t.sol",
"test": "testCall",
"name": "call a system via the World",
"gasUsed": 12335
"gasUsed": 12370
},
{
"file": "test/World.t.sol",
"test": "testCallFromNamespaceDelegation",
"name": "call a system via a namespace fallback delegation",
"gasUsed": 26073
"gasUsed": 26143
},
{
"file": "test/World.t.sol",
"test": "testCallFromUnlimitedDelegation",
"name": "register an unlimited delegation",
"gasUsed": 47588
"gasUsed": 47623
},
{
"file": "test/World.t.sol",
"test": "testCallFromUnlimitedDelegation",
"name": "call a system via an unlimited delegation",
"gasUsed": 12771
"gasUsed": 12806
},
{
"file": "test/World.t.sol",
Expand All @@ -93,31 +93,31 @@
"file": "test/World.t.sol",
"test": "testRegisterFunctionSelector",
"name": "Register a function selector",
"gasUsed": 83114
"gasUsed": 83149
},
{
"file": "test/World.t.sol",
"test": "testRegisterNamespace",
"name": "Register a new namespace",
"gasUsed": 120817
"gasUsed": 120887
},
{
"file": "test/World.t.sol",
"test": "testRegisterRootFunctionSelector",
"name": "Register a root function selector",
"gasUsed": 80398
"gasUsed": 80433
},
{
"file": "test/World.t.sol",
"test": "testRegisterSystem",
"name": "register a system",
"gasUsed": 162559
"gasUsed": 162594
},
{
"file": "test/World.t.sol",
"test": "testRegisterTable",
"name": "Register a new table in the namespace",
"gasUsed": 637329
"gasUsed": 637399
},
{
"file": "test/World.t.sol",
Expand Down
8 changes: 4 additions & 4 deletions packages/world/src/SystemCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ pragma solidity >=0.8.21;
import { Hook } from "@latticexyz/store/src/Hook.sol";

import { ResourceId, WorldResourceIdInstance } from "./WorldResourceId.sol";
import { WorldContextProvider } from "./WorldContext.sol";
import { WorldContextProviderLib } from "./WorldContext.sol";
import { AccessControl } from "./AccessControl.sol";
import { ROOT_NAMESPACE } from "./constants.sol";
import { WorldContextProvider } from "./WorldContext.sol";
import { WorldContextProviderLib } from "./WorldContext.sol";
import { revertWithBytes } from "./revertWithBytes.sol";
import { BEFORE_CALL_SYSTEM, AFTER_CALL_SYSTEM } from "./systemHookTypes.sol";

Expand Down Expand Up @@ -61,13 +61,13 @@ library SystemCall {

// Call the system and forward any return data
(success, data) = systemId.getNamespace() == ROOT_NAMESPACE // Use delegatecall for root systems (= registered in the root namespace)
? WorldContextProvider.delegatecallWithContext({
? WorldContextProviderLib.delegatecallWithContext({
msgSender: caller,
msgValue: value,
target: systemAddress,
callData: callData
})
: WorldContextProvider.callWithContext({
: WorldContextProviderLib.callWithContext({
msgSender: caller,
msgValue: value,
target: systemAddress,
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/World.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ResourceId, WorldResourceIdInstance } from "./WorldResourceId.sol";
import { ROOT_NAMESPACE_ID, ROOT_NAMESPACE, ROOT_NAME } from "./constants.sol";
import { AccessControl } from "./AccessControl.sol";
import { SystemCall } from "./SystemCall.sol";
import { WorldContextProvider } from "./WorldContext.sol";
import { WorldContextProviderLib } from "./WorldContext.sol";
import { revertWithBytes } from "./revertWithBytes.sol";
import { Delegation } from "./Delegation.sol";
import { requireInterface } from "./requireInterface.sol";
Expand Down Expand Up @@ -107,7 +107,7 @@ contract World is StoreData, IWorldKernel {
// Require the provided address to implement the IModule interface
requireInterface(address(module), MODULE_INTERFACE_ID);

WorldContextProvider.delegatecallWithContextOrRevert({
WorldContextProviderLib.delegatecallWithContextOrRevert({
msgSender: msg.sender,
msgValue: 0,
target: address(module),
Expand Down
59 changes: 44 additions & 15 deletions packages/world/src/WorldContext.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,12 @@ uint256 constant CONTEXT_BYTES = 20 + 32;
*/
abstract contract WorldContextConsumer is IWorldContextConsumer {
/**
* @notice Extracts the trusted msg.sender value from the appended calldata.
* @return sender The address of the trusted sender.
* @notice Extract the `msg.sender` from the context appended to the calldata.
* @return sender The `msg.sender` in the call to the World contract before the World routed the
* call to the WorldContextConsumer contract.
*/
function _msgSender() public view returns (address sender) {
assembly {
// Load 32 bytes from calldata at position calldatasize() - context size,
// then shift left 96 bits (to right-align the address)
// 96 = 256 - 20 * 8
sender := shr(96, calldataload(sub(calldatasize(), CONTEXT_BYTES)))
}
if (sender == address(0)) sender = msg.sender;
return WorldContextConsumerLib._msgSender();
}

/**
Expand All @@ -37,10 +32,7 @@ abstract contract WorldContextConsumer is IWorldContextConsumer {
* call to the WorldContextConsumer contract.
*/
function _msgValue() public pure returns (uint256 value) {
assembly {
// Load 32 bytes from calldata at position calldatasize() - 32 bytes,
value := calldataload(sub(calldatasize(), 32))
}
return WorldContextConsumerLib._msgValue();
}

/**
Expand All @@ -62,12 +54,49 @@ abstract contract WorldContextConsumer is IWorldContextConsumer {
}
}

library WorldContextConsumerLib {
/**
* @notice Extract the `msg.sender` from the context appended to the calldata.
* @return sender The `msg.sender` in the call to the World contract before the World routed the
* call to the WorldContextConsumer contract.
*/
function _msgSender() internal view returns (address sender) {
assembly {
// Load 32 bytes from calldata at position calldatasize() - context size,
// then shift left 96 bits (to right-align the address)
// 96 = 256 - 20 * 8
sender := shr(96, calldataload(sub(calldatasize(), CONTEXT_BYTES)))
}
if (sender == address(0)) sender = msg.sender;
}

/**
* @notice Extract the `msg.value` from the context appended to the calldata.
* @return value The `msg.value` in the call to the World contract before the World routed the
* call to the WorldContextConsumer contract.
*/
function _msgValue() internal pure returns (uint256 value) {
assembly {
// Load 32 bytes from calldata at position calldatasize() - 32 bytes,
value := calldataload(sub(calldatasize(), 32))
}
}

/**
* @notice Get the address of the World contract that routed the call to this WorldContextConsumer.
* @return The address of the World contract that routed the call to this WorldContextConsumer.
*/
function _world() internal view returns (address) {
return StoreSwitch.getStoreAddress();
}
}

/**
* @title WorldContextProvider - Utility functions to call contracts with context values appended to calldata.
* @title WorldContextProviderLib - Utility functions to call contracts with context values appended to calldata.
* @notice This library provides functions to make calls or delegatecalls to other contracts,
* appending the context values (like msg.sender and msg.value) to the calldata for WorldContextConsumer to consume.
*/
library WorldContextProvider {
library WorldContextProviderLib {
/**
* @notice Appends context values to the given calldata.
* @param callData The original calldata.
Expand Down
6 changes: 3 additions & 3 deletions packages/world/src/modules/core/CoreModule.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import { WorldContextProvider } from "../../WorldContext.sol";
import { WorldContextProviderLib } from "../../WorldContext.sol";
import { ROOT_NAMESPACE, ROOT_NAMESPACE_ID, WORLD_NAMESPACE_ID } from "../../constants.sol";
import { Module } from "../../Module.sol";

Expand Down Expand Up @@ -104,7 +104,7 @@ contract CoreModule is Module {
* @dev Uses the CoreSystem's `registerSystem` implementation to register itself on the World.
*/
function _registerCoreSystem() internal {
WorldContextProvider.delegatecallWithContextOrRevert({
WorldContextProviderLib.delegatecallWithContextOrRevert({
msgSender: _msgSender(),
msgValue: 0,
target: coreSystem,
Expand Down Expand Up @@ -148,7 +148,7 @@ contract CoreModule is Module {
for (uint256 i = 0; i < functionSignatures.length; i++) {
// Use the CoreSystem's `registerRootFunctionSelector` to register the
// root function selectors in the World.
WorldContextProvider.delegatecallWithContextOrRevert({
WorldContextProviderLib.delegatecallWithContextOrRevert({
msgSender: _msgSender(),
msgValue: 0,
target: coreSystem,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity >=0.8.21;
import { IModule, MODULE_INTERFACE_ID } from "../../../IModule.sol";
import { System } from "../../../System.sol";
import { AccessControl } from "../../../AccessControl.sol";
import { WorldContextProvider } from "../../../WorldContext.sol";
import { WorldContextProviderLib } from "../../../WorldContext.sol";
import { ResourceAccess } from "../../../codegen/tables/ResourceAccess.sol";
import { InstalledModules } from "../../../codegen/tables/InstalledModules.sol";
import { requireInterface } from "../../../requireInterface.sol";
Expand All @@ -25,7 +25,7 @@ contract ModuleInstallationSystem is System {
// Require the provided address to implement the IModule interface
requireInterface(address(module), MODULE_INTERFACE_ID);

WorldContextProvider.callWithContextOrRevert({
WorldContextProviderLib.callWithContextOrRevert({
msgSender: _msgSender(),
msgValue: 0,
target: address(module),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ROOT_NAMESPACE, ROOT_NAME } from "../../../constants.sol";
import { AccessControl } from "../../../AccessControl.sol";
import { requireInterface } from "../../../requireInterface.sol";
import { revertWithBytes } from "../../../revertWithBytes.sol";
import { WorldContextProvider } from "../../../WorldContext.sol";
import { WorldContextProviderLib } from "../../../WorldContext.sol";

import { NamespaceOwner } from "../../../codegen/tables/NamespaceOwner.sol";
import { ResourceAccess } from "../../../codegen/tables/ResourceAccess.sol";
Expand Down
Loading