From 6aaed39620136b85390ec839c59b33a2a10acffd Mon Sep 17 00:00:00 2001 From: Andy Cernera Date: Fri, 20 Dec 2024 15:57:19 +0900 Subject: [PATCH] fix: add test case for an array function argument --- .../render-solidity/renderSystemLibrary.ts | 5 +- test/system-libraries/mud.config.ts | 8 + .../src/codegen/world/IASystem.sol | 8 +- .../src/namespaces/a/ASystem.sol | 17 +- .../src/namespaces/a/ASystemTypes.sol | 6 + .../src/namespaces/a/codegen/index.sol | 1 + .../a/codegen/systems/ASystemLib.sol | 71 +++- .../a/codegen/tables/PositionValue.sol | 342 ++++++++++++++++++ test/system-libraries/test/Libraries.t.sol | 23 ++ 9 files changed, 477 insertions(+), 4 deletions(-) create mode 100644 test/system-libraries/src/namespaces/a/codegen/tables/PositionValue.sol diff --git a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts index a7e1c8fd0b..e926f3180d 100644 --- a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts +++ b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts @@ -263,7 +263,10 @@ function renderFunctionInterface(contractFunction: ContractInterfaceFunction) { function functionInterfaceName(contractFunction: ContractInterfaceFunction) { const { name, parameters } = contractFunction; - const paramTypes = parameters.map((param) => param.split(" ")[0]).join("_"); + const paramTypes = parameters + .map((param) => param.split(" ")[0]) + .map((type) => type.replace("[]", "Array")) + .join("_"); return `_I${name}${paramTypes.length === 0 ? "" : `_${paramTypes}`}`; } diff --git a/test/system-libraries/mud.config.ts b/test/system-libraries/mud.config.ts index 71785f0960..71585628a8 100644 --- a/test/system-libraries/mud.config.ts +++ b/test/system-libraries/mud.config.ts @@ -16,6 +16,14 @@ export default defineWorld({ }, key: [], }, + PositionValue: { + schema: { + x: "uint256", + y: "uint256", + z: "uint256", + }, + key: [], + }, }, }, b: {}, diff --git a/test/system-libraries/src/codegen/world/IASystem.sol b/test/system-libraries/src/codegen/world/IASystem.sol index aca4932c4d..85dcca4de8 100644 --- a/test/system-libraries/src/codegen/world/IASystem.sol +++ b/test/system-libraries/src/codegen/world/IASystem.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ -import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; +import { ASystemThing, Position } from "../../namespaces/a/ASystemTypes.sol"; /** * @title IASystem @@ -15,6 +15,12 @@ interface IASystem { function a__setValue(uint256 value) external; + function a__setPosition(Position memory position) external; + + function a__setPosition(uint256 x, uint256 y, uint256 z) external; + + function a__setPositions(Position[] memory positions) external; + function a__getValue() external view returns (uint256); function a__getTwoValues() external view returns (uint256, uint256); diff --git a/test/system-libraries/src/namespaces/a/ASystem.sol b/test/system-libraries/src/namespaces/a/ASystem.sol index 1a8d92f2de..0b1bfe853c 100644 --- a/test/system-libraries/src/namespaces/a/ASystem.sol +++ b/test/system-libraries/src/namespaces/a/ASystem.sol @@ -3,8 +3,9 @@ pragma solidity >=0.8.28; import { System } from "@latticexyz/world/src/System.sol"; import { Value } from "./codegen/tables/Value.sol"; +import { PositionValue } from "./codegen/tables/PositionValue.sol"; import { AddressValue } from "./codegen/tables/AddressValue.sol"; -import { ASystemThing } from "./ASystemTypes.sol"; +import { ASystemThing, Position } from "./ASystemTypes.sol"; contract ASystem is System { function setValue(ASystemThing memory value) external { @@ -15,6 +16,20 @@ contract ASystem is System { Value.set(value); } + function setPosition(Position memory position) external { + PositionValue.set(position.x, position.y, position.z); + } + + function setPosition(uint256 x, uint256 y, uint256 z) external { + PositionValue.set(x, y, z); + } + + function setPositions(Position[] memory positions) external { + for (uint256 i = 0; i < positions.length; i++) { + PositionValue.set(positions[i].x, positions[i].y, positions[i].z); + } + } + function getValue() external view returns (uint256) { return Value.get(); } diff --git a/test/system-libraries/src/namespaces/a/ASystemTypes.sol b/test/system-libraries/src/namespaces/a/ASystemTypes.sol index 45c42eedc8..687c54ccc0 100644 --- a/test/system-libraries/src/namespaces/a/ASystemTypes.sol +++ b/test/system-libraries/src/namespaces/a/ASystemTypes.sol @@ -4,3 +4,9 @@ pragma solidity >=0.8.28; struct ASystemThing { uint256 a; } + +struct Position { + uint256 x; + uint256 y; + uint256 z; +} diff --git a/test/system-libraries/src/namespaces/a/codegen/index.sol b/test/system-libraries/src/namespaces/a/codegen/index.sol index 690f6bc5b3..33261a0a17 100644 --- a/test/system-libraries/src/namespaces/a/codegen/index.sol +++ b/test/system-libraries/src/namespaces/a/codegen/index.sol @@ -5,3 +5,4 @@ pragma solidity >=0.8.24; import { Value } from "./tables/Value.sol"; import { AddressValue } from "./tables/AddressValue.sol"; +import { PositionValue, PositionValueData } from "./tables/PositionValue.sol"; diff --git a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol index fda1c37f8d..baa16e4268 100644 --- a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol +++ b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { ASystem } from "../../ASystem.sol"; -import { ASystemThing } from "../../ASystemTypes.sol"; +import { ASystemThing, Position } from "../../ASystemTypes.sol"; import { revertWithBytes } from "@latticexyz/world/src/revertWithBytes.sol"; import { IWorldCall } from "@latticexyz/world/src/IWorldKernel.sol"; import { SystemCall } from "@latticexyz/world/src/SystemCall.sol"; @@ -43,6 +43,18 @@ library ASystemLib { return CallWrapper(self.toResourceId(), address(0)).setValue(value); } + function setPosition(ASystemType self, Position memory position) internal { + return CallWrapper(self.toResourceId(), address(0)).setPosition(position); + } + + function setPosition(ASystemType self, uint256 x, uint256 y, uint256 z) internal { + return CallWrapper(self.toResourceId(), address(0)).setPosition(x, y, z); + } + + function setPositions(ASystemType self, Position[] memory positions) internal { + return CallWrapper(self.toResourceId(), address(0)).setPositions(positions); + } + function getValue(ASystemType self) internal view returns (uint256) { return CallWrapper(self.toResourceId(), address(0)).getValue(); } @@ -75,6 +87,36 @@ library ASystemLib { : _world().callFrom(self.from, self.systemId, systemCall); } + function setPosition(CallWrapper memory self, Position memory position) internal { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall(_IsetPosition_Position.setPosition, (position)); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + + function setPosition(CallWrapper memory self, uint256 x, uint256 y, uint256 z) internal { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall(_IsetPosition_uint256_uint256_uint256.setPosition, (x, y, z)); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + + function setPositions(CallWrapper memory self, Position[] memory positions) internal { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall(_IsetPositions_PositionArray.setPositions, (positions)); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + function getValue(CallWrapper memory self) internal view returns (uint256) { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); @@ -127,6 +169,21 @@ library ASystemLib { SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } + function setPosition(RootCallWrapper memory self, Position memory position) internal { + bytes memory systemCall = abi.encodeCall(_IsetPosition_Position.setPosition, (position)); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + + function setPosition(RootCallWrapper memory self, uint256 x, uint256 y, uint256 z) internal { + bytes memory systemCall = abi.encodeCall(_IsetPosition_uint256_uint256_uint256.setPosition, (x, y, z)); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + + function setPositions(RootCallWrapper memory self, Position[] memory positions) internal { + bytes memory systemCall = abi.encodeCall(_IsetPositions_PositionArray.setPositions, (positions)); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + function getValue(RootCallWrapper memory self) internal view returns (uint256) { bytes memory systemCall = abi.encodeCall(_IgetValue.getValue, ()); @@ -189,6 +246,18 @@ interface _IsetValue_uint256 { function setValue(uint256 value) external; } +interface _IsetPosition_Position { + function setPosition(Position memory position) external; +} + +interface _IsetPosition_uint256_uint256_uint256 { + function setPosition(uint256 x, uint256 y, uint256 z) external; +} + +interface _IsetPositions_PositionArray { + function setPositions(Position[] memory positions) external; +} + interface _IgetValue { function getValue() external; } diff --git a/test/system-libraries/src/namespaces/a/codegen/tables/PositionValue.sol b/test/system-libraries/src/namespaces/a/codegen/tables/PositionValue.sol new file mode 100644 index 0000000000..7783f5b37b --- /dev/null +++ b/test/system-libraries/src/namespaces/a/codegen/tables/PositionValue.sol @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { EncodedLengths, EncodedLengthsLib } from "@latticexyz/store/src/EncodedLengths.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +struct PositionValueData { + uint256 x; + uint256 y; + uint256 z; +} + +library PositionValue { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "a", name: "PositionValue", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x74626100000000000000000000000000506f736974696f6e56616c7565000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0060030020202000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of () + Schema constant _keySchema = Schema.wrap(0x0000000000000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (uint256, uint256, uint256) + Schema constant _valueSchema = Schema.wrap(0x006003001f1f1f00000000000000000000000000000000000000000000000000); + + /** + * @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[](0); + } + + /** + * @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[](3); + fieldNames[0] = "x"; + fieldNames[1] = "y"; + fieldNames[2] = "z"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get x. + */ + function getX() internal view returns (uint256 x) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get x. + */ + function _getX() internal view returns (uint256 x) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set x. + */ + function setX(uint256 x) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((x)), _fieldLayout); + } + + /** + * @notice Set x. + */ + function _setX(uint256 x) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((x)), _fieldLayout); + } + + /** + * @notice Get y. + */ + function getY() internal view returns (uint256 y) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get y. + */ + function _getY() internal view returns (uint256 y) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set y. + */ + function setY(uint256 y) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((y)), _fieldLayout); + } + + /** + * @notice Set y. + */ + function _setY(uint256 y) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((y)), _fieldLayout); + } + + /** + * @notice Get z. + */ + function getZ() internal view returns (uint256 z) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 2, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get z. + */ + function _getZ() internal view returns (uint256 z) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 2, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set z. + */ + function setZ(uint256 z) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 2, abi.encodePacked((z)), _fieldLayout); + } + + /** + * @notice Set z. + */ + function _setZ(uint256 z) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setStaticField(_tableId, _keyTuple, 2, abi.encodePacked((z)), _fieldLayout); + } + + /** + * @notice Get the full data. + */ + function get() internal view returns (PositionValueData memory _table) { + bytes32[] memory _keyTuple = new bytes32[](0); + + (bytes memory _staticData, EncodedLengths _encodedLengths, bytes memory _dynamicData) = StoreSwitch.getRecord( + _tableId, + _keyTuple, + _fieldLayout + ); + return decode(_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Get the full data. + */ + function _get() internal view returns (PositionValueData memory _table) { + bytes32[] memory _keyTuple = new bytes32[](0); + + (bytes memory _staticData, EncodedLengths _encodedLengths, bytes memory _dynamicData) = StoreCore.getRecord( + _tableId, + _keyTuple, + _fieldLayout + ); + return decode(_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Set the full data using individual values. + */ + function set(uint256 x, uint256 y, uint256 z) internal { + bytes memory _staticData = encodeStatic(x, y, z); + + EncodedLengths _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Set the full data using individual values. + */ + function _set(uint256 x, uint256 y, uint256 z) internal { + bytes memory _staticData = encodeStatic(x, y, z); + + EncodedLengths _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** + * @notice Set the full data using the data struct. + */ + function set(PositionValueData memory _table) internal { + bytes memory _staticData = encodeStatic(_table.x, _table.y, _table.z); + + EncodedLengths _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Set the full data using the data struct. + */ + function _set(PositionValueData memory _table) internal { + bytes memory _staticData = encodeStatic(_table.x, _table.y, _table.z); + + EncodedLengths _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** + * @notice Decode the tightly packed blob of static data using this table's field layout. + */ + function decodeStatic(bytes memory _blob) internal pure returns (uint256 x, uint256 y, uint256 z) { + x = (uint256(Bytes.getBytes32(_blob, 0))); + + y = (uint256(Bytes.getBytes32(_blob, 32))); + + z = (uint256(Bytes.getBytes32(_blob, 64))); + } + + /** + * @notice Decode the tightly packed blobs using this table's field layout. + * @param _staticData Tightly packed static fields. + * + * + */ + function decode( + bytes memory _staticData, + EncodedLengths, + bytes memory + ) internal pure returns (PositionValueData memory _table) { + (_table.x, _table.y, _table.z) = decodeStatic(_staticData); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + 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 x, uint256 y, uint256 z) internal pure returns (bytes memory) { + return abi.encodePacked(x, y, z); + } + + /** + * @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 dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(uint256 x, uint256 y, uint256 z) internal pure returns (bytes memory, EncodedLengths, bytes memory) { + bytes memory _staticData = encodeStatic(x, y, z); + + EncodedLengths _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple() internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](0); + + return _keyTuple; + } +} diff --git a/test/system-libraries/test/Libraries.t.sol b/test/system-libraries/test/Libraries.t.sol index 9e4d98615e..b03583bb9a 100644 --- a/test/system-libraries/test/Libraries.t.sol +++ b/test/system-libraries/test/Libraries.t.sol @@ -17,6 +17,8 @@ import { AddressValue } from "../src/namespaces/a/codegen/tables/AddressValue.so import { aSystem, ASystemThing } from "../src/namespaces/a/codegen/systems/ASystemLib.sol"; import { bSystem } from "../src/namespaces/b/codegen/systems/BSystemLib.sol"; import { rootSystem } from "../src/namespaces/root/codegen/systems/RootSystemLib.sol"; +import { PositionValue } from "../src/namespaces/a/codegen/tables/PositionValue.sol"; +import { Position } from "../src/namespaces/a/ASystemTypes.sol"; contract LibrariesTest is MudTest { function testNamespaceIdExists() public { @@ -32,6 +34,27 @@ contract LibrariesTest is MudTest { assertEq(aSystem.getValue(), value); } + function testCanCallSystemWithComplexArgumentTypes() public { + Position memory position = Position(1, 2, 3); + aSystem.setPosition(position); + assertEq(PositionValue.getX(), position.x); + assertEq(PositionValue.getY(), position.y); + assertEq(PositionValue.getZ(), position.z); + + aSystem.setPosition(1, 2, 3); + assertEq(PositionValue.getX(), 1); + assertEq(PositionValue.getY(), 2); + assertEq(PositionValue.getZ(), 3); + + Position[] memory positions = new Position[](2); + positions[0] = Position(1, 2, 3); + positions[1] = Position(4, 5, 6); + aSystem.setPositions(positions); + assertEq(PositionValue.getX(), 4); + assertEq(PositionValue.getY(), 5); + assertEq(PositionValue.getZ(), 6); + } + function testCanCallSystemFromOtherSystem() public { uint256 value = 0xDEADBEEF; ASystemThing memory thing = ASystemThing(value);