Skip to content

Commit b819749

Browse files
authored
feat: add getRecords util to fetch records from indexer, update deployer and explorer to use indexer (#3385)
1 parent ad02d17 commit b819749

35 files changed

+404
-308
lines changed

.changeset/big-cooks-fetch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@latticexyz/explorer": patch
3+
---
4+
5+
Improved the performance of the explorer's `Interact` tab by fetching the ABI from an indexer instead of from an Ethereum RPC if available.

.changeset/shy-eels-hide.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@latticexyz/store-sync": patch
3+
"@latticexyz/world": patch
4+
---
5+
6+
Added a `getRecords` util to fetch table records from an indexer or RPC.
7+
8+
Migrated the `getFunctions` and `getWorldAbi` utils from `@latticexyz/world` to `@latticexyz/store-sync/world` to allow `getFunctions` and `getWorldAbi` to use `getRecords` internally without circular dependencies.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@latticexyz/cli": patch
3+
---
4+
5+
Added an `indexerUrl` option to the `mud deploy` and `mud pull` CLI commands to read table records from an indexer instead of fetching logs from an Ethereum RPC.

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@latticexyz/protocol-parser": "workspace:*",
5050
"@latticexyz/schema-type": "workspace:*",
5151
"@latticexyz/store": "workspace:*",
52+
"@latticexyz/store-sync": "workspace:*",
5253
"@latticexyz/utils": "workspace:*",
5354
"@latticexyz/world": "workspace:*",
5455
"@latticexyz/world-module-metadata": "workspace:*",

packages/cli/src/commands/dev-contracts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const commandModule: CommandModule<typeof devOptions, InferredOptionTypes<typeof
9292
worldAddress,
9393
salt: "0x",
9494
kms: undefined,
95+
indexerUrl: undefined,
9596
});
9697
worldAddress = deploy.address;
9798
// if there were changes while we were deploying, trigger it again

packages/cli/src/commands/pull.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import chalk from "chalk";
55
import { WriteFileExistsError, pull } from "../pull/pull";
66
import path from "node:path";
77
import { build } from "../build";
8+
import { getChainId } from "viem/actions";
9+
import { defaultChains } from "../defaultChains";
810

911
const options = {
1012
worldAddress: { type: "string", required: true, desc: "Remote world address" },
@@ -18,6 +20,11 @@ const options = {
1820
type: "boolean",
1921
desc: "Replace existing files and directories with data from remote world.",
2022
},
23+
indexerUrl: {
24+
type: "string",
25+
desc: "The indexer URL to pull from.",
26+
required: false,
27+
},
2128
} as const;
2229

2330
type Options = InferredOptionTypes<typeof options>;
@@ -44,6 +51,8 @@ const commandModule: CommandModule<Options, Options> = {
4451
: undefined,
4552
}),
4653
});
54+
const chainId = await getChainId(client);
55+
const indexerUrl = opts.indexerUrl ?? defaultChains.find((chain) => chain.id === chainId)?.indexerUrl;
4756

4857
console.log(chalk.bgBlue(chalk.whiteBright(`\n Pulling MUD config from world at ${opts.worldAddress} \n`)));
4958
const rootDir = process.cwd();
@@ -53,6 +62,8 @@ const commandModule: CommandModule<Options, Options> = {
5362
rootDir,
5463
client,
5564
worldAddress: opts.worldAddress as Address,
65+
indexerUrl,
66+
chainId,
5667
replace: opts.replace,
5768
});
5869
await build({ rootDir, config, foundryProfile: profile });

packages/cli/src/defaultChains.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { redstone, garnet, rhodolite } from "@latticexyz/common/chains";
2+
3+
export const defaultChains = [redstone, garnet, rhodolite];

packages/cli/src/deploy/common.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Abi, Address, Hex, padHex } from "viem";
1+
import { Abi, Account, Address, Chain, Client, Hex, Transport, padHex } from "viem";
22
import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json" assert { type: "json" };
33
import { helloStoreEvent } from "@latticexyz/store";
44
import { helloWorldEvent } from "@latticexyz/world";
@@ -119,3 +119,10 @@ export type Module = DeterministicContract & {
119119
*/
120120
readonly optional?: boolean;
121121
};
122+
123+
export type CommonDeployOptions = {
124+
readonly client: Client<Transport, Chain | undefined, Account>;
125+
readonly worldDeploy: WorldDeploy;
126+
readonly indexerUrl?: string;
127+
readonly chainId?: number;
128+
};

packages/cli/src/deploy/deploy.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
import { Account, Address, Chain, Client, Hex, Transport, stringToHex } from "viem";
1+
import { Address, Hex, stringToHex } from "viem";
22
import { ensureDeployer } from "./ensureDeployer";
33
import { deployWorld } from "./deployWorld";
44
import { ensureTables } from "./ensureTables";
5-
import { Library, Module, System, WorldDeploy, supportedStoreVersions, supportedWorldVersions } from "./common";
5+
import {
6+
CommonDeployOptions,
7+
Library,
8+
Module,
9+
System,
10+
WorldDeploy,
11+
supportedStoreVersions,
12+
supportedWorldVersions,
13+
} from "./common";
614
import { ensureSystems } from "./ensureSystems";
715
import { getWorldDeploy } from "./getWorldDeploy";
816
import { ensureFunctions } from "./ensureFunctions";
@@ -23,7 +31,6 @@ import { getLibraryMap } from "./getLibraryMap";
2331

