Skip to content

Releases: latticexyz/mud

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release
@latticexyz/[email protected]

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Major Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Patch Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Major Changes

  • #1482 07dd6f32 Thanks @alvrs! - Renamed all occurrences of schema where it is used as "value schema" to valueSchema to clearly distinguish it from "key schema".
    The only breaking change for users is the change from schema to valueSchema in mud.config.ts.

    // mud.config.ts
    export default mudConfig({
      tables: {
        CounterTable: {
          keySchema: {},
    -     schema: {
    +     valueSchema: {
            value: "uint32",
          },
        },
      }
    }
  • #1354 331dbfdc Thanks @dk1a! - readHex was moved from @latticexyz/protocol-parser to @latticexyz/common

Minor Changes

  • #1336 de151fec Thanks @dk1a! - - Add FieldLayout, which is a bytes32 user-type similar to Schema.

    Both FieldLayout and Schema have the same kind of data in the first 4 bytes.

    • 2 bytes for total length of all static fields
    • 1 byte for number of static size fields
    • 1 byte for number of dynamic size fields

    But whereas Schema has SchemaType enum in each of the other 28 bytes, FieldLayout has static byte lengths in each of the other 28 bytes.

    • Replace Schema valueSchema with FieldLayout fieldLayout in Store and World contracts.

      FieldLayout is more gas-efficient because it already has lengths, and Schema has types which need to be converted to lengths.

    • Add getFieldLayout to IStore interface.

      There is no FieldLayout for keys, only for values, because key byte lengths aren't usually relevant on-chain. You can still use getKeySchema if you need key types.

    • Add fieldLayoutToHex utility to protocol-parser package.

    • Add constants.sol for constants shared between FieldLayout, Schema and PackedCounter.

  • #1476 9ff4dd95 Thanks @holic! - Adds valueSchemaToFieldLayoutHex helper

Patch Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Patch Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Major Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Major Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Minor Changes

  • #1517 9940fdb3 Thanks @holic! - New package to run your own faucet service. We'll use this soon for our testnet in place of @latticexyz/services.

    To run the faucet server:

    • Add the package with pnpm add @latticexyz/faucet
    • Add a .env file that has a RPC_HTTP_URL and FAUCET_PRIVATE_KEY (or pass the environment variables into the next command)
    • Run pnpm faucet-server to start the server

    You can also adjust the server's HOST (defaults to 0.0.0.0) and PORT (defaults to 3002). The tRPC routes are accessible under /trpc.

    To connect a tRPC client, add the package with pnpm add @latticexyz/faucet and then use createClient:

    import { createClient } from "@latticexyz/faucet";
    
    const faucet = createClient({ url: "http://localhost:3002/trpc" });
    
    await faucet.mutate.drip({ address: burnerAccount.address });

Patch Changes

@latticexyz/[email protected]

25 Sep 18:43
bdf2882
Compare
Choose a tag to compare
Pre-release

Major Changes

  • #1354 331dbfdc Thanks @dk1a! - We've updated Store events to be "schemaless", meaning there is enough information in each event to only need to operate on the bytes of each record to make an update to that record without having to first decode the record by its schema. This enables new kinds of indexers and sync strategies.

    As such, we've replaced blockStorageOperations# @latticexyz/dev-tools with storedBlockLogs# @latticexyz/dev-tools, a stream of simplified Store event logs after they've been synced to the configured storage adapter. These logs may not reflect exactly the events that are on chain when e.g. hydrating from an indexer, but they will still allow the client to "catch up" to the on-chain state of your tables.

Minor Changes

  • #1497 24a0dd44 Thanks @y77cao! - Improved rendering of transactions that make calls via World's call and callFrom methods

Patch Changes

  • #1505 e0193e57 Thanks @holic! - Updates store event key reference to keyTuple

  • #1502 e0377761 Thanks @holic! - Updates table reference to tableId

  • #1558 bfcb293d Thanks @alvrs! - What used to be known as ephemeral table is now called offchain table.
    The previous ephemeral tables only supported an emitEphemeral method, which emitted a StoreSetEphemeralRecord event.

    Now offchain tables support all regular table methods, except partial operations on dynamic fields (push, pop, update).
    Unlike regular tables they don't store data on-chain but emit the same events as regular tables (StoreSetRecord, StoreSpliceStaticData, StoreDeleteRecord), so their data can be indexed by offchain indexers/clients.

    - EphemeralTable.emitEphemeral(value);
    + OffchainTable.set(value);
  • #1577 af639a26 Thanks @alvrs! - Store events have been renamed for consistency and readability.
    If you're parsing Store events manually, you need to update your ABI.
    If you're using the MUD sync stack, the new events are already integrated and no further changes are necessary.

    - event StoreSetRecord(
    + event Store_SetRecord(
        ResourceId indexed tableId,
        bytes32[] keyTuple,
        bytes staticData,
        bytes32 encodedLengths,
        bytes dynamicData
      );
    - event StoreSpliceStaticData(
    + event Store_SpliceStaticData(
        ResourceId indexed tableId,
        bytes32[] keyTuple,
        uint48 start,
        uint40 deleteCount,
        bytes data
      );
    - event StoreSpliceDynamicData(
    + event Store_SpliceDynamicData(
        ResourceId indexed tableId,
        bytes32[] keyTuple,
        uint48 start,
        uint40 deleteCount,
        bytes data,
        bytes32 encodedLengths
      );
    - event StoreDeleteRecord(
    + event Store_DeleteRecord(
        ResourceId indexed tableId,
        bytes32[] keyTuple
      );
  • #1581 cea754dd Thanks @alvrs! - - The external setRecord and deleteRecord methods of IStore no longer accept a FieldLayout as input, but load it from storage instead.
    This is to prevent invalid FieldLayout values being passed, which could cause the onchain state to diverge from the indexer state.
    However, the internal StoreCore library still exposes a setRecord and deleteRecord method that allows a FieldLayout to be passed.
    This is because StoreCore can only be used internally, so the FieldLayout value can be trusted and we can save the gas for accessing storage.

    interface IStore {
      function setRecord(
        ResourceId tableId,
        bytes32[] calldata keyTuple,
        bytes calldata staticData,
        PackedCounter encodedLengths,
        bytes calldata dynamicData,
    -   FieldLayout fieldLayout
      ) external;
    
      function deleteRecord(
        ResourceId tableId,
        bytes32[] memory keyTuple,
    -   FieldLayout fieldLayout
      ) external;
    }
    • The spliceStaticData method and Store_SpliceStaticData event of IStore and StoreCore no longer include deleteCount in their signature.
      This is because when splicing static data, the data after start is always overwritten with data instead of being shifted, so deleteCount is always the length of the data to be written.

      event Store_SpliceStaticData(
        ResourceId indexed tableId,
        bytes32[] keyTuple,
        uint48 start,
      - uint40 deleteCount,
        bytes data
      );
      
      interface IStore {
        function spliceStaticData(
          ResourceId tableId,
          bytes32[] calldata keyTuple,
          uint48 start,
      -   uint40 deleteCount,
          bytes calldata data
        ) external;
      }
    • The updateInField method has been removed from IStore, as it's almost identical to the more general spliceDynamicData.
      If you're manually calling updateInField, here is how to upgrade to spliceDynamicData:

      - store.updateInField(tableId, keyTuple, fieldIndex, startByteIndex, dataToSet, fieldLayout);
      + uint8 dynamicFieldIndex = fieldIndex - fieldLayout.numStaticFields();
      + store.spliceDynamicData(tableId, keyTuple, dynamicFieldIndex, uint40(startByteIndex), uint40(dataToSet.length), dataToSet);
    • All other methods that are only valid for dynamic fields (pushToField, popFromField, getFieldSlice)
      have been renamed to make this more explicit (pushToDynamicField, popFromDynamicField, getDynamicFieldSlice).

      Their fieldIndex parameter has been replaced by a dynamicFieldIndex parameter, which is the index relative to the first dynamic field (i.e. dynamicFieldIndex = fieldIndex - numStaticFields).
      The FieldLayout parameter has been removed, as it was only used to calculate the dynamicFieldIndex in the method.

      interface IStore {
      - function pushToField(
      + function pushToDynamicField(
          ResourceId tableId,
          bytes32[] calldata keyTuple,
      -   uint8 fieldIndex,
      +   uint8 dynamicFieldIndex,
          bytes calldata dataToPush,
      -   FieldLayout fieldLayout
        ) external;
      
      - function popFromField(
      + function popFromDynamicField(
          ResourceId tableId,
          bytes32[] calldata keyTuple,
      -   uint8 fieldIndex,
      +   uint8 dynamicFieldIndex,
          uint256 byteLengthToPop,
      -   FieldLayout fieldLayout
        ) external;
      
      - function getFieldSlice(
      + function getDynamicFieldSlice(
          ResourceId tableId,
          bytes32[] memory keyTuple,
      -   uint8 fieldIndex,
      +   uint8 dynamicFieldIndex,
      -   FieldLayout fieldLayout,
          uint256 start,
          uint256 end
        ) external view returns (bytes memory data);
      }
    • IStore has a new getDynamicFieldLength length method, which returns the byte length of the given dynamic field and doesn't require the FieldLayout.

      IStore {
      + function getDynamicFieldLength(
      +   ResourceId tableId,
      +   bytes32[] memory keyTuple,
      +   uint8 dynamicFieldIndex
      + ) external view returns (uint256);
      }
      
    • IStore now has additional overloads for getRecord, getField, getFieldLength and setField that don't require a FieldLength to be passed, but instead load it from storage.

    • IStore now exposes setStaticField and setDynamicField to save gas by avoiding the dynamic inference of whether the field is static or dynamic.

    • The getDynamicFieldSlice method no longer accepts reading outside the bounds of the dynamic field.
      This is to avoid returning invalid data, as the data of a dynamic field is not deleted when the record is deleted, but only its length is set to zero.

  • Updated dependencies [77dce993, 748f4588, aea67c58, 07dd6f32, c07fa021, 90e4161b, 65c9546c, 331dbfdc, [f9f9609e](https://github.com/lat...

Read more