From 33ecbbc111dac80d345c38b206790973a8012ff9 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 9 Nov 2023 13:26:08 +0300 Subject: [PATCH 1/9] feat(world-modules): system bound delegation control --- packages/world-modules/mud.config.ts | 15 + packages/world-modules/src/index.sol | 1 + .../StandardDelegationsModule.sol | 11 +- .../SystemboundDelegationControl.sol | 54 ++++ .../src/modules/std-delegations/constants.sol | 5 + .../tables/SystemboundDelegations.sol | 290 ++++++++++++++++++ .../test/StandardDelegationsModule.t.sol | 30 +- 7 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol create mode 100644 packages/world-modules/src/modules/std-delegations/tables/SystemboundDelegations.sol diff --git a/packages/world-modules/mud.config.ts b/packages/world-modules/mud.config.ts index a830eecd1f..2a4ddd3d18 100644 --- a/packages/world-modules/mud.config.ts +++ b/packages/world-modules/mud.config.ts @@ -1,5 +1,9 @@ import { mudConfig } from "@latticexyz/world/register"; +// loading state +// promise for buttons +// design system +// admin export default mudConfig({ worldgenDirectory: "interfaces", worldInterfaceName: "IBaseWorld", @@ -80,6 +84,17 @@ export default mudConfig({ availableCalls: "uint256", }, }, + SystemboundDelegations: { + directory: "modules/std-delegations/tables", + keySchema: { + delegator: "address", + delegatee: "address", + systemId: "ResourceId", + }, + valueSchema: { + availableCalls: "uint256", + }, + }, TimeboundDelegations: { directory: "modules/std-delegations/tables", keySchema: { diff --git a/packages/world-modules/src/index.sol b/packages/world-modules/src/index.sol index b1d73d8c0d..6a983a0ac7 100644 --- a/packages/world-modules/src/index.sol +++ b/packages/world-modules/src/index.sol @@ -8,6 +8,7 @@ import { KeysInTable, KeysInTableData, KeysInTableTableId } from "./modules/keys import { UsedKeysIndex, UsedKeysIndexTableId } from "./modules/keysintable/tables/UsedKeysIndex.sol"; import { UniqueEntity } from "./modules/uniqueentity/tables/UniqueEntity.sol"; import { CallboundDelegations, CallboundDelegationsTableId } from "./modules/std-delegations/tables/CallboundDelegations.sol"; +import { SystemboundDelegations, SystemboundDelegationsTableId } from "./modules/std-delegations/tables/SystemboundDelegations.sol"; import { TimeboundDelegations, TimeboundDelegationsTableId } from "./modules/std-delegations/tables/TimeboundDelegations.sol"; import { PuppetRegistry } from "./modules/puppet/tables/PuppetRegistry.sol"; import { Balances } from "./modules/tokens/tables/Balances.sol"; diff --git a/packages/world-modules/src/modules/std-delegations/StandardDelegationsModule.sol b/packages/world-modules/src/modules/std-delegations/StandardDelegationsModule.sol index fe5ead7929..ceee1895e7 100644 --- a/packages/world-modules/src/modules/std-delegations/StandardDelegationsModule.sol +++ b/packages/world-modules/src/modules/std-delegations/StandardDelegationsModule.sol @@ -8,10 +8,12 @@ import { WorldContextConsumer } from "@latticexyz/world/src/WorldContext.sol"; import { revertWithBytes } from "@latticexyz/world/src/revertWithBytes.sol"; import { CallboundDelegationControl } from "./CallboundDelegationControl.sol"; +import { SystemboundDelegationControl } from "./SystemboundDelegationControl.sol"; import { TimeboundDelegationControl } from "./TimeboundDelegationControl.sol"; -import { MODULE_NAME, CALLBOUND_DELEGATION, TIMEBOUND_DELEGATION } from "./constants.sol"; +import { MODULE_NAME, CALLBOUND_DELEGATION, SYSTEMBOUND_DELEGATION, TIMEBOUND_DELEGATION } from "./constants.sol"; import { CallboundDelegations } from "./tables/CallboundDelegations.sol"; +import { SystemboundDelegations } from "./tables/SystemboundDelegations.sol"; import { TimeboundDelegations } from "./tables/TimeboundDelegations.sol"; /** @@ -19,6 +21,7 @@ import { TimeboundDelegations } from "./tables/TimeboundDelegations.sol"; */ contract StandardDelegationsModule is Module { CallboundDelegationControl private immutable callboundDelegationControl = new CallboundDelegationControl(); + SystemboundDelegationControl private immutable systemboundDelegationControl = new SystemboundDelegationControl(); TimeboundDelegationControl private immutable timeboundDelegationControl = new TimeboundDelegationControl(); function getName() public pure returns (bytes16) { @@ -30,6 +33,7 @@ contract StandardDelegationsModule is Module { // Register tables CallboundDelegations.register(); + SystemboundDelegations.register(); TimeboundDelegations.register(); // Register systems @@ -38,6 +42,11 @@ contract StandardDelegationsModule is Module { ); if (!success) revertWithBytes(returnData); + (success, returnData) = address(world).delegatecall( + abi.encodeCall(world.registerSystem, (SYSTEMBOUND_DELEGATION, systemboundDelegationControl, true)) + ); + if (!success) revertWithBytes(returnData); + (success, returnData) = address(world).delegatecall( abi.encodeCall(world.registerSystem, (TIMEBOUND_DELEGATION, timeboundDelegationControl, true)) ); diff --git a/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol b/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol new file mode 100644 index 0000000000..a8fb06a282 --- /dev/null +++ b/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.21; + +import { DelegationControl } from "@latticexyz/world/src/DelegationControl.sol"; +import { ResourceId } from "@latticexyz/world/src/WorldResourceId.sol"; +import { SystemboundDelegations } from "./tables/SystemboundDelegations.sol"; + +contract SystemboundDelegationControl is DelegationControl { + /** + * Verify a delegation by checking if the delegator has any available calls left in the SystemboundDelegations table and decrementing the available calls if so. + */ + function verify(address delegator, ResourceId systemId, bytes memory) public returns (bool) { + // Get the number of available calls for the given delegator, systemId and callData + uint256 availableCalls = SystemboundDelegations.get({ + delegator: delegator, + delegatee: _msgSender(), + systemId: systemId + }); + + if (availableCalls == 1) { + // Remove the delegation from the SystemboundDelegations table + SystemboundDelegations.deleteRecord({ delegator: delegator, delegatee: _msgSender(), systemId: systemId }); + return true; + } + + if (availableCalls > 0) { + // Decrement the number of available calls + unchecked { + availableCalls--; + } + SystemboundDelegations.set({ + delegator: delegator, + delegatee: _msgSender(), + systemId: systemId, + availableCalls: availableCalls + }); + return true; + } + + return false; + } + + /** + * Initialize a delegation by setting the number of available calls in the SystemboundDelegations table + */ + function initDelegation(address delegatee, ResourceId systemId, uint256 numCalls) public { + SystemboundDelegations.set({ + delegator: _msgSender(), + delegatee: delegatee, + systemId: systemId, + availableCalls: numCalls + }); + } +} diff --git a/packages/world-modules/src/modules/std-delegations/constants.sol b/packages/world-modules/src/modules/std-delegations/constants.sol index bc6b4096b9..1e788a0bfa 100644 --- a/packages/world-modules/src/modules/std-delegations/constants.sol +++ b/packages/world-modules/src/modules/std-delegations/constants.sol @@ -12,6 +12,11 @@ ResourceId constant CALLBOUND_DELEGATION = ResourceId.wrap( bytes32(abi.encodePacked(RESOURCE_SYSTEM, ROOT_NAMESPACE, bytes16("callbound"))) ); +// Systembound delegation +ResourceId constant SYSTEMBOUND_DELEGATION = ResourceId.wrap( + bytes32(abi.encodePacked(RESOURCE_SYSTEM, ROOT_NAMESPACE, bytes16("systembound"))) +); + // Timebound delegation ResourceId constant TIMEBOUND_DELEGATION = ResourceId.wrap( bytes32(abi.encodePacked(RESOURCE_SYSTEM, ROOT_NAMESPACE, bytes16("timebound"))) diff --git a/packages/world-modules/src/modules/std-delegations/tables/SystemboundDelegations.sol b/packages/world-modules/src/modules/std-delegations/tables/SystemboundDelegations.sol new file mode 100644 index 0000000000..49fd116cc1 --- /dev/null +++ b/packages/world-modules/src/modules/std-delegations/tables/SystemboundDelegations.sol @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.21; + +/* Autogenerated file. Do not edit manually. */ + +// Import schema type +import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; + +// Import store internals +import { IStore } from "@latticexyz/store/src/IStore.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; +import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; +import { Bytes } from "@latticexyz/store/src/Bytes.sol"; +import { Memory } from "@latticexyz/store/src/Memory.sol"; +import { SliceLib } from "@latticexyz/store/src/Slice.sol"; +import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; +import { FieldLayout, FieldLayoutLib } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; +import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "@latticexyz/store/src/storeResourceTypes.sol"; + +// Import user types +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +ResourceId constant _tableId = ResourceId.wrap( + bytes32(abi.encodePacked(RESOURCE_TABLE, bytes14(""), bytes16("SystemboundDeleg"))) +); +ResourceId constant SystemboundDelegationsTableId = _tableId; + +FieldLayout constant _fieldLayout = FieldLayout.wrap( + 0x0020010020000000000000000000000000000000000000000000000000000000 +); + +library SystemboundDelegations { + /** + * @notice Get the table values' field layout. + * @return _fieldLayout The field layout for the table. + */ + function getFieldLayout() internal pure returns (FieldLayout) { + return _fieldLayout; + } + + /** + * @notice Get the table's key schema. + * @return _keySchema The key schema for the table. + */ + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _keySchema = new SchemaType[](3); + _keySchema[0] = SchemaType.ADDRESS; + _keySchema[1] = SchemaType.ADDRESS; + _keySchema[2] = SchemaType.BYTES32; + + return SchemaLib.encode(_keySchema); + } + + /** + * @notice Get the table's value schema. + * @return _valueSchema The value schema for the table. + */ + function getValueSchema() internal pure returns (Schema) { + SchemaType[] memory _valueSchema = new SchemaType[](1); + _valueSchema[0] = SchemaType.UINT256; + + return SchemaLib.encode(_valueSchema); + } + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](3); + keyNames[0] = "delegator"; + keyNames[1] = "delegatee"; + keyNames[2] = "systemId"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "availableCalls"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** + * @notice Get availableCalls. + */ + function getAvailableCalls( + address delegator, + address delegatee, + ResourceId systemId + ) internal view returns (uint256 availableCalls) { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get availableCalls. + */ + function _getAvailableCalls( + address delegator, + address delegatee, + ResourceId systemId + ) internal view returns (uint256 availableCalls) { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get availableCalls. + */ + function get( + address delegator, + address delegatee, + ResourceId systemId + ) internal view returns (uint256 availableCalls) { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get availableCalls. + */ + function _get( + address delegator, + address delegatee, + ResourceId systemId + ) internal view returns (uint256 availableCalls) { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set availableCalls. + */ + function setAvailableCalls( + address delegator, + address delegatee, + ResourceId systemId, + uint256 availableCalls + ) internal { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); + } + + /** + * @notice Set availableCalls. + */ + function _setAvailableCalls( + address delegator, + address delegatee, + ResourceId systemId, + uint256 availableCalls + ) internal { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); + } + + /** + * @notice Set availableCalls. + */ + function set(address delegator, address delegatee, ResourceId systemId, uint256 availableCalls) internal { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); + } + + /** + * @notice Set availableCalls. + */ + function _set(address delegator, address delegatee, ResourceId systemId, uint256 availableCalls) internal { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((availableCalls)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(address delegator, address delegatee, ResourceId systemId) internal { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(address delegator, address delegatee, ResourceId systemId) internal { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(uint256 availableCalls) internal pure returns (bytes memory) { + return abi.encodePacked(availableCalls); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dyanmic (variable length) data, encoded into a sequence of bytes. + */ + function encode(uint256 availableCalls) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(availableCalls); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple( + address delegator, + address delegatee, + ResourceId systemId + ) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](3); + _keyTuple[0] = bytes32(uint256(uint160(delegator))); + _keyTuple[1] = bytes32(uint256(uint160(delegatee))); + _keyTuple[2] = ResourceId.unwrap(systemId); + + return _keyTuple; + } +} diff --git a/packages/world-modules/test/StandardDelegationsModule.t.sol b/packages/world-modules/test/StandardDelegationsModule.t.sol index 4734a7751d..3f09f32995 100644 --- a/packages/world-modules/test/StandardDelegationsModule.t.sol +++ b/packages/world-modules/test/StandardDelegationsModule.t.sol @@ -18,8 +18,9 @@ import { Systems } from "@latticexyz/world/src/codegen/tables/Systems.sol"; import { StandardDelegationsModule } from "../src/modules/std-delegations/StandardDelegationsModule.sol"; import { CallboundDelegationControl } from "../src/modules/std-delegations/CallboundDelegationControl.sol"; +import { SystemboundDelegationControl } from "../src/modules/std-delegations/SystemboundDelegationControl.sol"; import { TimeboundDelegationControl } from "../src/modules/std-delegations/TimeboundDelegationControl.sol"; -import { CALLBOUND_DELEGATION, TIMEBOUND_DELEGATION } from "../src/modules/std-delegations/StandardDelegationsModule.sol"; +import { CALLBOUND_DELEGATION, SYSTEMBOUND_DELEGATION, TIMEBOUND_DELEGATION } from "../src/modules/std-delegations/StandardDelegationsModule.sol"; import { WorldTestSystem } from "@latticexyz/world/test/World.t.sol"; @@ -70,6 +71,33 @@ contract StandardDelegationsModuleTest is Test, GasReporter { world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); } + function testCallFromSystemDelegation() public { + // Register the systembound delegation for one call to the system's msgSender function + vm.prank(delegator); + startGasReport("register a systembound delegation"); + world.registerDelegation( + delegatee, + SYSTEMBOUND_DELEGATION, + abi.encodeCall(SystemboundDelegationControl.initDelegation, (delegatee, systemId, 1)) + ); + endGasReport(); + + // Call a system from the delegatee on behalf of the delegator + vm.prank(delegatee); + startGasReport("call a system via a systembound delegation"); + bytes memory returnData = world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); + endGasReport(); + address returnedAddress = abi.decode(returnData, (address)); + + // Expect the system to have received the delegator's address + assertEq(returnedAddress, delegator); + + // Expect the delegation to have been used up + vm.prank(delegatee); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.World_DelegationNotFound.selector, delegator, delegatee)); + world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.msgSender, ())); + } + function testCallFromTimeboundDelegation() public { uint256 maxTimestamp = 4242; From 770584b5cde436333b234e6765a13976aebdf9a4 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 9 Nov 2023 13:37:13 +0300 Subject: [PATCH 2/9] chore: delete comments --- packages/world-modules/mud.config.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/world-modules/mud.config.ts b/packages/world-modules/mud.config.ts index 2a4ddd3d18..aa8099f3fa 100644 --- a/packages/world-modules/mud.config.ts +++ b/packages/world-modules/mud.config.ts @@ -1,9 +1,5 @@ import { mudConfig } from "@latticexyz/world/register"; -// loading state -// promise for buttons -// design system -// admin export default mudConfig({ worldgenDirectory: "interfaces", worldInterfaceName: "IBaseWorld", From 90148cff3457779d5ecd69e0b19dc9450fcd6935 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 9 Nov 2023 13:39:49 +0300 Subject: [PATCH 3/9] chore: gas report --- packages/world-modules/gas-report.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index e5cf4c39a0..e7db4ea393 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -225,7 +225,7 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "register a callbound delegation", - "gasUsed": 117420 + "gasUsed": 117426 }, { "file": "test/StandardDelegationsModule.t.sol", @@ -233,11 +233,23 @@ "name": "call a system via a callbound delegation", "gasUsed": 36688 }, + { + "file": "test/StandardDelegationsModule.t.sol", + "test": "testCallFromSystemDelegation", + "name": "register a systembound delegation", + "gasUsed": 114982 + }, + { + "file": "test/StandardDelegationsModule.t.sol", + "test": "testCallFromSystemDelegation", + "name": "call a system via a systembound delegation", + "gasUsed": 35924 + }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "register a timebound delegation", - "gasUsed": 111914 + "gasUsed": 111920 }, { "file": "test/StandardDelegationsModule.t.sol", From 5b309ac5052b2ab693859e907a2c8266e712b1b9 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 9 Nov 2023 13:59:07 +0300 Subject: [PATCH 4/9] test: check multiple function calls --- .../test/StandardDelegationsModule.t.sol | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/world-modules/test/StandardDelegationsModule.t.sol b/packages/world-modules/test/StandardDelegationsModule.t.sol index 3f09f32995..82a7f74e7e 100644 --- a/packages/world-modules/test/StandardDelegationsModule.t.sol +++ b/packages/world-modules/test/StandardDelegationsModule.t.sol @@ -22,7 +22,7 @@ import { SystemboundDelegationControl } from "../src/modules/std-delegations/Sys import { TimeboundDelegationControl } from "../src/modules/std-delegations/TimeboundDelegationControl.sol"; import { CALLBOUND_DELEGATION, SYSTEMBOUND_DELEGATION, TIMEBOUND_DELEGATION } from "../src/modules/std-delegations/StandardDelegationsModule.sol"; -import { WorldTestSystem } from "@latticexyz/world/test/World.t.sol"; +import { WorldTestSystem, WorldTestSystemReturn } from "@latticexyz/world/test/World.t.sol"; contract StandardDelegationsModuleTest is Test, GasReporter { IBaseWorld private world; @@ -78,7 +78,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { world.registerDelegation( delegatee, SYSTEMBOUND_DELEGATION, - abi.encodeCall(SystemboundDelegationControl.initDelegation, (delegatee, systemId, 1)) + abi.encodeCall(SystemboundDelegationControl.initDelegation, (delegatee, systemId, 2)) ); endGasReport(); @@ -92,6 +92,14 @@ contract StandardDelegationsModuleTest is Test, GasReporter { // Expect the system to have received the delegator's address assertEq(returnedAddress, delegator); + // Call another system from the delegatee on behalf of the delegator + vm.prank(delegatee); + returnData = world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.echo, (bytes32(0)))); + WorldTestSystemReturn memory returnedStruct = abi.decode(returnData, (WorldTestSystemReturn)); + + // Expect the system to have received the delegator's address + assertEq(returnedStruct.sender, delegator); + // Expect the delegation to have been used up vm.prank(delegatee); vm.expectRevert(abi.encodeWithSelector(IWorldErrors.World_DelegationNotFound.selector, delegator, delegatee)); From 97f23c290600eccbc5772f610a364cda66c94237 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 9 Nov 2023 13:59:28 +0300 Subject: [PATCH 5/9] chore: update comment --- packages/world-modules/test/StandardDelegationsModule.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/world-modules/test/StandardDelegationsModule.t.sol b/packages/world-modules/test/StandardDelegationsModule.t.sol index 82a7f74e7e..4636e0b03b 100644 --- a/packages/world-modules/test/StandardDelegationsModule.t.sol +++ b/packages/world-modules/test/StandardDelegationsModule.t.sol @@ -92,7 +92,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { // Expect the system to have received the delegator's address assertEq(returnedAddress, delegator); - // Call another system from the delegatee on behalf of the delegator + // Call a different system from the delegatee on behalf of the delegator vm.prank(delegatee); returnData = world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.echo, (bytes32(0)))); WorldTestSystemReturn memory returnedStruct = abi.decode(returnData, (WorldTestSystemReturn)); From 739397b98c8ce5d9da4158ade0e3e998fda7dd44 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Thu, 9 Nov 2023 13:59:43 +0300 Subject: [PATCH 6/9] chore: fix comment --- packages/world-modules/test/StandardDelegationsModule.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/world-modules/test/StandardDelegationsModule.t.sol b/packages/world-modules/test/StandardDelegationsModule.t.sol index 4636e0b03b..fd7b4a65de 100644 --- a/packages/world-modules/test/StandardDelegationsModule.t.sol +++ b/packages/world-modules/test/StandardDelegationsModule.t.sol @@ -92,7 +92,7 @@ contract StandardDelegationsModuleTest is Test, GasReporter { // Expect the system to have received the delegator's address assertEq(returnedAddress, delegator); - // Call a different system from the delegatee on behalf of the delegator + // Call a different function from the delegatee on behalf of the delegator vm.prank(delegatee); returnData = world.callFrom(delegator, systemId, abi.encodeCall(WorldTestSystem.echo, (bytes32(0)))); WorldTestSystemReturn memory returnedStruct = abi.decode(returnData, (WorldTestSystemReturn)); From 678b6d3f52764d5cee02e856a325fbbd4ddf49ed Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 10 Nov 2023 10:57:09 +0300 Subject: [PATCH 7/9] chore: gas report --- packages/world-modules/gas-report.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index e7db4ea393..b036a94012 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -243,7 +243,7 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "call a system via a systembound delegation", - "gasUsed": 35924 + "gasUsed": 33831 }, { "file": "test/StandardDelegationsModule.t.sol", From 831842ede6a5f78ac928e45aa7837febc654f2eb Mon Sep 17 00:00:00 2001 From: yonada Date: Fri, 10 Nov 2023 11:44:49 +0300 Subject: [PATCH 8/9] chore: update verify comment Co-authored-by: alvarius --- .../modules/std-delegations/SystemboundDelegationControl.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol b/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol index a8fb06a282..ea61274a2b 100644 --- a/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol +++ b/packages/world-modules/src/modules/std-delegations/SystemboundDelegationControl.sol @@ -7,7 +7,7 @@ import { SystemboundDelegations } from "./tables/SystemboundDelegations.sol"; contract SystemboundDelegationControl is DelegationControl { /** - * Verify a delegation by checking if the delegator has any available calls left in the SystemboundDelegations table and decrementing the available calls if so. + * Verify a delegation by checking if the caller (delegatee) has any available calls left for the given delegator in the SystemboundDelegations table and decrementing the available calls if so. */ function verify(address delegator, ResourceId systemId, bytes memory) public returns (bool) { // Get the number of available calls for the given delegator, systemId and callData From 9d0e8903b3119eaa24f67fc8be4613f3297766bd Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 10 Nov 2023 12:49:05 +0300 Subject: [PATCH 9/9] chore: prettier --- next-docs/pages/cli/deploy.mdx | 14 +++++++------- next-docs/pages/cli/set-version.mdx | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/next-docs/pages/cli/deploy.mdx b/next-docs/pages/cli/deploy.mdx index c3390ff24d..7fbd94656e 100644 --- a/next-docs/pages/cli/deploy.mdx +++ b/next-docs/pages/cli/deploy.mdx @@ -35,16 +35,16 @@ Again, there are several ways to do this: These are the command line options you can specify on `mud deploy`: -| Option | Meaning | Type | Default value | -| ----------------------- | ------------------------------------------------ | ------- | -------------------------------------------------------- | +| Option | Meaning | Type | Default value | +| ----------------------- | ------------------------------------------------ | ------- | ---------------------------------------------------------- | | `--version` | Show version number | boolean | `false` | -| `--configPath` | Path to the config file | string | `foundry.toml` | +| `--configPath` | Path to the config file | string | `foundry.toml` | | `--printConfig` | Print the resolved config | boolean | `false` | | `--saveDeployment | Save the deployment info to a file | boolean | `true` | -| `--profile` | The foundry profile to use | string | `local` | -| `--rpc`1 | The RPC URL to use | string | RPC url from `foundry.toml` | -| `--worldAddress` | Deploy to an existing World at the given address | string | Empty, deploy new `World` | -| `--srcDir` | Source directory | string | Foundry `src` directory | +| `--profile` | The foundry profile to use | string | `local` | +| `--rpc`1 | The RPC URL to use | string | RPC url from `foundry.toml` | +| `--worldAddress` | Deploy to an existing World at the given address | string | Empty, deploy new `World` | +| `--srcDir` | Source directory | string | Foundry `src` directory | | `--skipBuild` | Skip rebuilding the contracts before deploying | boolean | `false` | | `--alwaysRunPostDeploy` | Run `PostDeploy.s.sol` after each deploy | boolean | `false` (run the script only when deploying a new `World`) | | `--help` | Show help | boolean | `false` | diff --git a/next-docs/pages/cli/set-version.mdx b/next-docs/pages/cli/set-version.mdx index 6f30fe92e3..a4a5ea5611 100644 --- a/next-docs/pages/cli/set-version.mdx +++ b/next-docs/pages/cli/set-version.mdx @@ -15,10 +15,10 @@ pnpm install These are the command line options you can specify on `mud set-version`: -| Option | Meaning | Type | Default value | -| -------------- | ------------------------------------------------------------ | ------- | ------------- | -| `--version` | Show version number | boolean | false | -| `--mudVersion` | Set MUD to the given version | string | true | -| `--tag` | Set MUD to the latest version with the given tag from npm | string | | -| `--commit` | Set MUD to the version based on a given git commit hash | string | -| `--help` | Show help | boolean | false | +| Option | Meaning | Type | Default value | +| -------------- | --------------------------------------------------------- | ------- | ------------- | +| `--version` | Show version number | boolean | false | +| `--mudVersion` | Set MUD to the given version | string | true | +| `--tag` | Set MUD to the latest version with the given tag from npm | string | | +| `--commit` | Set MUD to the version based on a given git commit hash | string | +| `--help` | Show help | boolean | false |