2432
type DeployOptions = {
2533
config: World;
26-
client: Client<Transport, Chain | undefined, Account>;
2734
tables: readonly Table[];
2835
systems: readonly System[];
2936
libraries: readonly Library[];
@@ -39,7 +46,7 @@ type DeployOptions = {
3946
*/
4047
deployerAddress?: Hex;
4148
withWorldProxy?: boolean;
42-
};
49+
} & Omit<CommonDeployOptions, "worldDeploy">;
4350

4451
/**
4552
* Given a viem client and MUD config, we attempt to introspect the world
@@ -58,6 +65,8 @@ export async function deploy({
5865
salt,
5966
worldAddress: existingWorldAddress,
6067
deployerAddress: initialDeployerAddress,
68+
indexerUrl,
69+
chainId,
6170
}: DeployOptions): Promise<WorldDeploy> {
6271
const deployerAddress = initialDeployerAddress ?? (await ensureDeployer(client));
6372

@@ -77,6 +86,13 @@ export async function deploy({
7786
config.deploy.upgradeableWorldImplementation,
7887
);
7988

89+
const commonDeployOptions = {
90+
client,
91+
indexerUrl,
92+
chainId,
93+
worldDeploy,
94+
} satisfies CommonDeployOptions;
95+
8096
if (!supportedStoreVersions.includes(worldDeploy.storeVersion)) {
8197
throw new Error(`Unsupported Store version: ${worldDeploy.storeVersion}`);
8298
}
@@ -86,7 +102,7 @@ export async function deploy({
86102

87103
const libraryMap = getLibraryMap(libraries);
88104
await ensureContractsDeployed({
89-
client,
105+
...commonDeployOptions,
90106
deployerAddress,
91107
contracts: [
92108
...libraries.map((library) => ({
@@ -108,24 +124,21 @@ export async function deploy({
108124
});
109125

110126
const namespaceTxs = await ensureNamespaceOwner({
111-
client,
112-
worldDeploy,
127+
...commonDeployOptions,
113128
resourceIds: [...tables.map(({ tableId }) => tableId), ...systems.map(({ systemId }) => systemId)],
114129
});
115130
// Wait for namespaces to be available, otherwise referencing them below may fail.
116131
// This is only here because OPStack chains don't let us estimate gas with pending block tag.
117132
await waitForTransactions({ client, hashes: namespaceTxs, debugLabel: "namespace registrations" });
118133

119134
const tableTxs = await ensureTables({
120-
client,
121-
worldDeploy,
135+
...commonDeployOptions,
122136
tables,
123137
});
124138
const systemTxs = await ensureSystems({
125-
client,
139+
...commonDeployOptions,
126140
deployerAddress,
127141
libraryMap,
128-
worldDeploy,
129142
systems,
130143
});
131144
// Wait for tables and systems to be available, otherwise referencing their resource IDs below may fail.
@@ -137,15 +150,13 @@ export async function deploy({
137150
});
138151

139152
const functionTxs = await ensureFunctions({
140-
client,
141-
worldDeploy,
153+
...commonDeployOptions,
142154
functions: systems.flatMap((system) => system.worldFunctions),
143155
});
144156
const moduleTxs = await ensureModules({
145-
client,
157+
...commonDeployOptions,
146158
deployerAddress,
147159
libraryMap,
148-
worldDeploy,
149160
modules,
150161
});
151162

@@ -174,10 +185,9 @@ export async function deploy({
174185
]);
175186

176187
const tagTxs = await ensureResourceTags({
177-
client,
188+
...commonDeployOptions,
178189
deployerAddress,
179190
libraryMap,
180-
worldDeploy,
181191
tags: [...namespaceTags, ...tableTags, ...systemTags],
182192
valueToHex: stringToHex,
183193
});

packages/cli/src/deploy/ensureFunctions.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
1-
import { Client, Transport, Chain, Account, Hex } from "viem";
1+
import { Hex } from "viem";
22
import { hexToResource, writeContract } from "@latticexyz/common";
3-
import { getFunctions } from "@latticexyz/world/internal";
4-
import { WorldDeploy, WorldFunction, worldAbi } from "./common";
3+
import { getFunctions } from "@latticexyz/store-sync/world";
4+
import { CommonDeployOptions, WorldFunction, worldAbi } from "./common";
55
import { debug } from "./debug";
66
import pRetry from "p-retry";
77

88
export async function ensureFunctions({
99
client,
1010
worldDeploy,
1111
functions,
12-
}: {
13-
readonly client: Client<Transport, Chain | undefined, Account>;
14-
readonly worldDeploy: WorldDeploy;
12+
indexerUrl,
13+
chainId,
14+
}: CommonDeployOptions & {
1515
readonly functions: readonly WorldFunction[];
1616
}): Promise<readonly Hex[]> {
1717
const worldFunctions = await getFunctions({
1818
client,
1919
worldAddress: worldDeploy.address,
2020
fromBlock: worldDeploy.deployBlock,
2121
toBlock: worldDeploy.stateBlock,
22+
indexerUrl,
23+
chainId,
2224
});
2325
const worldSelectorToFunction = Object.fromEntries(worldFunctions.map((func) => [func.selector, func]));
2426

0 commit comments

Comments
 (0)