diff --git a/.changeset/hungry-olives-attack.md b/.changeset/hungry-olives-attack.md new file mode 100644 index 0000000000..d31ecd8fe3 --- /dev/null +++ b/.changeset/hungry-olives-attack.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/store": patch +--- + +`Memory.copy` now internally uses `mcopy`, which is available since solidity version 0.8.24 diff --git a/.github/actions/setup-prerequisites/action.yml b/.github/actions/setup-prerequisites/action.yml index b4d6534721..2a8d93b223 100644 --- a/.github/actions/setup-prerequisites/action.yml +++ b/.github/actions/setup-prerequisites/action.yml @@ -16,4 +16,4 @@ runs: - name: Setup foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly + version: nightly-f47d7e0c29a36372908b917cd74aa589d5888f8e diff --git a/docs/pages/store/reference/misc.mdx b/docs/pages/store/reference/misc.mdx index ea3c6ff629..7c21caa2f4 100644 --- a/docs/pages/store/reference/misc.mdx +++ b/docs/pages/store/reference/misc.mdx @@ -1796,7 +1796,8 @@ function dataPointer(bytes memory data) internal pure returns (uint256 memoryPoi Copies memory from one location to another. -_Safely copies memory in chunks of 32 bytes, then handles any residual bytes._ +_Length does not have to be a multiple of 32, mcopy safely handles unaligned words. +Copying takes place as if an intermediate buffer was used, allowing the destination and source to overlap._ ```solidity function copy(uint256 fromPointer, uint256 toPointer, uint256 length) internal pure; diff --git a/packages/cli/src/deploy/common.ts b/packages/cli/src/deploy/common.ts index b489105d18..d663b9561a 100644 --- a/packages/cli/src/deploy/common.ts +++ b/packages/cli/src/deploy/common.ts @@ -10,7 +10,7 @@ export const worldAbi = IBaseWorldAbi; // Ideally, this should be an append-only list. Before adding more versions here, be sure to add backwards-compatible support for old Store/World versions. export const supportedStoreVersions = ["2.0.0", "2.0.1", "2.0.2"]; -export const supportedWorldVersions = ["2.0.0", "2.0.1", "2.0.2"]; +export const supportedWorldVersions = ["2.0.0", "2.0.1", "2.0.2", "2.1.0"]; // TODO: extend this to include factory+deployer address? so we can reuse the deployer for a world? export type WorldDeploy = { diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index 0f81481a95..da88b6c81b 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -27,13 +27,13 @@ "file": "test/Callbacks.t.sol:CallbacksTest", "test": "testSetAndGet", "name": "Callbacks: get field (warm)", - "gasUsed": 8591 + "gasUsed": 2591 }, { "file": "test/Callbacks.t.sol:CallbacksTest", "test": "testSetAndGet", "name": "Callbacks: push 1 element", - "gasUsed": 40341 + "gasUsed": 32341 }, { "file": "test/EncodedLengths.t.sol:EncodedLengthsTest", @@ -177,7 +177,7 @@ "file": "test/Gas.t.sol:GasTest", "test": "testCompareAbiEncodeVsCustom", "name": "custom decode", - "gasUsed": 1939 + "gasUsed": 1839 }, { "file": "test/Gas.t.sol:GasTest", @@ -189,7 +189,7 @@ "file": "test/Gas.t.sol:GasTest", "test": "testCompareAbiEncodeVsCustom", "name": "pass custom encoded bytes to external contract", - "gasUsed": 27801 + "gasUsed": 23301 }, { "file": "test/Gas.t.sol:GasTest", @@ -213,19 +213,19 @@ "file": "test/Gas.t.sol:GasTest", "test": "testCompareStorageWriteMUD", "name": "MUD storage write (warm, 1 word)", - "gasUsed": 2453 + "gasUsed": 353 }, { "file": "test/Gas.t.sol:GasTest", "test": "testCompareStorageWriteMUD", "name": "MUD storage write (warm, 1 word, partial)", - "gasUsed": 2519 + "gasUsed": 519 }, { "file": "test/Gas.t.sol:GasTest", "test": "testCompareStorageWriteMUD", "name": "MUD storage write (warm, 10 words)", - "gasUsed": 20709 + "gasUsed": 1809 }, { "file": "test/Gas.t.sol:GasTest", @@ -249,19 +249,19 @@ "file": "test/Gas.t.sol:GasTest", "test": "testCompareStorageWriteSolidity", "name": "solidity storage write (warm, 1 word)", - "gasUsed": 2207 + "gasUsed": 107 }, { "file": "test/Gas.t.sol:GasTest", "test": "testCompareStorageWriteSolidity", "name": "solidity storage write (warm, 1 word, partial)", - "gasUsed": 2236 + "gasUsed": 236 }, { "file": "test/Gas.t.sol:GasTest", "test": "testCompareStorageWriteSolidity", "name": "solidity storage write (warm, 10 words)", - "gasUsed": 21057 + "gasUsed": 2257 }, { "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", @@ -285,7 +285,7 @@ "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", "test": "testCompareStorageLoadMUD", "name": "MUD storage load (warm, 1 word)", - "gasUsed": 2410 + "gasUsed": 410 }, { "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", @@ -297,7 +297,7 @@ "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", "test": "testCompareStorageLoadMUD", "name": "MUD storage load (warm, 1 word, partial)", - "gasUsed": 2478 + "gasUsed": 478 }, { "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", @@ -309,7 +309,7 @@ "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", "test": "testCompareStorageLoadMUD", "name": "MUD storage load (warm, 10 words)", - "gasUsed": 19914 + "gasUsed": 1914 }, { "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", @@ -333,19 +333,19 @@ "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", "test": "testCompareStorageLoadSolidity", "name": "solidity storage load (warm, 1 word)", - "gasUsed": 2109 + "gasUsed": 109 }, { "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", "test": "testCompareStorageLoadSolidity", "name": "solidity storage load (warm, 1 word, partial)", - "gasUsed": 2126 + "gasUsed": 126 }, { "file": "test/GasStorageLoad.t.sol:GasStorageLoadTest", "test": "testCompareStorageLoadSolidity", "name": "solidity storage load (warm, 10 words)", - "gasUsed": 19895 + "gasUsed": 1895 }, { "file": "test/Hook.t.sol:HookTest", @@ -387,13 +387,13 @@ "file": "test/Mixed.t.sol:MixedTest", "test": "testSetGetDeleteExternal", "name": "get record from Mixed (external, warm)", - "gasUsed": 16687 + "gasUsed": 6592 }, { "file": "test/Mixed.t.sol:MixedTest", "test": "testSetGetDeleteExternal", "name": "delete record from Mixed (external, warm)", - "gasUsed": 17875 + "gasUsed": 7775 }, { "file": "test/Mixed.t.sol:MixedTest", @@ -405,13 +405,13 @@ "file": "test/Mixed.t.sol:MixedTest", "test": "testSetGetDeleteInternal", "name": "get record from Mixed (internal, warm)", - "gasUsed": 14378 + "gasUsed": 6283 }, { "file": "test/Mixed.t.sol:MixedTest", "test": "testSetGetDeleteInternal", "name": "delete record from Mixed (internal, warm)", - "gasUsed": 13088 + "gasUsed": 6988 }, { "file": "test/ResourceId.t.sol:ResourceIdTest", @@ -519,37 +519,37 @@ "file": "test/Slice.t.sol:SliceTest", "test": "testToBytes", "name": "Slice (0 bytes) to bytes memory", - "gasUsed": 295 + "gasUsed": 262 }, { "file": "test/Slice.t.sol:SliceTest", "test": "testToBytes", "name": "Slice (2 bytes) to bytes memory", - "gasUsed": 526 + "gasUsed": 299 }, { "file": "test/Slice.t.sol:SliceTest", "test": "testToBytes", "name": "Slice (32 bytes) to bytes memory", - "gasUsed": 542 + "gasUsed": 430 }, { "file": "test/Slice.t.sol:SliceTest", "test": "testToBytes", "name": "Slice (34 bytes) to bytes memory", - "gasUsed": 742 + "gasUsed": 436 }, { "file": "test/Slice.t.sol:SliceTest", "test": "testToBytes", "name": "Slice (1024 bytes) to bytes memory", - "gasUsed": 7261 + "gasUsed": 4700 }, { "file": "test/Slice.t.sol:SliceTest", "test": "testToBytes", "name": "Slice (1024x1024 bytes) to bytes memory", - "gasUsed": 9205062 + "gasUsed": 6616357 }, { "file": "test/Slice.t.sol:SliceTest", @@ -567,7 +567,7 @@ "file": "test/Storage.t.sol:StorageTest", "test": "testStoreLoad", "name": "store 34 bytes over 3 storage slots (with offset and safeTrail))", - "gasUsed": 25021 + "gasUsed": 23021 }, { "file": "test/Storage.t.sol:StorageTest", @@ -585,19 +585,19 @@ "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", "test": "testGetDynamicFieldSlice", "name": "get field slice (warm, 1 slot)", - "gasUsed": 5654 + "gasUsed": 1654 }, { "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", "test": "testGetDynamicFieldSlice", "name": "get field slice (semi-cold, 1 slot)", - "gasUsed": 5647 + "gasUsed": 3647 }, { "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", "test": "testGetDynamicFieldSlice", "name": "get field slice (warm, 2 slots)", - "gasUsed": 7870 + "gasUsed": 3870 }, { "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", @@ -609,7 +609,7 @@ "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", "test": "testGetSecondFieldLength", "name": "get field length (warm, 1 slot)", - "gasUsed": 3154 + "gasUsed": 1154 }, { "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", @@ -621,7 +621,7 @@ "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", "test": "testGetThirdFieldLength", "name": "get field length (warm, 2 slots)", - "gasUsed": 3153 + "gasUsed": 1153 }, { "file": "test/StoreCoreDynamic.t.sol:StoreCoreDynamicTest", @@ -657,19 +657,19 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testAccessEmptyData", "name": "access static field of non-existing record", - "gasUsed": 3322 + "gasUsed": 1322 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testAccessEmptyData", "name": "access dynamic field of non-existing record", - "gasUsed": 4051 + "gasUsed": 2051 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testAccessEmptyData", "name": "access length of dynamic field of non-existing record", - "gasUsed": 3152 + "gasUsed": 1152 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -717,19 +717,19 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testHooks", "name": "set record on table with subscriber", - "gasUsed": 106642 + "gasUsed": 98142 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testHooks", "name": "set static field on table with subscriber", - "gasUsed": 61292 + "gasUsed": 52792 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testHooks", "name": "delete record on table with subscriber", - "gasUsed": 57882 + "gasUsed": 47382 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -741,19 +741,19 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testHooksDynamicData", "name": "set (dynamic) record on table with subscriber", - "gasUsed": 199970 + "gasUsed": 191470 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testHooksDynamicData", "name": "set (dynamic) field on table with subscriber", - "gasUsed": 70737 + "gasUsed": 60237 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testHooksDynamicData", "name": "delete (dynamic) record on table with subscriber", - "gasUsed": 61745 + "gasUsed": 49145 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -765,7 +765,7 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testPushToDynamicField", "name": "push to field (2 slots, 10 uint32 items)", - "gasUsed": 38157 + "gasUsed": 32157 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -777,19 +777,19 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: get field layout (warm)", - "gasUsed": 2505 + "gasUsed": 505 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: get value schema (warm)", - "gasUsed": 3431 + "gasUsed": 1431 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: get key schema (warm)", - "gasUsed": 6294 + "gasUsed": 2294 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -801,7 +801,7 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetDynamicData", "name": "get complex record with dynamic data (4 slots)", - "gasUsed": 12196 + "gasUsed": 4196 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -825,13 +825,13 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetDynamicDataLength", "name": "set dynamic length of dynamic index 1", - "gasUsed": 2962 + "gasUsed": 962 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetDynamicDataLength", "name": "reduce dynamic length of dynamic index 0", - "gasUsed": 2951 + "gasUsed": 951 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -843,43 +843,43 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "get static field (1 slot)", - "gasUsed": 3323 + "gasUsed": 1323 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "set static field (overlap 2 slot)", - "gasUsed": 33570 + "gasUsed": 29570 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "get static field (overlap 2 slot)", - "gasUsed": 5803 + "gasUsed": 1803 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, first dynamic field)", - "gasUsed": 55968 + "gasUsed": 53968 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "get dynamic field (1 slot, first dynamic field)", - "gasUsed": 6214 + "gasUsed": 2214 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, second dynamic field)", - "gasUsed": 36193 + "gasUsed": 32193 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetField", "name": "get dynamic field (1 slot, second dynamic field)", - "gasUsed": 6216 + "gasUsed": 2216 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -891,7 +891,7 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetStaticData", "name": "get static record (1 slot)", - "gasUsed": 3539 + "gasUsed": 1539 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -903,7 +903,7 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testSetAndGetStaticDataSpanningWords", "name": "get static record (2 slots)", - "gasUsed": 5724 + "gasUsed": 1724 }, { "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", @@ -921,7 +921,7 @@ "file": "test/StoreCoreGas.t.sol:StoreCoreGasTest", "test": "testUpdateInDynamicField", "name": "push to field (2 slots, 6 uint64 items)", - "gasUsed": 17295 + "gasUsed": 9295 }, { "file": "test/StoreHook.t.sol:StoreHookTest", @@ -963,43 +963,43 @@ "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: get field (warm)", - "gasUsed": 8587 + "gasUsed": 2587 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: push 1 element (cold)", - "gasUsed": 20430 + "gasUsed": 12430 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: pop 1 element (warm)", - "gasUsed": 11738 + "gasUsed": 9738 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: push 1 element (warm)", - "gasUsed": 14446 + "gasUsed": 10446 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: update 1 element (warm)", - "gasUsed": 31687 + "gasUsed": 29687 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: delete record (warm)", - "gasUsed": 11503 + "gasUsed": 9503 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", "test": "testTable", "name": "StoreHooks: set field (warm)", - "gasUsed": 34195 + "gasUsed": 30195 }, { "file": "test/StoreHooks.t.sol:StoreHooksTest", @@ -1125,6 +1125,6 @@ "file": "test/Vector2.t.sol:Vector2Test", "test": "testSetAndGet", "name": "get Vector2 record", - "gasUsed": 6285 + "gasUsed": 2285 } ] diff --git a/packages/store/src/Memory.sol b/packages/store/src/Memory.sol index d530150a24..e5d0c6876b 100644 --- a/packages/store/src/Memory.sol +++ b/packages/store/src/Memory.sol @@ -26,40 +26,16 @@ library Memory { /** * @notice Copies memory from one location to another. - * @dev Safely copies memory in chunks of 32 bytes, then handles any residual bytes. + * @dev Length does not have to be a multiple of 32, mcopy safely handles unaligned words. + * Copying takes place as if an intermediate buffer was used, allowing the destination and source to overlap. * @param fromPointer The memory location to copy from. * @param toPointer The memory location to copy to. * @param length The number of bytes to copy. */ function copy(uint256 fromPointer, uint256 toPointer, uint256 length) internal pure { - // Copy 32-byte chunks - while (length >= 32) { - /// @solidity memory-safe-assembly - assembly { - mstore(toPointer, mload(fromPointer)) - } - // Safe because total addition will be <= length (ptr+len is implicitly safe) - unchecked { - toPointer += 32; - fromPointer += 32; - length -= 32; - } - } - if (length == 0) return; - - // Copy the 0-31 length tail - uint256 mask = rightMask(length); /// @solidity memory-safe-assembly assembly { - mstore( - toPointer, - or( - // store the left part - and(mload(fromPointer), not(mask)), - // preserve the right part - and(mload(toPointer), mask) - ) - ) + mcopy(toPointer, fromPointer, length) } } } diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 696bb399f6..5784ade397 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -1003,8 +1003,8 @@ library StoreCoreInternal { } // The start index can't be larger than the previous length of the field - if (startWithinField > previousFieldLength) { - revert IStoreErrors.Store_IndexOutOfBounds(previousFieldLength, startWithinField); + if (startWithinField > previousFieldLength - deleteCount) { + revert IStoreErrors.Store_IndexOutOfBounds(previousFieldLength - deleteCount, startWithinField); } // Update the encoded length diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index 27a38b54cd..893ec22b73 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -1023,7 +1023,7 @@ contract StoreCoreTest is Test, StoreMock { vm.expectRevert( abi.encodeWithSelector( IStoreErrors.Store_IndexOutOfBounds.selector, - data.newThirdDataBytes.length, + data.newThirdDataBytes.length - uint40(data.thirdDataForUpdate.length), uint40(type(uint56).max) ) ); @@ -1035,6 +1035,23 @@ contract StoreCoreTest is Test, StoreMock { uint40(data.thirdDataForUpdate.length), data.thirdDataForUpdate ); + + // startByteIndex + deleteCount must not overflow + vm.expectRevert( + abi.encodeWithSelector( + IStoreErrors.Store_IndexOutOfBounds.selector, + data.newThirdDataBytes.length - 8, + data.newThirdDataBytes.length + ) + ); + this.spliceDynamicData( + data.tableId, + data.keyTuple, + 1, + uint40(data.newThirdDataBytes.length), // set start to end of the field + uint40(8), // delete 8 bytes (after the start index, so after the size of the field) + abi.encodePacked(uint64(1)) // append 8 bytes + ); } function testAccessEmptyData() public { diff --git a/packages/store/ts/flattenStoreLogs.test.ts b/packages/store/ts/flattenStoreLogs.test.ts index 45093624f1..4111c3e3a0 100644 --- a/packages/store/ts/flattenStoreLogs.test.ts +++ b/packages/store/ts/flattenStoreLogs.test.ts @@ -53,10 +53,10 @@ describe("flattenStoreLogs", async () => { "Store_SetRecord store__ResourceIds (0x6e73000000000000000000000000000000000000000000000000000000000000)", "Store_SetRecord store__ResourceIds (0x6e7373746f726500000000000000000000000000000000000000000000000000)", "Store_SetRecord world__NamespaceOwner (0x6e7373746f726500000000000000000000000000000000000000000000000000)", - "Store_SetRecord world__ResourceAccess (0x6e7373746f726500000000000000000000000000000000000000000000000000,0x0000000000000000000000008dc4168dc8e582f0ef5adbab3c0873856682639b)", + "Store_SetRecord world__ResourceAccess (0x6e7373746f726500000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", "Store_SetRecord store__ResourceIds (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", "Store_SetRecord world__NamespaceOwner (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", - "Store_SetRecord world__ResourceAccess (0x6e73776f726c6400000000000000000000000000000000000000000000000000,0x0000000000000000000000008dc4168dc8e582f0ef5adbab3c0873856682639b)", + "Store_SetRecord world__ResourceAccess (0x6e73776f726c6400000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", "Store_SetRecord store__ResourceIds (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", "Store_SetRecord world__Systems (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", "Store_SetRecord world__SystemRegistry (0x00000000000000000000000073e872dcf77241b6d2afe4169ac27f9d31767292)", @@ -71,8 +71,8 @@ describe("flattenStoreLogs", async () => { "Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000002aac36425e74ff6c0778da582c55176394a067b0)", "Store_SetRecord store__ResourceIds (0x73790000000000000000000000000000526567697374726174696f6e00000000)", "Store_SetRecord world__Systems (0x73790000000000000000000000000000526567697374726174696f6e00000000)", - "Store_SetRecord world__SystemRegistry (0x000000000000000000000000047f80b91559887ab304519858c0bce90f2a00a6)", - "Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000047f80b91559887ab304519858c0bce90f2a00a6)", + "Store_SetRecord world__SystemRegistry (0x0000000000000000000000009fd59d184a359e7f14590d68fd08e57e4d9fded5)", + "Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000009fd59d184a359e7f14590d68fd08e57e4d9fded5)", "Store_SetRecord world__FunctionSelector (0x40554c3a00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0x40554c3a00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSelector (0x8d53b20800000000000000000000000000000000000000000000000000000000)", @@ -117,7 +117,7 @@ describe("flattenStoreLogs", async () => { "Store_SetRecord world__FunctionSignatur (0xbfdfaff700000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSelector (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", - "Store_SetRecord world__InstalledModules (0x0000000000000000000000009fcc45958071325949b488a784268371f17cb2d7,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_SetRecord world__InstalledModules (0x000000000000000000000000e4928465c9808ba23b78452855ac2018242abb35,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", "Store_SetRecord world__NamespaceOwner (0x6e73000000000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266)", "Store_SetRecord store__Tables (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", @@ -134,8 +134,8 @@ describe("flattenStoreLogs", async () => { "Store_SetRecord store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)", "Store_SetRecord store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)", "Store_SetRecord world__Systems (0x737900000000000000000000000000004d6f766553797374656d000000000000)", - "Store_SetRecord world__SystemRegistry (0x000000000000000000000000cbcdc66f9301ccf30b6b46efba8a3015d332dc13)", - "Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000cbcdc66f9301ccf30b6b46efba8a3015d332dc13)", + "Store_SetRecord world__SystemRegistry (0x00000000000000000000000020ee62756b46500fc00d90a73d325b5af1800268)", + "Store_SetRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000020ee62756b46500fc00d90a73d325b5af1800268)", "Store_SetRecord world__FunctionSelector (0xb591186e00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord store__Tables (0x7462000000000000000000000000000043616c6c576974685369676e61747572)", @@ -154,8 +154,8 @@ describe("flattenStoreLogs", async () => { "Store_SetRecord store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", "Store_SetRecord store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", "Store_SetRecord world__Systems (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", - "Store_SetRecord world__SystemRegistry (0x00000000000000000000000077c97a668f68dc030a3688fb7655780a1d800f95)", - "Store_SetRecord world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x00000000000000000000000077c97a668f68dc030a3688fb7655780a1d800f95)", + "Store_SetRecord world__SystemRegistry (0x000000000000000000000000443ae8e9e5c698a141c400b5d1ee6b4264f1fdc2)", + "Store_SetRecord world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x000000000000000000000000443ae8e9e5c698a141c400b5d1ee6b4264f1fdc2)", "Store_SetRecord world__FunctionSelector (0xff66f05f00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xc6972e9300000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xff66f05f00000000000000000000000000000000000000000000000000000000)", @@ -165,7 +165,7 @@ describe("flattenStoreLogs", async () => { "Store_SetRecord world__FunctionSelector (0x5ce7ca1a00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xf128760200000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0x5ce7ca1a00000000000000000000000000000000000000000000000000000000)", - "Store_SetRecord world__InstalledModules (0x0000000000000000000000004eb6f2596d44971d7d8065669c5bdba0a77e76a9,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_SetRecord world__InstalledModules (0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", "Store_SetRecord metadata__ResourceTag (0x737900000000000000000000000000004d6f766553797374656d000000000000,0x6162690000000000000000000000000000000000000000000000000000000000)", "Store_SetRecord metadata__ResourceTag (0x737900000000000000000000000000004d6f766553797374656d000000000000,0x776f726c64416269000000000000000000000000000000000000000000000000)", "Store_SetRecord Position (0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e)", diff --git a/packages/store/ts/getStoreLogs.test.ts b/packages/store/ts/getStoreLogs.test.ts index bef32fa93f..c347781275 100644 --- a/packages/store/ts/getStoreLogs.test.ts +++ b/packages/store/ts/getStoreLogs.test.ts @@ -50,13 +50,13 @@ describe("getStoreLogs", async () => { "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e69744d6f64756c65416464726573)", "Store_SpliceStaticData store__ResourceIds (0x6e73000000000000000000000000000000000000000000000000000000000000)", "Store_SpliceStaticData world__NamespaceOwner (0x6e73000000000000000000000000000000000000000000000000000000000000)", - "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000008dc4168dc8e582f0ef5adbab3c0873856682639b)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", "Store_SpliceStaticData store__ResourceIds (0x6e7373746f726500000000000000000000000000000000000000000000000000)", "Store_SpliceStaticData world__NamespaceOwner (0x6e7373746f726500000000000000000000000000000000000000000000000000)", - "Store_SpliceStaticData world__ResourceAccess (0x6e7373746f726500000000000000000000000000000000000000000000000000,0x0000000000000000000000008dc4168dc8e582f0ef5adbab3c0873856682639b)", + "Store_SpliceStaticData world__ResourceAccess (0x6e7373746f726500000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", "Store_SpliceStaticData store__ResourceIds (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", "Store_SpliceStaticData world__NamespaceOwner (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", - "Store_SpliceStaticData world__ResourceAccess (0x6e73776f726c6400000000000000000000000000000000000000000000000000,0x0000000000000000000000008dc4168dc8e582f0ef5adbab3c0873856682639b)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73776f726c6400000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", "Store_SetRecord world__Systems (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", "Store_SpliceStaticData world__SystemRegistry (0x00000000000000000000000073e872dcf77241b6d2afe4169ac27f9d31767292)", @@ -71,8 +71,8 @@ describe("getStoreLogs", async () => { "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000002aac36425e74ff6c0778da582c55176394a067b0)", "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000526567697374726174696f6e00000000)", "Store_SetRecord world__Systems (0x73790000000000000000000000000000526567697374726174696f6e00000000)", - "Store_SpliceStaticData world__SystemRegistry (0x000000000000000000000000047f80b91559887ab304519858c0bce90f2a00a6)", - "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000047f80b91559887ab304519858c0bce90f2a00a6)", + "Store_SpliceStaticData world__SystemRegistry (0x0000000000000000000000009fd59d184a359e7f14590d68fd08e57e4d9fded5)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000009fd59d184a359e7f14590d68fd08e57e4d9fded5)", "Store_SetRecord world__FunctionSelector (0x40554c3a00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0x40554c3a00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0x40554c3a00000000000000000000000000000000000000000000000000000000)", @@ -139,9 +139,9 @@ describe("getStoreLogs", async () => { "Store_SetRecord world__FunctionSelector (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", - "Store_SpliceStaticData world__InstalledModules (0x0000000000000000000000009fcc45958071325949b488a784268371f17cb2d7,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_SpliceStaticData world__InstalledModules (0x000000000000000000000000e4928465c9808ba23b78452855ac2018242abb35,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", "Store_SpliceStaticData world__NamespaceOwner (0x6e73000000000000000000000000000000000000000000000000000000000000)", - "Store_DeleteRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000008dc4168dc8e582f0ef5adbab3c0873856682639b)", + "Store_DeleteRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266)", "Store_SetRecord store__Tables (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", @@ -157,8 +157,8 @@ describe("getStoreLogs", async () => { "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)", "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)", "Store_SetRecord world__Systems (0x737900000000000000000000000000004d6f766553797374656d000000000000)", - "Store_SpliceStaticData world__SystemRegistry (0x000000000000000000000000cbcdc66f9301ccf30b6b46efba8a3015d332dc13)", - "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000cbcdc66f9301ccf30b6b46efba8a3015d332dc13)", + "Store_SpliceStaticData world__SystemRegistry (0x00000000000000000000000020ee62756b46500fc00d90a73d325b5af1800268)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000020ee62756b46500fc00d90a73d325b5af1800268)", "Store_SetRecord world__FunctionSelector (0xb591186e00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)", @@ -172,7 +172,7 @@ describe("getStoreLogs", async () => { "Store_SetRecord world__FunctionSignatur (0x1fae630800000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0x1fae630800000000000000000000000000000000000000000000000000000000)", "Store_SpliceStaticData world__InstalledModules (0x00000000000000000000000051bd8d2de7017c23ee5bdc885e70dfdd0862b837,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", - "Store_SpliceStaticData world__UserDelegationCo (0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266,0x0000000000000000000000004eb6f2596d44971d7d8065669c5bdba0a77e76a9)", + "Store_SpliceStaticData world__UserDelegationCo (0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266,0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3)", "Store_SpliceStaticData store__ResourceIds (0x6e736d6574616461746100000000000000000000000000000000000000000000)", "Store_SpliceStaticData world__NamespaceOwner (0x6e736d6574616461746100000000000000000000000000000000000000000000)", "Store_SpliceStaticData world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266)", @@ -180,8 +180,8 @@ describe("getStoreLogs", async () => { "Store_SpliceStaticData store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", "Store_SpliceStaticData store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", "Store_SetRecord world__Systems (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", - "Store_SpliceStaticData world__SystemRegistry (0x00000000000000000000000077c97a668f68dc030a3688fb7655780a1d800f95)", - "Store_SpliceStaticData world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x00000000000000000000000077c97a668f68dc030a3688fb7655780a1d800f95)", + "Store_SpliceStaticData world__SystemRegistry (0x000000000000000000000000443ae8e9e5c698a141c400b5d1ee6b4264f1fdc2)", + "Store_SpliceStaticData world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x000000000000000000000000443ae8e9e5c698a141c400b5d1ee6b4264f1fdc2)", "Store_SetRecord world__FunctionSelector (0xff66f05f00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xc6972e9300000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xff66f05f00000000000000000000000000000000000000000000000000000000)", @@ -191,8 +191,194 @@ describe("getStoreLogs", async () => { "Store_SetRecord world__FunctionSelector (0x5ce7ca1a00000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0xf128760200000000000000000000000000000000000000000000000000000000)", "Store_SetRecord world__FunctionSignatur (0x5ce7ca1a00000000000000000000000000000000000000000000000000000000)", - "Store_SpliceStaticData world__InstalledModules (0x0000000000000000000000004eb6f2596d44971d7d8065669c5bdba0a77e76a9,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", - "Store_DeleteRecord world__UserDelegationCo (0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266,0x0000000000000000000000004eb6f2596d44971d7d8065669c5bdba0a77e76a9)", + "Store_SpliceStaticData world__InstalledModules (0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_DeleteRecord world__UserDelegationCo (0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266,0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3)", + "Store_SpliceDynamicData metadata__ResourceTag (0x737900000000000000000000000000004d6f766553797374656d000000000000,0x6162690000000000000000000000000000000000000000000000000000000000)", + "Store_SpliceDynamicData metadata__ResourceTag (0x737900000000000000000000000000004d6f766553797374656d000000000000,0x776f726c64416269000000000000000000000000000000000000000000000000)", + "Store_SetRecord Position (0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e)", + "Store_SpliceStaticData Health (0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e)", + "Store_SetRecord Position (0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6)", + "Store_SpliceStaticData Health (0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6)", + "Store_SetRecord Position (0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb)", + "Store_SpliceStaticData Health (0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb)", + "Store_SetRecord Position (0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2)", + "Store_SpliceStaticData Terrain (0x0000000000000000000000000000000000000000000000000000000000000003,0x0000000000000000000000000000000000000000000000000000000000000005)", + "Store_SpliceStaticData world__InitModuleAddres ()", + "Store_SetRecord store__Tables (0x746273746f72650000000000000000005461626c657300000000000000000000)", + "Store_SetRecord store__Tables (0x746273746f72650000000000000000005265736f757263654964730000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f72650000000000000000005461626c657300000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f72650000000000000000005265736f757263654964730000000000)", + "Store_SetRecord store__Tables (0x746273746f726500000000000000000053746f7265486f6f6b73000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f726500000000000000000053746f7265486f6f6b73000000000000)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000004e616d6573706163654f776e65720000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000004e616d6573706163654f776e65720000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000042616c616e6365730000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000042616c616e6365730000000000000000)", + "Store_SetRecord store__Tables (0x7462776f726c64000000000000000000496e7374616c6c65644d6f64756c6573)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e7374616c6c65644d6f64756c6573)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000005573657244656c65676174696f6e436f)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000005573657244656c65676174696f6e436f)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000004e616d65737061636544656c65676174)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000004e616d65737061636544656c65676174)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000005265736f757263654163636573730000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000005265736f757263654163636573730000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000053797374656d73000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d73000000000000000000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000046756e6374696f6e53656c6563746f72)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000046756e6374696f6e53656c6563746f72)", + "Store_SetRecord store__Tables (0x6f74776f726c6400000000000000000046756e6374696f6e5369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x6f74776f726c6400000000000000000046756e6374696f6e5369676e61747572)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000053797374656d486f6f6b730000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d486f6f6b730000000000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000053797374656d52656769737472790000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d52656769737472790000)", + "Store_SetRecord store__Tables (0x7462776f726c64000000000000000000496e69744d6f64756c65416464726573)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e69744d6f64756c65416464726573)", + "Store_SpliceStaticData store__ResourceIds (0x6e73000000000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__NamespaceOwner (0x6e73000000000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", + "Store_SpliceStaticData store__ResourceIds (0x6e7373746f726500000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__NamespaceOwner (0x6e7373746f726500000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__ResourceAccess (0x6e7373746f726500000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", + "Store_SpliceStaticData store__ResourceIds (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__NamespaceOwner (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73776f726c6400000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", + "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", + "Store_SetRecord world__Systems (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", + "Store_SpliceStaticData world__SystemRegistry (0x00000000000000000000000073e872dcf77241b6d2afe4169ac27f9d31767292)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000073e872dcf77241b6d2afe4169ac27f9d31767292)", + "Store_SpliceStaticData store__ResourceIds (0x7379000000000000000000000000000042616c616e63655472616e7366657200)", + "Store_SetRecord world__Systems (0x7379000000000000000000000000000042616c616e63655472616e7366657200)", + "Store_SpliceStaticData world__SystemRegistry (0x00000000000000000000000050418155710200d0266e683a93209aa60501b7b3)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000050418155710200d0266e683a93209aa60501b7b3)", + "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000426174636843616c6c00000000000000)", + "Store_SetRecord world__Systems (0x73790000000000000000000000000000426174636843616c6c00000000000000)", + "Store_SpliceStaticData world__SystemRegistry (0x0000000000000000000000002aac36425e74ff6c0778da582c55176394a067b0)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000002aac36425e74ff6c0778da582c55176394a067b0)", + "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000526567697374726174696f6e00000000)", + "Store_SetRecord world__Systems (0x73790000000000000000000000000000526567697374726174696f6e00000000)", + "Store_SpliceStaticData world__SystemRegistry (0x0000000000000000000000009fd59d184a359e7f14590d68fd08e57e4d9fded5)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000009fd59d184a359e7f14590d68fd08e57e4d9fded5)", + "Store_SetRecord world__FunctionSelector (0x40554c3a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x40554c3a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x40554c3a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x8d53b20800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x8d53b20800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x8d53b20800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xef5d6bbb00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xef5d6bbb00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xef5d6bbb00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x219adc2e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x219adc2e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x219adc2e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xc9c85a6000000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xc9c85a6000000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xc9c85a6000000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x45afd19900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x45afd19900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x45afd19900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xce5e8dd900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xce5e8dd900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xce5e8dd900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x8fc8cf7e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x8fc8cf7e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x8fc8cf7e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x8da798da00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x8da798da00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x8da798da00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x0ba51f4900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x0ba51f4900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x0ba51f4900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x530f4b6000000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x530f4b6000000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x530f4b6000000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x0560912900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x0560912900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x0560912900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xb29e408900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xb29e408900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xb29e408900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xd5f8337f00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xd5f8337f00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xd5f8337f00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xa92813ad00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xa92813ad00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xa92813ad00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x3350b6a900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x3350b6a900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x3350b6a900000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x26d9810200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x26d9810200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x26d9810200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x6548a90a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x6548a90a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x6548a90a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x1d2257ba00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x1d2257ba00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x1d2257ba00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xcdc938c500000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xcdc938c500000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xcdc938c500000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xbfdfaff700000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xbfdfaff700000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xbfdfaff700000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xaa66e9c800000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__InstalledModules (0x000000000000000000000000e4928465c9808ba23b78452855ac2018242abb35,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_SpliceStaticData world__NamespaceOwner (0x6e73000000000000000000000000000000000000000000000000000000000000)", + "Store_DeleteRecord world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000e244df0041ee77b1f0cda4155879ba8e338ed23b)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266)", + "Store_SetRecord store__Tables (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", + "Store_SetRecord store__Tables (0x746200000000000000000000000000004865616c746800000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000004865616c746800000000000000000000)", + "Store_SetRecord store__Tables (0x74620000000000000000000000000000496e76656e746f727900000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000496e76656e746f727900000000000000)", + "Store_SetRecord store__Tables (0x7462000000000000000000000000000053636f72650000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000053636f72650000000000000000000000)", + "Store_SetRecord store__Tables (0x7462000000000000000000000000000057696e6e657200000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000057696e6e657200000000000000000000)", + "Store_SetRecord store__Tables (0x746200000000000000000000000000005465727261696e000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)", + "Store_SetRecord world__Systems (0x737900000000000000000000000000004d6f766553797374656d000000000000)", + "Store_SpliceStaticData world__SystemRegistry (0x0000000000000000000000003e68253943ba3065f212dba41669e9cf47566956)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000003e68253943ba3065f212dba41669e9cf47566956)", + "Store_SetRecord world__FunctionSelector (0xb591186e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xb591186e00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord store__Tables (0x7462000000000000000000000000000043616c6c576974685369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000043616c6c576974685369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x7379000000000000000000000000000044656c65676174696f6e000000000000)", + "Store_SetRecord world__Systems (0x7379000000000000000000000000000044656c65676174696f6e000000000000)", + "Store_SpliceStaticData world__SystemRegistry (0x0000000000000000000000003381d30ec2b116ce996ab7c17852c3ea34eb1823)", + "Store_SpliceStaticData world__ResourceAccess (0x6e73000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000003381d30ec2b116ce996ab7c17852c3ea34eb1823)", + "Store_SetRecord world__FunctionSelector (0x1fae630800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x1fae630800000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x1fae630800000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__InstalledModules (0x00000000000000000000000051bd8d2de7017c23ee5bdc885e70dfdd0862b837,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_SpliceStaticData world__UserDelegationCo (0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266,0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3)", + "Store_SpliceStaticData store__ResourceIds (0x6e736d6574616461746100000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__NamespaceOwner (0x6e736d6574616461746100000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266)", + "Store_SetRecord store__Tables (0x74626d657461646174610000000000005265736f757263655461670000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", + "Store_SpliceStaticData store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", + "Store_SetRecord world__Systems (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", + "Store_SpliceStaticData world__SystemRegistry (0x000000000000000000000000443ae8e9e5c698a141c400b5d1ee6b4264f1fdc2)", + "Store_SpliceStaticData world__ResourceAccess (0x6e736d6574616461746100000000000000000000000000000000000000000000,0x000000000000000000000000443ae8e9e5c698a141c400b5d1ee6b4264f1fdc2)", + "Store_SetRecord world__FunctionSelector (0xff66f05f00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xc6972e9300000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xff66f05f00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0xefc1704200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x116e68f200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xefc1704200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSelector (0x5ce7ca1a00000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0xf128760200000000000000000000000000000000000000000000000000000000)", + "Store_SetRecord world__FunctionSignatur (0x5ce7ca1a00000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData world__InstalledModules (0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3,0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470)", + "Store_DeleteRecord world__UserDelegationCo (0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266,0x000000000000000000000000c8606bdf3035f73cf194f458e28b1d1f5ea161b3)", "Store_SpliceDynamicData metadata__ResourceTag (0x737900000000000000000000000000004d6f766553797374656d000000000000,0x6162690000000000000000000000000000000000000000000000000000000000)", "Store_SpliceDynamicData metadata__ResourceTag (0x737900000000000000000000000000004d6f766553797374656d000000000000,0x776f726c64416269000000000000000000000000000000000000000000000000)", "Store_SetRecord Position (0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e)", @@ -249,6 +435,40 @@ describe("getStoreLogs", async () => { "Store_SpliceStaticData store__ResourceIds (0x6e736d6574616461746100000000000000000000000000000000000000000000)", "Store_SpliceStaticData store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", "Store_SpliceStaticData store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f72650000000000000000005461626c657300000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f72650000000000000000005265736f757263654964730000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f726500000000000000000053746f7265486f6f6b73000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000004e616d6573706163654f776e65720000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000042616c616e6365730000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e7374616c6c65644d6f64756c6573)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000005573657244656c65676174696f6e436f)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000004e616d65737061636544656c65676174)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000005265736f757263654163636573730000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d73000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000046756e6374696f6e53656c6563746f72)", + "Store_SpliceStaticData store__ResourceIds (0x6f74776f726c6400000000000000000046756e6374696f6e5369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d486f6f6b730000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d52656769737472790000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e69744d6f64756c65416464726573)", + "Store_SpliceStaticData store__ResourceIds (0x6e73000000000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x6e7373746f726500000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", + "Store_SpliceStaticData store__ResourceIds (0x7379000000000000000000000000000042616c616e63655472616e7366657200)", + "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000426174636843616c6c00000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000526567697374726174696f6e00000000)", + "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000004865616c746800000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000496e76656e746f727900000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000053636f72650000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000057696e6e657200000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000043616c6c576974685369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x7379000000000000000000000000000044656c65676174696f6e000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x6e736d6574616461746100000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", + "Store_SpliceStaticData store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", ] `); }); @@ -318,6 +538,63 @@ describe("getStoreLogs", async () => { "Store_SetRecord store__Tables (0x74626d657461646174610000000000005265736f757263655461670000000000)", "Store_SpliceStaticData store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", "Store_SpliceStaticData store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", + "Store_SetRecord store__Tables (0x746273746f72650000000000000000005461626c657300000000000000000000)", + "Store_SetRecord store__Tables (0x746273746f72650000000000000000005265736f757263654964730000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f72650000000000000000005461626c657300000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f72650000000000000000005265736f757263654964730000000000)", + "Store_SetRecord store__Tables (0x746273746f726500000000000000000053746f7265486f6f6b73000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746273746f726500000000000000000053746f7265486f6f6b73000000000000)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000004e616d6573706163654f776e65720000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000004e616d6573706163654f776e65720000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000042616c616e6365730000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000042616c616e6365730000000000000000)", + "Store_SetRecord store__Tables (0x7462776f726c64000000000000000000496e7374616c6c65644d6f64756c6573)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e7374616c6c65644d6f64756c6573)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000005573657244656c65676174696f6e436f)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000005573657244656c65676174696f6e436f)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000004e616d65737061636544656c65676174)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000004e616d65737061636544656c65676174)", + "Store_SetRecord store__Tables (0x7462776f726c640000000000000000005265736f757263654163636573730000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c640000000000000000005265736f757263654163636573730000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000053797374656d73000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d73000000000000000000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000046756e6374696f6e53656c6563746f72)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000046756e6374696f6e53656c6563746f72)", + "Store_SetRecord store__Tables (0x6f74776f726c6400000000000000000046756e6374696f6e5369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x6f74776f726c6400000000000000000046756e6374696f6e5369676e61747572)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000053797374656d486f6f6b730000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d486f6f6b730000000000)", + "Store_SetRecord store__Tables (0x7462776f726c6400000000000000000053797374656d52656769737472790000)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c6400000000000000000053797374656d52656769737472790000)", + "Store_SetRecord store__Tables (0x7462776f726c64000000000000000000496e69744d6f64756c65416464726573)", + "Store_SpliceStaticData store__ResourceIds (0x7462776f726c64000000000000000000496e69744d6f64756c65416464726573)", + "Store_SpliceStaticData store__ResourceIds (0x6e73000000000000000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x6e7373746f726500000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x6e73776f726c6400000000000000000000000000000000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004163636573734d616e6167656d656e74)", + "Store_SpliceStaticData store__ResourceIds (0x7379000000000000000000000000000042616c616e63655472616e7366657200)", + "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000426174636843616c6c00000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x73790000000000000000000000000000526567697374726174696f6e00000000)", + "Store_SetRecord store__Tables (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000506f736974696f6e0000000000000000)", + "Store_SetRecord store__Tables (0x746200000000000000000000000000004865616c746800000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000004865616c746800000000000000000000)", + "Store_SetRecord store__Tables (0x74620000000000000000000000000000496e76656e746f727900000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74620000000000000000000000000000496e76656e746f727900000000000000)", + "Store_SetRecord store__Tables (0x7462000000000000000000000000000053636f72650000000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000053636f72650000000000000000000000)", + "Store_SetRecord store__Tables (0x7462000000000000000000000000000057696e6e657200000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000057696e6e657200000000000000000000)", + "Store_SetRecord store__Tables (0x746200000000000000000000000000005465727261696e000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x746200000000000000000000000000005465727261696e000000000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x737900000000000000000000000000004d6f766553797374656d000000000000)", + "Store_SetRecord store__Tables (0x7462000000000000000000000000000043616c6c576974685369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x7462000000000000000000000000000043616c6c576974685369676e61747572)", + "Store_SpliceStaticData store__ResourceIds (0x7379000000000000000000000000000044656c65676174696f6e000000000000)", + "Store_SpliceStaticData store__ResourceIds (0x6e736d6574616461746100000000000000000000000000000000000000000000)", + "Store_SetRecord store__Tables (0x74626d657461646174610000000000005265736f757263655461670000000000)", + "Store_SpliceStaticData store__ResourceIds (0x74626d657461646174610000000000005265736f757263655461670000000000)", + "Store_SpliceStaticData store__ResourceIds (0x73796d657461646174610000000000004d6574616461746153797374656d0000)", ] `); }); diff --git a/packages/world-module-callwithsignature/mud.config.ts b/packages/world-module-callwithsignature/mud.config.ts index 24479e3c98..0870297988 100644 --- a/packages/world-module-callwithsignature/mud.config.ts +++ b/packages/world-module-callwithsignature/mud.config.ts @@ -10,4 +10,5 @@ export default defineWorld({ key: ["signer"], }, }, + excludeSystems: ["CallWithSignatureSystem"], }); diff --git a/packages/world-module-callwithsignature/src/codegen/world/IWorld.sol b/packages/world-module-callwithsignature/src/codegen/world/IWorld.sol index 05230cf85d..4761e84790 100644 --- a/packages/world-module-callwithsignature/src/codegen/world/IWorld.sol +++ b/packages/world-module-callwithsignature/src/codegen/world/IWorld.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.24; /* Autogenerated file. Do not edit manually. */ import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol"; -import { ICallWithSignatureSystem } from "./ICallWithSignatureSystem.sol"; /** * @title IWorld @@ -13,4 +12,4 @@ import { ICallWithSignatureSystem } from "./ICallWithSignatureSystem.sol"; * that are dynamically registered in the World during deployment. * @dev This is an autogenerated file; do not edit manually. */ -interface IWorld is IBaseWorld, ICallWithSignatureSystem {} +interface IWorld is IBaseWorld {} diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index f5224bc38e..e763ac62c8 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -110,6 +110,10 @@ export const tablesConfig = defineWorld({ }, key: [], }, + CallWithSignatureNonces: { + schema: { signer: "address", nonce: "uint256" }, + key: ["signer"], + }, }, }); @@ -147,6 +151,9 @@ export const systemsConfig = defineWorld({ WorldRegistrationSystem: { name: "Registration", }, + CallWithSignatureSystem: { + name: "SignatureCall", + }, }, }); diff --git a/packages/world/src/IWorldErrors.sol b/packages/world/src/IWorldErrors.sol index e702f86695..1aeed7c5aa 100644 --- a/packages/world/src/IWorldErrors.sol +++ b/packages/world/src/IWorldErrors.sol @@ -107,4 +107,9 @@ interface IWorldErrors { * @param functionSelector The function selector of the disallowed callback. */ error World_CallbackNotAllowed(bytes4 functionSelector); + + /** + * @notice Raised when the signature of a call to `callWithSignature` is invalid. + */ + error World_InvalidSignature(); } diff --git a/packages/world/src/codegen/experimental/systems/CallWithSignatureSystemLib.sol b/packages/world/src/codegen/experimental/systems/CallWithSignatureSystemLib.sol new file mode 100644 index 0000000000..eb30510713 --- /dev/null +++ b/packages/world/src/codegen/experimental/systems/CallWithSignatureSystemLib.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +import { CallWithSignatureSystem } from "../../../modules/init/implementations/CallWithSignatureSystem/CallWithSignatureSystem.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; +import { revertWithBytes } from "../../../revertWithBytes.sol"; +import { IWorldCall } from "../../../IWorldKernel.sol"; +import { SystemCall } from "../../../SystemCall.sol"; +import { WorldContextConsumerLib } from "../../../WorldContext.sol"; +import { Systems } from "../../../codegen/tables/Systems.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; + +type CallWithSignatureSystemType is bytes32; + +// equivalent to WorldResourceIdLib.encode({ typeId: RESOURCE_SYSTEM, namespace: "", name: "SignatureCall" })) +CallWithSignatureSystemType constant callWithSignatureSystem = CallWithSignatureSystemType.wrap( + 0x737900000000000000000000000000005369676e617475726543616c6c000000 +); + +struct CallWrapper { + ResourceId systemId; + address from; +} + +struct RootCallWrapper { + ResourceId systemId; + address from; +} + +/** + * @title CallWithSignatureSystemLib + * @author MUD (https://mud.dev) by Lattice (https://lattice.xyz) + * @dev This library is automatically generated from the corresponding system contract. Do not edit manually. + */ +library CallWithSignatureSystemLib { + error CallWithSignatureSystemLib_CallingFromRootSystem(); + + function callWithSignature( + CallWithSignatureSystemType self, + address signer, + ResourceId systemId, + bytes memory callData, + bytes memory signature + ) internal returns (bytes memory) { + return CallWrapper(self.toResourceId(), address(0)).callWithSignature(signer, systemId, callData, signature); + } + + function callWithSignature( + CallWrapper memory self, + address signer, + ResourceId systemId, + bytes memory callData, + bytes memory signature + ) internal returns (bytes memory) { + // if the contract calling this function is a root system, it should use `callAsRoot` + if (address(_world()) == address(this)) revert CallWithSignatureSystemLib_CallingFromRootSystem(); + + bytes memory systemCall = abi.encodeCall( + _callWithSignature_address_ResourceId_bytes_bytes.callWithSignature, + (signer, systemId, callData, signature) + ); + + bytes memory result = self.from == address(0) + ? _world().call(self.systemId, systemCall) + : _world().callFrom(self.from, self.systemId, systemCall); + return abi.decode(result, (bytes)); + } + + function callWithSignature( + RootCallWrapper memory self, + address signer, + ResourceId systemId, + bytes memory callData, + bytes memory signature + ) internal returns (bytes memory) { + bytes memory systemCall = abi.encodeCall( + _callWithSignature_address_ResourceId_bytes_bytes.callWithSignature, + (signer, systemId, callData, signature) + ); + + bytes memory result = SystemCall.callWithHooksOrRevert(self.from, self.systemId, systemCall, msg.value); + return abi.decode(result, (bytes)); + } + + function callFrom(CallWithSignatureSystemType self, address from) internal pure returns (CallWrapper memory) { + return CallWrapper(self.toResourceId(), from); + } + + function callAsRoot(CallWithSignatureSystemType self) internal view returns (RootCallWrapper memory) { + return RootCallWrapper(self.toResourceId(), WorldContextConsumerLib._msgSender()); + } + + function callAsRootFrom( + CallWithSignatureSystemType self, + address from + ) internal pure returns (RootCallWrapper memory) { + return RootCallWrapper(self.toResourceId(), from); + } + + function toResourceId(CallWithSignatureSystemType self) internal pure returns (ResourceId) { + return ResourceId.wrap(CallWithSignatureSystemType.unwrap(self)); + } + + function fromResourceId(ResourceId resourceId) internal pure returns (CallWithSignatureSystemType) { + return CallWithSignatureSystemType.wrap(resourceId.unwrap()); + } + + function getAddress(CallWithSignatureSystemType self) internal view returns (address) { + return Systems.getSystem(self.toResourceId()); + } + + function _world() private view returns (IWorldCall) { + return IWorldCall(StoreSwitch.getStoreAddress()); + } +} + +/** + * System Function Interfaces + * + * We generate an interface for each system function, which is then used for encoding system calls. + * This is necessary to handle function overloading correctly (which abi.encodeCall cannot). + * + * Each interface is uniquely named based on the function name and parameters to prevent collisions. + */ + +interface _callWithSignature_address_ResourceId_bytes_bytes { + function callWithSignature( + address signer, + ResourceId systemId, + bytes memory callData, + bytes memory signature + ) external; +} + +using CallWithSignatureSystemLib for CallWithSignatureSystemType global; +using CallWithSignatureSystemLib for CallWrapper global; +using CallWithSignatureSystemLib for RootCallWrapper global; diff --git a/packages/world/src/codegen/index.sol b/packages/world/src/codegen/index.sol index b00d58a490..c845d4d753 100644 --- a/packages/world/src/codegen/index.sol +++ b/packages/world/src/codegen/index.sol @@ -15,3 +15,4 @@ import { SystemHooks } from "./tables/SystemHooks.sol"; import { FunctionSelectors } from "./tables/FunctionSelectors.sol"; import { FunctionSignatures } from "./tables/FunctionSignatures.sol"; import { InitModuleAddress } from "./tables/InitModuleAddress.sol"; +import { CallWithSignatureNonces } from "./tables/CallWithSignatureNonces.sol"; diff --git a/packages/world/src/codegen/interfaces/IBaseWorld.sol b/packages/world/src/codegen/interfaces/IBaseWorld.sol index 144be64d0f..6a751ea271 100644 --- a/packages/world/src/codegen/interfaces/IBaseWorld.sol +++ b/packages/world/src/codegen/interfaces/IBaseWorld.sol @@ -9,6 +9,7 @@ import { IRegistrationSystem } from "./IRegistrationSystem.sol"; import { IAccessManagementSystem } from "./IAccessManagementSystem.sol"; import { IBalanceTransferSystem } from "./IBalanceTransferSystem.sol"; import { IBatchCallSystem } from "./IBatchCallSystem.sol"; +import { ICallWithSignatureSystem } from "./ICallWithSignatureSystem.sol"; import { IModuleInstallationSystem } from "./IModuleInstallationSystem.sol"; import { IWorldRegistrationSystem } from "./IWorldRegistrationSystem.sol"; @@ -26,6 +27,7 @@ interface IBaseWorld is IAccessManagementSystem, IBalanceTransferSystem, IBatchCallSystem, + ICallWithSignatureSystem, IModuleInstallationSystem, IWorldRegistrationSystem {} diff --git a/packages/world-module-callwithsignature/src/codegen/world/ICallWithSignatureSystem.sol b/packages/world/src/codegen/interfaces/ICallWithSignatureSystem.sol similarity index 100% rename from packages/world-module-callwithsignature/src/codegen/world/ICallWithSignatureSystem.sol rename to packages/world/src/codegen/interfaces/ICallWithSignatureSystem.sol diff --git a/packages/world/src/codegen/tables/CallWithSignatureNonces.sol b/packages/world/src/codegen/tables/CallWithSignatureNonces.sol new file mode 100644 index 0000000000..941283b504 --- /dev/null +++ b/packages/world/src/codegen/tables/CallWithSignatureNonces.sol @@ -0,0 +1,199 @@ +// 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 CallWithSignatureNonces { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "world", name: "CallWithSignatur", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x7462776f726c6400000000000000000043616c6c576974685369676e61747572); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0020010020000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (address) + Schema constant _keySchema = Schema.wrap(0x0014010061000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (uint256) + Schema constant _valueSchema = Schema.wrap(0x002001001f000000000000000000000000000000000000000000000000000000); + + /** + * @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[](1); + keyNames[0] = "signer"; + } + + /** + * @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] = "nonce"; + } + + /** + * @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 nonce. + */ + function getNonce(address signer) internal view returns (uint256 nonce) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get nonce. + */ + function _getNonce(address signer) internal view returns (uint256 nonce) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get nonce. + */ + function get(address signer) internal view returns (uint256 nonce) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get nonce. + */ + function _get(address signer) internal view returns (uint256 nonce) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set nonce. + */ + function setNonce(address signer, uint256 nonce) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((nonce)), _fieldLayout); + } + + /** + * @notice Set nonce. + */ + function _setNonce(address signer, uint256 nonce) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((nonce)), _fieldLayout); + } + + /** + * @notice Set nonce. + */ + function set(address signer, uint256 nonce) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((nonce)), _fieldLayout); + } + + /** + * @notice Set nonce. + */ + function _set(address signer, uint256 nonce) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((nonce)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(address signer) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(address signer) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(uint256 nonce) internal pure returns (bytes memory) { + return abi.encodePacked(nonce); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(uint256 nonce) internal pure returns (bytes memory, EncodedLengths, bytes memory) { + bytes memory _staticData = encodeStatic(nonce); + + EncodedLengths _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(address signer) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(signer))); + + return _keyTuple; + } +} diff --git a/packages/world/src/modules/init/InitModule.sol b/packages/world/src/modules/init/InitModule.sol index 417b2f91b3..4a580a61b6 100644 --- a/packages/world/src/modules/init/InitModule.sol +++ b/packages/world/src/modules/init/InitModule.sol @@ -19,10 +19,11 @@ import { NamespaceDelegationControl } from "../../codegen/tables/NamespaceDelega import { AccessManagementSystem } from "./implementations/AccessManagementSystem.sol"; import { BalanceTransferSystem } from "./implementations/BalanceTransferSystem.sol"; import { BatchCallSystem } from "./implementations/BatchCallSystem.sol"; +import { CallWithSignatureSystem } from "./implementations/CallWithSignatureSystem/CallWithSignatureSystem.sol"; import { RegistrationSystem } from "./RegistrationSystem.sol"; -import { ACCESS_MANAGEMENT_SYSTEM_ID, BALANCE_TRANSFER_SYSTEM_ID, BATCH_CALL_SYSTEM_ID, REGISTRATION_SYSTEM_ID } from "./constants.sol"; -import { getFunctionSignaturesAccessManagement, getFunctionSignaturesBalanceTransfer, getFunctionSignaturesBatchCall, getFunctionSignaturesRegistration } from "./functionSignatures.sol"; +import { ACCESS_MANAGEMENT_SYSTEM_ID, BALANCE_TRANSFER_SYSTEM_ID, BATCH_CALL_SYSTEM_ID, REGISTRATION_SYSTEM_ID, CALL_WITH_SIGNATURE_SYSTEM_ID } from "./constants.sol"; +import { getFunctionSignaturesAccessManagement, getFunctionSignaturesBalanceTransfer, getFunctionSignaturesBatchCall, getFunctionSignaturesRegistration, getFunctionSignaturesCallWithSignature } from "./functionSignatures.sol"; import { Systems } from "../../codegen/tables/Systems.sol"; import { FunctionSelectors } from "../../codegen/tables/FunctionSelectors.sol"; @@ -31,6 +32,7 @@ import { SystemHooks } from "../../codegen/tables/SystemHooks.sol"; import { SystemRegistry } from "../../codegen/tables/SystemRegistry.sol"; import { InitModuleAddress } from "../../codegen/tables/InitModuleAddress.sol"; import { Balances } from "../../codegen/tables/Balances.sol"; +import { CallWithSignatureNonces } from "../../codegen/tables/CallWithSignatureNonces.sol"; import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; @@ -45,17 +47,20 @@ contract InitModule is Module { address internal immutable balanceTransferSystem; address internal immutable batchCallSystem; address internal immutable registrationSystem; + address internal immutable delegationSystem; constructor( AccessManagementSystem _accessManagementSystem, BalanceTransferSystem _balanceTransferSystem, BatchCallSystem _batchCallSystem, - RegistrationSystem _registrationSystem + RegistrationSystem _registrationSystem, + CallWithSignatureSystem _delegationSystem ) { accessManagementSystem = address(_accessManagementSystem); balanceTransferSystem = address(_balanceTransferSystem); batchCallSystem = address(_batchCallSystem); registrationSystem = address(_registrationSystem); + delegationSystem = address(_delegationSystem); } /** @@ -86,6 +91,7 @@ contract InitModule is Module { SystemHooks.register(); SystemRegistry.register(); InitModuleAddress.register(); + CallWithSignatureNonces.register(); ResourceIds._setExists(ROOT_NAMESPACE_ID, true); NamespaceOwner._set(ROOT_NAMESPACE_ID, _msgSender()); @@ -108,6 +114,7 @@ contract InitModule is Module { _registerSystem(balanceTransferSystem, BALANCE_TRANSFER_SYSTEM_ID); _registerSystem(batchCallSystem, BATCH_CALL_SYSTEM_ID); _registerSystem(registrationSystem, REGISTRATION_SYSTEM_ID); + _registerSystem(delegationSystem, CALL_WITH_SIGNATURE_SYSTEM_ID); } /** @@ -147,6 +154,11 @@ contract InitModule is Module { for (uint256 i = 0; i < functionSignaturesRegistration.length; i++) { _registerRootFunctionSelector(REGISTRATION_SYSTEM_ID, functionSignaturesRegistration[i]); } + + string[1] memory functionSignaturesCallWithSignature = getFunctionSignaturesCallWithSignature(); + for (uint256 i = 0; i < functionSignaturesCallWithSignature.length; i++) { + _registerRootFunctionSelector(CALL_WITH_SIGNATURE_SYSTEM_ID, functionSignaturesCallWithSignature[i]); + } } /** diff --git a/packages/world/src/modules/init/constants.sol b/packages/world/src/modules/init/constants.sol index e17ab3635a..96db868ac8 100644 --- a/packages/world/src/modules/init/constants.sol +++ b/packages/world/src/modules/init/constants.sol @@ -37,3 +37,11 @@ ResourceId constant BATCH_CALL_SYSTEM_ID = ResourceId.wrap( ResourceId constant REGISTRATION_SYSTEM_ID = ResourceId.wrap( bytes32(abi.encodePacked(RESOURCE_SYSTEM, ROOT_NAMESPACE, bytes16("Registration"))) ); + +/** + * @dev Resource ID for the call with signature system. + * @dev This ID is derived from the RESOURCE_SYSTEM type, the ROOT_NAMESPACE, and the system name. + */ +ResourceId constant CALL_WITH_SIGNATURE_SYSTEM_ID = ResourceId.wrap( + (bytes32(abi.encodePacked(RESOURCE_SYSTEM, ROOT_NAMESPACE, bytes16("CallWithSignatur")))) +); diff --git a/packages/world/src/modules/init/functionSignatures.sol b/packages/world/src/modules/init/functionSignatures.sol index e9a7fe13bd..c11df904cd 100644 --- a/packages/world/src/modules/init/functionSignatures.sol +++ b/packages/world/src/modules/init/functionSignatures.sol @@ -60,3 +60,13 @@ function getFunctionSignaturesRegistration() pure returns (string[14] memory) { "unregisterNamespaceDelegation(bytes32)" ]; } + +/** + * @dev Function signatures for call with signature system + */ +function getFunctionSignaturesCallWithSignature() pure returns (string[1] memory) { + return [ + // --- CallWithSignatureSystem --- + "callWithSignature(address,bytes32,bytes,bytes)" + ]; +} diff --git a/packages/world/src/modules/init/implementations/BatchCallSystem.sol b/packages/world/src/modules/init/implementations/BatchCallSystem.sol index 9a62614193..71450d2cc5 100644 --- a/packages/world/src/modules/init/implementations/BatchCallSystem.sol +++ b/packages/world/src/modules/init/implementations/BatchCallSystem.sol @@ -6,6 +6,7 @@ import { IBaseWorld } from "../../../codegen/interfaces/IBaseWorld.sol"; import { revertWithBytes } from "../../../revertWithBytes.sol"; import { SystemCallData, SystemCallFromData } from "../types.sol"; import { LimitedCallContext } from "../LimitedCallContext.sol"; +import { SystemCall } from "../../../SystemCall.sol"; /** * @title Batch Call System @@ -22,16 +23,15 @@ contract BatchCallSystem is System, LimitedCallContext { function batchCall( SystemCallData[] calldata systemCalls ) public onlyDelegatecall returns (bytes[] memory returnDatas) { - IBaseWorld world = IBaseWorld(_world()); returnDatas = new bytes[](systemCalls.length); for (uint256 i; i < systemCalls.length; i++) { - (bool success, bytes memory returnData) = address(world).delegatecall( - abi.encodeCall(world.call, (systemCalls[i].systemId, systemCalls[i].callData)) + returnDatas[i] = SystemCall.callWithHooksOrRevert( + _msgSender(), + systemCalls[i].systemId, + systemCalls[i].callData, + 0 ); - if (!success) revertWithBytes(returnData); - - returnDatas[i] = abi.decode(returnData, (bytes)); } } @@ -48,11 +48,11 @@ contract BatchCallSystem is System, LimitedCallContext { returnDatas = new bytes[](systemCalls.length); for (uint256 i; i < systemCalls.length; i++) { + // TODO: swap this with SystemCall.callFromWithHooksOrRevert once available (bool success, bytes memory returnData) = address(world).delegatecall( abi.encodeCall(world.callFrom, (systemCalls[i].from, systemCalls[i].systemId, systemCalls[i].callData)) ); if (!success) revertWithBytes(returnData); - returnDatas[i] = abi.decode(returnData, (bytes)); } } diff --git a/packages/world/src/modules/init/implementations/CallWithSignatureSystem/CallWithSignatureSystem.sol b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/CallWithSignatureSystem.sol new file mode 100644 index 0000000000..e564aca8ee --- /dev/null +++ b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/CallWithSignatureSystem.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +import { System } from "../../../../System.sol"; +import { SystemCall } from "../../../../SystemCall.sol"; +import { CallWithSignatureNonces } from "../../../../codegen/tables/CallWithSignatureNonces.sol"; +import { IWorldErrors } from "../../../../IWorldErrors.sol"; +import { LimitedCallContext } from "../../LimitedCallContext.sol"; +import { createDelegation } from "../createDelegation.sol"; +import { getSignedMessageHash } from "./getSignedMessageHash.sol"; +import { ECDSA } from "./ECDSA.sol"; +import { validateCallWithSignature } from "./validateCallWithSignature.sol"; + +contract CallWithSignatureSystem is System, IWorldErrors, LimitedCallContext { + /** + * @notice Calls a system with a given system ID using the given signature. + * @param signer The address on whose behalf the system is called. + * @param systemId The ID of the system to be called. + * @param callData The ABI data for the system call. + * @param signature The EIP712 signature. + * @return Return data from the system call. + */ + function callWithSignature( + address signer, + ResourceId systemId, + bytes memory callData, + bytes memory signature + ) public payable onlyDelegatecall returns (bytes memory) { + validateCallWithSignature(signer, systemId, callData, signature); + + CallWithSignatureNonces._set(signer, CallWithSignatureNonces._get(signer) + 1); + + return SystemCall.callWithHooksOrRevert(signer, systemId, callData, _msgValue()); + } +} diff --git a/packages/world/src/modules/init/implementations/CallWithSignatureSystem/ECDSA.sol b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/ECDSA.sol new file mode 100644 index 0000000000..01201021db --- /dev/null +++ b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/ECDSA.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) + +pragma solidity >=0.8.24; + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS + } + + /** + * @dev The signature derives the `address(0)`. + */ + error ECDSAInvalidSignature(); + + /** + * @dev The signature has an invalid length. + */ + error ECDSAInvalidSignatureLength(uint256 length); + + /** + * @dev The signature has an S value that is in the upper half order. + */ + error ECDSAInvalidSignatureS(bytes32 s); + + /** + * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not + * return address(0) without also returning an error description. Errors are documented using an enum (error type) + * and a bytes32 providing additional information about the error. + * + * If no error is returned, then the address can be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures] + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { + unchecked { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + // We do not check for an overflow here since the shift operation results in 0 or 1. + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function tryRecover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address, RecoverError, bytes32) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS, s); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature, bytes32(0)); + } + + return (signer, RecoverError.NoError, bytes32(0)); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. + */ + function _throwError(RecoverError error, bytes32 errorArg) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert ECDSAInvalidSignature(); + } else if (error == RecoverError.InvalidSignatureLength) { + revert ECDSAInvalidSignatureLength(uint256(errorArg)); + } else if (error == RecoverError.InvalidSignatureS) { + revert ECDSAInvalidSignatureS(errorArg); + } + } +} diff --git a/packages/world/src/modules/init/implementations/CallWithSignatureSystem/IERC1271.sol b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/IERC1271.sol new file mode 100644 index 0000000000..a1fd71358a --- /dev/null +++ b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/IERC1271.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) + +pragma solidity ^0.8.24; + +/** + * @dev Interface of the ERC-1271 standard signature validation method for + * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. + */ +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param hash Hash of the data to be signed + * @param signature Signature byte array associated with _data + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/packages/world/src/modules/init/implementations/CallWithSignatureSystem/SignatureChecker.sol b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/SignatureChecker.sol new file mode 100644 index 0000000000..cbadd6d679 --- /dev/null +++ b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/SignatureChecker.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol) + +pragma solidity ^0.8.24; + +import { ECDSA } from "./ECDSA.sol"; +import { IERC1271 } from "./IERC1271.sol"; + +/** + * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA + * signatures from externally owned accounts (EOAs) as well as ERC-1271 signatures from smart contract wallets like + * Argent and Safe Wallet (previously Gnosis Safe). + */ +library SignatureChecker { + /** + * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the + * signature is validated against that smart contract using ERC-1271, otherwise it's validated using `ECDSA.recover`. + * + * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus + * change through time. It could return true at block N and false at block N+1 (or the opposite). + */ + function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + if (signer.code.length == 0) { + (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); + return err == ECDSA.RecoverError.NoError && recovered == signer; + } else { + return isValidERC1271SignatureNow(signer, hash, signature); + } + } + + /** + * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated + * against the signer smart contract using ERC-1271. + * + * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus + * change through time. It could return true at block N and false at block N+1 (or the opposite). + */ + function isValidERC1271SignatureNow( + address signer, + bytes32 hash, + bytes memory signature + ) internal view returns (bool) { + (bool success, bytes memory result) = signer.staticcall( + abi.encodeCall(IERC1271.isValidSignature, (hash, signature)) + ); + return (success && + result.length >= 32 && + abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); + } +} diff --git a/packages/world/src/modules/init/implementations/CallWithSignatureSystem/getSignedMessageHash.sol b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/getSignedMessageHash.sol new file mode 100644 index 0000000000..57048a9c2e --- /dev/null +++ b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/getSignedMessageHash.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { ResourceId, WorldResourceIdLib, WorldResourceIdInstance } from "../../../../WorldResourceId.sol"; + +using WorldResourceIdInstance for ResourceId; + +// Note the intended value of the `salt` field is the chain ID. +// It is not included in `chainId`, to allow cross-chain signing without requiring wallets to switch networks. +// The value of this field should be the chain on which the world lives, rather than the chain the wallet is connected to. +bytes32 constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(address verifyingContract,bytes32 salt)"); +bytes32 constant CALL_TYPEHASH = keccak256( + "Call(address signer,string systemNamespace,string systemName,bytes callData,uint256 nonce)" +); + +/** + * @notice Generate the message hash for a given delegation signature. + * For EIP712 signatures https://eips.ethereum.org/EIPS/eip-712 + * @dev We include the signer address to prevent generating a signature that recovers to a random address that didn't sign the message. + * @param signer The address on whose behalf the system is called. + * @param systemId The ID of the system to be called. + * @param callData The ABI data for the system call. + * @param nonce The nonce of the signer + * @param worldAddress The world address + * @return Return the message hash. + */ +function getSignedMessageHash( + address signer, + ResourceId systemId, + bytes memory callData, + uint256 nonce, + address worldAddress +) view returns (bytes32) { + bytes32 domainSeperator = keccak256(abi.encode(DOMAIN_TYPEHASH, worldAddress, bytes32(block.chainid))); + + return + keccak256( + abi.encodePacked( + "\x19\x01", + domainSeperator, + keccak256( + abi.encode( + CALL_TYPEHASH, + signer, + keccak256(bytes(WorldResourceIdLib.toTrimmedString(systemId.getNamespace()))), + keccak256(bytes(WorldResourceIdLib.toTrimmedString(systemId.getName()))), + keccak256(callData), + nonce + ) + ) + ) + ); +} diff --git a/packages/world/src/modules/init/implementations/CallWithSignatureSystem/validateCallWithSignature.sol b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/validateCallWithSignature.sol new file mode 100644 index 0000000000..f3a95a24c0 --- /dev/null +++ b/packages/world/src/modules/init/implementations/CallWithSignatureSystem/validateCallWithSignature.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; +import { ResourceId } from "../../../../WorldResourceId.sol"; +import { WorldContextConsumerLib } from "../../../../WorldContext.sol"; +import { CallWithSignatureNonces } from "../../../../codegen/tables/CallWithSignatureNonces.sol"; +import { IWorldErrors } from "../../../../IWorldErrors.sol"; +import { getSignedMessageHash } from "./getSignedMessageHash.sol"; +import { ECDSA } from "./ECDSA.sol"; +import { SignatureChecker } from "./SignatureChecker.sol"; + +/** + * @notice Verifies the given system call corresponds to the given signature. + * @param signer The address on whose behalf the system is called. + * @param systemId The ID of the system to be called. + * @param callData The ABI data for the system call. + * @param signature The EIP712 signature. + * @dev Reverts with InvalidSignature(recoveredSigner) if the signature is invalid. + */ +function validateCallWithSignature( + address signer, + ResourceId systemId, + bytes memory callData, + bytes memory signature +) view { + uint256 nonce = CallWithSignatureNonces._get(signer); + bytes32 hash = getSignedMessageHash(signer, systemId, callData, nonce, WorldContextConsumerLib._world()); + + if (!SignatureChecker.isValidSignatureNow(signer, hash, signature)) { + revert IWorldErrors.World_InvalidSignature(); + } +} diff --git a/packages/world/test/BatchCall.t.sol b/packages/world/test/BatchCall.t.sol index 0af2b6b434..d9cb3710aa 100644 --- a/packages/world/test/BatchCall.t.sol +++ b/packages/world/test/BatchCall.t.sol @@ -14,6 +14,8 @@ import { RESOURCE_SYSTEM } from "../src/worldResourceTypes.sol"; import { IWorldErrors } from "../src/IWorldErrors.sol"; import { IBaseWorld } from "../src/codegen/interfaces/IBaseWorld.sol"; import { SystemCallData, SystemCallFromData } from "../src/modules/init/types.sol"; +import { BATCH_CALL_SYSTEM_ID } from "../src/modules/init/constants.sol"; +import { BatchCallSystem } from "../src/modules/init/implementations/BatchCallSystem.sol"; import { createWorld } from "./createWorld.sol"; @@ -175,4 +177,45 @@ contract BatchCallTest is Test, GasReporter { assertEq(abi.decode(returnDatas[0], (address)), delegatee, "wrong delegatee returned"); assertEq(abi.decode(returnDatas[1], (address)), delegator, "wrong delegator returned"); } + + /** + * If all calls come from the same delegation, it should be simpler and cheaper to compose + * calls via `callFrom(batchCall(...))` instead of `batchCallFrom(...)`. + */ + function testCallFromBatchCall() public { + // Register a new system + TestSystem system = new TestSystem(); + world.registerSystem(systemId, system, true); + + // Try to increment the counter without creating a delegation + SystemCallData[] memory systemCalls = new SystemCallData[](1); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(delegatee); + vm.expectRevert(abi.encodeWithSelector(IWorldErrors.World_DelegationNotFound.selector, delegator, delegatee)); + world.callFrom(delegator, BATCH_CALL_SYSTEM_ID, abi.encodeCall(BatchCallSystem.batchCall, (systemCalls))); + + // Create an unlimited delegation + vm.prank(delegator); + world.registerDelegation(delegatee, UNLIMITED_DELEGATION, new bytes(0)); + + // Try to increment the counter without setting the admin + vm.prank(delegatee); + vm.expectRevert("sender is not admin"); + world.callFrom(delegator, BATCH_CALL_SYSTEM_ID, abi.encodeCall(BatchCallSystem.batchCall, (systemCalls))); + + assertEq(system.admin(), address(0)); + + // Set the admin and increment the counter twice + systemCalls = new SystemCallData[](3); + systemCalls[0] = SystemCallData(systemId, abi.encodeCall(TestSystem.setAdmin, (delegator))); + systemCalls[1] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + systemCalls[2] = SystemCallData(systemId, abi.encodeCall(TestSystem.increment, ())); + + vm.prank(delegatee); + world.callFrom(delegator, BATCH_CALL_SYSTEM_ID, abi.encodeCall(BatchCallSystem.batchCall, (systemCalls))); + + assertEq(system.admin(), delegator); + assertEq(system.counter(), 2, "wrong counter value"); + } } diff --git a/packages/world/test/InitSystems.t.sol b/packages/world/test/InitSystems.t.sol index 99c9714911..d0623118ed 100644 --- a/packages/world/test/InitSystems.t.sol +++ b/packages/world/test/InitSystems.t.sol @@ -9,9 +9,9 @@ import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; import { createWorld } from "./createWorld.sol"; import { LimitedCallContext } from "../src/modules/init/LimitedCallContext.sol"; -import { getFunctionSignaturesAccessManagement, getFunctionSignaturesBalanceTransfer, getFunctionSignaturesBatchCall, getFunctionSignaturesRegistration } from "../src/modules/init/functionSignatures.sol"; +import { getFunctionSignaturesAccessManagement, getFunctionSignaturesBalanceTransfer, getFunctionSignaturesBatchCall, getFunctionSignaturesRegistration, getFunctionSignaturesCallWithSignature } from "../src/modules/init/functionSignatures.sol"; -import { ACCESS_MANAGEMENT_SYSTEM_ID, BALANCE_TRANSFER_SYSTEM_ID, BATCH_CALL_SYSTEM_ID, REGISTRATION_SYSTEM_ID } from "../src/modules/init/constants.sol"; +import { ACCESS_MANAGEMENT_SYSTEM_ID, BALANCE_TRANSFER_SYSTEM_ID, BATCH_CALL_SYSTEM_ID, REGISTRATION_SYSTEM_ID, CALL_WITH_SIGNATURE_SYSTEM_ID } from "../src/modules/init/constants.sol"; import { Systems } from "../src/codegen/tables/Systems.sol"; @@ -69,4 +69,12 @@ contract LimitedCallContextTest is Test { callSystem(REGISTRATION_SYSTEM_ID, functionSignaturesRegistration[i]); } } + + function testCallWithSignatureSystem() public { + string[1] memory functionSignaturesCallWithSignature = getFunctionSignaturesCallWithSignature(); + + for (uint256 i; i < functionSignaturesCallWithSignature.length; i++) { + callSystem(CALL_WITH_SIGNATURE_SYSTEM_ID, functionSignaturesCallWithSignature[i]); + } + } } diff --git a/packages/world/test/createInitModule.sol b/packages/world/test/createInitModule.sol index 8354584c5a..fba7b3db73 100644 --- a/packages/world/test/createInitModule.sol +++ b/packages/world/test/createInitModule.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.24; import { AccessManagementSystem } from "../src/modules/init/implementations/AccessManagementSystem.sol"; import { BalanceTransferSystem } from "../src/modules/init/implementations/BalanceTransferSystem.sol"; import { BatchCallSystem } from "../src/modules/init/implementations/BatchCallSystem.sol"; +import { CallWithSignatureSystem } from "../src/modules/init/implementations/CallWithSignatureSystem/CallWithSignatureSystem.sol"; import { InitModule } from "../src/modules/init/InitModule.sol"; import { RegistrationSystem } from "../src/modules/init/RegistrationSystem.sol"; @@ -14,6 +15,7 @@ function createInitModule() returns (InitModule) { new AccessManagementSystem(), new BalanceTransferSystem(), new BatchCallSystem(), - new RegistrationSystem() + new RegistrationSystem(), + new CallWithSignatureSystem() ); } diff --git a/packages/world/ts/protocol-snapshots/2.0.2.snap b/packages/world/ts/protocol-snapshots/2.0.2.snap index aed3400889..cf9a91cf58 100644 --- a/packages/world/ts/protocol-snapshots/2.0.2.snap +++ b/packages/world/ts/protocol-snapshots/2.0.2.snap @@ -37,6 +37,7 @@ "error World_InvalidNamespace(bytes14 namespace)", "error World_InvalidResourceId(bytes32 resourceId, string resourceIdString)", "error World_InvalidResourceType(bytes2 expected, bytes32 resourceId, string resourceIdString)", + "error World_InvalidSignature()", "error World_ResourceAlreadyExists(bytes32 resourceId, string resourceIdString)", "error World_ResourceNotFound(bytes32 resourceId, string resourceIdString)", "error World_SystemAlreadyExists(address system)", @@ -51,6 +52,7 @@ "function batchCallFrom((address from, bytes32 systemId, bytes callData)[] systemCalls) returns (bytes[] returnDatas)", "function call(bytes32 systemId, bytes callData) payable returns (bytes)", "function callFrom(address delegator, bytes32 systemId, bytes callData) payable returns (bytes)", + "function callWithSignature(address signer, bytes32 systemId, bytes callData, bytes signature) payable returns (bytes)", "function creator() view returns (address)", "function deleteRecord(bytes32 tableId, bytes32[] keyTuple)", "function getDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (bytes)", diff --git a/packages/world/ts/protocolVersions.ts b/packages/world/ts/protocolVersions.ts index b91dcbbbc2..3884514361 100644 --- a/packages/world/ts/protocolVersions.ts +++ b/packages/world/ts/protocolVersions.ts @@ -1,5 +1,7 @@ // History of protocol versions and a short description of what changed in each. export const protocolVersions = { + "2.1.0": + "Added `callWithSignature` to allow calling functions on behalf of another address by providing a signature.", "2.0.2": "Patched `StoreCore.registerTable` to prevent registering both an offchain and onchain table with the same name.", "2.0.1": "Patched `StoreRead.getDynamicFieldLength` to use the correct method to read the dynamic field length.",