From e97d1b814bda794fc13561f5116665f8208f7fb8 Mon Sep 17 00:00:00 2001 From: Andy Cernera Date: Tue, 10 Dec 2024 13:52:51 +0900 Subject: [PATCH 01/11] chore: example of broken relative imports --- test/system-libraries/src/codegen/world/IASystem.sol | 4 +++- test/system-libraries/src/codegen/world/IBSystem.sol | 4 +++- test/system-libraries/src/namespaces/a/ASystem.sol | 5 +++-- test/system-libraries/src/namespaces/a/ASystemTypes.sol | 6 ++++++ .../src/namespaces/a/codegen/systems/ASystemLib.sol | 7 ++++--- test/system-libraries/src/namespaces/b/BSystem.sol | 5 +++-- .../src/namespaces/b/codegen/systems/BSystemLib.sol | 7 ++++--- 7 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 test/system-libraries/src/namespaces/a/ASystemTypes.sol diff --git a/test/system-libraries/src/codegen/world/IASystem.sol b/test/system-libraries/src/codegen/world/IASystem.sol index 859eab22e4..e99392b810 100644 --- a/test/system-libraries/src/codegen/world/IASystem.sol +++ b/test/system-libraries/src/codegen/world/IASystem.sol @@ -3,13 +3,15 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ +import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; + /** * @title IASystem * @author MUD (https://mud.dev) by Lattice (https://lattice.xyz) * @dev This interface is automatically generated from the corresponding system contract. Do not edit manually. */ interface IASystem { - function a__setValue(uint256 value) external; + function a__setValue(ASystemThing memory value) external; function a__getValue() external view returns (uint256); diff --git a/test/system-libraries/src/codegen/world/IBSystem.sol b/test/system-libraries/src/codegen/world/IBSystem.sol index b0db384230..ebcf882ac5 100644 --- a/test/system-libraries/src/codegen/world/IBSystem.sol +++ b/test/system-libraries/src/codegen/world/IBSystem.sol @@ -3,13 +3,15 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ +import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; + /** * @title IBSystem * @author MUD (https://mud.dev) by Lattice (https://lattice.xyz) * @dev This interface is automatically generated from the corresponding system contract. Do not edit manually. */ interface IBSystem { - function b__setValueInA(uint256 value) external; + function b__setValueInA(ASystemThing memory value) external; function b__getValueFromA() external view returns (uint256); } diff --git a/test/system-libraries/src/namespaces/a/ASystem.sol b/test/system-libraries/src/namespaces/a/ASystem.sol index a0edaa4f6a..f67d064bdd 100644 --- a/test/system-libraries/src/namespaces/a/ASystem.sol +++ b/test/system-libraries/src/namespaces/a/ASystem.sol @@ -4,10 +4,11 @@ pragma solidity >=0.8.28; import { System } from "@latticexyz/world/src/System.sol"; import { Value } from "./codegen/tables/Value.sol"; import { AddressValue } from "./codegen/tables/AddressValue.sol"; +import { ASystemThing } from "./ASystemTypes.sol"; contract ASystem is System { - function setValue(uint256 value) external { - Value.set(value); + function setValue(ASystemThing memory value) external { + Value.set(value.a); } function getValue() external view returns (uint256) { diff --git a/test/system-libraries/src/namespaces/a/ASystemTypes.sol b/test/system-libraries/src/namespaces/a/ASystemTypes.sol new file mode 100644 index 0000000000..45c42eedc8 --- /dev/null +++ b/test/system-libraries/src/namespaces/a/ASystemTypes.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.28; + +struct ASystemThing { + uint256 a; +} 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 9732eb90e7..5322628aae 100644 --- a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol +++ b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { ASystem } from "../../ASystem.sol"; +import { ASystemThing } from "../../namespaces/a/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"; @@ -34,7 +35,7 @@ struct RootCallWrapper { library ASystemLib { error ASystemLib_CallingFromRootSystem(); - function setValue(ASystemType self, uint256 value) internal { + function setValue(ASystemType self, ASystemThing memory value) internal { return CallWrapper(self.toResourceId(), address(0)).setValue(value); } @@ -50,7 +51,7 @@ library ASystemLib { return CallWrapper(self.toResourceId(), address(0)).setAddress(); } - function setValue(CallWrapper memory self, uint256 value) internal { + function setValue(CallWrapper memory self, ASystemThing memory value) internal { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); @@ -102,7 +103,7 @@ library ASystemLib { return abi.decode(result, (address)); } - function setValue(RootCallWrapper memory self, uint256 value) internal { + function setValue(RootCallWrapper memory self, ASystemThing memory value) internal { bytes memory systemCall = abi.encodeCall(ASystem.setValue, (value)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } diff --git a/test/system-libraries/src/namespaces/b/BSystem.sol b/test/system-libraries/src/namespaces/b/BSystem.sol index 9546a8d7b1..682affc533 100644 --- a/test/system-libraries/src/namespaces/b/BSystem.sol +++ b/test/system-libraries/src/namespaces/b/BSystem.sol @@ -2,11 +2,12 @@ pragma solidity >=0.8.28; import { System } from "@latticexyz/world/src/System.sol"; +import { ASystemThing } from "../a/ASystemTypes.sol"; import { aSystem } from "../a/codegen/systems/ASystemLib.sol"; contract BSystem is System { - function setValueInA(uint256 value) external { - aSystem.setValue(value); + function setValueInA(ASystemThing memory value) external { + aSystem.setValue(value.a); } function getValueFromA() external view returns (uint256) { diff --git a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index f71c305fb1..67d0ada23b 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { BSystem } from "../../BSystem.sol"; +import { ASystemThing } from "../../namespaces/a/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"; @@ -34,7 +35,7 @@ struct RootCallWrapper { library BSystemLib { error BSystemLib_CallingFromRootSystem(); - function setValueInA(BSystemType self, uint256 value) internal { + function setValueInA(BSystemType self, ASystemThing memory value) internal { return CallWrapper(self.toResourceId(), address(0)).setValueInA(value); } @@ -42,7 +43,7 @@ library BSystemLib { return CallWrapper(self.toResourceId(), address(0)).getValueFromA(); } - function setValueInA(CallWrapper memory self, uint256 value) internal { + function setValueInA(CallWrapper memory self, ASystemThing memory value) internal { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); @@ -67,7 +68,7 @@ library BSystemLib { return abi.decode(result, (uint256)); } - function setValueInA(RootCallWrapper memory self, uint256 value) internal { + function setValueInA(RootCallWrapper memory self, ASystemThing memory value) internal { bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (value)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } From 25731d2561c944368d50c6c9fde0263e6ee6d5b3 Mon Sep 17 00:00:00 2001 From: vdrg Date: Thu, 12 Dec 2024 09:53:12 -0300 Subject: [PATCH 02/11] Fix relative library imports --- .../world/ts/node/render-solidity/worldgen.ts | 20 ++++++++++++++++--- .../a/codegen/systems/ASystemLib.sol | 2 +- .../src/namespaces/b/BSystem.sol | 2 +- .../b/codegen/systems/BSystemLib.sol | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/world/ts/node/render-solidity/worldgen.ts b/packages/world/ts/node/render-solidity/worldgen.ts index 645cdfaebe..78e2698ece 100644 --- a/packages/world/ts/node/render-solidity/worldgen.ts +++ b/packages/world/ts/node/render-solidity/worldgen.ts @@ -80,7 +80,7 @@ export async function worldgen({ const source = await fs.readFile(path.join(rootDir, system.sourcePath), "utf8"); // get external functions from a contract const { functions, errors, symbolImports } = contractToInterface(source, system.label); - const imports = symbolImports.map( + const interfaceImports = symbolImports.map( ({ symbol, path: importPath }): ImportDatum => ({ symbol, path: importPath.startsWith(".") @@ -88,12 +88,13 @@ export async function worldgen({ : importPath, }), ); + const systemInterface = renderSystemInterface({ name: system.interfaceName, functionPrefix: system.namespace === "" ? "" : `${system.namespace}__`, functions, errors, - imports, + imports: interfaceImports, }); // write to file await formatAndWriteSolidity(systemInterface, system.interfacePath, "Generated system interface"); @@ -103,6 +104,19 @@ export async function worldgen({ path: "./" + path.relative(path.dirname(system.libraryPath), system.sourcePath), }; + const libraryImports = symbolImports.map( + ({ symbol, path: importPath }): ImportDatum => ({ + symbol, + path: importPath.startsWith(".") + ? "./" + + path.relative( + path.dirname(system.libraryPath), + path.join(rootDir, path.dirname(system.sourcePath), importPath), + ) + : importPath, + }), + ); + if (config.codegen.generateSystemLibraries) { const systemLibrary = renderSystemLibrary({ libraryName: system.libraryName, @@ -113,7 +127,7 @@ export async function worldgen({ resourceId: resourceToHex({ type: "system", namespace: system.namespace, name: system.name }), functions, errors, - imports: [systemImport, ...imports], + imports: [systemImport, ...libraryImports], storeImportPath, worldImportPath, }); 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 5322628aae..47f00a29d0 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 "../../namespaces/a/ASystemTypes.sol"; +import { ASystemThing } 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"; diff --git a/test/system-libraries/src/namespaces/b/BSystem.sol b/test/system-libraries/src/namespaces/b/BSystem.sol index 682affc533..1cf086f845 100644 --- a/test/system-libraries/src/namespaces/b/BSystem.sol +++ b/test/system-libraries/src/namespaces/b/BSystem.sol @@ -7,7 +7,7 @@ import { aSystem } from "../a/codegen/systems/ASystemLib.sol"; contract BSystem is System { function setValueInA(ASystemThing memory value) external { - aSystem.setValue(value.a); + aSystem.setValue(value); } function getValueFromA() external view returns (uint256) { diff --git a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index 67d0ada23b..bf4653d7c3 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { BSystem } from "../../BSystem.sol"; -import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; +import { ASystemThing } from "../../../a/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"; From b2cf1c7e4ea93dd1ad83200e02624092acde54ad Mon Sep 17 00:00:00 2001 From: vdrg Date: Thu, 12 Dec 2024 09:59:16 -0300 Subject: [PATCH 03/11] Fix libraries test --- .../system-libraries/src/codegen/world/IBSystem.sol | 2 +- .../src/codegen/world/IRootSystem.sol | 4 +++- test/system-libraries/src/namespaces/b/BSystem.sol | 4 ++-- .../src/namespaces/b/codegen/systems/BSystemLib.sol | 12 ++++++------ .../src/namespaces/root/RootSystem.sol | 6 +++--- .../root/codegen/systems/RootSystemLib.sol | 13 +++++++------ test/system-libraries/test/Libraries.t.sol | 11 +++++++---- 7 files changed, 29 insertions(+), 23 deletions(-) diff --git a/test/system-libraries/src/codegen/world/IBSystem.sol b/test/system-libraries/src/codegen/world/IBSystem.sol index ebcf882ac5..a1fcea3d49 100644 --- a/test/system-libraries/src/codegen/world/IBSystem.sol +++ b/test/system-libraries/src/codegen/world/IBSystem.sol @@ -11,7 +11,7 @@ import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; * @dev This interface is automatically generated from the corresponding system contract. Do not edit manually. */ interface IBSystem { - function b__setValueInA(ASystemThing memory value) external; + function b__setValueInA(ASystemThing memory thing) external; function b__getValueFromA() external view returns (uint256); } diff --git a/test/system-libraries/src/codegen/world/IRootSystem.sol b/test/system-libraries/src/codegen/world/IRootSystem.sol index e7d8d7c8fd..ba463b424d 100644 --- a/test/system-libraries/src/codegen/world/IRootSystem.sol +++ b/test/system-libraries/src/codegen/world/IRootSystem.sol @@ -3,13 +3,15 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ +import { ASystemThing } from "../../namespaces/a/codegen/systems/ASystemLib.sol"; + /** * @title IRootSystem * @author MUD (https://mud.dev) by Lattice (https://lattice.xyz) * @dev This interface is automatically generated from the corresponding system contract. Do not edit manually. */ interface IRootSystem { - function setValueInA(uint256 value) external; + function setValueInA(ASystemThing memory thing) external; function getValueFromA() external view returns (uint256); } diff --git a/test/system-libraries/src/namespaces/b/BSystem.sol b/test/system-libraries/src/namespaces/b/BSystem.sol index 1cf086f845..4ac845d12f 100644 --- a/test/system-libraries/src/namespaces/b/BSystem.sol +++ b/test/system-libraries/src/namespaces/b/BSystem.sol @@ -6,8 +6,8 @@ import { ASystemThing } from "../a/ASystemTypes.sol"; import { aSystem } from "../a/codegen/systems/ASystemLib.sol"; contract BSystem is System { - function setValueInA(ASystemThing memory value) external { - aSystem.setValue(value); + function setValueInA(ASystemThing memory thing) external { + aSystem.setValue(thing); } function getValueFromA() external view returns (uint256) { diff --git a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index bf4653d7c3..bc12e8a41a 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -35,19 +35,19 @@ struct RootCallWrapper { library BSystemLib { error BSystemLib_CallingFromRootSystem(); - function setValueInA(BSystemType self, ASystemThing memory value) internal { - return CallWrapper(self.toResourceId(), address(0)).setValueInA(value); + function setValueInA(BSystemType self, ASystemThing memory thing) internal { + return CallWrapper(self.toResourceId(), address(0)).setValueInA(thing); } function getValueFromA(BSystemType self) internal view returns (uint256) { return CallWrapper(self.toResourceId(), address(0)).getValueFromA(); } - function setValueInA(CallWrapper memory self, ASystemThing memory value) internal { + function setValueInA(CallWrapper memory self, ASystemThing memory thing) internal { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (value)); + bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (thing)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -68,8 +68,8 @@ library BSystemLib { return abi.decode(result, (uint256)); } - function setValueInA(RootCallWrapper memory self, ASystemThing memory value) internal { - bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (value)); + function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { + bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (thing)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } diff --git a/test/system-libraries/src/namespaces/root/RootSystem.sol b/test/system-libraries/src/namespaces/root/RootSystem.sol index eceb396834..4e071ff12b 100644 --- a/test/system-libraries/src/namespaces/root/RootSystem.sol +++ b/test/system-libraries/src/namespaces/root/RootSystem.sol @@ -2,11 +2,11 @@ pragma solidity >=0.8.28; import { System } from "@latticexyz/world/src/System.sol"; -import { aSystem } from "../a/codegen/systems/ASystemLib.sol"; +import { aSystem, ASystemThing } from "../a/codegen/systems/ASystemLib.sol"; contract RootSystem is System { - function setValueInA(uint256 value) external { - aSystem.callAsRoot().setValue(value); + function setValueInA(ASystemThing memory thing) external { + aSystem.callAsRoot().setValue(thing); } function getValueFromA() external view returns (uint256) { diff --git a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol index de6d5dcee7..e2cebdbdd9 100644 --- a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol +++ b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { RootSystem } from "../../RootSystem.sol"; +import { ASystemThing } from "../../../a/codegen/systems/ASystemLib.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"; @@ -36,19 +37,19 @@ struct RootCallWrapper { library RootSystemLib { error RootSystemLib_CallingFromRootSystem(); - function setValueInA(RootSystemType self, uint256 value) internal { - return CallWrapper(self.toResourceId(), address(0)).setValueInA(value); + function setValueInA(RootSystemType self, ASystemThing memory thing) internal { + return CallWrapper(self.toResourceId(), address(0)).setValueInA(thing); } function getValueFromA(RootSystemType self) internal view returns (uint256) { return CallWrapper(self.toResourceId(), address(0)).getValueFromA(); } - function setValueInA(CallWrapper memory self, uint256 value) internal { + function setValueInA(CallWrapper memory self, ASystemThing memory thing) internal { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeCall(RootSystem.setValueInA, (value)); + bytes memory systemCall = abi.encodeCall(RootSystem.setValueInA, (thing)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -69,8 +70,8 @@ library RootSystemLib { return abi.decode(result, (uint256)); } - function setValueInA(RootCallWrapper memory self, uint256 value) internal { - bytes memory systemCall = abi.encodeCall(RootSystem.setValueInA, (value)); + function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { + bytes memory systemCall = abi.encodeCall(RootSystem.setValueInA, (thing)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } diff --git a/test/system-libraries/test/Libraries.t.sol b/test/system-libraries/test/Libraries.t.sol index 988d5d1504..9e4d98615e 100644 --- a/test/system-libraries/test/Libraries.t.sol +++ b/test/system-libraries/test/Libraries.t.sol @@ -14,7 +14,7 @@ import { SYSTEMBOUND_DELEGATION } from "@latticexyz/world-modules/src/modules/st import { Value } from "../src/namespaces/a/codegen/tables/Value.sol"; import { AddressValue } from "../src/namespaces/a/codegen/tables/AddressValue.sol"; -import { aSystem } from "../src/namespaces/a/codegen/systems/ASystemLib.sol"; +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"; @@ -26,14 +26,16 @@ contract LibrariesTest is MudTest { function testCanCallSystemWithLibrary() public { uint256 value = 0xDEADBEEF; - aSystem.setValue(value); + ASystemThing memory thing = ASystemThing(value); + aSystem.setValue(thing); assertEq(Value.get(), value); assertEq(aSystem.getValue(), value); } function testCanCallSystemFromOtherSystem() public { uint256 value = 0xDEADBEEF; - bSystem.setValueInA(value); + ASystemThing memory thing = ASystemThing(value); + bSystem.setValueInA(thing); assertEq(Value.get(), value); assertEq(bSystem.getValueFromA(), value); } @@ -56,8 +58,9 @@ contract LibrariesTest is MudTest { function testCanCallFromRootSystemWithLibrary() public { uint256 value = 0xDEADBEEF; + ASystemThing memory thing = ASystemThing(value); // internally, rootSystem uses callAsRoot to call aSystem - rootSystem.setValueInA(value); + rootSystem.setValueInA(thing); assertEq(Value.get(), value); assertEq(aSystem.getValue(), value); assertEq(rootSystem.getValueFromA(), value); From 81c85d3f3da5f9b70f959eaa1601b435a755c7ec Mon Sep 17 00:00:00 2001 From: V Date: Thu, 12 Dec 2024 10:02:04 -0300 Subject: [PATCH 04/11] Create real-pigs-bake.md --- .changeset/real-pigs-bake.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/real-pigs-bake.md diff --git a/.changeset/real-pigs-bake.md b/.changeset/real-pigs-bake.md new file mode 100644 index 0000000000..9c56eddb55 --- /dev/null +++ b/.changeset/real-pigs-bake.md @@ -0,0 +1,6 @@ +--- +"@latticexyz/world": patch +"system-libraries-test": patch +--- + +Fix relative system imports in system libraries. From 6a7b92ef5a8fcf95bcf5bc62620c96cfc649ca08 Mon Sep 17 00:00:00 2001 From: V Date: Thu, 12 Dec 2024 12:09:21 -0300 Subject: [PATCH 05/11] Update real-pigs-bake.md --- .changeset/real-pigs-bake.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/real-pigs-bake.md b/.changeset/real-pigs-bake.md index 9c56eddb55..3d3ea0ed0c 100644 --- a/.changeset/real-pigs-bake.md +++ b/.changeset/real-pigs-bake.md @@ -1,6 +1,5 @@ --- "@latticexyz/world": patch -"system-libraries-test": patch --- Fix relative system imports in system libraries. From c462db302b62dd8de40e1d17cd96a2904f6f6285 Mon Sep 17 00:00:00 2001 From: vdrg Date: Fri, 13 Dec 2024 17:47:57 -0300 Subject: [PATCH 06/11] Also use relative path if path starts with '..' --- .../world/ts/node/render-solidity/worldgen.ts | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/world/ts/node/render-solidity/worldgen.ts b/packages/world/ts/node/render-solidity/worldgen.ts index 78e2698ece..40af6502bc 100644 --- a/packages/world/ts/node/render-solidity/worldgen.ts +++ b/packages/world/ts/node/render-solidity/worldgen.ts @@ -99,25 +99,26 @@ export async function worldgen({ // write to file await formatAndWriteSolidity(systemInterface, system.interfacePath, "Generated system interface"); - const systemImport = { - symbol: system.label, - path: "./" + path.relative(path.dirname(system.libraryPath), system.sourcePath), - }; - - const libraryImports = symbolImports.map( - ({ symbol, path: importPath }): ImportDatum => ({ - symbol, - path: importPath.startsWith(".") - ? "./" + - path.relative( - path.dirname(system.libraryPath), - path.join(rootDir, path.dirname(system.sourcePath), importPath), - ) - : importPath, - }), - ); - if (config.codegen.generateSystemLibraries) { + const systemImport = { + symbol: system.label, + path: "./" + path.relative(path.dirname(system.libraryPath), system.sourcePath), + }; + + const libraryImports = symbolImports.map( + ({ symbol, path: importPath }): ImportDatum => ({ + symbol, + path: + importPath.startsWith(".") || importPath.startsWith("..") + ? "./" + + path.relative( + path.dirname(system.libraryPath), + path.join(rootDir, path.dirname(system.sourcePath), importPath), + ) + : importPath, + }), + ); + const systemLibrary = renderSystemLibrary({ libraryName: system.libraryName, interfaceName: system.interfaceName, From 15afa74d168d4bd99ee7ab299877245de09c3681 Mon Sep 17 00:00:00 2001 From: vdrg Date: Fri, 13 Dec 2024 17:50:33 -0300 Subject: [PATCH 07/11] Undo last change --- .../world/ts/node/render-solidity/worldgen.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/world/ts/node/render-solidity/worldgen.ts b/packages/world/ts/node/render-solidity/worldgen.ts index 40af6502bc..c86c9b6ed2 100644 --- a/packages/world/ts/node/render-solidity/worldgen.ts +++ b/packages/world/ts/node/render-solidity/worldgen.ts @@ -108,14 +108,13 @@ export async function worldgen({ const libraryImports = symbolImports.map( ({ symbol, path: importPath }): ImportDatum => ({ symbol, - path: - importPath.startsWith(".") || importPath.startsWith("..") - ? "./" + - path.relative( - path.dirname(system.libraryPath), - path.join(rootDir, path.dirname(system.sourcePath), importPath), - ) - : importPath, + path: importPath.startsWith(".") + ? "./" + + path.relative( + path.dirname(system.libraryPath), + path.join(rootDir, path.dirname(system.sourcePath), importPath), + ) + : importPath, }), ); From e77725c83c628ad0aa6da6e8e1ccaf1e8538f001 Mon Sep 17 00:00:00 2001 From: Andy Cernera Date: Sun, 15 Dec 2024 10:01:56 +0900 Subject: [PATCH 08/11] fix: use encodeWithSelector in system libs to support overloaded system functions --- .../render-solidity/renderSystemLibrary.ts | 2 +- .../src/codegen/world/IASystem.sol | 2 ++ .../src/namespaces/a/ASystem.sol | 4 +++ .../a/codegen/systems/ASystemLib.sol | 35 ++++++++++++++----- .../b/codegen/systems/BSystemLib.sol | 8 ++--- .../root/codegen/systems/RootSystemLib.sol | 6 ++-- 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts index 85f4925a86..f1ced466b6 100644 --- a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts +++ b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts @@ -250,7 +250,7 @@ function renderRootCallWrapperFunction( function renderEncodeSystemCall(interfaceName: string, functionName: string, parameters: string[]) { const paramNames = parameters.map((param) => param.split(" ").slice(-1)[0]).join(", "); - return `abi.encodeCall(${interfaceName}.${functionName}, (${paramNames}))`; + return `abi.encodeWithSelector(bytes4(keccak256("${interfaceName}.${functionName}"))${paramNames ? `, (${paramNames})` : ""})`; } function renderAbiDecode(expression: string, returnParameters: string[]) { diff --git a/test/system-libraries/src/codegen/world/IASystem.sol b/test/system-libraries/src/codegen/world/IASystem.sol index e99392b810..aca4932c4d 100644 --- a/test/system-libraries/src/codegen/world/IASystem.sol +++ b/test/system-libraries/src/codegen/world/IASystem.sol @@ -13,6 +13,8 @@ import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; interface IASystem { function a__setValue(ASystemThing memory value) external; + function a__setValue(uint256 value) 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 f67d064bdd..1a8d92f2de 100644 --- a/test/system-libraries/src/namespaces/a/ASystem.sol +++ b/test/system-libraries/src/namespaces/a/ASystem.sol @@ -11,6 +11,10 @@ contract ASystem is System { Value.set(value.a); } + function setValue(uint256 value) external { + Value.set(value); + } + function getValue() external view returns (uint256) { return Value.get(); } 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 47f00a29d0..a8e522e62c 100644 --- a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol +++ b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol @@ -39,6 +39,10 @@ library ASystemLib { return CallWrapper(self.toResourceId(), address(0)).setValue(value); } + function setValue(ASystemType self, uint256 value) internal { + return CallWrapper(self.toResourceId(), address(0)).setValue(value); + } + function getValue(ASystemType self) internal view returns (uint256) { return CallWrapper(self.toResourceId(), address(0)).getValue(); } @@ -55,7 +59,17 @@ library ASystemLib { // 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(ASystem.setValue, (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + + function setValue(CallWrapper memory self, uint256 value) 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.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -65,7 +79,7 @@ library ASystemLib { // 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(ASystem.getValue, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.getValue"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -80,7 +94,7 @@ library ASystemLib { // 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(ASystem.getTwoValues, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.getTwoValues"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -95,7 +109,7 @@ library ASystemLib { // 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(ASystem.setAddress, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setAddress"))); bytes memory result = self.from == address(0) ? _world().call(self.systemId, systemCall) @@ -104,26 +118,31 @@ library ASystemLib { } function setValue(RootCallWrapper memory self, ASystemThing memory value) internal { - bytes memory systemCall = abi.encodeCall(ASystem.setValue, (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + + function setValue(RootCallWrapper memory self, uint256 value) internal { + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function getValue(RootCallWrapper memory self) internal view returns (uint256) { - bytes memory systemCall = abi.encodeCall(ASystem.getValue, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.getValue"))); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256)); } function getTwoValues(RootCallWrapper memory self) internal view returns (uint256, uint256) { - bytes memory systemCall = abi.encodeCall(ASystem.getTwoValues, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.getTwoValues"))); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256, uint256)); } function setAddress(RootCallWrapper memory self) internal returns (address) { - bytes memory systemCall = abi.encodeCall(ASystem.setAddress, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setAddress"))); bytes memory result = SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); return abi.decode(result, (address)); diff --git a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index bc12e8a41a..cc1b90fc9a 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -47,7 +47,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), (thing)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -57,7 +57,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeCall(BSystem.getValueFromA, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.getValueFromA"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -69,12 +69,12 @@ library BSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeCall(BSystem.setValueInA, (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), (thing)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function getValueFromA(RootCallWrapper memory self) internal view returns (uint256) { - bytes memory systemCall = abi.encodeCall(BSystem.getValueFromA, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.getValueFromA"))); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256)); diff --git a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol index e2cebdbdd9..143277fc58 100644 --- a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol +++ b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol @@ -49,7 +49,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeCall(RootSystem.setValueInA, (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), (thing)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -59,7 +59,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeCall(RootSystem.getValueFromA, ()); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.getValueFromA"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -71,7 +71,7 @@ library RootSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeCall(RootSystem.setValueInA, (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), (thing)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } From 85bbf111f6d86890de40928d0b8e4492bfcb758c Mon Sep 17 00:00:00 2001 From: Andy Cernera Date: Sun, 15 Dec 2024 10:13:51 +0900 Subject: [PATCH 09/11] fix: parens issue --- .../world/ts/node/render-solidity/renderSystemLibrary.ts | 2 +- .../src/namespaces/a/codegen/systems/ASystemLib.sol | 8 ++++---- .../src/namespaces/b/codegen/systems/BSystemLib.sol | 4 ++-- .../src/namespaces/root/codegen/systems/RootSystemLib.sol | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts index f1ced466b6..df0aa945c5 100644 --- a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts +++ b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts @@ -250,7 +250,7 @@ function renderRootCallWrapperFunction( function renderEncodeSystemCall(interfaceName: string, functionName: string, parameters: string[]) { const paramNames = parameters.map((param) => param.split(" ").slice(-1)[0]).join(", "); - return `abi.encodeWithSelector(bytes4(keccak256("${interfaceName}.${functionName}"))${paramNames ? `, (${paramNames})` : ""})`; + return `abi.encodeWithSelector(bytes4(keccak256("${interfaceName}.${functionName}"))${paramNames ? `, ${paramNames}` : ""})`; } function renderAbiDecode(expression: string, returnParameters: string[]) { 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 a8e522e62c..091709d54d 100644 --- a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol +++ b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol @@ -59,7 +59,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -69,7 +69,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -118,12 +118,12 @@ library ASystemLib { } function setValue(RootCallWrapper memory self, ASystemThing memory value) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function setValue(RootCallWrapper memory self, uint256 value) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } diff --git a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index cc1b90fc9a..afd4926087 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -47,7 +47,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), thing); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -69,7 +69,7 @@ library BSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), thing); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } diff --git a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol index 143277fc58..ae251fe9a1 100644 --- a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol +++ b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol @@ -49,7 +49,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), thing); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -71,7 +71,7 @@ library RootSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), thing); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } From b127d3568c39e849704627848e30d7468c21e35c Mon Sep 17 00:00:00 2001 From: Andy Cernera Date: Thu, 19 Dec 2024 12:35:51 +0900 Subject: [PATCH 10/11] feat: support function overloads in system libraries by using encodeWithSignature --- .../src/codegen/utils/contractToInterface.ts | 27 ++++++++++++++++ .../render-solidity/renderSystemLibrary.ts | 32 +++++++++++++++---- .../world/ts/node/render-solidity/types.ts | 9 +++++- .../world/ts/node/render-solidity/worldgen.ts | 24 +++++++++++++- .../src/codegen/world/IRootSystem.sol | 2 +- .../a/codegen/systems/ASystemLib.sol | 20 ++++++------ .../b/codegen/systems/BSystemLib.sol | 8 ++--- .../src/namespaces/root/RootSystem.sol | 3 +- .../root/codegen/systems/RootSystemLib.sol | 8 ++--- 9 files changed, 105 insertions(+), 28 deletions(-) diff --git a/packages/common/src/codegen/utils/contractToInterface.ts b/packages/common/src/codegen/utils/contractToInterface.ts index a896404fac..6187d4d02e 100644 --- a/packages/common/src/codegen/utils/contractToInterface.ts +++ b/packages/common/src/codegen/utils/contractToInterface.ts @@ -19,11 +19,38 @@ export interface ContractInterfaceError { parameters: string[]; } +export interface ContractInterfaceStruct { + name: string; + members: { name: string; type: string }[]; +} + interface SymbolImport { symbol: string; path: string; } +export function extractStructs(source: string): ContractInterfaceStruct[] { + const ast = parse(source); + const structs: ContractInterfaceStruct[] = []; + + visit(ast, { + StructDefinition({ name, members }) { + structs.push({ + name, + members: members.map((member) => { + const [type, name] = parseParameter(member).split(" "); + return { + name, + type, + }; + }), + }); + }, + }); + + return structs; +} + /** * Parse the contract data to get the functions necessary to generate an interface, * and symbols to import from the original contract. diff --git a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts index df0aa945c5..344091c703 100644 --- a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts +++ b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts @@ -4,6 +4,7 @@ import { renderedSolidityHeader, renderImports, ContractInterfaceFunction, + ContractInterfaceStruct, } from "@latticexyz/common/codegen"; import { RenderSystemLibraryOptions } from "./types"; import { ContractInterfaceError } from "@latticexyz/common/codegen"; @@ -20,6 +21,7 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) { errors: systemErrors, worldImportPath, storeImportPath, + symbolDefinitions, } = options; // Add required imports, if they are already included they will get removed in renderImports @@ -87,9 +89,9 @@ export function renderSystemLibrary(options: RenderSystemLibraryOptions) { ${renderList(functions, (contractFunction) => renderUserTypeFunction(contractFunction, userTypeName))} - ${renderList(functions, (contractFunction) => renderCallWrapperFunction(contractFunction, systemLabel, callingFromRootSystemErrorName))} + ${renderList(functions, (contractFunction) => renderCallWrapperFunction(contractFunction, systemLabel, callingFromRootSystemErrorName, symbolDefinitions))} - ${renderList(functions, (contractFunction) => renderRootCallWrapperFunction(contractFunction, systemLabel, namespace))} + ${renderList(functions, (contractFunction) => renderRootCallWrapperFunction(contractFunction, systemLabel, namespace, symbolDefinitions))} function callFrom(${userTypeName} self, address from) internal pure returns (CallWrapper memory) { return CallWrapper(self.toResourceId(), from); @@ -156,6 +158,7 @@ function renderCallWrapperFunction( contractFunction: ContractInterfaceFunction, systemLabel: string, callingFromRootSystemErrorName: string, + symbolDefinitions: Record, ) { const { name, parameters, stateMutability, returnParameters } = contractFunction; @@ -174,7 +177,7 @@ function renderCallWrapperFunction( if (address(_world()) == address(this)) revert ${callingFromRootSystemErrorName}(); `; - const encodedSystemCall = renderEncodeSystemCall(systemLabel, name, parameters); + const encodedSystemCall = renderEncodeSystemCall(name, parameters, symbolDefinitions); if (stateMutability === "") { return ` @@ -207,6 +210,7 @@ function renderRootCallWrapperFunction( contractFunction: ContractInterfaceFunction, systemLabel: string, namespace: string, + symbolDefinitions: Record, ) { const { name, parameters, stateMutability, returnParameters } = contractFunction; @@ -226,7 +230,7 @@ function renderRootCallWrapperFunction( ${renderReturnParameters(returnParameters)} `; - const encodedSystemCall = renderEncodeSystemCall(systemLabel, name, parameters); + const encodedSystemCall = renderEncodeSystemCall(name, parameters, symbolDefinitions); if (stateMutability === "") { return ` @@ -248,9 +252,25 @@ function renderRootCallWrapperFunction( } } -function renderEncodeSystemCall(interfaceName: string, functionName: string, parameters: string[]) { +function renderEncodeSystemCall( + functionName: string, + parameters: string[], + symbolDefinitions: Record, +) { const paramNames = parameters.map((param) => param.split(" ").slice(-1)[0]).join(", "); - return `abi.encodeWithSelector(bytes4(keccak256("${interfaceName}.${functionName}"))${paramNames ? `, ${paramNames}` : ""})`; + const paramTypes = parameters + .map((param) => param.split(" ")[0]) + .map((paramType) => { + // If param is a struct, we need to break it down into its component types for the function signature + if (symbolDefinitions[paramType]) { + const typeList = symbolDefinitions[paramType].members.map((member) => member.type).join(", "); + return `(${typeList})`; + } + + return paramType; + }); + + return `abi.encodeWithSignature("${functionName}(${paramTypes})"${paramNames.length > 0 ? `, (${paramNames})` : ""})`; } function renderAbiDecode(expression: string, returnParameters: string[]) { diff --git a/packages/world/ts/node/render-solidity/types.ts b/packages/world/ts/node/render-solidity/types.ts index 4172a84137..86aa763763 100644 --- a/packages/world/ts/node/render-solidity/types.ts +++ b/packages/world/ts/node/render-solidity/types.ts @@ -1,4 +1,9 @@ -import type { ImportDatum, ContractInterfaceFunction, ContractInterfaceError } from "@latticexyz/common/codegen"; +import type { + ImportDatum, + ContractInterfaceFunction, + ContractInterfaceError, + ContractInterfaceStruct, +} from "@latticexyz/common/codegen"; export interface RenderSystemInterfaceOptions { /** List of symbols to import, and their file paths */ @@ -25,4 +30,6 @@ export interface RenderSystemLibraryOptions { storeImportPath: string; /** Path for world package imports */ worldImportPath: string; + + symbolDefinitions: Record; } diff --git a/packages/world/ts/node/render-solidity/worldgen.ts b/packages/world/ts/node/render-solidity/worldgen.ts index c86c9b6ed2..8d863403ad 100644 --- a/packages/world/ts/node/render-solidity/worldgen.ts +++ b/packages/world/ts/node/render-solidity/worldgen.ts @@ -1,6 +1,12 @@ import fs from "node:fs/promises"; import path from "node:path"; -import { formatAndWriteSolidity, contractToInterface, type ImportDatum } from "@latticexyz/common/codegen"; +import { + formatAndWriteSolidity, + contractToInterface, + type ImportDatum, + extractStructs, + ContractInterfaceStruct, +} from "@latticexyz/common/codegen"; import { renderSystemInterface } from "./renderSystemInterface"; import { renderWorldInterface } from "./renderWorldInterface"; import { renderSystemLibrary } from "./renderSystemLibrary"; @@ -80,6 +86,21 @@ export async function worldgen({ const source = await fs.readFile(path.join(rootDir, system.sourcePath), "utf8"); // get external functions from a contract const { functions, errors, symbolImports } = contractToInterface(source, system.label); + + const symbolDefinitions: Record = {}; + const uniqueSymbolImportPaths = new Set( + symbolImports.map(({ path }) => path).filter((path) => !path.includes("codegen")), + ); + + for (const symbolImportPath of uniqueSymbolImportPaths) { + const symbolPath = path.resolve(rootDir, path.dirname(system.sourcePath), symbolImportPath); + const symbolImportSource = await fs.readFile(symbolPath, "utf8"); + const structs = extractStructs(symbolImportSource); + for (const struct of structs) { + symbolDefinitions[struct.name] = struct; + } + } + const interfaceImports = symbolImports.map( ({ symbol, path: importPath }): ImportDatum => ({ symbol, @@ -130,6 +151,7 @@ export async function worldgen({ imports: [systemImport, ...libraryImports], storeImportPath, worldImportPath, + symbolDefinitions, }); // write to file await formatAndWriteSolidity(systemLibrary, system.libraryPath, "Generated system library"); diff --git a/test/system-libraries/src/codegen/world/IRootSystem.sol b/test/system-libraries/src/codegen/world/IRootSystem.sol index ba463b424d..a1e2512662 100644 --- a/test/system-libraries/src/codegen/world/IRootSystem.sol +++ b/test/system-libraries/src/codegen/world/IRootSystem.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ -import { ASystemThing } from "../../namespaces/a/codegen/systems/ASystemLib.sol"; +import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; /** * @title IRootSystem 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 091709d54d..c426d78f20 100644 --- a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol +++ b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol @@ -59,7 +59,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); + bytes memory systemCall = abi.encodeWithSignature("setValue((uint256))", (value)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -69,7 +69,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); + bytes memory systemCall = abi.encodeWithSignature("setValue(uint256)", (value)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -79,7 +79,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.getValue"))); + bytes memory systemCall = abi.encodeWithSignature("getValue()"); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -94,7 +94,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.getTwoValues"))); + bytes memory systemCall = abi.encodeWithSignature("getTwoValues()"); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -109,7 +109,7 @@ library ASystemLib { // 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.encodeWithSelector(bytes4(keccak256("ASystem.setAddress"))); + bytes memory systemCall = abi.encodeWithSignature("setAddress()"); bytes memory result = self.from == address(0) ? _world().call(self.systemId, systemCall) @@ -118,31 +118,31 @@ library ASystemLib { } function setValue(RootCallWrapper memory self, ASystemThing memory value) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); + bytes memory systemCall = abi.encodeWithSignature("setValue((uint256))", (value)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function setValue(RootCallWrapper memory self, uint256 value) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setValue")), value); + bytes memory systemCall = abi.encodeWithSignature("setValue(uint256)", (value)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function getValue(RootCallWrapper memory self) internal view returns (uint256) { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.getValue"))); + bytes memory systemCall = abi.encodeWithSignature("getValue()"); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256)); } function getTwoValues(RootCallWrapper memory self) internal view returns (uint256, uint256) { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.getTwoValues"))); + bytes memory systemCall = abi.encodeWithSignature("getTwoValues()"); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256, uint256)); } function setAddress(RootCallWrapper memory self) internal returns (address) { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("ASystem.setAddress"))); + bytes memory systemCall = abi.encodeWithSignature("setAddress()"); bytes memory result = SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); return abi.decode(result, (address)); diff --git a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index afd4926087..d845f52cdb 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -47,7 +47,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), thing); + bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -57,7 +57,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.getValueFromA"))); + bytes memory systemCall = abi.encodeWithSignature("getValueFromA()"); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -69,12 +69,12 @@ library BSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.setValueInA")), thing); + bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function getValueFromA(RootCallWrapper memory self) internal view returns (uint256) { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("BSystem.getValueFromA"))); + bytes memory systemCall = abi.encodeWithSignature("getValueFromA()"); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256)); diff --git a/test/system-libraries/src/namespaces/root/RootSystem.sol b/test/system-libraries/src/namespaces/root/RootSystem.sol index 4e071ff12b..4b1bad8245 100644 --- a/test/system-libraries/src/namespaces/root/RootSystem.sol +++ b/test/system-libraries/src/namespaces/root/RootSystem.sol @@ -2,7 +2,8 @@ pragma solidity >=0.8.28; import { System } from "@latticexyz/world/src/System.sol"; -import { aSystem, ASystemThing } from "../a/codegen/systems/ASystemLib.sol"; +import { aSystem } from "../a/codegen/systems/ASystemLib.sol"; +import { ASystemThing } from "../a/ASystemTypes.sol"; contract RootSystem is System { function setValueInA(ASystemThing memory thing) external { diff --git a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol index ae251fe9a1..06a781542a 100644 --- a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol +++ b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { RootSystem } from "../../RootSystem.sol"; -import { ASystemThing } from "../../../a/codegen/systems/ASystemLib.sol"; +import { ASystemThing } from "../../../a/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"; @@ -49,7 +49,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), thing); + bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -59,7 +59,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.getValueFromA"))); + bytes memory systemCall = abi.encodeWithSignature("getValueFromA()"); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -71,7 +71,7 @@ library RootSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("RootSystem.setValueInA")), thing); + bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } From 3bc9fc37a733dafcaa0b26b39a1ff77c586f43ee Mon Sep 17 00:00:00 2001 From: Andy Cernera Date: Thu, 19 Dec 2024 13:41:59 +0900 Subject: [PATCH 11/11] fix: switch to encodeWithSelector --- .../render-solidity/renderSystemLibrary.ts | 42 +- .../world/ts/node/render-solidity/worldgen.ts | 5 + test/system-libraries/mud.config.ts | 6 + .../src/codegen/world/IASystem.sol | 4 +- .../src/namespaces/a/ASystem.sol | 8 +- .../src/namespaces/a/ASystemTypes.sol | 6 + .../src/namespaces/a/codegen/index.sol | 1 + .../a/codegen/systems/ASystemLib.sol | 53 ++- .../namespaces/a/codegen/tables/NameValue.sol | 417 ++++++++++++++++++ .../b/codegen/systems/BSystemLib.sol | 8 +- .../root/codegen/systems/RootSystemLib.sol | 6 +- test/system-libraries/test/Libraries.t.sol | 10 +- 12 files changed, 534 insertions(+), 32 deletions(-) create mode 100644 test/system-libraries/src/namespaces/a/codegen/tables/NameValue.sol diff --git a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts index 344091c703..7fa2634344 100644 --- a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts +++ b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts @@ -257,20 +257,40 @@ function renderEncodeSystemCall( parameters: string[], symbolDefinitions: Record, ) { - const paramNames = parameters.map((param) => param.split(" ").slice(-1)[0]).join(", "); - const paramTypes = parameters - .map((param) => param.split(" ")[0]) - .map((paramType) => { - // If param is a struct, we need to break it down into its component types for the function signature - if (symbolDefinitions[paramType]) { - const typeList = symbolDefinitions[paramType].members.map((member) => member.type).join(", "); - return `(${typeList})`; + const { paramNames, paramTypes } = parameters.reduce( + (res, param) => { + const paramArray = param.split(" "); + let name = paramArray.slice(-1)[0]; + let type = paramArray[0]; + + const symbolDefinition = symbolDefinitions[type]; + if (symbolDefinition) { + const typeList = symbolDefinition.members.map((member) => member.type).join(","); + type = `(${typeList})`; + + const nameList = symbolDefinition.members + .map((member) => { + return `${name}.${member.name}`; + }) + .join(","); + name = `${nameList}`; } - return paramType; - }); + res.paramNames.push(name); + res.paramTypes.push(type); - return `abi.encodeWithSignature("${functionName}(${paramTypes})"${paramNames.length > 0 ? `, (${paramNames})` : ""})`; + return res; + }, + { + paramNames: [] as string[], + paramTypes: [] as string[], + }, + ); + + const selector = `bytes4(keccak256("${functionName}(${paramTypes})"))`; + const systemCall = `abi.encodeWithSelector(${selector}${paramNames.length > 0 ? `, ${paramNames.join(", ")}` : ""})`; + + return systemCall; } function renderAbiDecode(expression: string, returnParameters: string[]) { diff --git a/packages/world/ts/node/render-solidity/worldgen.ts b/packages/world/ts/node/render-solidity/worldgen.ts index 8d863403ad..c3aa67b892 100644 --- a/packages/world/ts/node/render-solidity/worldgen.ts +++ b/packages/world/ts/node/render-solidity/worldgen.ts @@ -93,6 +93,11 @@ export async function worldgen({ ); for (const symbolImportPath of uniqueSymbolImportPaths) { + // TODO: import structs from non-relative paths + if (!symbolImportPath.startsWith(".")) { + continue; + } + const symbolPath = path.resolve(rootDir, path.dirname(system.sourcePath), symbolImportPath); const symbolImportSource = await fs.readFile(symbolPath, "utf8"); const structs = extractStructs(symbolImportSource); diff --git a/test/system-libraries/mud.config.ts b/test/system-libraries/mud.config.ts index 71785f0960..f6ccf1b472 100644 --- a/test/system-libraries/mud.config.ts +++ b/test/system-libraries/mud.config.ts @@ -16,6 +16,12 @@ export default defineWorld({ }, key: [], }, + NameValue: { + schema: { + value: "string", + }, + key: [], + }, }, }, b: {}, diff --git a/test/system-libraries/src/codegen/world/IASystem.sol b/test/system-libraries/src/codegen/world/IASystem.sol index aca4932c4d..f026c5dc26 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 { ASystemThing2, ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; /** * @title IASystem @@ -11,6 +11,8 @@ import { ASystemThing } from "../../namespaces/a/ASystemTypes.sol"; * @dev This interface is automatically generated from the corresponding system contract. Do not edit manually. */ interface IASystem { + function a__setComplexValue(ASystemThing2 memory value, string memory name) external; + function a__setValue(ASystemThing memory value) external; function a__setValue(uint256 value) external; diff --git a/test/system-libraries/src/namespaces/a/ASystem.sol b/test/system-libraries/src/namespaces/a/ASystem.sol index 1a8d92f2de..43b0e9bd4b 100644 --- a/test/system-libraries/src/namespaces/a/ASystem.sol +++ b/test/system-libraries/src/namespaces/a/ASystem.sol @@ -4,9 +4,15 @@ pragma solidity >=0.8.28; import { System } from "@latticexyz/world/src/System.sol"; import { Value } from "./codegen/tables/Value.sol"; import { AddressValue } from "./codegen/tables/AddressValue.sol"; -import { ASystemThing } from "./ASystemTypes.sol"; +import { NameValue } from "./codegen/tables/NameValue.sol"; +import { ASystemThing, ASystemThing2 } from "./ASystemTypes.sol"; contract ASystem is System { + function setComplexValue(ASystemThing2 memory value, string memory name) external { + Value.set(value.a); + NameValue.set(name); + } + function setValue(ASystemThing memory value) external { Value.set(value.a); } diff --git a/test/system-libraries/src/namespaces/a/ASystemTypes.sol b/test/system-libraries/src/namespaces/a/ASystemTypes.sol index 45c42eedc8..79259e7059 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 ASystemThing2 { + uint256 a; + uint256 b; + uint256 c; +} diff --git a/test/system-libraries/src/namespaces/a/codegen/index.sol b/test/system-libraries/src/namespaces/a/codegen/index.sol index 690f6bc5b3..b5d695a07f 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 { NameValue } from "./tables/NameValue.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 c426d78f20..092c1a0842 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 { ASystemThing2, ASystemThing } 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"; @@ -35,6 +35,10 @@ struct RootCallWrapper { library ASystemLib { error ASystemLib_CallingFromRootSystem(); + function setComplexValue(ASystemType self, ASystemThing2 memory value, string memory name) internal { + return CallWrapper(self.toResourceId(), address(0)).setComplexValue(value, name); + } + function setValue(ASystemType self, ASystemThing memory value) internal { return CallWrapper(self.toResourceId(), address(0)).setValue(value); } @@ -55,11 +59,27 @@ library ASystemLib { return CallWrapper(self.toResourceId(), address(0)).setAddress(); } + function setComplexValue(CallWrapper memory self, ASystemThing2 memory value, string memory name) 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.encodeWithSelector( + bytes4(keccak256("setComplexValue((uint256,uint256,uint256),string)")), + value.a, + value.b, + value.c, + name + ); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + function setValue(CallWrapper memory self, ASystemThing memory value) 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.encodeWithSignature("setValue((uint256))", (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValue((uint256))")), value.a); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -69,7 +89,7 @@ library ASystemLib { // 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.encodeWithSignature("setValue(uint256)", (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValue(uint256)")), value); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -79,7 +99,7 @@ library ASystemLib { // 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.encodeWithSignature("getValue()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getValue()"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -94,7 +114,7 @@ library ASystemLib { // 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.encodeWithSignature("getTwoValues()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getTwoValues()"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -109,7 +129,7 @@ library ASystemLib { // 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.encodeWithSignature("setAddress()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setAddress()"))); bytes memory result = self.from == address(0) ? _world().call(self.systemId, systemCall) @@ -117,32 +137,43 @@ library ASystemLib { return abi.decode(result, (address)); } + function setComplexValue(RootCallWrapper memory self, ASystemThing2 memory value, string memory name) internal { + bytes memory systemCall = abi.encodeWithSelector( + bytes4(keccak256("setComplexValue((uint256,uint256,uint256),string)")), + value.a, + value.b, + value.c, + name + ); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + function setValue(RootCallWrapper memory self, ASystemThing memory value) internal { - bytes memory systemCall = abi.encodeWithSignature("setValue((uint256))", (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValue((uint256))")), value.a); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function setValue(RootCallWrapper memory self, uint256 value) internal { - bytes memory systemCall = abi.encodeWithSignature("setValue(uint256)", (value)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValue(uint256)")), value); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function getValue(RootCallWrapper memory self) internal view returns (uint256) { - bytes memory systemCall = abi.encodeWithSignature("getValue()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getValue()"))); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256)); } function getTwoValues(RootCallWrapper memory self) internal view returns (uint256, uint256) { - bytes memory systemCall = abi.encodeWithSignature("getTwoValues()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getTwoValues()"))); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256, uint256)); } function setAddress(RootCallWrapper memory self) internal returns (address) { - bytes memory systemCall = abi.encodeWithSignature("setAddress()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setAddress()"))); bytes memory result = SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); return abi.decode(result, (address)); diff --git a/test/system-libraries/src/namespaces/a/codegen/tables/NameValue.sol b/test/system-libraries/src/namespaces/a/codegen/tables/NameValue.sol new file mode 100644 index 0000000000..afaf4dff4f --- /dev/null +++ b/test/system-libraries/src/namespaces/a/codegen/tables/NameValue.sol @@ -0,0 +1,417 @@ +// 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"; + +library NameValue { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "a", name: "NameValue", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x746261000000000000000000000000004e616d6556616c756500000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0000000100000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of () + Schema constant _keySchema = Schema.wrap(0x0000000000000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (string) + Schema constant _valueSchema = Schema.wrap(0x00000001c5000000000000000000000000000000000000000000000000000000); + + /** + * @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[](1); + fieldNames[0] = "value"; + } + + /** + * @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 value. + */ + function getValue() internal view returns (string memory value) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes memory _blob = StoreSwitch.getDynamicField(_tableId, _keyTuple, 0); + return (string(_blob)); + } + + /** + * @notice Get value. + */ + function _getValue() internal view returns (string memory value) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes memory _blob = StoreCore.getDynamicField(_tableId, _keyTuple, 0); + return (string(_blob)); + } + + /** + * @notice Get value. + */ + function get() internal view returns (string memory value) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes memory _blob = StoreSwitch.getDynamicField(_tableId, _keyTuple, 0); + return (string(_blob)); + } + + /** + * @notice Get value. + */ + function _get() internal view returns (string memory value) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes memory _blob = StoreCore.getDynamicField(_tableId, _keyTuple, 0); + return (string(_blob)); + } + + /** + * @notice Set value. + */ + function setValue(string memory value) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setDynamicField(_tableId, _keyTuple, 0, bytes((value))); + } + + /** + * @notice Set value. + */ + function _setValue(string memory value) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setDynamicField(_tableId, _keyTuple, 0, bytes((value))); + } + + /** + * @notice Set value. + */ + function set(string memory value) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setDynamicField(_tableId, _keyTuple, 0, bytes((value))); + } + + /** + * @notice Set value. + */ + function _set(string memory value) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setDynamicField(_tableId, _keyTuple, 0, bytes((value))); + } + + /** + * @notice Get the length of value. + */ + function lengthValue() internal view returns (uint256) { + bytes32[] memory _keyTuple = new bytes32[](0); + + uint256 _byteLength = StoreSwitch.getDynamicFieldLength(_tableId, _keyTuple, 0); + unchecked { + return _byteLength / 1; + } + } + + /** + * @notice Get the length of value. + */ + function _lengthValue() internal view returns (uint256) { + bytes32[] memory _keyTuple = new bytes32[](0); + + uint256 _byteLength = StoreCore.getDynamicFieldLength(_tableId, _keyTuple, 0); + unchecked { + return _byteLength / 1; + } + } + + /** + * @notice Get the length of value. + */ + function length() internal view returns (uint256) { + bytes32[] memory _keyTuple = new bytes32[](0); + + uint256 _byteLength = StoreSwitch.getDynamicFieldLength(_tableId, _keyTuple, 0); + unchecked { + return _byteLength / 1; + } + } + + /** + * @notice Get the length of value. + */ + function _length() internal view returns (uint256) { + bytes32[] memory _keyTuple = new bytes32[](0); + + uint256 _byteLength = StoreCore.getDynamicFieldLength(_tableId, _keyTuple, 0); + unchecked { + return _byteLength / 1; + } + } + + /** + * @notice Get an item of value. + * @dev Reverts with Store_IndexOutOfBounds if `_index` is out of bounds for the array. + */ + function getItemValue(uint256 _index) internal view returns (string memory) { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _blob = StoreSwitch.getDynamicFieldSlice(_tableId, _keyTuple, 0, _index * 1, (_index + 1) * 1); + return (string(_blob)); + } + } + + /** + * @notice Get an item of value. + * @dev Reverts with Store_IndexOutOfBounds if `_index` is out of bounds for the array. + */ + function _getItemValue(uint256 _index) internal view returns (string memory) { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _blob = StoreCore.getDynamicFieldSlice(_tableId, _keyTuple, 0, _index * 1, (_index + 1) * 1); + return (string(_blob)); + } + } + + /** + * @notice Get an item of value. + * @dev Reverts with Store_IndexOutOfBounds if `_index` is out of bounds for the array. + */ + function getItem(uint256 _index) internal view returns (string memory) { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _blob = StoreSwitch.getDynamicFieldSlice(_tableId, _keyTuple, 0, _index * 1, (_index + 1) * 1); + return (string(_blob)); + } + } + + /** + * @notice Get an item of value. + * @dev Reverts with Store_IndexOutOfBounds if `_index` is out of bounds for the array. + */ + function _getItem(uint256 _index) internal view returns (string memory) { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _blob = StoreCore.getDynamicFieldSlice(_tableId, _keyTuple, 0, _index * 1, (_index + 1) * 1); + return (string(_blob)); + } + } + + /** + * @notice Push a slice to value. + */ + function pushValue(string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.pushToDynamicField(_tableId, _keyTuple, 0, bytes((_slice))); + } + + /** + * @notice Push a slice to value. + */ + function _pushValue(string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.pushToDynamicField(_tableId, _keyTuple, 0, bytes((_slice))); + } + + /** + * @notice Push a slice to value. + */ + function push(string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.pushToDynamicField(_tableId, _keyTuple, 0, bytes((_slice))); + } + + /** + * @notice Push a slice to value. + */ + function _push(string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.pushToDynamicField(_tableId, _keyTuple, 0, bytes((_slice))); + } + + /** + * @notice Pop a slice from value. + */ + function popValue() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.popFromDynamicField(_tableId, _keyTuple, 0, 1); + } + + /** + * @notice Pop a slice from value. + */ + function _popValue() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.popFromDynamicField(_tableId, _keyTuple, 0, 1); + } + + /** + * @notice Pop a slice from value. + */ + function pop() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.popFromDynamicField(_tableId, _keyTuple, 0, 1); + } + + /** + * @notice Pop a slice from value. + */ + function _pop() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.popFromDynamicField(_tableId, _keyTuple, 0, 1); + } + + /** + * @notice Update a slice of value at `_index`. + */ + function updateValue(uint256 _index, string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _encoded = bytes((_slice)); + StoreSwitch.spliceDynamicData(_tableId, _keyTuple, 0, uint40(_index * 1), uint40(_encoded.length), _encoded); + } + } + + /** + * @notice Update a slice of value at `_index`. + */ + function _updateValue(uint256 _index, string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _encoded = bytes((_slice)); + StoreCore.spliceDynamicData(_tableId, _keyTuple, 0, uint40(_index * 1), uint40(_encoded.length), _encoded); + } + } + + /** + * @notice Update a slice of value at `_index`. + */ + function update(uint256 _index, string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _encoded = bytes((_slice)); + StoreSwitch.spliceDynamicData(_tableId, _keyTuple, 0, uint40(_index * 1), uint40(_encoded.length), _encoded); + } + } + + /** + * @notice Update a slice of value at `_index`. + */ + function _update(uint256 _index, string memory _slice) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + unchecked { + bytes memory _encoded = bytes((_slice)); + StoreCore.spliceDynamicData(_tableId, _keyTuple, 0, uint40(_index * 1), uint40(_encoded.length), _encoded); + } + } + + /** + * @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 dynamic data lengths using this table's schema. + * @return _encodedLengths The lengths of the dynamic fields (packed into a single bytes32 value). + */ + function encodeLengths(string memory value) internal pure returns (EncodedLengths _encodedLengths) { + // Lengths are effectively checked during copy by 2**40 bytes exceeding gas limits + unchecked { + _encodedLengths = EncodedLengthsLib.pack(bytes(value).length); + } + } + + /** + * @notice Tightly pack dynamic (variable length) data using this table's schema. + * @return The dynamic data, encoded into a sequence of bytes. + */ + function encodeDynamic(string memory value) internal pure returns (bytes memory) { + return abi.encodePacked(bytes((value))); + } + + /** + * @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(string memory value) internal pure returns (bytes memory, EncodedLengths, bytes memory) { + bytes memory _staticData; + EncodedLengths _encodedLengths = encodeLengths(value); + bytes memory _dynamicData = encodeDynamic(value); + + 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/src/namespaces/b/codegen/systems/BSystemLib.sol b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol index d845f52cdb..849be511ac 100644 --- a/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol +++ b/test/system-libraries/src/namespaces/b/codegen/systems/BSystemLib.sol @@ -47,7 +47,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValueInA((uint256))")), thing.a); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -57,7 +57,7 @@ library BSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert BSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSignature("getValueFromA()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getValueFromA()"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -69,12 +69,12 @@ library BSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValueInA((uint256))")), thing.a); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } function getValueFromA(RootCallWrapper memory self) internal view returns (uint256) { - bytes memory systemCall = abi.encodeWithSignature("getValueFromA()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getValueFromA()"))); bytes memory result = SystemCall.staticcallOrRevert(self.from, self.systemId, systemCall); return abi.decode(result, (uint256)); diff --git a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol index 06a781542a..bf799af504 100644 --- a/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol +++ b/test/system-libraries/src/namespaces/root/codegen/systems/RootSystemLib.sol @@ -49,7 +49,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValueInA((uint256))")), thing.a); self.from == address(0) ? _world().call(self.systemId, systemCall) : _world().callFrom(self.from, self.systemId, systemCall); @@ -59,7 +59,7 @@ library RootSystemLib { // if the contract calling this function is a root system, it should use `callAsRoot` if (address(_world()) == address(this)) revert RootSystemLib_CallingFromRootSystem(); - bytes memory systemCall = abi.encodeWithSignature("getValueFromA()"); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("getValueFromA()"))); bytes memory worldCall = self.from == address(0) ? abi.encodeCall(IWorldCall.call, (self.systemId, systemCall)) : abi.encodeCall(IWorldCall.callFrom, (self.from, self.systemId, systemCall)); @@ -71,7 +71,7 @@ library RootSystemLib { } function setValueInA(RootCallWrapper memory self, ASystemThing memory thing) internal { - bytes memory systemCall = abi.encodeWithSignature("setValueInA((uint256))", (thing)); + bytes memory systemCall = abi.encodeWithSelector(bytes4(keccak256("setValueInA((uint256))")), thing.a); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); } diff --git a/test/system-libraries/test/Libraries.t.sol b/test/system-libraries/test/Libraries.t.sol index 9e4d98615e..fe1c810e7e 100644 --- a/test/system-libraries/test/Libraries.t.sol +++ b/test/system-libraries/test/Libraries.t.sol @@ -14,7 +14,8 @@ import { SYSTEMBOUND_DELEGATION } from "@latticexyz/world-modules/src/modules/st import { Value } from "../src/namespaces/a/codegen/tables/Value.sol"; import { AddressValue } from "../src/namespaces/a/codegen/tables/AddressValue.sol"; -import { aSystem, ASystemThing } from "../src/namespaces/a/codegen/systems/ASystemLib.sol"; +import { NameValue } from "../src/namespaces/a/codegen/tables/NameValue.sol"; +import { aSystem, ASystemThing, ASystemThing2 } 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"; @@ -40,6 +41,13 @@ contract LibrariesTest is MudTest { assertEq(bSystem.getValueFromA(), value); } + function testCanCallSystemWithComplexStruct() public { + ASystemThing2 memory thing = ASystemThing2(1, 2, 3); + aSystem.setComplexValue(thing, "test"); + assertEq(Value.get(), 1, "Value should be 1"); + assertEq(NameValue.get(), "test", "NameValue should be test"); + } + function testCallFrom() public { address alice = address(0xDEADBEEF);