MUD is a framework for building ambitious onchain applications
MIT License
Bot releases are visible (Hide)
Published by github-actions[bot] about 1 year ago
#1284 939916bc
Thanks @holic! - 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({ ... });
}
#1240 753bdce4
Thanks @holic! - 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
.
#1302 5294a7d5
Thanks @holic! - Improves support for internal/client-only RECS components
Updated dependencies [a2588116
, 939916bc
, b8a6158d
, 48c51b52
, b8a6158d
, 753bdce4
, 5294a7d5
, b8a6158d
, 939916bc
]:
Published by github-actions[bot] about 1 year ago
#1278 48c51b52
Thanks @holic! - 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.ts
from client/src/mud
Remove components
argument from syncToRecs
Update build:mud
and dev
scripts in contracts/package.json
to 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",
#1284 939916bc
Thanks @holic! - 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({ ... });
}
Published by github-actions[bot] about 1 year ago
939916bc
, b8a6158d
, b8a6158d
]:
Published by github-actions[bot] about 1 year ago
#1284 939916bc
Thanks @holic! - 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),
});
#1308 b8a6158d
Thanks @holic! - - adds defaultPriorityFee
to mudFoundry
for better support with MUD's default anvil config and removes workaround in createContract
Updated dependencies [b8a6158d
]:
Published by github-actions[bot] about 1 year ago
#1278 48c51b52
Thanks @holic! - 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.ts
from client/src/mud
Remove components
argument from syncToRecs
Update build:mud
and dev
scripts in contracts/package.json
to 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",
a2588116
, 939916bc
, b8a6158d
, 48c51b52
, b8a6158d
]:
Published by github-actions[bot] about 1 year ago
b8a6158d
Thanks @holic! - - removes our own getLogs
function now that viem's getLogs
supports using multiple events
per RPC call.
isNonPendingBlock
and isNonPendingLog
helpers now that viem narrows Block
and Log
types based on inputsgroupLogsByBlockNumber
types and testsUpdated dependencies [939916bc
, b8a6158d
, b8a6158d
]:
Published by github-actions[bot] about 1 year ago
cc2c8da0
Thanks @dk1a! - - Refactor tightcoder to use typescript functions instead of ejs
TightCoder
libraryisLeftAligned
and getLeftPaddingBits
common codegen helpersc963b46c
, 3fb9ce28
, 35c9f33d
, 5c965a91
, b02f9d0e
, 60cfd089
, 6071163f
, 6c673325
, cd5abcc3
, cc2c8da0
]:
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
#1198 e86fbc12
Thanks @holic! - 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",
});
#1234 131c63e5
Thanks @holic! - - Accept a plain viem PublicClient
(instead of requiring a Chain
to be set) in store-sync
and store-indexer
functions. These functions now fetch chain ID using publicClient.getChainId()
when no publicClient.chain.id
is present.
store-indexer
with a set of RPC URLs (RPC_HTTP_URL
and RPC_WS_URL
) instead of CHAIN_ID
.#1235 582388ba
Thanks @holic! - Export singletonEntity
as const rather than within the syncToRecs
result.
- const { singletonEntity, ... } = syncToRecs({ ... });
+ import { singletonEntity, syncToRecs } from "@latticexyz/store-sync/recs";
+ const { ... } = syncToRecs({ ... });
#1228 57a52608
Thanks @holic! - Adds latestBlockNumber
and lastBlockNumberProcessed
to internal SyncProgress
component
#1197 9e5baf4f
Thanks @holic! - 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(...),
});
#1235 582388ba
Thanks @holic! - Add startBlock
option to syncToRecs
.
import { syncToRecs } from "@latticexyz/store-sync/recs";
import worlds from "contracts/worlds.json";
syncToRecs({
startBlock: worlds['31337'].blockNumber,
...
});
#1258 6c673325
Thanks @holic! - Add tableIdToHex
and hexToTableId
pure functions and move/deprecate TableId
.
Updated dependencies [c963b46c
, 3fb9ce28
, 35c9f33d
, 5c965a91
, b02f9d0e
, 60cfd089
, 6071163f
, 6c673325
, cd5abcc3
, afdba793
, cc2c8da0
]:
Published by github-actions[bot] about 1 year ago
#1198 e86fbc12
Thanks @holic! - 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",
});
131c63e5
Thanks @holic! - - Accept a plain viem PublicClient
(instead of requiring a Chain
to be set) in store-sync
and store-indexer
functions. These functions now fetch chain ID using publicClient.getChainId()
when no publicClient.chain.id
is present.
store-indexer
with a set of RPC URLs (RPC_HTTP_URL
and RPC_WS_URL
) instead of CHAIN_ID
.#1214 60cfd089
Thanks @holic! - Templates and examples now use MUD's new sync packages, all built on top of viem. 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-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 and let us know if we missed anything.
Add @latticexyz/store-sync
package to your app's client
package and make sure viem
is pinned to version 1.3.1
(otherwise you may get type errors)
In your supportedChains.ts
, replace foundry
chain with our new mudFoundry
chain.
- 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 viem chain
object.
- 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
, replace setupMUDV2Network
with syncToRecs
.
- 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 setupNetwork
is 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 createSystemCalls
with the new return type of setupNetwork
.
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!
}
Updated dependencies [c963b46c
, e86fbc12
, 3fb9ce28
, 35c9f33d
, 57a52608
, 9e5baf4f
, 131c63e5
, 5c965a91
, 582388ba
, 582388ba
, 60cfd089
, 6071163f
, 6c673325
, cd5abcc3
, cc2c8da0
]:
Published by github-actions[bot] about 1 year ago
c963b46c
, 3fb9ce28
, 35c9f33d
, 5c965a91
, b02f9d0e
, 60cfd089
, 6071163f
, 6c673325
, cd5abcc3
, cc2c8da0
]:
Published by github-actions[bot] about 1 year ago
#1237 5c965a91
Thanks @alvrs! - Align Store events parameter naming between IStoreWrite and StoreCore
#1210 cc2c8da0
Thanks @dk1a! - - Refactor tightcoder to use typescript functions instead of ejs
TightCoder
libraryisLeftAligned
and getLeftPaddingBits
common codegen helpersUpdated dependencies [3fb9ce28
, 35c9f33d
, b02f9d0e
, 60cfd089
, 6071163f
, 6c673325
, cd5abcc3
, cc2c8da0
]:
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
#1206 e259ef79
Thanks @holic! - Generated contractComponents
now properly import World
as type
#1258 6c673325
Thanks @holic! - Add tableIdToHex
and hexToTableId
pure functions and move/deprecate TableId
.
#1195 afdba793
Thanks @holic! - 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.id
is now the on-chain bytes32
hex representation of the table IDcomponent.metadata.componentName
is the table name (e.g. Position
)component.metadata.tableName
is the namespaced table name (e.g. myworld:Position
)component.metadata.keySchema
is an object with key names and their corresponding ABI typescomponent.metadata.valueSchema
is an object with field names and their corresponding ABI typesUpdated dependencies [168a4cb4
, c963b46c
, 3fb9ce28
, 35c9f33d
, 5c965a91
, e259ef79
, 60cfd089
, 6071163f
, 6c673325
, cd5abcc3
, afdba793
, cc2c8da0
]:
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
Published by github-actions[bot] about 1 year ago
#1214 60cfd089
Thanks @holic! - Templates and examples now use MUD's new sync packages, all built on top of viem. 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-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 and let us know if we missed anything.
Add @latticexyz/store-sync
package to your app's client
package and make sure viem
is pinned to version 1.3.1
(otherwise you may get type errors)
In your supportedChains.ts
, replace foundry
chain with our new mudFoundry
chain.
- 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 viem chain
object.
- 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
, replace setupMUDV2Network
with syncToRecs
.
- 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 setupNetwork
is 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 createSystemCalls
with the new return type of setupNetwork
.
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!
}
#1195 afdba793
Thanks @holic! - 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.id
is now the on-chain bytes32
hex representation of the table IDcomponent.metadata.componentName
is the table name (e.g. Position
)component.metadata.tableName
is the namespaced table name (e.g. myworld:Position
)component.metadata.keySchema
is an object with key names and their corresponding ABI typescomponent.metadata.valueSchema
is an object with field names and their corresponding ABI typesUpdated dependencies [b02f9d0e
]: