Version 2.0.0-next.7
Major changes
feat(store,world): more granularity for onchain hooks (#1399) (opens in a new tab) (@latticexyz/store, @latticexyz/world)
-
The
onSetRecordhook is split intoonBeforeSetRecordandonAfterSetRecordand theonDeleteRecordhook is split intoonBeforeDeleteRecordandonAfterDeleteRecord. The purpose of this change is to allow more fine-grained control over the point in the lifecycle at which hooks are executed.The previous hooks were executed before modifying data, so they can be replaced with the respective
onBeforehooks.- function onSetRecord( + function onBeforeSetRecord( bytes32 table, bytes32[] memory key, bytes memory data, Schema valueSchema ) public; - function onDeleteRecord( + function onBeforeDeleteRecord( bytes32 table, bytes32[] memory key, Schema valueSchema ) public; -
It is now possible to specify which methods of a hook contract should be called when registering a hook. The purpose of this change is to save gas by avoiding to call no-op hook methods.
function registerStoreHook( bytes32 tableId, - IStoreHook hookAddress + IStoreHook hookAddress, + uint8 enabledHooksBitmap ) public; function registerSystemHook( bytes32 systemId, - ISystemHook hookAddress + ISystemHook hookAddress, + uint8 enabledHooksBitmap ) public;There are
StoreHookLibandSystemHookLibwith helper functions to encode the bitmap of enabled hooks.import { StoreHookLib } from "@latticexyz/store/src/StoreHook.sol"; uint8 storeHookBitmap = StoreBookLib.encodeBitmap({ onBeforeSetRecord: true, onAfterSetRecord: true, onBeforeSetField: true, onAfterSetField: true, onBeforeDeleteRecord: true, onAfterDeleteRecord: true });import { SystemHookLib } from "@latticexyz/world/src/SystemHook.sol"; uint8 systemHookBitmap = SystemHookLib.encodeBitmap({ onBeforeCallSystem: true, onAfterCallSystem: true }); -
The
onSetRecordhook call foremitEphemeralRecordhas been removed to save gas and to more clearly distinguish ephemeral tables as offchain tables.
Patch changes
fix(abi-ts): remove cwd join (#1418) (opens in a new tab) (@latticexyz/abi-ts)
Let glob handle resolving the glob against the current working directory.
feat(world): allow callFrom from own address without explicit delegation (#1407) (opens in a new tab) (@latticexyz/world)
Allow callFrom with the own address as delegator without requiring an explicit delegation
Version 2.0.0-next.6
Major changes
style(gas-report): rename mud-gas-report to gas-report (#1410) (opens in a new tab) (@latticexyz/gas-report)
Renames mud-gas-report binary to gas-report, since it's no longer MUD specific.
Minor changes
docs: rework abi-ts changesets (#1413) (opens in a new tab) (@latticexyz/abi-ts, @latticexyz/cli)
Added a new @latticexyz/abi-ts package to generate TS type declaration files (.d.ts) for each ABI JSON file.
This allows you to import your JSON ABI and use it directly with libraries like viem (opens in a new tab) and abitype (opens in a new tab).
pnpm add @latticexyz/abi-ts
pnpm abi-tsBy default, abi-ts looks for files with the glob **/*.abi.json, but you can customize this glob with the --input argument, e.g.
pnpm abi-ts --input 'abi/IWorld.sol/IWorld.abi.json'docs: rework abi-ts changesets (#1413) (opens in a new tab) (create-mud)
We now use @latticexyz/abi-ts to generate TS type declaration files (.d.ts) for each ABI JSON file. This replaces our usage TypeChain everywhere.
If you have a MUD project created from an older template, you can replace TypeChain with abi-ts by first updating your contracts' package.json:
-"build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:typechain",
+"build": "pnpm run build:mud && pnpm run build:abi && pnpm run build:abi-ts",
-"build:abi": "forge clean && forge build",
+"build:abi": "rimraf abi && forge build --extra-output-files abi --out abi --skip test script MudTest.sol",
+"build:abi-ts": "mud abi-ts --input 'abi/IWorld.sol/IWorld.abi.json' && prettier --write '**/*.abi.json.d.ts'",
"build:mud": "mud tablegen && mud worldgen",
-"build:typechain": "rimraf types && typechain --target=ethers-v5 out/IWorld.sol/IWorld.json",And update your client's setupNetwork.ts with:
-import { IWorld__factory } from "contracts/types/ethers-contracts/factories/IWorld__factory";
+import IWorldAbi from "contracts/abi/IWorld.sol/IWorld.abi.json";
const worldContract = createContract({
address: networkConfig.worldAddress as Hex,
- abi: IWorld__factory.abi,
+ abi: IWorldAbi,docs: rework abi-ts changesets (#1413) (opens in a new tab) (@latticexyz/store, @latticexyz/world)
We now use @latticexyz/abi-ts to generate TS type declaration files (.d.ts) for each ABI JSON file. This replaces our usage TypeChain everywhere.
If you previously relied on TypeChain types from @latticexyz/store or @latticexyz/world, you will either need to migrate to viem or abitype using ABI JSON imports or generate TypeChain types from our exported ABI JSON files.
import { getContract } from "viem";
import IStoreAbi from "@latticexyz/store/abi/IStore.sol/IStore.abi.json";
const storeContract = getContract({
abi: IStoreAbi,
...
});
await storeContract.write.setRecord(...);Version 2.0.0-next.5
Major changes
refactor(world): separate call utils into WorldContextProvider and SystemCall (#1370) (opens in a new tab) (@latticexyz/world)
-
The previous
Call.withSenderutil is replaced withWorldContextProvider, since the usecase of appending themsg.senderto the calldata is tightly coupled withWorldContextConsumer(which extracts the appended context from the calldata).The previous
Call.withSenderutility reverted if the call failed and only returned the returndata on success. This is replaced withcallWithContextOrRevert/delegatecallWithContextOrRevert-import { Call } from "@latticexyz/world/src/Call.sol"; +import { WorldContextProvider } from "@latticexyz/world/src/WorldContext.sol"; -Call.withSender({ - delegate: false, - value: 0, - ... -}); +WorldContextProvider.callWithContextOrRevert({ + value: 0, + ... +}); -Call.withSender({ - delegate: true, - value: 0, - ... -}); +WorldContextProvider.delegatecallWithContextOrRevert({ + ... +});In addition there are utils that return a
bool successflag instead of reverting on errors. This mirrors the behavior of Solidity's low levelcall/delegatecallfunctions and is useful in situations where additional logic should be executed in case of a reverting external call.library WorldContextProvider { function callWithContext( address target, // Address to call bytes memory funcSelectorAndArgs, // Abi encoded function selector and arguments to pass to pass to the contract address msgSender, // Address to append to the calldata as context for msgSender uint256 value // Value to pass with the call ) internal returns (bool success, bytes memory data); function delegatecallWithContext( address target, // Address to call bytes memory funcSelectorAndArgs, // Abi encoded function selector and arguments to pass to pass to the contract address msgSender // Address to append to the calldata as context for msgSender ) internal returns (bool success, bytes memory data); } -
WorldContextis renamed toWorldContextConsumerto clarify the relationship betweenWorldContextProvider(appending context to the calldata) andWorldContextConsumer(extracting context from the calldata)-import { WorldContext } from "@latticexyz/world/src/WorldContext.sol"; -import { WorldContextConsumer } from "@latticexyz/world/src/WorldContext.sol"; -
The
Worldcontract previously had a_callmethod to handle calling systems via their resource selector, performing accesss control checks and call hooks registered for the system.library SystemCall { /** * Calls a system via its resource selector and perform access control checks. * Does not revert if the call fails, but returns a `success` flag along with the returndata. */ function call( address caller, bytes32 resourceSelector, bytes memory funcSelectorAndArgs, uint256 value ) internal returns (bool success, bytes memory data); /** * Calls a system via its resource selector, perform access control checks and trigger hooks registered for the system. * Does not revert if the call fails, but returns a `success` flag along with the returndata. */ function callWithHooks( address caller, bytes32 resourceSelector, bytes memory funcSelectorAndArgs, uint256 value ) internal returns (bool success, bytes memory data); /** * Calls a system via its resource selector, perform access control checks and trigger hooks registered for the system. * Reverts if the call fails. */ function callWithHooksOrRevert( address caller, bytes32 resourceSelector, bytes memory funcSelectorAndArgs, uint256 value ) internal returns (bytes memory data); } -
System hooks now are called with the system's resource selector instead of its address. The system's address can still easily obtained within the hook via
Systems.get(resourceSelector)if necessary.interface ISystemHook { function onBeforeCallSystem( address msgSender, - address systemAddress, + bytes32 resourceSelector, bytes memory funcSelectorAndArgs ) external; function onAfterCallSystem( address msgSender, - address systemAddress, + bytes32 resourceSelector, bytes memory funcSelectorAndArgs ) external; }
Minor changes
feat(world): add support for upgrading systems (#1378) (opens in a new tab) (@latticexyz/world)
It is now possible to upgrade systems by calling registerSystem again with an existing system id (resource selector).
// Register a system
world.registerSystem(systemId, systemAddress, publicAccess);
// Upgrade the system by calling `registerSystem` with the
// same system id but a new system address or publicAccess flag
world.registerSystem(systemId, newSystemAddress, newPublicAccess);feat(world): add callFrom entry point (#1364) (opens in a new tab) (@latticexyz/world)
The World has a new callFrom entry point which allows systems to be called on behalf of other addresses if those addresses have registered a delegation.
If there is a delegation, the call is forwarded to the system with delegator as msgSender.
interface IBaseWorld {
function callFrom(
address delegator,
bytes32 resourceSelector,
bytes memory funcSelectorAndArgs
) external payable virtual returns (bytes memory);
}A delegation can be registered via the World's registerDelegation function.
If delegatee is address(0), the delegation is considered to be a "fallback" delegation and is used in callFrom if there is no delegation is found for the specific caller.
Otherwise the delegation is registered for the specific delegatee.
interface IBaseWorld {
function registerDelegation(
address delegatee,
bytes32 delegationControl,
bytes memory initFuncSelectorAndArgs
) external;
}The delegationControl refers to the resource selector of a DelegationControl system that must have been registered beforehand.
As part of registering the delegation, the DelegationControl system is called with the provided initFuncSelectorAndArgs.
This can be used to initialize data in the given DelegationControl system.
The DelegationControl system must implement the IDelegationControl interface:
interface IDelegationControl {
function verify(address delegator, bytes32 systemId, bytes calldata funcSelectorAndArgs) external returns (bool);
}When callFrom is called, the World checks if a delegation is registered for the given caller, and if so calls the delegation control's verify function with the same same arguments as callFrom.
If the call to verify is successful and returns true, the delegation is valid and the call is forwarded to the system with delegator as msgSender.
Note: if UNLIMITED_DELEGATION (from @latticexyz/world/src/constants.sol) is passed as delegationControl, the external call to the delegation control contract is skipped and the delegation is considered valid.
For examples of DelegationControl systems, check out the CallboundDelegationControl or TimeboundDelegationControl systems in the std-delegations module.
See StandardDelegations.t.sol for usage examples.
feat(world): allow transferring ownership of namespaces (#1274) (opens in a new tab) (@latticexyz/world)
It is now possible to transfer ownership of namespaces!
// Register a new namespace
world.registerNamespace("namespace");
// It's owned by the caller of the function (address(this))
// Transfer ownership of the namespace to address(42)
world.transferOwnership("namespace", address(42));
// It's now owned by address(42)Patch changes
fix(services): correctly export typescript types (#1377) (opens in a new tab) (@latticexyz/services)
Fixed an issue where the TypeScript types for createFaucetService were not exported correctly from the @latticexyz/services package
feat: docker monorepo build (#1219) (opens in a new tab) (@latticexyz/services)
The build phase of services now works on machines with older protobuf compilers
refactor: remove v1 network package, remove snap sync module, deprecate std-client (#1311) (opens in a new tab) (@latticexyz/common, @latticexyz/store, @latticexyz/world)
- Refactor tightcoder to use typescript functions instead of ejs
- Optimize
TightCoderlibrary - Add
isLeftAlignedandgetLeftPaddingBitscommon codegen helpers
fix(cli): make mud test exit with code 1 on test error (#1371) (opens in a new tab) (@latticexyz/cli)
The mud test cli now exits with code 1 on test failure. It used to exit with code 0, which meant that CIs didn't notice test failures.
Version 2.0.0-next.4
Major changes
docs: changeset for deleted network package (#1348) (opens in a new tab) (@latticexyz/network)
Removes network package. Please see the changelog (opens in a new tab) for how to migrate your app to the new store-sync package. Or create a new project from an up-to-date template with pnpm create mud@next your-app-name.
chore: delete std-contracts package (#1341) (opens in a new tab) (@latticexyz/cli, @latticexyz/std-contracts)
Removes std-contracts package. These were v1 contracts, now entirely replaced by our v2 tooling. See the MUD docs (opens in a new tab) for building with v2 or create a new project from our v2 templates with pnpm create mud@next your-app-name.
chore: delete solecs package (#1340) (opens in a new tab) (@latticexyz/cli, @latticexyz/recs, @latticexyz/solecs, @latticexyz/std-client)
Removes solecs package. These were v1 contracts, now entirely replaced by our v2 tooling. See the MUD docs (opens in a new tab) for building with v2 or create a new project from our v2 templates with pnpm create mud@next your-app-name.
feat(recs,std-client): move action system to recs (#1351) (opens in a new tab) (@latticexyz/recs, @latticexyz/std-client)
-
Moved
createActionSystemfromstd-clienttorecspackage and updated it to better support v2 sync stack.If you want to use
createActionSystemalongsidesyncToRecs, you'll need to pass in arguments like so:import { syncToRecs } from "@latticexyz/store-sync/recs"; import { createActionSystem } from "@latticexyz/recs/deprecated"; import { from, mergeMap } from "rxjs"; const { blockLogsStorage$, waitForTransaction } = syncToRecs({ world, ... }); const txReduced$ = blockLogsStorage$.pipe( mergeMap(({ operations }) => from(operations.map((op) => op.log?.transactionHash).filter(isDefined))) ); const actionSystem = createActionSystem(world, txReduced$, waitForTransaction); -
Fixed a bug in
waitForComponentValueInthat caused the promise to not resolve if the component value was already set when the function was called. -
Fixed a bug in
createActionSystemthat caused optimistic updates to be incorrectly propagated to requirement checks. To fix the bug, you must now pass in the full component object to the action'supdatesinstead of just the component name.actions.add({ updates: () => [ { - component: "Resource", + component: Resource, ... } ], ... });
chore: delete std-client package (#1342) (opens in a new tab) (@latticexyz/std-client)
Removes std-client package. Please see the changelog (opens in a new tab) for how to migrate your app to the new store-sync package. Or create a new project from an up-to-date template with pnpm create mud@next your-app-name.
chore: delete ecs-browser package (#1339) (opens in a new tab) (@latticexyz/ecs-browser)
Removes ecs-browser package. This has now been replaced by dev-tools, which comes out-of-the-box when creating a new MUD app from the templates (pnpm create mud@next your-app-name). We'll be adding deeper RECS support (querying for entities) in a future release.
chore: delete store-cache package (#1343) (opens in a new tab) (@latticexyz/store-cache)
Removes store-cache package. Please see the changelog (opens in a new tab) for how to migrate your app to the new store-sync package. Or create a new project from an up-to-date template with pnpm create mud@next your-app-name.
If you need reactivity, we recommend using recs package and syncToRecs. We'll be adding reactivity to syncToSqlite in a future release.
chore: delete store-cache package (#1343) (opens in a new tab) (@latticexyz/react)
Removes useRow and useRows hooks, previously powered by store-cache, which is now deprecated. Please use recs and the corresponding useEntityQuery and useComponentValue hooks. We'll have more hooks soon for SQL.js sync backends.
Version 2.0.0-next.3
Major changes
feat(world, store): stop loading schema from storage, require schema as an argument (#1174) (opens in a new tab) (@latticexyz/cli, @latticexyz/store, @latticexyz/world, create-mud)
All Store methods now require the table's value schema to be passed in as an argument instead of loading it from storage.
This decreases gas cost and removes circular dependencies of the Schema table (where it was not possible to write to the Schema table before the Schema table was registered).
function setRecord(
bytes32 table,
bytes32[] calldata key,
bytes calldata data,
+ Schema valueSchema
) external;The same diff applies to getRecord, getField, setField, pushToField, popFromField, updateInField, and deleteRecord.
This change only requires changes in downstream projects if the Store methods were accessed directly. In most cases it is fully abstracted in the generated table libraries,
so downstream projects only need to regenerate their table libraries after updating MUD.
refactor(world): combine name and namespace to resource selector in World methods (#1208) (opens in a new tab) (@latticexyz/cli, @latticexyz/world)
-
All
Worldfunction selectors that previously hadbytes16 namespace, bytes16 namearguments now usebytes32 resourceSelectorinstead. This includessetRecord,setField,pushToField,popFromField,updateInField,deleteRecord,call,grantAccess,revokeAccess,registerTable,registerStoreHook,registerSystemHook,registerFunctionSelector,registerSystemandregisterRootFunctionSelector. This change aligns theWorldfunction selectors with theStorefunction selectors, reduces clutter, reduces gas cost and reduces theWorld's contract size. -
The
World'sregisterHookfunction is removed. UseregisterStoreHookorregisterSystemHookinstead. -
The
deployscript is updated to integrate the World interface changes
refactor: remove v1 network package, remove snap sync module, deprecate std-client (#1311) (opens in a new tab) (@latticexyz/world)
The SnapSyncModule is removed. The recommended way of loading the initial state of a MUD app is via the new store-indexer (opens in a new tab). Loading state via contract getter functions is not recommended, as it's computationally heavy on the RPC, can't be cached, and is an easy way to shoot yourself in the foot with exploding RPC costs.
The @latticexyz/network package was deprecated and is now removed. All consumers should upgrade to the new sync stack from @latticexyz/store-sync.
refactor(store): optimize PackedCounter (#1231) (opens in a new tab) (@latticexyz/cli, @latticexyz/protocol-parser, @latticexyz/services, @latticexyz/store-sync, @latticexyz/store, @latticexyz/world)
Reverse PackedCounter encoding, to optimize gas for bitshifts. Ints are right-aligned, shifting using an index is straightforward if they are indexed right-to-left.
- Previous encoding: (7 bytes | accumulator),(5 bytes | counter 1),...,(5 bytes | counter 5)
- New encoding: (5 bytes | counter 5),...,(5 bytes | counter 1),(7 bytes | accumulator)
feat(store,world): combine schema and metadata registration, rename getSchema to getValueSchema, change Schema table id (#1182) (opens in a new tab) (@latticexyz/cli, @latticexyz/store, @latticexyz/world, @latticexyz/store-sync, create-mud)
-
Store's internal schema table is now a normal table instead of using special code paths. It is renamed to Tables, and the table ID changed frommudstore:schematomudstore:Tables -
Store'sregisterSchemaandsetMetadataare combined into a singleregisterTablemethod. This means metadata (key names, field names) is immutable and indexers can create tables with this metadata when a new table is registered on-chain.- function registerSchema(bytes32 table, Schema schema, Schema keySchema) external; - - function setMetadata(bytes32 table, string calldata tableName, string[] calldata fieldNames) external; + function registerTable( + bytes32 table, + Schema keySchema, + Schema valueSchema, + string[] calldata keyNames, + string[] calldata fieldNames + ) external; -
World'sregisterTablemethod is updated to match theStoreinterface,setMetadatais removed -
The
getSchemamethod is renamed togetValueSchemaon all interfaces- function getSchema(bytes32 table) external view returns (Schema schema); + function getValueSchema(bytes32 table) external view returns (Schema valueSchema); -
The
store-syncandclipackages are updated to integrate the breaking protocol changes. Downstream projects only need to manually integrate these changes if they access low levelStoreorWorldfunctions. Otherwise, a fresh deploy with the latest MUD will get you these changes.
refactor: remove v1 network package, remove snap sync module, deprecate std-client (#1311) (opens in a new tab) (@latticexyz/services, create-mud)
Move createFaucetService from @latticexyz/network to @latticexyz/services/faucet.
- import { createFaucetService } from "@latticexyz/network";
+ import { createFaucetService } from "@latticexyz/services/faucet";refactor: remove v1 network package, remove snap sync module, deprecate std-client (#1311) (opens in a new tab) (@latticexyz/std-client, @latticexyz/common, create-mud)
Deprecate @latticexyz/std-client and remove v1 network dependencies.
-
getBurnerWalletis replaced bygetBurnerPrivateKeyfrom@latticexyz/common. It now returns aHexstring instead of anrxjsBehaviorSubject.- import { getBurnerWallet } from "@latticexyz/std-client"; + import { getBurnerPrivateKey } from "@latticexyz/common"; - const privateKey = getBurnerWallet().value; - const privateKey = getBurnerPrivateKey(); -
All functions from
std-clientthat depended on v1 network code are removed (most notablysetupMUDNetworkandsetupMUDV2Network). Consumers should upgrade to v2 networking code from@latticexyz/store-sync. -
The following functions are removed from
std-clientbecause they are very use-case specific and depend on deprecated code:getCurrentTurn,getTurnAtTime,getGameConfig,isUntraversable,getPlayerEntity,resolveRelationshipChain,findEntityWithComponentInRelationshipChain,findInRelationshipChain. Consumers should vendor these functions if they are still needed. -
Remaining exports from
std-clientare moved to/deprecated. The package will be removed in a future release (once there are replacements for the deprecated exports).- import { ... } from "@latticexyz/std-client"; + import { ... } from "@latticexyz/std-client/deprecated";
Patch changes
feat(common,store-sync): improve initial sync to not block returned promise (#1315) (opens in a new tab) (@latticexyz/common, @latticexyz/store-sync)
Initial sync from indexer no longer blocks the promise returning from createStoreSync, syncToRecs, and syncToSqlite. This should help with rendering loading screens using the SyncProgress RECS component and avoid the long flashes of no content in templates.
By default, syncToRecs and syncToSqlite will start syncing (via observable subscription) immediately after called.
If your app needs to control when syncing starts, you can use the startSync: false option and then blockStoreOperations$.subscribe() to start the sync yourself. Just be sure to unsubscribe to avoid memory leaks.
const { blockStorageOperations$ } = syncToRecs({
...
startSync: false,
});
// start sync manually by subscribing to `blockStorageOperation$`
const subcription = blockStorageOperation$.subscribe();
// clean up subscription
subscription.unsubscribe();refactor(store): optimize table libraries (#1303) (opens in a new tab) (@latticexyz/store)
Optimize autogenerated table libraries
feat(store-sync): add more logging to waitForTransaction (#1317) (opens in a new tab) (@latticexyz/store-sync)
add retry attempts and more logging to waitForTransaction
refactor(store): optimize Schema (#1252) (opens in a new tab) (@latticexyz/store, @latticexyz/world)
Optimize Schema methods.
Return uint256 instead of uint8 in SchemaInstance numFields methods
Version 2.0.0-next.2
Major changes
feat(store-indexer): use fastify, move trpc to /trpc (#1232) (opens in a new tab) (@latticexyz/store-indexer)
Adds a Fastify (opens in a new tab) server in front of tRPC and puts tRPC endpoints under /trpc to make way for other top-level endpoints (e.g. tRPC panel (opens in a new tab) or other API frontends like REST or gRPC).
If you're using @latticexyz/store-sync packages with an indexer (either createIndexerClient or indexerUrl argument of syncToRecs), then you'll want to update your indexer URL:
createIndexerClient({
- url: "https://indexer.dev.linfra.xyz",
+ url: "https://indexer.dev.linfra.xyz/trpc",
}); syncToRecs({
...
- indexerUrl: "https://indexer.dev.linfra.xyz",
+ indexerUrl: "https://indexer.dev.linfra.xyz/trpc",
});refactor(store): remove TableId library (#1279) (opens in a new tab) (@latticexyz/store)
Remove TableId library to simplify store package
feat(create-mud): infer recs components from config (#1278) (opens in a new tab) (@latticexyz/cli, @latticexyz/std-client, @latticexyz/store-sync, @latticexyz/store, @latticexyz/world, create-mud)
RECS components are now dynamically created and inferred from your MUD config when using syncToRecs.
To migrate existing projects after upgrading to this MUD version:
-
Remove
contractComponents.tsfromclient/src/mud -
Remove
componentsargument fromsyncToRecs -
Update
build:mudanddevscripts incontracts/package.jsonto remove tsgen- "build:mud": "mud tablegen && mud worldgen && mud tsgen --configPath mud.config.ts --out ../client/src/mud", + "build:mud": "mud tablegen && mud worldgen",- "dev": "pnpm mud dev-contracts --tsgenOutput ../client/src/mud", + "dev": "pnpm mud dev-contracts",
feat: bump viem to 1.6.0 (#1308) (opens in a new tab) (@latticexyz/block-logs-stream)
- removes our own
getLogsfunction now that viem'sgetLogssupports using multipleeventsper RPC call. - removes
isNonPendingBlockandisNonPendingLoghelpers now that viem narrowsBlockandLogtypes based on inputs - simplifies
groupLogsByBlockNumbertypes and tests
feat(dev-tools): use new sync stack (#1284) (opens in a new tab) (@latticexyz/dev-tools, create-mud)
MUD dev tools is updated to latest sync stack. You must now pass in all of its data requirements rather than relying on magic globals.
import { mount as mountDevTools } from "@latticexyz/dev-tools";
- mountDevTools();
+ mountDevTools({
+ config,
+ publicClient,
+ walletClient,
+ latestBlock$,
+ blockStorageOperations$,
+ worldAddress,
+ worldAbi,
+ write$,
+ // if you're using recs
+ recsWorld,
+ });It's also advised to wrap dev tools so that it is only mounted during development mode. Here's how you do this with Vite:
// https://vitejs.dev/guide/env-and-mode.html
if (import.meta.env.DEV) {
mountDevTools({ ... });
}Minor changes
feat(dev-tools): use new sync stack (#1284) (opens in a new tab) (@latticexyz/common)
createContract now has an onWrite callback so you can observe writes. This is useful for wiring up the transanction log in MUD dev tools.
import { createContract, ContractWrite } from "@latticexyz/common";
import { Subject } from "rxjs";
const write$ = new Subject<ContractWrite>();
creactContract({
...
onWrite: (write) => write$.next(write),
});feat: bump viem to 1.6.0 (#1308) (opens in a new tab) (@latticexyz/common)
- adds
defaultPriorityFeetomudFoundryfor better support with MUD's default anvil config and removes workaround increateContract - improves nonce error detection using viem's custom errors
feat(store-sync,store-indexer): consolidate sync logic, add syncToSqlite (#1240) (opens in a new tab) (@latticexyz/dev-tools, @latticexyz/store-indexer, @latticexyz/store-sync)
Store sync logic is now consolidated into a createStoreSync function exported from @latticexyz/store-sync. This simplifies each storage sync strategy to just a simple wrapper around the storage adapter. You can now sync to RECS with syncToRecs or SQLite with syncToSqlite and PostgreSQL support coming soon.
There are no breaking changes if you were just using syncToRecs from @latticexyz/store-sync or running the sqlite-indexer binary from @latticexyz/store-indexer.
feat(dev-tools): use new sync stack (#1284) (opens in a new tab) (@latticexyz/react)
Adds a usePromise hook that returns a native PromiseSettledResult object (opens in a new tab).
const promise = fetch(url);
const result = usePromise(promise);
if (result.status === "idle" || result.status === "pending") {
return <>fetching</>;
}
if (result.status === "rejected") {
return <>error fetching: {String(result.reason)}</>;
}
if (result.status === "fulfilled") {
return <>fetch status: {result.value.status}</>;
}Patch changes
feat: bump viem to 1.6.0 (#1308) (opens in a new tab) (@latticexyz/block-logs-stream, @latticexyz/common, @latticexyz/dev-tools, @latticexyz/network, @latticexyz/protocol-parser, @latticexyz/schema-type, @latticexyz/std-client, @latticexyz/store-indexer, @latticexyz/store-sync, create-mud)
bump viem to 1.6.0
feat(dev-tools): improve support for non-store recs components (#1302) (opens in a new tab) (@latticexyz/dev-tools, @latticexyz/store-sync)
Improves support for internal/client-only RECS components
feat: bump viem to 1.6.0 (#1308) (opens in a new tab) (@latticexyz/store-sync)
remove usages of isNonPendingBlock and isNonPendingLog (fixed with more specific viem types)
Version 2.0.0-next.1
Major changes
chore: fix changeset type (#1220) (opens in a new tab) (@latticexyz/store-indexer, @latticexyz/store-sync)
Adds store indexer service package with utils to query the indexer service.
You can run the indexer locally by checking out the MUD monorepo, installing/building everything, and running pnpm start:local from packages/store-indexer.
To query the indexer in the client, you can create a tRPC client with a URL pointing to the indexer service and call the available tRPC methods:
import { createIndexerClient } from "@latticexyz/store-sync/trpc-indexer";
const indexer = createIndexerClient({ url: indexerUrl });
const result = await indexer.findAll.query({
chainId: publicClient.chain.id,
address,
});If you're using syncToRecs, you can just pass in the indexerUrl option as a shortcut to the above:
import { syncToRecs } from "@latticexyz/store-sync/recs";
syncToRecs({
...
indexerUrl: "https://your.indexer.service",
});fix: changeset package name (#1270) (opens in a new tab) (@latticexyz/cli, @latticexyz/common, @latticexyz/recs, @latticexyz/store-indexer, create-mud)
Templates and examples now use MUD's new sync packages, all built on top of viem (opens in a new tab). This greatly speeds up and stabilizes our networking code and improves types throughout.
These new sync packages come with support for our recs package, including encodeEntity and decodeEntity utilities for composite keys.
If you're using store-cache and useRow/useRows, you should wait to upgrade until we have a suitable replacement for those libraries. We're working on a sql.js (opens in a new tab)-powered sync module that will replace store-cache.
Migrate existing RECS apps to new sync packages
As you migrate, you may find some features replaced, removed, or not included by default. Please open an issue (opens in a new tab) and let us know if we missed anything.
-
Add
@latticexyz/store-syncpackage to your app'sclientpackage and make sureviemis pinned to version1.3.1(otherwise you may get type errors) -
In your
supportedChains.ts, replacefoundrychain with our newmudFoundrychain.- import { foundry } from "viem/chains"; - import { MUDChain, latticeTestnet } from "@latticexyz/common/chains"; + import { MUDChain, latticeTestnet, mudFoundry } from "@latticexyz/common/chains"; - export const supportedChains: MUDChain[] = [foundry, latticeTestnet]; + export const supportedChains: MUDChain[] = [mudFoundry, latticeTestnet]; -
In
getNetworkConfig.ts, remove the return type (to let TS infer it for now), remove now-unused config values, and add the viemchainobject.- export async function getNetworkConfig(): Promise<NetworkConfig> { + export async function getNetworkConfig() {const initialBlockNumber = params.has("initialBlockNumber") ? Number(params.get("initialBlockNumber")) - : world?.blockNumber ?? -1; // -1 will attempt to find the block number from RPC + : world?.blockNumber ?? 0n;+ return { + privateKey: getBurnerWallet().value, + chain, + worldAddress, + initialBlockNumber, + faucetServiceUrl: params.get("faucet") ?? chain.faucetUrl, + }; -
In
setupNetwork.ts, replacesetupMUDV2NetworkwithsyncToRecs.- import { setupMUDV2Network } from "@latticexyz/std-client"; - import { createFastTxExecutor, createFaucetService, getSnapSyncRecords } from "@latticexyz/network"; + import { createFaucetService } from "@latticexyz/network"; + import { createPublicClient, fallback, webSocket, http, createWalletClient, getContract, Hex, parseEther, ClientConfig } from "viem"; + import { encodeEntity, syncToRecs } from "@latticexyz/store-sync/recs"; + import { createBurnerAccount, createContract, transportObserver } from "@latticexyz/common";- const result = await setupMUDV2Network({ - ... - }); + const clientOptions = { + chain: networkConfig.chain, + transport: transportObserver(fallback([webSocket(), http()])), + pollingInterval: 1000, + } as const satisfies ClientConfig; + const publicClient = createPublicClient(clientOptions); + const burnerAccount = createBurnerAccount(networkConfig.privateKey as Hex); + const burnerWalletClient = createWalletClient({ + ...clientOptions, + account: burnerAccount, + }); + const { components, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({ + world, + config: storeConfig, + address: networkConfig.worldAddress as Hex, + publicClient, + components: contractComponents, + startBlock: BigInt(networkConfig.initialBlockNumber), + indexerUrl: networkConfig.indexerUrl ?? undefined, + }); + const worldContract = createContract({ + address: networkConfig.worldAddress as Hex, + abi: IWorld__factory.abi, + publicClient, + walletClient: burnerWalletClient, + });// Request drip from faucet - const signer = result.network.signer.get(); - if (networkConfig.faucetServiceUrl && signer) { - const address = await signer.getAddress(); + if (networkConfig.faucetServiceUrl) { + const address = burnerAccount.address;const requestDrip = async () => { - const balance = await signer.getBalance(); + const balance = await publicClient.getBalance({ address }); console.info(`[Dev Faucet]: Player balance -> ${balance}`); - const lowBalance = balance?.lte(utils.parseEther("1")); + const lowBalance = balance < parseEther("1");You can remove the previous ethers
worldContract, snap sync code, and fast transaction executor.The return of
setupNetworkis a bit different than before, so you may have to do corresponding app changes.+ return { + world, + components, + playerEntity: encodeEntity({ address: "address" }, { address: burnerWalletClient.account.address }), + publicClient, + walletClient: burnerWalletClient, + latestBlock$, + blockStorageOperations$, + waitForTransaction, + worldContract, + }; -
Update
createSystemCallswith the new return type ofsetupNetwork.export function createSystemCalls( - { worldSend, txReduced$, singletonEntity }: SetupNetworkResult, + { worldContract, waitForTransaction }: SetupNetworkResult, { Counter }: ClientComponents ) { const increment = async () => { - const tx = await worldSend("increment", []); - await awaitStreamValue(txReduced$, (txHash) => txHash === tx.hash); + const tx = await worldContract.write.increment(); + await waitForTransaction(tx); return getComponentValue(Counter, singletonEntity); }; -
(optional) If you still need a clock, you can create it with:
import { map, filter } from "rxjs"; import { createClock } from "@latticexyz/network"; const clock = createClock({ period: 1000, initialTime: 0, syncInterval: 5000, }); world.registerDisposer(() => clock.dispose()); latestBlock$ .pipe( map((block) => Number(block.timestamp) * 1000), // Map to timestamp in ms filter((blockTimestamp) => blockTimestamp !== clock.lastUpdateTime), // Ignore if the clock was already refreshed with this block filter((blockTimestamp) => blockTimestamp !== clock.currentTime) // Ignore if the current local timestamp is correct ) .subscribe(clock.update); // Update the local clock
If you're using the previous LoadingState component, you'll want to migrate to the new SyncProgress:
import { SyncStep, singletonEntity } from "@latticexyz/store-sync/recs";
const syncProgress = useComponentValue(SyncProgress, singletonEntity, {
message: "Connecting",
percentage: 0,
step: SyncStep.INITIALIZE,
});
if (syncProgress.step === SyncStep.LIVE) {
// we're live!
}feat(common): replace TableId with tableIdToHex/hexToTableId (#1258) (opens in a new tab) (@latticexyz/cli, @latticexyz/common, @latticexyz/dev-tools, @latticexyz/network, @latticexyz/std-client, @latticexyz/store-sync)
Add tableIdToHex and hexToTableId pure functions and move/deprecate TableId.
feat(common): add createContract, createNonceManager utils (#1261) (opens in a new tab) (@latticexyz/common)
Add utils for using viem with MUD
createContractis a wrapper around viem'sgetContract(opens in a new tab) but with better nonce handling for faster executing of transactions. It has the same arguments and return type asgetContract.createNonceManagerhelps track local nonces, used bycreateContract.
Also renames mudTransportObserver to transportObserver.
Minor changes
feat(common): add viem utils (#1245) (opens in a new tab) (@latticexyz/common)
Add utils for using viem with MUD
mudFoundrychain with a transaction request formatter that temporarily removes max fees to work better with anvil--base-fee 0createBurnerAccountthat also temporarily removes max fees during transaction signing to work better with anvil--base-fee 0mudTransportObserverthat will soon let MUD Dev Tools observe transactions
You can use them like:
import { createBurnerAccount, mudTransportObserver } from "@latticexyz/common";
import { mudFoundry } from "@latticexyz/common/chains";
createWalletClient({
account: createBurnerAccount(privateKey),
chain: mudFoundry,
transport: mudTransportObserver(http()),
pollingInterval: 1000,
});feat(store-indexer,store-sync): make chain optional, configure indexer with RPC (#1234) (opens in a new tab) (@latticexyz/store-indexer, @latticexyz/store-sync)
- Accept a plain viem
PublicClient(instead of requiring aChainto be set) instore-syncandstore-indexerfunctions. These functions now fetch chain ID usingpublicClient.getChainId()when nopublicClient.chain.idis present. - Allow configuring
store-indexerwith a set of RPC URLs (RPC_HTTP_URLandRPC_WS_URL) instead ofCHAIN_ID.
feat(store-sync): export singletonEntity as const, allow startBlock in syncToRecs (#1235) (opens in a new tab) (@latticexyz/store-sync)
Export singletonEntity as const rather than within the syncToRecs result.
- const { singletonEntity, ... } = syncToRecs({ ... });
+ import { singletonEntity, syncToRecs } from "@latticexyz/store-sync/recs";
+ const { ... } = syncToRecs({ ... });feat(schema-type): add type narrowing isStaticAbiType (#1196) (opens in a new tab) (@latticexyz/schema-type)
add type narrowing isStaticAbiType
feat(common): move zero gas fee override to createContract (#1266) (opens in a new tab) (@latticexyz/common)
- Moves zero gas fee override to
createContractuntil https://github.com/wagmi-dev/viem/pull/963 (opens in a new tab) or similar feature lands - Skip simulation if
gasis provided
Patch changes
fix(cli): add support for legacy transactions in deploy script (#1178) (opens in a new tab) (@latticexyz/cli)
Add support for legacy transactions in deploy script by falling back to gasPrice if lastBaseFeePerGas is not available
feat: protocol-parser in go (#1116) (opens in a new tab) (@latticexyz/services)
protocol-parser in Go
refactor(store): optimize Storage library (#1194) (opens in a new tab) (@latticexyz/store)
Optimize storage library
feat(common): remove need for tx queue in createContract (#1271) (opens in a new tab) (@latticexyz/common)
- Remove need for tx queue in
createContract
feat(store-sync): add block numbers to SyncProgress (#1228) (opens in a new tab) (@latticexyz/store-sync)
Adds latestBlockNumber and lastBlockNumberProcessed to internal SyncProgress component
feat(store-sync): sync to RECS (#1197) (opens in a new tab) (@latticexyz/store-sync)
Add RECS sync strategy and corresponding utils
import { createPublicClient, http } from 'viem';
import { syncToRecs } from '@latticexyz/store-sync';
import storeConfig from 'contracts/mud.config';
import { defineContractComponents } from './defineContractComponents';
const publicClient = createPublicClient({
chain,
transport: http(),
pollingInterval: 1000,
});
const { components, singletonEntity, latestBlock$, blockStorageOperations$, waitForTransaction } = await syncToRecs({
world,
config: storeConfig,
address: '0x...',
publicClient,
components: defineContractComponents(...),
});fix(store): align Store event names between IStoreWrite and StoreCore (#1237) (opens in a new tab) (@latticexyz/store)
Align Store events parameter naming between IStoreWrite and StoreCore
fix(cli): explicit import of world as type (#1206) (opens in a new tab) (@latticexyz/cli, @latticexyz/std-client)
Generated contractComponents now properly import World as type
feat(store-sync): export singletonEntity as const, allow startBlock in syncToRecs (#1235) (opens in a new tab) (@latticexyz/store-sync)
Add startBlock option to syncToRecs.
import { syncToRecs } from "@latticexyz/store-sync/recs";
import worlds from "contracts/worlds.json";
syncToRecs({
startBlock: worlds['31337'].blockNumber,
...
});chore: pin node to 18.16.1 (#1200) (opens in a new tab) (@latticexyz/network)
Remove devEmit function when sending network events from SyncWorker because they can't be serialized across the web worker boundary.
feat(cli,recs,std-client): update RECS components with v2 key/value schemas (#1195) (opens in a new tab) (@latticexyz/cli, @latticexyz/recs, @latticexyz/std-client)
Update RECS components with v2 key/value schemas. This helps with encoding/decoding composite keys and strong types for keys/values.
This may break if you were previously dependent on component.id, component.metadata.componentId, or component.metadata.tableId:
component.idis now the on-chainbytes32hex representation of the table IDcomponent.metadata.componentNameis the table name (e.g.Position)component.metadata.tableNameis the namespaced table name (e.g.myworld:Position)component.metadata.keySchemais an object with key names and their corresponding ABI typescomponent.metadata.valueSchemais an object with field names and their corresponding ABI types
refactor(store): update tightcoder codegen, optimize TightCoder library (#1210) (opens in a new tab) (@latticexyz/common, @latticexyz/store, @latticexyz/world)
- Refactor tightcoder to use typescript functions instead of ejs
- Optimize
TightCoderlibrary - Add
isLeftAlignedandgetLeftPaddingBitscommon codegen helpers
Version 2.0.0-next.0
Minor changes
feat(store-sync): add store sync package (#1075) (opens in a new tab) (@latticexyz/block-logs-stream, @latticexyz/protocol-parser, @latticexyz/store-sync, @latticexyz/store)
Add store sync package
feat(protocol-parser): add abiTypesToSchema (#1100) (opens in a new tab) (@latticexyz/protocol-parser)
feat: add abiTypesToSchema, a util to turn a list of abi types into a Schema by separating static and dynamic types
chore(protocol-parser): add changeset for #1099 (#1111) (opens in a new tab) (@latticexyz/protocol-parser)
feat: add encodeKeyTuple, a util to encode key tuples in Typescript (equivalent to key tuple encoding in Solidity and inverse of decodeKeyTuple).
Example:
encodeKeyTuple({ staticFields: ["uint256", "int32", "bytes16", "address", "bool", "int8"], dynamicFields: [] }, [
42n,
-42,
"0x12340000000000000000000000000000",
"0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF",
true,
3,
]);
// [
// "0x000000000000000000000000000000000000000000000000000000000000002a",
// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd6",
// "0x1234000000000000000000000000000000000000000000000000000000000000",
// "0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff",
// "0x0000000000000000000000000000000000000000000000000000000000000001",
// "0x0000000000000000000000000000000000000000000000000000000000000003",
// ]feat(store-sync): rework blockLogsToStorage (#1176) (opens in a new tab) (@latticexyz/block-logs-stream, @latticexyz/store-sync)
- Replace
blockEventsToStoragewithblockLogsToStoragethat exposes astoreOperationscallback to perform database writes from store operations. This helps encapsulates database adapters into a single wrapper/instance ofblockLogsToStorageand allows for wrapping a block of store operations in a database transaction. - Add
toBlockoption togroupLogsByBlockNumberand removeblockHashfrom results. This helps track the last block number for a given set of logs when used in the context of RxJS streams.
feat(block-logs-stream): add block logs stream package (#1070) (opens in a new tab) (@latticexyz/block-logs-stream)
Add block logs stream package
import { filter, map, mergeMap } from "rxjs";
import { createPublicClient, parseAbi } from "viem";
import {
createBlockStream,
isNonPendingBlock,
groupLogsByBlockNumber,
blockRangeToLogs,
} from "@latticexyz/block-logs-stream";
const publicClient = createPublicClient({
// your viem public client config here
});
const latestBlock$ = await createBlockStream({ publicClient, blockTag: "latest" });
const latestBlockNumber$ = latestBlock$.pipe(
filter(isNonPendingBlock),
map((block) => block.number)
);
latestBlockNumber$
.pipe(
map((latestBlockNumber) => ({ startBlock: 0n, endBlock: latestBlockNumber })),
blockRangeToLogs({
publicClient,
address,
events: parseAbi([
"event StoreDeleteRecord(bytes32 table, bytes32[] key)",
"event StoreSetField(bytes32 table, bytes32[] key, uint8 schemaIndex, bytes data)",
"event StoreSetRecord(bytes32 table, bytes32[] key, bytes data)",
"event StoreEphemeralRecord(bytes32 table, bytes32[] key, bytes data)",
]),
}),
mergeMap(({ logs }) => from(groupLogsByBlockNumber(logs)))
)
.subscribe((block) => {
console.log("got events for block", block);
});feat(gas-report): create package, move relevant files to it (#1147) (opens in a new tab) (@latticexyz/cli, @latticexyz/gas-report, @latticexyz/store)
Create gas-report package, move gas-report cli command and GasReporter contract to it
refactor(store,world): replace isStore with storeAddress (#1061) (opens in a new tab) (@latticexyz/std-contracts, @latticexyz/store, @latticexyz/world)
Rename MudV2Test to MudTest and move from @latticexyz/std-contracts to @latticexyz/store.
// old import
import { MudV2Test } from "@latticexyz/std-contracts/src/test/MudV2Test.t.sol";
// new import
import { MudTest } from "@latticexyz/store/src/MudTest.sol";Refactor StoreSwitch to use a storage slot instead of function isStore() to determine which contract is Store:
- Previously
StoreSwitchcalledisStore()onmsg.senderto determine ifmsg.senderis aStorecontract. If the call succeeded, theStoremethods were called onmsg.sender, otherwise the data was written to the own storage. - With this change
StoreSwitchinstead checks for anaddressin a known storage slot. If the address equals the own address, data is written to the own storage. If it is an external address,Storemethods are called on this address. If it is unset (address(0)), store methods are called onmsg.sender. - In practice this has the same effect as before: By default the
Worldcontracts sets its own address inStoreSwitch, whileSystemcontracts keep the Store address undefined, soSystemswrite to their caller (World) if they are executed viacallor directly to theWorldstorage if they are executed viadelegatecall. - Besides gas savings, this change has two additional benefits:
- it is now possible for
Systemsto explicitly set aStoreaddress to make them exclusive to thatStoreand - table libraries can now be used in tests without having to provide an explicit
Storeargument, because theMudTestbase contract redirects reads and writes to the internalWorldcontract.
- it is now possible for
feat(store-sync): sync to sqlite (#1185) (opens in a new tab) (@latticexyz/store-sync)
blockLogsToStorage(sqliteStorage(...)) converts block logs to SQLite operations. You can use it like:
import { drizzle } from "drizzle-orm/better-sqlite3";
import Database from "better-sqlite3";
import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
import { createPublicClient } from "viem";
import { blockLogsToStorage } from "@latticexyz/store-sync";
import { sqliteStorage } from "@latticexyz/store-sync/sqlite";
const database = drizzle(new Database('store.db')) as any as BaseSQLiteDatabase<"sync", void>;
const publicClient = createPublicClient({ ... });
blockLogs$
.pipe(
concatMap(blockLogsToStorage(sqliteStorage({ database, publicClient }))),
tap(({ blockNumber, operations }) => {
console.log("stored", operations.length, "operations for block", blockNumber);
})
)
.subscribe();feat(common): new utils, truncate table ID parts (#1173) (opens in a new tab) (@latticexyz/common)
TableId.toHex() now truncates name/namespace to 16 bytes each, to properly fit into a bytes32 hex string.
Also adds a few utils we'll need in the indexer:
bigIntMinis similar toMath.minbut forbigintsbigIntMaxis similar toMath.maxbut forbigintsbigIntSortfor sorting an array ofbigintschunkto split an array into chunkswaitreturns aPromisethat resolves after specified number of milliseconds
feat(cli): update set-version to match new release structure, add --tag, --commit (#1157) (opens in a new tab) (@latticexyz/cli)
- update the
set-versioncli command to work with the new release process by adding two new options:--tag: install the latest version of the given tag. For snapshot releases tags correspond to the branch name, commits tomainresult in an automatic snapshot release, so--tag mainis equivalent to what used to be-v canary--commit: install a version based on a given commit hash. Since commits frommainresult in an automatic snapshot release it works for all commits on main, and it works for manual snapshot releases from branches other than main
set-versionnow updates allpackage.jsonnested below the current working directory (expectnode_modules), so no need for running it each workspace of a monorepo separately.
Example:
pnpm mud set-version --tag main && pnpm install
pnpm mud set-version --commit db19ea39 && pnpm installPatch changes
fix(protocol-parser): properly decode empty records (#1177) (opens in a new tab) (@latticexyz/protocol-parser)
decodeRecord now properly decodes empty records
refactor(store): clean up Memory, make mcopy pure (#1153) (opens in a new tab) (@latticexyz/cli, @latticexyz/common, @latticexyz/store, @latticexyz/world)
Clean up Memory.sol, make mcopy pure
fix(recs): improve messages for v2 components (#1167) (opens in a new tab) (@latticexyz/recs)
improve RECS error messages for v2 components
test: bump forge-std and ds-test (#1168) (opens in a new tab) (@latticexyz/cli, @latticexyz/gas-report, @latticexyz/noise, @latticexyz/schema-type, @latticexyz/solecs, @latticexyz/std-contracts, @latticexyz/store, @latticexyz/world, create-mud)
bump forge-std and ds-test dependencies
fix(schema-type): fix byte lengths for uint64/int64 (#1175) (opens in a new tab) (@latticexyz/schema-type)
Fix byte lengths for uint64 and int64.
build: bump TS (#1165) (opens in a new tab) (@latticexyz/cli, create-mud, @latticexyz/utils, @latticexyz/world)
bump to latest TS version (5.1.6)
build: bump viem, abitype (#1179) (opens in a new tab) (@latticexyz/block-logs-stream, @latticexyz/cli, @latticexyz/common, @latticexyz/dev-tools, @latticexyz/network, @latticexyz/protocol-parser, @latticexyz/schema-type, @latticexyz/std-client, @latticexyz/store-cache, @latticexyz/store-sync, @latticexyz/store)
- bump to viem 1.3.0 and abitype 0.9.3
- move
@wagmi/chainsimports toviem/chains - refine a few types
test(e2e): add more test cases (#1074) (opens in a new tab) (@latticexyz/services)
fix a bug related to encoding negative bigints in MODE
fix: remove devEmit when sending events from SyncWorker (#1109) (opens in a new tab) (@latticexyz/network)
Remove devEmit function when sending network events from SyncWorker because they can't be serialized across the web worker boundary.