diff --git a/.changeset/lovely-knives-leave.md b/.changeset/lovely-knives-leave.md new file mode 100644 index 0000000000..c3684aa11b --- /dev/null +++ b/.changeset/lovely-knives-leave.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/world": patch +--- + +Fix static array arguments in system libraries. diff --git a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts index fa51bcded6..f5ffcaae3b 100644 --- a/packages/world/ts/node/render-solidity/renderSystemLibrary.ts +++ b/packages/world/ts/node/render-solidity/renderSystemLibrary.ts @@ -7,6 +7,7 @@ import { } from "@latticexyz/common/codegen"; import { RenderSystemLibraryOptions } from "./types"; import { ContractInterfaceError } from "@latticexyz/common/codegen"; +import { stringToHex } from "viem"; export function renderSystemLibrary(options: RenderSystemLibraryOptions) { const { @@ -289,6 +290,8 @@ function functionInterfaceName(contractFunction: ContractInterfaceFunction) { const paramTypes = parameters .map((param) => param.split(" ")[0]) .map((type) => type.replace("[]", "Array")) + // Static arrays may contain multiple disallowed symbols, for name uniqueness toHex is easier than escaping + .map((type) => type.replace(/\[.+\]/, (match) => stringToHex(match))) .join("_"); return `_${name}${paramTypes.length === 0 ? "" : `_${paramTypes}`}`; } diff --git a/test/system-libraries/src/codegen/world/IASystem.sol b/test/system-libraries/src/codegen/world/IASystem.sol index 85dcca4de8..1160967ced 100644 --- a/test/system-libraries/src/codegen/world/IASystem.sol +++ b/test/system-libraries/src/codegen/world/IASystem.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { ASystemThing, Position } from "../../namespaces/a/ASystemTypes.sol"; +import { THREE } from "../../namespaces/a/ASystemConstants.sol"; /** * @title IASystem @@ -26,4 +27,10 @@ interface IASystem { function a__getTwoValues() external view returns (uint256, uint256); function a__setAddress() external returns (address); + + function a__setValuesStaticArray(uint256[1] memory values) external; + + function a__setValuesStaticArray(uint256[2] memory values) external; + + function a__setValuesStaticArray(uint256[THREE] memory values) external; } diff --git a/test/system-libraries/src/namespaces/a/ASystem.sol b/test/system-libraries/src/namespaces/a/ASystem.sol index 0b1bfe853c..664f501fb1 100644 --- a/test/system-libraries/src/namespaces/a/ASystem.sol +++ b/test/system-libraries/src/namespaces/a/ASystem.sol @@ -6,6 +6,7 @@ import { Value } from "./codegen/tables/Value.sol"; import { PositionValue } from "./codegen/tables/PositionValue.sol"; import { AddressValue } from "./codegen/tables/AddressValue.sol"; import { ASystemThing, Position } from "./ASystemTypes.sol"; +import { THREE } from "./ASystemConstants.sol"; contract ASystem is System { function setValue(ASystemThing memory value) external { @@ -43,4 +44,24 @@ contract ASystem is System { AddressValue.set(addr); return addr; } + + function setValuesStaticArray(uint256[1] memory values) external { + Value.set(values[0]); + } + + function setValuesStaticArray(uint256[2] memory values) external { + Value.set(values[1]); + } + + function setValuesStaticArray(uint256[THREE] memory values) external { + Value.set(values[2]); + } + + /* + // TODO: support this case + // (see flattenTypeName in contractToInterface.ts) + function setValuesStaticArray(uint256[1 - 0 * 2 + THREE] memory values) external { + Value.set(values[3]); + } + */ } diff --git a/test/system-libraries/src/namespaces/a/ASystemConstants.sol b/test/system-libraries/src/namespaces/a/ASystemConstants.sol new file mode 100644 index 0000000000..f4287e034b --- /dev/null +++ b/test/system-libraries/src/namespaces/a/ASystemConstants.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.28; + +uint256 constant THREE = 3; 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 36dc010904..12ac5aeb37 100644 --- a/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol +++ b/test/system-libraries/src/namespaces/a/codegen/systems/ASystemLib.sol @@ -5,6 +5,7 @@ pragma solidity >=0.8.24; import { ASystem } from "../../ASystem.sol"; import { ASystemThing, Position } from "../../ASystemTypes.sol"; +import { THREE } from "../../ASystemConstants.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"; @@ -68,6 +69,18 @@ library ASystemLib { return CallWrapper(self.toResourceId(), address(0)).setAddress(); } + function setValuesStaticArray(ASystemType self, uint256[1] memory values) internal { + return CallWrapper(self.toResourceId(), address(0)).setValuesStaticArray(values); + } + + function setValuesStaticArray(ASystemType self, uint256[2] memory values) internal { + return CallWrapper(self.toResourceId(), address(0)).setValuesStaticArray(values); + } + + function setValuesStaticArray(ASystemType self, uint256[THREE] memory values) internal { + return CallWrapper(self.toResourceId(), address(0)).setValuesStaticArray(values); + } + 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(); @@ -160,6 +173,39 @@ library ASystemLib { return abi.decode(result, (address)); } + function setValuesStaticArray(CallWrapper memory self, uint256[1] memory values) internal { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall(_setValuesStaticArray_uint2560x5b315d.setValuesStaticArray, (values)); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + + function setValuesStaticArray(CallWrapper memory self, uint256[2] memory values) internal { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall(_setValuesStaticArray_uint2560x5b325d.setValuesStaticArray, (values)); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + + function setValuesStaticArray(CallWrapper memory self, uint256[THREE] memory values) internal { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert ASystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall( + _setValuesStaticArray_uint2560x5b54485245455d.setValuesStaticArray, + (values) + ); + self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + } + function setValue(RootCallWrapper memory self, ASystemThing memory value) internal { bytes memory systemCall = abi.encodeCall(_setValue_ASystemThing.setValue, (value)); SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); @@ -206,6 +252,24 @@ library ASystemLib { return abi.decode(result, (address)); } + function setValuesStaticArray(RootCallWrapper memory self, uint256[1] memory values) internal { + bytes memory systemCall = abi.encodeCall(_setValuesStaticArray_uint2560x5b315d.setValuesStaticArray, (values)); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + + function setValuesStaticArray(RootCallWrapper memory self, uint256[2] memory values) internal { + bytes memory systemCall = abi.encodeCall(_setValuesStaticArray_uint2560x5b325d.setValuesStaticArray, (values)); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + + function setValuesStaticArray(RootCallWrapper memory self, uint256[THREE] memory values) internal { + bytes memory systemCall = abi.encodeCall( + _setValuesStaticArray_uint2560x5b54485245455d.setValuesStaticArray, + (values) + ); + SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + } + function callFrom(ASystemType self, address from) internal pure returns (CallWrapper memory) { return CallWrapper(self.toResourceId(), from); } @@ -276,6 +340,18 @@ interface _setAddress { function setAddress() external; } +interface _setValuesStaticArray_uint2560x5b315d { + function setValuesStaticArray(uint256[1] memory values) external; +} + +interface _setValuesStaticArray_uint2560x5b325d { + function setValuesStaticArray(uint256[2] memory values) external; +} + +interface _setValuesStaticArray_uint2560x5b54485245455d { + function setValuesStaticArray(uint256[THREE] memory values) external; +} + using ASystemLib for ASystemType global; using ASystemLib for CallWrapper global; using ASystemLib for RootCallWrapper global; diff --git a/test/system-libraries/test/Libraries.t.sol b/test/system-libraries/test/Libraries.t.sol index b03583bb9a..1c5b63e19a 100644 --- a/test/system-libraries/test/Libraries.t.sol +++ b/test/system-libraries/test/Libraries.t.sol @@ -53,6 +53,13 @@ contract LibrariesTest is MudTest { assertEq(PositionValue.getX(), 4); assertEq(PositionValue.getY(), 5); assertEq(PositionValue.getZ(), 6); + + aSystem.setValuesStaticArray([uint256(1)]); + assertEq(Value.get(), 1); + aSystem.setValuesStaticArray([uint256(1), 2]); + assertEq(Value.get(), 2); + aSystem.setValuesStaticArray([uint256(1), 2, 3]); + assertEq(Value.get(), 3); } function testCanCallSystemFromOtherSystem() public {