diff --git a/.changeset/pink-pandas-fetch.md b/.changeset/pink-pandas-fetch.md deleted file mode 100644 index 74d4675ea7..0000000000 --- a/.changeset/pink-pandas-fetch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@latticexyz/store": major ---- - -Moved Solidity custom errors (e.g. `Store_TableNotFound`) from `IStoreErrors` interface to file-level errors in `errors.sol`. If you were using these errors before, you may need to update your imports. diff --git a/docs/pages/store/reference/store.mdx b/docs/pages/store/reference/store.mdx index 4053966495..df300ce8c7 100644 --- a/docs/pages/store/reference/store.mdx +++ b/docs/pages/store/reference/store.mdx @@ -5,7 +5,7 @@ [Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStore.sol) **Inherits:** -[IStoreData](/store/reference/store#istoredata), [IStoreRegistration](/store/reference/store#istoreregistration) +[IStoreData](/store/reference/store#istoredata), [IStoreRegistration](/store/reference/store#istoreregistration), [IStoreErrors](/store/reference/store#istoreerrors) ## IStoreEvents @@ -96,100 +96,82 @@ event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); | `tableId` | `ResourceId` | The ID of the table where the record is deleted. | | `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | -## Store_IndexOutOfBounds +## IStoreErrors -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreErrors.sol) + +### Errors + +#### Store_TableAlreadyExists ```solidity -error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex); +error Store_TableAlreadyExists(ResourceId tableId, string tableIdString); ``` -## Store_InvalidBounds - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_TableNotFound ```solidity -error Store_InvalidBounds(uint256 start, uint256 end); +error Store_TableNotFound(ResourceId tableId, string tableIdString); ``` -## Store_InvalidFieldNamesLength - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidResourceType ```solidity -error Store_InvalidFieldNamesLength(uint256 expected, uint256 received); +error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString); ``` -## Store_InvalidKeyNamesLength - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidStaticDataLength ```solidity -error Store_InvalidKeyNamesLength(uint256 expected, uint256 received); +error Store_InvalidStaticDataLength(uint256 expected, uint256 received); ``` -## Store_InvalidResourceType - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidBounds ```solidity -error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString); +error Store_InvalidBounds(uint256 start, uint256 end); ``` -## Store_InvalidSplice - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_IndexOutOfBounds ```solidity -error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength); +error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex); ``` -## Store_InvalidStaticDataLength - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidKeyNamesLength ```solidity -error Store_InvalidStaticDataLength(uint256 expected, uint256 received); +error Store_InvalidKeyNamesLength(uint256 expected, uint256 received); ``` -## Store_InvalidValueSchemaDynamicLength - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidFieldNamesLength ```solidity -error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received); +error Store_InvalidFieldNamesLength(uint256 expected, uint256 received); ``` -## Store_InvalidValueSchemaLength - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidValueSchemaLength ```solidity error Store_InvalidValueSchemaLength(uint256 expected, uint256 received); ``` -## Store_InvalidValueSchemaStaticLength - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidValueSchemaStaticLength ```solidity error Store_InvalidValueSchemaStaticLength(uint256 expected, uint256 received); ``` -## Store_TableAlreadyExists - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidValueSchemaDynamicLength ```solidity -error Store_TableAlreadyExists(ResourceId tableId, string tableIdString); +error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received); ``` -## Store_TableNotFound - -[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/errors.sol) +#### Store_InvalidSplice ```solidity -error Store_TableNotFound(ResourceId tableId, string tableIdString); +error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength); ``` ## IStoreData diff --git a/docs/pages/world/reference/world-external.mdx b/docs/pages/world/reference/world-external.mdx index 9659749299..4e5d2dc854 100644 --- a/docs/pages/world/reference/world-external.mdx +++ b/docs/pages/world/reference/world-external.mdx @@ -451,6 +451,80 @@ function unregisterNamespaceDelegation(ResourceId namespaceId) public onlyDelega | ------------- | ------------ | ----------------------- | | `namespaceId` | `ResourceId` | The ID of the namespace | +### Errors + +#### Store_TableAlreadyExists + +```solidity +error Store_TableAlreadyExists(ResourceId tableId, string tableIdString); +``` + +#### Store_TableNotFound + +```solidity +error Store_TableNotFound(ResourceId tableId, string tableIdString); +``` + +#### Store_InvalidResourceType + +```solidity +error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString); +``` + +#### Store_InvalidStaticDataLength + +```solidity +error Store_InvalidStaticDataLength(uint256 expected, uint256 received); +``` + +#### Store_InvalidBounds + +```solidity +error Store_InvalidBounds(uint256 start, uint256 end); +``` + +#### Store_IndexOutOfBounds + +```solidity +error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex); +``` + +#### Store_InvalidKeyNamesLength + +```solidity +error Store_InvalidKeyNamesLength(uint256 expected, uint256 received); +``` + +#### Store_InvalidFieldNamesLength + +```solidity +error Store_InvalidFieldNamesLength(uint256 expected, uint256 received); +``` + +#### Store_InvalidValueSchemaLength + +```solidity +error Store_InvalidValueSchemaLength(uint256 expected, uint256 received); +``` + +#### Store_InvalidValueSchemaStaticLength + +```solidity +error Store_InvalidValueSchemaStaticLength(uint256 expected, uint256 received); +``` + +#### Store_InvalidValueSchemaDynamicLength + +```solidity +error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received); +``` + +#### Store_InvalidSplice + +```solidity +error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength); +``` + ## IWorldCall [Git Source](https://github.com/latticexyz/mud/blob/main/packages/world/src/IWorldKernel.sol) diff --git a/packages/cli/contracts/test/Tablegen.t.sol b/packages/cli/contracts/test/Tablegen.t.sol index ba7ff85ec5..d00c63c0f3 100644 --- a/packages/cli/contracts/test/Tablegen.t.sol +++ b/packages/cli/contracts/test/Tablegen.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.24; import "forge-std/Test.sol"; import { StoreMock } from "@latticexyz/store/test/StoreMock.sol"; -import { Store_IndexOutOfBounds } from "@latticexyz/store/src/errors.sol"; +import { IStoreErrors } from "@latticexyz/store/src/IStoreErrors.sol"; import { Statics, StaticsData, Dynamics1, Dynamics1Data, Dynamics2, Dynamics2Data, Singleton, Offchain, UserTyped, UserTypedData } from "../src/codegen/index.sol"; import { TestTypeAddress, TestTypeInt64, TestTypeLibrary } from "../src/types.sol"; @@ -143,7 +143,7 @@ contract TablegenTest is Test, StoreMock { assertEq(abi.encode(Singleton.getV4()), abi.encode([uint32(5)])); assertEq(Singleton.lengthV4(), 1); assertEq(Singleton.getItemV4(0), 5); - vm.expectRevert(abi.encodeWithSelector(Store_IndexOutOfBounds.selector, 4, 4)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_IndexOutOfBounds.selector, 4, 4)); assertEq(Singleton.getItemV4(1), 0); } diff --git a/packages/store/src/IStore.sol b/packages/store/src/IStore.sol index c2cceb6f21..2809f10339 100644 --- a/packages/store/src/IStore.sol +++ b/packages/store/src/IStore.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.24; +import { IStoreErrors } from "./IStoreErrors.sol"; import { IStoreData } from "./IStoreData.sol"; import { IStoreRegistration } from "./IStoreRegistration.sol"; -interface IStore is IStoreData, IStoreRegistration {} +interface IStore is IStoreData, IStoreRegistration, IStoreErrors {} diff --git a/packages/store/src/IStoreErrors.sol b/packages/store/src/IStoreErrors.sol new file mode 100644 index 0000000000..62d63f085d --- /dev/null +++ b/packages/store/src/IStoreErrors.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { ResourceId } from "./ResourceId.sol"; + +interface IStoreErrors { + // Errors include a stringified version of the tableId for easier debugging if cleartext tableIds are used + error Store_TableAlreadyExists(ResourceId tableId, string tableIdString); + error Store_TableNotFound(ResourceId tableId, string tableIdString); + error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString); + + error Store_InvalidStaticDataLength(uint256 expected, uint256 received); + error Store_InvalidBounds(uint256 start, uint256 end); + error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex); + error Store_InvalidKeyNamesLength(uint256 expected, uint256 received); + error Store_InvalidFieldNamesLength(uint256 expected, uint256 received); + error Store_InvalidValueSchemaLength(uint256 expected, uint256 received); + error Store_InvalidValueSchemaStaticLength(uint256 expected, uint256 received); + error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received); + error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength); +} diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index e960b60bea..d6e4bd17d1 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -10,7 +10,7 @@ import { Schema, SchemaLib } from "./Schema.sol"; import { PackedCounter } from "./PackedCounter.sol"; import { Slice, SliceLib } from "./Slice.sol"; import { Tables, ResourceIds, StoreHooks } from "./codegen/index.sol"; -import "./errors.sol"; +import { IStoreErrors } from "./IStoreErrors.sol"; import { IStoreHook } from "./IStoreHook.sol"; import { StoreSwitch } from "./StoreSwitch.sol"; import { Hook, HookLib } from "./Hook.sol"; @@ -103,10 +103,13 @@ library StoreCore { // then the `ResourceIds` table. The logic here ought to be kept in sync with the internals // of the `registerTable` function below. if (ResourceIds._getExists(Tables._tableId)) { - revert Store_TableAlreadyExists(Tables._tableId, string(abi.encodePacked(Tables._tableId))); + revert IStoreErrors.Store_TableAlreadyExists(Tables._tableId, string(abi.encodePacked(Tables._tableId))); } if (ResourceIds._getExists(ResourceIds._tableId)) { - revert Store_TableAlreadyExists(ResourceIds._tableId, string(abi.encodePacked(ResourceIds._tableId))); + revert IStoreErrors.Store_TableAlreadyExists( + ResourceIds._tableId, + string(abi.encodePacked(ResourceIds._tableId)) + ); } Tables._set( Tables._tableId, @@ -169,7 +172,7 @@ library StoreCore { keySchema = Tables._getKeySchema(tableId); // key schemas can be empty for singleton tables, so we can't depend on key schema for table check if (!ResourceIds._getExists(tableId)) { - revert Store_TableNotFound(tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_TableNotFound(tableId, string(abi.encodePacked(tableId))); } } @@ -182,7 +185,7 @@ library StoreCore { function getValueSchema(ResourceId tableId) internal view returns (Schema valueSchema) { valueSchema = Tables._getValueSchema(tableId); if (valueSchema.isEmpty()) { - revert Store_TableNotFound(tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_TableNotFound(tableId, string(abi.encodePacked(tableId))); } } @@ -212,7 +215,7 @@ library StoreCore { ) internal { // Verify the table ID is of type RESOURCE_TABLE if (tableId.getType() != RESOURCE_TABLE && tableId.getType() != RESOURCE_OFFCHAIN_TABLE) { - revert Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); } // Verify the field layout is valid @@ -224,35 +227,44 @@ library StoreCore { // Verify the number of key names matches the number of key schema types if (keyNames.length != keySchema.numFields()) { - revert Store_InvalidKeyNamesLength(keySchema.numFields(), keyNames.length); + revert IStoreErrors.Store_InvalidKeyNamesLength(keySchema.numFields(), keyNames.length); } // Verify the number of value names if (fieldNames.length != fieldLayout.numFields()) { - revert Store_InvalidFieldNamesLength(fieldLayout.numFields(), fieldNames.length); + revert IStoreErrors.Store_InvalidFieldNamesLength(fieldLayout.numFields(), fieldNames.length); } // Verify the number of value schema types if (valueSchema.numFields() != fieldLayout.numFields()) { - revert Store_InvalidValueSchemaLength(fieldLayout.numFields(), valueSchema.numFields()); + revert IStoreErrors.Store_InvalidValueSchemaLength(fieldLayout.numFields(), valueSchema.numFields()); } if (valueSchema.numStaticFields() != fieldLayout.numStaticFields()) { - revert Store_InvalidValueSchemaStaticLength(fieldLayout.numStaticFields(), valueSchema.numStaticFields()); + revert IStoreErrors.Store_InvalidValueSchemaStaticLength( + fieldLayout.numStaticFields(), + valueSchema.numStaticFields() + ); } if (valueSchema.numDynamicFields() != fieldLayout.numDynamicFields()) { - revert Store_InvalidValueSchemaDynamicLength(fieldLayout.numDynamicFields(), valueSchema.numDynamicFields()); + revert IStoreErrors.Store_InvalidValueSchemaDynamicLength( + fieldLayout.numDynamicFields(), + valueSchema.numDynamicFields() + ); } // Verify that static field lengths are consistent between Schema and FieldLayout for (uint256 i; i < fieldLayout.numStaticFields(); i++) { if (fieldLayout.atIndex(i) != valueSchema.atIndex(i).getStaticByteLength()) { - revert Store_InvalidStaticDataLength(fieldLayout.atIndex(i), valueSchema.atIndex(i).getStaticByteLength()); + revert IStoreErrors.Store_InvalidStaticDataLength( + fieldLayout.atIndex(i), + valueSchema.atIndex(i).getStaticByteLength() + ); } } // Verify there is no resource with this ID yet if (ResourceIds._getExists(tableId)) { - revert Store_TableAlreadyExists(tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_TableAlreadyExists(tableId, string(abi.encodePacked(tableId))); } // Register the table metadata @@ -279,12 +291,12 @@ library StoreCore { function registerStoreHook(ResourceId tableId, IStoreHook hookAddress, uint8 enabledHooksBitmap) internal { // Hooks are only supported for tables, not for offchain tables if (tableId.getType() != RESOURCE_TABLE) { - revert Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); } // Require the table to exist if (!ResourceIds._getExists(tableId)) { - revert Store_TableNotFound(tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_TableNotFound(tableId, string(abi.encodePacked(tableId))); } StoreHooks._push(tableId, Hook.unwrap(HookLib.encode(address(hookAddress), enabledHooksBitmap))); @@ -962,7 +974,7 @@ library StoreCore { ) internal view returns (bytes memory) { // Verify the slice bounds are valid if (start > end) { - revert Store_InvalidBounds(start, end); + revert IStoreErrors.Store_InvalidBounds(start, end); } // Verify the accessed data is within the bounds of the dynamic field. // This is necessary because we don't delete the dynamic data when a record is deleted, @@ -970,7 +982,7 @@ library StoreCore { PackedCounter encodedLengths = StoreCoreInternal._loadEncodedDynamicDataLength(tableId, keyTuple); uint256 fieldLength = encodedLengths.atIndex(dynamicFieldIndex); if (start >= fieldLength || end > fieldLength) { - revert Store_IndexOutOfBounds(fieldLength, start >= fieldLength ? start : end - 1); + revert IStoreErrors.Store_IndexOutOfBounds(fieldLength, start >= fieldLength ? start : end - 1); } // Get the length and storage location of the dynamic field @@ -1028,7 +1040,7 @@ library StoreCoreInternal { // Splicing dynamic data is not supported for offchain tables, because it // requires reading the previous encoded lengths from storage if (tableId.getType() != RESOURCE_TABLE) { - revert Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); + revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); } uint256 previousFieldLength = previousEncodedLengths.atIndex(dynamicFieldIndex); @@ -1037,12 +1049,12 @@ library StoreCoreInternal { // If the total length of the field is changed, the data has to be appended/removed at the end of the field. // Otherwise offchain indexers would shift the data after inserted data, while onchain the data is truncated at the end. if (previousFieldLength != updatedFieldLength && startWithinField + deleteCount != previousFieldLength) { - revert Store_InvalidSplice(startWithinField, deleteCount, uint40(previousFieldLength)); + revert IStoreErrors.Store_InvalidSplice(startWithinField, deleteCount, uint40(previousFieldLength)); } // The start index can't be larger than the previous length of the field if (startWithinField > previousFieldLength) { - revert Store_IndexOutOfBounds(previousFieldLength, startWithinField); + revert IStoreErrors.Store_IndexOutOfBounds(previousFieldLength, startWithinField); } // Update the encoded length diff --git a/packages/store/src/errors.sol b/packages/store/src/errors.sol deleted file mode 100644 index 66ab6e5307..0000000000 --- a/packages/store/src/errors.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.24; - -import { ResourceId } from "./ResourceId.sol"; - -// Errors include a human-readable resource/table ID string for better logging and debugging -error Store_TableAlreadyExists(ResourceId tableId, string tableIdString); -error Store_TableNotFound(ResourceId tableId, string tableIdString); -error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString); - -error Store_InvalidStaticDataLength(uint256 expected, uint256 received); -error Store_InvalidBounds(uint256 start, uint256 end); -error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex); -error Store_InvalidKeyNamesLength(uint256 expected, uint256 received); -error Store_InvalidFieldNamesLength(uint256 expected, uint256 received); -error Store_InvalidValueSchemaLength(uint256 expected, uint256 received); -error Store_InvalidValueSchemaStaticLength(uint256 expected, uint256 received); -error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received); -error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength); diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index 72e5ffe46b..2b88c5c6dd 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -11,7 +11,7 @@ import { FieldLayout, FieldLayoutLib } from "../src/FieldLayout.sol"; import { Schema } from "../src/Schema.sol"; import { PackedCounter, PackedCounterLib } from "../src/PackedCounter.sol"; import { StoreMock } from "../test/StoreMock.sol"; -import "../src/errors.sol"; +import { IStoreErrors } from "../src/IStoreErrors.sol"; import { IStore } from "../src/IStore.sol"; import { StoreSwitch } from "../src/StoreSwitch.sol"; import { IStoreHook } from "../src/IStoreHook.sol"; @@ -116,7 +116,7 @@ contract StoreCoreTest is Test, StoreMock { // Expect a revert when registering a table that already exists vm.expectRevert( - abi.encodeWithSelector(Store_TableAlreadyExists.selector, tableId, string(abi.encodePacked(tableId))) + abi.encodeWithSelector(IStoreErrors.Store_TableAlreadyExists.selector, tableId, string(abi.encodePacked(tableId))) ); IStore(this).registerTable(tableId, fieldLayout, keySchema, valueSchema, keyNames, fieldNames); } @@ -151,7 +151,7 @@ contract StoreCoreTest is Test, StoreMock { vm.expectRevert( abi.encodeWithSelector( - Store_InvalidResourceType.selector, + IStoreErrors.Store_InvalidResourceType.selector, RESOURCE_TABLE, invalidTableId, string(abi.encodePacked(invalidTableId)) @@ -191,10 +191,14 @@ contract StoreCoreTest is Test, StoreMock { assertTrue(IStore(this).getFieldLayout(tableId2).isEmpty()); - vm.expectRevert(abi.encodeWithSelector(Store_TableNotFound.selector, tableId2, string(abi.encodePacked(tableId2)))); + vm.expectRevert( + abi.encodeWithSelector(IStoreErrors.Store_TableNotFound.selector, tableId2, string(abi.encodePacked(tableId2))) + ); IStore(this).getValueSchema(tableId2); - vm.expectRevert(abi.encodeWithSelector(Store_TableNotFound.selector, tableId2, string(abi.encodePacked(tableId2)))); + vm.expectRevert( + abi.encodeWithSelector(IStoreErrors.Store_TableNotFound.selector, tableId2, string(abi.encodePacked(tableId2))) + ); IStore(this).getKeySchema(tableId2); } @@ -213,11 +217,11 @@ contract StoreCoreTest is Test, StoreMock { string[] memory oneName = new string[](1); // Register table with invalid key names - vm.expectRevert(abi.encodeWithSelector(Store_InvalidKeyNamesLength.selector, 4, 1)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_InvalidKeyNamesLength.selector, 4, 1)); IStore(this).registerTable(tableId, fieldLayout, keySchema, valueSchema, oneName, oneName); // Register table with invalid value names - vm.expectRevert(abi.encodeWithSelector(Store_InvalidFieldNamesLength.selector, 1, 4)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_InvalidFieldNamesLength.selector, 1, 4)); IStore(this).registerTable(tableId, fieldLayout, keySchema, valueSchema, fourNames, fourNames); } @@ -1043,7 +1047,11 @@ contract StoreCoreTest is Test, StoreMock { // startByteIndex must not overflow vm.expectRevert( - abi.encodeWithSelector(Store_IndexOutOfBounds.selector, data.newThirdDataBytes.length, uint40(type(uint56).max)) + abi.encodeWithSelector( + IStoreErrors.Store_IndexOutOfBounds.selector, + data.newThirdDataBytes.length, + uint40(type(uint56).max) + ) ); IStore(this).spliceDynamicData( data.tableId, @@ -1079,7 +1087,7 @@ contract StoreCoreTest is Test, StoreMock { uint256 data3Length = IStore(this).getFieldLength(tableId, keyTuple, 1, fieldLayout); assertEq(data3Length, 0); - vm.expectRevert(abi.encodeWithSelector(Store_IndexOutOfBounds.selector, 0, 0)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_IndexOutOfBounds.selector, 0, 0)); bytes memory data3Slice = IStore(this).getDynamicFieldSlice(tableId, keyTuple, 0, 0, 0); assertEq(data3Slice.length, 0); } @@ -1150,7 +1158,9 @@ contract StoreCoreTest is Test, StoreMock { new string[](1) ); - vm.expectRevert(abi.encodeWithSelector(Store_TableNotFound.selector, tableId, string(abi.encodePacked(tableId)))); + vm.expectRevert( + abi.encodeWithSelector(IStoreErrors.Store_TableNotFound.selector, tableId, string(abi.encodePacked(tableId))) + ); IStore(this).registerStoreHook(tableId, subscriber, BEFORE_ALL); } diff --git a/packages/store/test/StoreCoreDynamic.t.sol b/packages/store/test/StoreCoreDynamic.t.sol index c0e5a9dd7c..79080a0b14 100644 --- a/packages/store/test/StoreCoreDynamic.t.sol +++ b/packages/store/test/StoreCoreDynamic.t.sol @@ -12,7 +12,7 @@ import { FieldLayout } from "../src/FieldLayout.sol"; import { Schema } from "../src/Schema.sol"; import { ResourceId, ResourceIdLib } from "../src/ResourceId.sol"; import { RESOURCE_TABLE } from "../src/storeResourceTypes.sol"; -import { Store_IndexOutOfBounds } from "../src/errors.sol"; +import { IStoreErrors } from "../src/IStoreErrors.sol"; import { StoreMock } from "../test/StoreMock.sol"; import { FieldLayoutEncodeHelper } from "./FieldLayoutEncodeHelper.sol"; import { SchemaEncodeHelper } from "./SchemaEncodeHelper.sol"; @@ -232,11 +232,11 @@ contract StoreCoreDynamicTest is Test, GasReporter, StoreMock { // Expect a revert if the end index is out of bounds uint256 length = secondDataBytes.length; - vm.expectRevert(abi.encodeWithSelector(Store_IndexOutOfBounds.selector, length, length)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_IndexOutOfBounds.selector, length, length)); StoreCore.getDynamicFieldSlice(tableId, keyTuple, 0, 0, length + 1); // Expect a revert if the start index is out of bounds - vm.expectRevert(abi.encodeWithSelector(Store_IndexOutOfBounds.selector, length, length)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_IndexOutOfBounds.selector, length, length)); StoreCore.getDynamicFieldSlice(tableId, keyTuple, 0, length, length); } } diff --git a/packages/store/test/StoreCoreGas.t.sol b/packages/store/test/StoreCoreGas.t.sol index acd35f5f4b..8eaaa3a708 100644 --- a/packages/store/test/StoreCoreGas.t.sol +++ b/packages/store/test/StoreCoreGas.t.sol @@ -12,7 +12,7 @@ import { FieldLayout } from "../src/FieldLayout.sol"; import { Schema } from "../src/Schema.sol"; import { PackedCounter, PackedCounterLib } from "../src/PackedCounter.sol"; import { StoreMock } from "../test/StoreMock.sol"; -import { Store_IndexOutOfBounds } from "../src/errors.sol"; +import { IStoreErrors } from "../src/IStoreErrors.sol"; import { IStore } from "../src/IStore.sol"; import { ResourceId, ResourceIdLib } from "../src/ResourceId.sol"; import { ResourceIds } from "../src/codegen/tables/ResourceIds.sol"; @@ -627,7 +627,7 @@ contract StoreCoreGasTest is Test, GasReporter, StoreMock { StoreCore.getFieldLength(tableId, keyTuple, 1, fieldLayout); endGasReport(); - vm.expectRevert(abi.encodeWithSelector(Store_IndexOutOfBounds.selector, 0, 0)); + vm.expectRevert(abi.encodeWithSelector(IStoreErrors.Store_IndexOutOfBounds.selector, 0, 0)); StoreCore.getDynamicFieldSlice(tableId, keyTuple, 0, 0, 0); } diff --git a/packages/world-modules/test/SystemSwitch.t.sol b/packages/world-modules/test/SystemSwitch.t.sol index b0017408a6..0371107ce9 100644 --- a/packages/world-modules/test/SystemSwitch.t.sol +++ b/packages/world-modules/test/SystemSwitch.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.24; import { Test } from "forge-std/Test.sol"; import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; -import { Store_TableNotFound } from "@latticexyz/store/src/errors.sol"; +import { IStoreErrors } from "@latticexyz/store/src/IStoreErrors.sol"; import { ResourceIds } from "@latticexyz/store/src/codegen/tables/ResourceIds.sol"; import { Schema } from "@latticexyz/store/src/Schema.sol"; import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; @@ -221,7 +221,7 @@ contract SystemSwitchTest is Test, GasReporter { // Call reverts because the non-root system storage does not have table schemas vm.expectRevert( abi.encodeWithSelector( - Store_TableNotFound.selector, + IStoreErrors.Store_TableNotFound.selector, ResourceIds._tableId, string(abi.encodePacked(ResourceIds._tableId)) ) @@ -268,7 +268,7 @@ contract SystemSwitchTest is Test, GasReporter { // Call reverts because the non-root system storage does not have table schemas vm.expectRevert( abi.encodeWithSelector( - Store_TableNotFound.selector, + IStoreErrors.Store_TableNotFound.selector, ResourceIds._tableId, string(abi.encodePacked(ResourceIds._tableId)) ) diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index 8ec7dedc5c..8f24cffb4d 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -8,7 +8,7 @@ import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol" import { IStoreHook } from "@latticexyz/store/src/IStoreHook.sol"; import { StoreCore, StoreCoreInternal } from "@latticexyz/store/src/StoreCore.sol"; -import { Store_TableAlreadyExists, Store_InvalidResourceType } from "@latticexyz/store/src/errors.sol"; +import { IStoreErrors } from "@latticexyz/store/src/IStoreErrors.sol"; import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; import { FieldLayout, FieldLayoutLib } from "@latticexyz/store/src/FieldLayout.sol"; import { FieldLayoutEncodeHelper } from "@latticexyz/store/test/FieldLayoutEncodeHelper.sol"; @@ -508,7 +508,7 @@ contract WorldTest is Test, GasReporter { // Expect an error when registering an existing table vm.expectRevert( - abi.encodeWithSelector(Store_TableAlreadyExists.selector, tableId, string(abi.encodePacked(tableId))) + abi.encodeWithSelector(IStoreErrors.Store_TableAlreadyExists.selector, tableId, string(abi.encodePacked(tableId))) ); world.registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, keyNames, fieldNames); @@ -732,7 +732,7 @@ contract WorldTest is Test, GasReporter { // Expect an error when trying to register a table at the same ID vm.expectRevert( abi.encodeWithSelector( - Store_InvalidResourceType.selector, + IStoreErrors.Store_InvalidResourceType.selector, RESOURCE_TABLE, systemId, string(abi.encodePacked(systemId)) @@ -749,7 +749,7 @@ contract WorldTest is Test, GasReporter { // Expect an error when trying to register a new table at an existing table ID vm.expectRevert( - abi.encodeWithSelector(Store_TableAlreadyExists.selector, tableId, string(abi.encodePacked(tableId))) + abi.encodeWithSelector(IStoreErrors.Store_TableAlreadyExists.selector, tableId, string(abi.encodePacked(tableId))) ); world.registerTable( tableId, diff --git a/scripts/render-api-docs.ts b/scripts/render-api-docs.ts index cf9bc4afb5..24cb0b6d3d 100644 --- a/scripts/render-api-docs.ts +++ b/scripts/render-api-docs.ts @@ -35,7 +35,7 @@ const PUBLIC_APIS: PublicApis = { inputFiles: [ { source: "store/src/IStore.sol" }, { source: "store/src/IStoreEvents.sol" }, - { source: "store/src/errors.sol" }, + { source: "store/src/IStoreErrors.sol" }, { source: "store/src/IStoreData.sol" }, { source: "store/src/IStoreRead.sol" }, { source: "store/src/IStoreWrite.sol" }, @@ -240,6 +240,7 @@ const PUBLIC_APIS: PublicApis = { { source: "world/src/modules/init/implementations/ModuleInstallationSystem.sol" }, { source: "world/src/modules/init/RegistrationSystem.sol" }, { source: "world/src/modules/init/implementations/WorldRegistrationSystem.sol" }, + { source: "store/src/IStoreErrors.sol" }, // Back to adding contracts and interfaces to the docs. { source: "world/src/IWorldKernel.sol" }, @@ -286,7 +287,8 @@ const PUBLIC_APIS: PublicApis = { .replace(/## BatchCallSystem((.|\n)*?)### Functions/m, "") .replace(/## ModuleInstallationSystem((.|\n)*?)### Functions/m, "") .replace(/## RegistrationSystem((.|\n)*?)### Functions/m, "") - .replace(/## WorldRegistrationSystem((.|\n)*?)### Functions/m, ""); + .replace(/## WorldRegistrationSystem((.|\n)*?)### Functions/m, "") + .replace(/## IStoreErrors((.|\n)*?)### Errors/m, "### Errors"); }, }, "world/reference/world-context.mdx": { @@ -409,6 +411,7 @@ const inheritence = [ { contract: "IStoreData", link: "/store/reference/store#istoredata" }, { contract: "IStoreRead", link: "/store/reference/store#istoreread" }, { contract: "IStoreWrite", link: "/store/reference/store#istorewrite" }, + { contract: "IStoreErrors", link: "/store/reference/store#istoreerrors" }, { contract: "IStoreEvents", link: "/store/reference/store#istoreevents" }, { contract: "IStoreRegistration", link: "/store/reference/store#istoreregistration" }, { contract: "Module", link: "/world/reference/module#module" },