Skip to content

Commit

Permalink
refactor(store): event interfaces for Store libraries (#2348)
Browse files Browse the repository at this point in the history
  • Loading branch information
yonadaaa authored Mar 1, 2024
1 parent 4be22ba commit c991c71
Show file tree
Hide file tree
Showing 16 changed files with 137 additions and 123 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-shirts-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@latticexyz/store": patch
---

Added interfaces for all errors that are used by `StoreCore`, which includes `FieldLayout`, `PackedCounter`, `Schema`, and `Slice`. This interfaces are inherited by `IStore`, ensuring that all possible errors are included in the `IStore` ABI for proper decoding in the frontend.
70 changes: 0 additions & 70 deletions docs/pages/store/reference/misc.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -470,50 +470,6 @@ function encode(uint256[] memory _staticFieldLengths, uint256 numDynamicFields)
| -------- | ------------- | ------------------------------------------------------------ |
| `<none>` | `FieldLayout` | A FieldLayout structure containing the encoded field layout. |

### Errors

#### FieldLayoutLib_TooManyFields

```solidity
error FieldLayoutLib_TooManyFields(uint256 numFields, uint256 maxFields);
```

#### FieldLayoutLib_TooManyDynamicFields

```solidity
error FieldLayoutLib_TooManyDynamicFields(uint256 numFields, uint256 maxFields);
```

#### FieldLayoutLib_Empty

```solidity
error FieldLayoutLib_Empty();
```

#### FieldLayoutLib_InvalidStaticDataLength

```solidity
error FieldLayoutLib_InvalidStaticDataLength(uint256 staticDataLength, uint256 computedStaticDataLength);
```

#### FieldLayoutLib_StaticLengthIsZero

```solidity
error FieldLayoutLib_StaticLengthIsZero(uint256 index);
```

#### FieldLayoutLib_StaticLengthIsNotZero

```solidity
error FieldLayoutLib_StaticLengthIsNotZero(uint256 index);
```

#### FieldLayoutLib_StaticLengthDoesNotFitInAWord

```solidity
error FieldLayoutLib_StaticLengthDoesNotFitInAWord(uint256 index);
```

## FieldLayout

[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/FieldLayout.sol)
Expand Down Expand Up @@ -991,24 +947,6 @@ function encode(SchemaType[] memory schemas) internal pure returns (Schema);
| -------- | -------- | ------------------- |
| `<none>` | `Schema` | The encoded Schema. |

### Errors

#### SchemaLib_InvalidLength

_Error raised when the provided schema has an invalid length._

```solidity
error SchemaLib_InvalidLength(uint256 length);
```

#### SchemaLib_StaticTypeAfterDynamicType

_Error raised when a static type is placed after a dynamic type in a schema._

```solidity
error SchemaLib_StaticTypeAfterDynamicType();
```

## Schema

[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/Schema.sol)
Expand Down Expand Up @@ -1192,14 +1130,6 @@ function getSubslice(bytes memory data, uint256 start, uint256 end) internal pur
| -------- | ------- | ------------------------------------- |
| `<none>` | `Slice` | A new Slice representing the subslice |

### Errors

#### Slice_OutOfBounds

```solidity
error Slice_OutOfBounds(bytes data, uint256 start, uint256 end);
```

## Slice

[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/Slice.sol)
Expand Down
9 changes: 8 additions & 1 deletion docs/pages/store/reference/store.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
[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), [IStoreErrors](/store/reference/store#istoreerrors)
[IStoreData](/store/reference/store#istoredata), [IStoreRegistration](/store/reference/store#istoreregistration), [IStoreErrors](/store/reference/store#istoreerrors), [IFieldLayoutErrors](/src/IFieldLayoutErrors.sol/interface.IFieldLayoutErrors.md), [IPackedCounterErrors](/src/IPackedCounterErrors.sol/interface.IPackedCounterErrors.md), [ISchemaErrors](/src/ISchemaErrors.sol/interface.ISchemaErrors.md), [ISliceErrors](/src/ISliceErrors.sol/interface.ISliceErrors.md)

IStore implements the error interfaces for each library that it uses.

## IStoreEvents

Expand Down Expand Up @@ -104,6 +106,11 @@ event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple);

[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreErrors.sol)

This interface includes errors for Store.

_We bundle these errors in an interface (instead of at the file-level or in their corresponding library) so they can be inherited by IStore.
This ensures that all possible errors are included in the IStore ABI for proper decoding in the frontend._

### Errors

#### Store_TableAlreadyExists
Expand Down
32 changes: 13 additions & 19 deletions packages/store/src/FieldLayout.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity >=0.8.24;

import { WORD_SIZE, WORD_LAST_INDEX, BYTE_TO_BITS, MAX_TOTAL_FIELDS, MAX_DYNAMIC_FIELDS, LayoutOffsets } from "./constants.sol";
import { IFieldLayoutErrors } from "./IFieldLayoutErrors.sol";

/**
* @title FieldLayout
Expand All @@ -27,14 +28,6 @@ using FieldLayoutInstance for FieldLayout global;
* various constraints regarding the length and size of the fields.
*/
library FieldLayoutLib {
error FieldLayoutLib_TooManyFields(uint256 numFields, uint256 maxFields);
error FieldLayoutLib_TooManyDynamicFields(uint256 numFields, uint256 maxFields);
error FieldLayoutLib_Empty();
error FieldLayoutLib_InvalidStaticDataLength(uint256 staticDataLength, uint256 computedStaticDataLength);
error FieldLayoutLib_StaticLengthIsZero(uint256 index);
error FieldLayoutLib_StaticLengthIsNotZero(uint256 index);
error FieldLayoutLib_StaticLengthDoesNotFitInAWord(uint256 index);

/**
* @notice Encodes the given field layout into a single bytes32.
* @dev Ensures various constraints on the length and size of the fields.
Expand All @@ -47,17 +40,18 @@ library FieldLayoutLib {
uint256 fieldLayout;
uint256 totalLength;
uint256 totalFields = _staticFieldLengths.length + numDynamicFields;
if (totalFields > MAX_TOTAL_FIELDS) revert FieldLayoutLib_TooManyFields(totalFields, MAX_TOTAL_FIELDS);
if (totalFields > MAX_TOTAL_FIELDS)
revert IFieldLayoutErrors.FieldLayout_TooManyFields(totalFields, MAX_TOTAL_FIELDS);
if (numDynamicFields > MAX_DYNAMIC_FIELDS)
revert FieldLayoutLib_TooManyDynamicFields(numDynamicFields, MAX_DYNAMIC_FIELDS);
revert IFieldLayoutErrors.FieldLayout_TooManyDynamicFields(numDynamicFields, MAX_DYNAMIC_FIELDS);

// Compute the total static length and store the field lengths in the encoded fieldLayout
for (uint256 i; i < _staticFieldLengths.length; ) {
uint256 staticByteLength = _staticFieldLengths[i];
if (staticByteLength == 0) {
revert FieldLayoutLib_StaticLengthIsZero(i);
revert IFieldLayoutErrors.FieldLayout_StaticLengthIsZero(i);
} else if (staticByteLength > WORD_SIZE) {
revert FieldLayoutLib_StaticLengthDoesNotFitInAWord(i);
revert IFieldLayoutErrors.FieldLayout_StaticLengthDoesNotFitInAWord(i);
}

unchecked {
Expand Down Expand Up @@ -156,28 +150,28 @@ library FieldLayoutInstance {
*/
function validate(FieldLayout fieldLayout) internal pure {
if (fieldLayout.isEmpty()) {
revert FieldLayoutLib.FieldLayoutLib_Empty();
revert IFieldLayoutErrors.FieldLayout_Empty();
}

uint256 _numDynamicFields = fieldLayout.numDynamicFields();
if (_numDynamicFields > MAX_DYNAMIC_FIELDS) {
revert FieldLayoutLib.FieldLayoutLib_TooManyDynamicFields(_numDynamicFields, MAX_DYNAMIC_FIELDS);
revert IFieldLayoutErrors.FieldLayout_TooManyDynamicFields(_numDynamicFields, MAX_DYNAMIC_FIELDS);
}

uint256 _numStaticFields = fieldLayout.numStaticFields();
uint256 _numTotalFields = _numStaticFields + _numDynamicFields;
if (_numTotalFields > MAX_TOTAL_FIELDS) {
revert FieldLayoutLib.FieldLayoutLib_TooManyFields(_numTotalFields, MAX_TOTAL_FIELDS);
revert IFieldLayoutErrors.FieldLayout_TooManyFields(_numTotalFields, MAX_TOTAL_FIELDS);
}

// Static lengths must be valid
uint256 _staticDataLength;
for (uint256 i; i < _numStaticFields; ) {
uint256 staticByteLength = fieldLayout.atIndex(i);
if (staticByteLength == 0) {
revert FieldLayoutLib.FieldLayoutLib_StaticLengthIsZero(i);
revert IFieldLayoutErrors.FieldLayout_StaticLengthIsZero(i);
} else if (staticByteLength > WORD_SIZE) {
revert FieldLayoutLib.FieldLayoutLib_StaticLengthDoesNotFitInAWord(i);
revert IFieldLayoutErrors.FieldLayout_StaticLengthDoesNotFitInAWord(i);
}
_staticDataLength += staticByteLength;
unchecked {
Expand All @@ -186,13 +180,13 @@ library FieldLayoutInstance {
}
// Static length sums must match
if (_staticDataLength != fieldLayout.staticDataLength()) {
revert FieldLayoutLib.FieldLayoutLib_InvalidStaticDataLength(fieldLayout.staticDataLength(), _staticDataLength);
revert IFieldLayoutErrors.FieldLayout_InvalidStaticDataLength(fieldLayout.staticDataLength(), _staticDataLength);
}
// Unused fields must be zero
for (uint256 i = _numStaticFields; i < MAX_TOTAL_FIELDS; i++) {
uint256 staticByteLength = fieldLayout.atIndex(i);
if (staticByteLength != 0) {
revert FieldLayoutLib.FieldLayoutLib_StaticLengthIsNotZero(i);
revert IFieldLayoutErrors.FieldLayout_StaticLengthIsNotZero(i);
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions packages/store/src/IFieldLayoutErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;

/**
* @title IFieldLayoutErrors
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice This interface includes errors for the FieldLayout library.
* @dev We bundle these errors in an interface (instead of at the file-level or in their corresponding libraries) so they can be inherited by IStore.
* This ensures that all possible errors are included in the IStore ABI for proper decoding in the frontend.
*/
interface IFieldLayoutErrors {
error FieldLayout_TooManyFields(uint256 numFields, uint256 maxFields);
error FieldLayout_TooManyDynamicFields(uint256 numFields, uint256 maxFields);
error FieldLayout_Empty();
error FieldLayout_InvalidStaticDataLength(uint256 staticDataLength, uint256 computedStaticDataLength);
error FieldLayout_StaticLengthIsZero(uint256 index);
error FieldLayout_StaticLengthIsNotZero(uint256 index);
error FieldLayout_StaticLengthDoesNotFitInAWord(uint256 index);
}
13 changes: 13 additions & 0 deletions packages/store/src/IPackedCounterErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;

/**
* @title IPackedCounterErrors
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice This interface includes errors for the PackedCounter library.
* @dev We bundle these errors in an interface (instead of at the file-level or in their corresponding libraries) so they can be inherited by IStore.
* This ensures that all possible errors are included in the IStore ABI for proper decoding in the frontend.
*/
interface IPackedCounterErrors {
error PackedCounter_InvalidLength(uint256 length);
}
17 changes: 17 additions & 0 deletions packages/store/src/ISchemaErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;

/**
* @title ISchemaErrors
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice This interface includes errors for the Schema library.
* @dev We bundle these errors in an interface (instead of at the file-level or in their corresponding libraries) so they can be inherited by IStore.
* This ensures that all possible errors are included in the IStore ABI for proper decoding in the frontend.
*/
interface ISchemaErrors {
/// @dev Error raised when the provided schema has an invalid length.
error Schema_InvalidLength(uint256 length);

/// @dev Error raised when a static type is placed after a dynamic type in a schema.
error Schema_StaticTypeAfterDynamicType();
}
13 changes: 13 additions & 0 deletions packages/store/src/ISliceErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.24;

/**
* @title ISliceErrors
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice This interface includes errors for the Slice library.
* @dev We bundle these errors in an interface (instead of at the file-level or in their corresponding libraries) so they can be inherited by IStore.
* This ensures that all possible errors are included in the IStore ABI for proper decoding in the frontend.
*/
interface ISliceErrors {
error Slice_OutOfBounds(bytes data, uint256 start, uint256 end);
}
15 changes: 14 additions & 1 deletion packages/store/src/IStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@ pragma solidity >=0.8.24;
import { IStoreErrors } from "./IStoreErrors.sol";
import { IStoreData } from "./IStoreData.sol";
import { IStoreRegistration } from "./IStoreRegistration.sol";
import { IFieldLayoutErrors } from "./IFieldLayoutErrors.sol";
import { IPackedCounterErrors } from "./IPackedCounterErrors.sol";
import { ISchemaErrors } from "./ISchemaErrors.sol";
import { ISliceErrors } from "./ISliceErrors.sol";

/**
* @title IStore
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice IStore implements the error interfaces for each library that it uses.
*/
interface IStore is IStoreData, IStoreRegistration, IStoreErrors {}
interface IStore is
IStoreData,
IStoreRegistration,
IStoreErrors,
IFieldLayoutErrors,
IPackedCounterErrors,
ISchemaErrors,
ISliceErrors
{}
7 changes: 7 additions & 0 deletions packages/store/src/IStoreErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ pragma solidity >=0.8.24;

import { ResourceId } from "./ResourceId.sol";

/**
* @title IStoreErrors
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice This interface includes errors for Store.
* @dev We bundle these errors in an interface (instead of at the file-level or in their corresponding library) so they can be inherited by IStore.
* This ensures that all possible errors are included in the IStore ABI for proper decoding in the frontend.
*/
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);
Expand Down
5 changes: 2 additions & 3 deletions packages/store/src/PackedCounter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity >=0.8.24;

import { BYTE_TO_BITS } from "./constants.sol";
import { IPackedCounterErrors } from "./IPackedCounterErrors.sol";

/**
* @title PackedCounter Type Definition
Expand Down Expand Up @@ -139,8 +140,6 @@ library PackedCounterLib {
* @dev Offers decoding, extracting, and setting functionalities for a PackedCounter.
*/
library PackedCounterInstance {
error PackedCounter_InvalidLength(uint256 length);

/**
* @notice Decode the accumulated counter from a PackedCounter.
* @dev Extracts the right-most 7 bytes of a PackedCounter.
Expand Down Expand Up @@ -178,7 +177,7 @@ library PackedCounterInstance {
uint256 newValueAtIndex
) internal pure returns (PackedCounter) {
if (newValueAtIndex > MAX_VAL) {
revert PackedCounter_InvalidLength(newValueAtIndex);
revert IPackedCounterErrors.PackedCounter_InvalidLength(newValueAtIndex);
}

uint256 rawPackedCounter = uint256(PackedCounter.unwrap(packedCounter));
Expand Down
Loading

0 comments on commit c991c71

Please sign in to comment.