@latticexyz/cli 2.0.0-main-711f6e2a → 2.0.0-march-19-skystrife-playtest-f0a343b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/commands-RZOPG5RM.js +27 -0
  2. package/dist/commands-RZOPG5RM.js.map +1 -0
  3. package/dist/mud.js +1 -1
  4. package/dist/mud.js.map +1 -1
  5. package/package.json +15 -17
  6. package/src/commands/deploy.ts +1 -1
  7. package/src/commands/dev-contracts.ts +1 -4
  8. package/src/commands/set-version.ts +1 -1
  9. package/src/commands/trace.ts +1 -1
  10. package/src/deploy/assertNamespaceOwner.ts +42 -0
  11. package/src/deploy/common.ts +2 -44
  12. package/src/deploy/configToTables.ts +3 -5
  13. package/src/deploy/create2/README.md +0 -4
  14. package/src/deploy/create2/deployment.json +1 -2
  15. package/src/deploy/deploy.ts +18 -43
  16. package/src/deploy/deployWorld.ts +4 -9
  17. package/src/deploy/ensureContract.ts +7 -12
  18. package/src/deploy/ensureContractsDeployed.ts +1 -9
  19. package/src/deploy/ensureDeployer.ts +22 -61
  20. package/src/deploy/ensureFunctions.ts +5 -5
  21. package/src/deploy/ensureModules.ts +10 -16
  22. package/src/deploy/ensureSystems.ts +83 -108
  23. package/src/deploy/ensureTables.ts +8 -7
  24. package/src/deploy/ensureWorldFactory.ts +37 -95
  25. package/src/deploy/getFunctions.ts +4 -4
  26. package/src/deploy/getResourceAccess.ts +2 -2
  27. package/src/deploy/getSystems.ts +7 -6
  28. package/src/deploy/getTables.ts +1 -1
  29. package/src/deploy/logsToWorldDeploy.ts +1 -1
  30. package/src/deploy/resolveConfig.ts +55 -52
  31. package/src/deploy/resourceLabel.ts +3 -0
  32. package/src/mud.ts +1 -1
  33. package/src/mudPackages.ts +1 -1
  34. package/src/runDeploy.ts +7 -34
  35. package/src/utils/{defaultModuleContracts.ts → modules/constants.ts} +0 -4
  36. package/src/utils/printMUD.ts +1 -1
  37. package/src/utils/{getContractData.ts → utils/getContractData.ts} +5 -11
  38. package/src/utils/{postDeploy.ts → utils/postDeploy.ts} +2 -2
  39. package/dist/commands-22M65L4E.js +0 -36
  40. package/dist/commands-22M65L4E.js.map +0 -1
  41. package/src/deploy/createPrepareDeploy.ts +0 -28
  42. package/src/deploy/ensureNamespaceOwner.ts +0 -71
  43. package/src/deploy/findLibraries.ts +0 -36
  44. package/src/deploy/orderByDependencies.ts +0 -12
  45. package/src/utils/findPlaceholders.ts +0 -27
@@ -1,18 +1,25 @@
1
- import path from "path";
2
1
  import { resolveWorldConfig } from "@latticexyz/world";
3
- import { Config, ConfigInput, Library, Module, System, WorldFunction } from "./common";
4
- import { resourceToHex } from "@latticexyz/common";
2
+ import { Config, ConfigInput, WorldFunction, salt } from "./common";
3
+ import { resourceToHex, hexToResource } from "@latticexyz/common";
5
4
  import { resolveWithContext } from "@latticexyz/config";
6
5
  import { encodeField } from "@latticexyz/protocol-parser";
7
6
  import { SchemaAbiType, SchemaAbiTypeToPrimitiveType } from "@latticexyz/schema-type";
8
- import { Hex, hexToBytes, bytesToHex, toFunctionSelector, toFunctionSignature } from "viem";
7
+ import {
8
+ getFunctionSelector,
9
+ Hex,
10
+ getCreate2Address,
11
+ getAddress,
12
+ hexToBytes,
13
+ Abi,
14
+ bytesToHex,
15
+ getFunctionSignature,
16
+ } from "viem";
9
17
  import { getExistingContracts } from "../utils/getExistingContracts";
10
- import { defaultModuleContracts } from "../utils/defaultModuleContracts";
11
- import { getContractData } from "../utils/getContractData";
18
+ import { defaultModuleContracts } from "../utils/modules/constants";
19
+ import { getContractData } from "../utils/utils/getContractData";
12
20
  import { configToTables } from "./configToTables";
13
- import { groupBy } from "@latticexyz/common/utils";
14
- import { findLibraries } from "./findLibraries";
15
- import { createPrepareDeploy } from "./createPrepareDeploy";
21
+ import { deployer } from "./ensureDeployer";
22
+ import { resourceLabel } from "./resourceLabel";
16
23
 
17
24
  // TODO: this should be replaced by https://github.com/latticexyz/mud/issues/1668
18
25
 
@@ -25,47 +32,35 @@ export function resolveConfig<config extends ConfigInput>({
25
32
  forgeSourceDir: string;
26
33
  forgeOutDir: string;
27
34
  }): Config<config> {
28
- const libraries = findLibraries(forgeOutDir).map((library): Library => {
29
- // foundry/solc flattens artifacts, so we just use the path basename
30
- const contractData = getContractData(path.basename(library.path), library.name, forgeOutDir);
31
- return {
32
- path: library.path,
33
- name: library.name,
34
- abi: contractData.abi,
35
- prepareDeploy: createPrepareDeploy(contractData.bytecode, contractData.placeholders),
36
- deployedBytecodeSize: contractData.deployedBytecodeSize,
37
- };
38
- });
39
-
40
35
  const tables = configToTables(config);
41
36
 
42
37
  // TODO: should the config parser/loader help with resolving systems?
43
38
  const contractNames = getExistingContracts(forgeSourceDir).map(({ basename }) => basename);
44
39
  const resolvedConfig = resolveWorldConfig(config, contractNames);
45
- const baseSystemContractData = getContractData("System.sol", "System", forgeOutDir);
40
+ const baseSystemContractData = getContractData("System", forgeOutDir);
46
41
  const baseSystemFunctions = baseSystemContractData.abi
47
42
  .filter((item): item is typeof item & { type: "function" } => item.type === "function")
48
- .map(toFunctionSignature);
43
+ .map(getFunctionSignature);
49
44
 
50
- const systems = Object.entries(resolvedConfig.systems).map(([systemName, system]): System => {
45
+ const systems = Object.entries(resolvedConfig.systems).map(([systemName, system]) => {
51
46
  const namespace = config.namespace;
52
47
  const name = system.name;
53
48
  const systemId = resourceToHex({ type: "system", namespace, name });
54
- const contractData = getContractData(`${systemName}.sol`, systemName, forgeOutDir);
49
+ const contractData = getContractData(systemName, forgeOutDir);
55
50
 
56
51
  const systemFunctions = contractData.abi
57
52
  .filter((item): item is typeof item & { type: "function" } => item.type === "function")
58
- .map(toFunctionSignature)
53
+ .map(getFunctionSignature)
59
54
  .filter((sig) => !baseSystemFunctions.includes(sig))
60
55
  .map((sig): WorldFunction => {
61
56
  // TODO: figure out how to not duplicate contract behavior (https://github.com/latticexyz/mud/issues/1708)
62
- const worldSignature = namespace === "" ? sig : `${namespace}__${sig}`;
57
+ const worldSignature = namespace === "" ? sig : `${namespace}_${name}_${sig}`;
63
58
  return {
64
59
  signature: worldSignature,
65
- selector: toFunctionSelector(worldSignature),
60
+ selector: getFunctionSelector(worldSignature),
66
61
  systemId,
67
62
  systemFunctionSignature: sig,
68
- systemFunctionSelector: toFunctionSelector(sig),
63
+ systemFunctionSelector: getFunctionSelector(sig),
69
64
  };
70
65
  });
71
66
 
@@ -76,29 +71,37 @@ export function resolveConfig<config extends ConfigInput>({
76
71
  allowAll: system.openAccess,
77
72
  allowedAddresses: system.accessListAddresses as Hex[],
78
73
  allowedSystemIds: system.accessListSystems.map((name) =>
79
- resourceToHex({ type: "system", namespace, name: resolvedConfig.systems[name].name }),
74
+ resourceToHex({ type: "system", namespace, name: resolvedConfig.systems[name].name })
80
75
  ),
81
- prepareDeploy: createPrepareDeploy(contractData.bytecode, contractData.placeholders),
76
+ address: getCreate2Address({ from: deployer, bytecode: contractData.bytecode, salt }),
77
+ bytecode: contractData.bytecode,
82
78
  deployedBytecodeSize: contractData.deployedBytecodeSize,
83
79
  abi: contractData.abi,
84
80
  functions: systemFunctions,
85
81
  };
86
82
  });
87
83
 
88
- // Check for overlapping system IDs (since names get truncated when turning into IDs)
89
- // TODO: move this into the world config resolve step once it resolves system IDs
90
- const systemsById = groupBy(systems, (system) => system.systemId);
91
- const overlappingSystems = Array.from(systemsById.values())
92
- .filter((matches) => matches.length > 1)
93
- .flat();
94
- if (overlappingSystems.length) {
95
- const names = overlappingSystems.map((system) => system.name);
96
- throw new Error(
97
- `Found systems with overlapping system ID: ${names.join(
98
- ", ",
99
- )}.\n\nSystem IDs are generated from the first 16 bytes of the name, so you may need to rename them to avoid the overlap.`,
100
- );
101
- }
84
+ // resolve allowedSystemIds
85
+ // TODO: resolve this at deploy time so we can allow for arbitrary system IDs registered in the world as the source-of-truth rather than config
86
+ const systemsWithAccess = systems.map(({ allowedAddresses, allowedSystemIds, ...system }) => {
87
+ const allowedSystemAddresses = allowedSystemIds.map((systemId) => {
88
+ const targetSystem = systems.find((s) => s.systemId === systemId);
89
+ if (!targetSystem) {
90
+ throw new Error(
91
+ `System ${resourceLabel(system)} wanted access to ${resourceLabel(
92
+ hexToResource(systemId)
93
+ )}, but it wasn't found in the config.`
94
+ );
95
+ }
96
+ return targetSystem.address;
97
+ });
98
+ return {
99
+ ...system,
100
+ allowedAddresses: Array.from(
101
+ new Set([...allowedAddresses, ...allowedSystemAddresses].map((addr) => getAddress(addr)))
102
+ ),
103
+ };
104
+ });
102
105
 
103
106
  // ugh (https://github.com/latticexyz/mud/issues/1668)
104
107
  const resolveContext = {
@@ -110,16 +113,16 @@ export function resolveConfig<config extends ConfigInput>({
110
113
  type: table.offchainOnly ? "offchainTable" : "table",
111
114
  namespace: config.namespace,
112
115
  name: table.name,
113
- }),
116
+ })
114
117
  ),
115
- ]),
118
+ ])
116
119
  ),
117
120
  };
118
121
 
119
- const modules = config.modules.map((mod): Module => {
122
+ const modules = config.modules.map((mod) => {
120
123
  const contractData =
121
124
  defaultModuleContracts.find((defaultMod) => defaultMod.name === mod.name) ??
122
- getContractData(`${mod.name}.sol`, mod.name, forgeOutDir);
125
+ getContractData(mod.name, forgeOutDir);
123
126
  const installArgs = mod.args
124
127
  .map((arg) => resolveWithContext(arg, resolveContext))
125
128
  .map((arg) => {
@@ -133,7 +136,8 @@ export function resolveConfig<config extends ConfigInput>({
133
136
  name: mod.name,
134
137
  installAsRoot: mod.root,
135
138
  installData: installArgs.length === 0 ? "0x" : installArgs[0],
136
- prepareDeploy: createPrepareDeploy(contractData.bytecode, contractData.placeholders),
139
+ address: getCreate2Address({ from: deployer, bytecode: contractData.bytecode, salt }),
140
+ bytecode: contractData.bytecode,
137
141
  deployedBytecodeSize: contractData.deployedBytecodeSize,
138
142
  abi: contractData.abi,
139
143
  };
@@ -141,8 +145,7 @@ export function resolveConfig<config extends ConfigInput>({
141
145
 
142
146
  return {
143
147
  tables,
144
- systems,
148
+ systems: systemsWithAccess,
145
149
  modules,
146
- libraries,
147
150
  };
148
151
  }
@@ -0,0 +1,3 @@
1
+ export function resourceLabel({ namespace, name }: { readonly namespace: string; readonly name: string }): string {
2
+ return `${namespace}:${name}`;
3
+ }
package/src/mud.ts CHANGED
@@ -26,7 +26,7 @@ async function run() {
26
26
  console.error(chalk.red(msg));
27
27
  if (msg.includes("Missing required argument")) {
28
28
  console.log(
29
- chalk.yellow(`Run 'pnpm mud ${process.argv[2]} --help' for a list of available and required arguments.`),
29
+ chalk.yellow(`Run 'pnpm mud ${process.argv[2]} --help' for a list of available and required arguments.`)
30
30
  );
31
31
  }
32
32
  console.log("");
@@ -13,7 +13,7 @@ function parseEnv(): z.infer<typeof envSchema> {
13
13
  });
14
14
  } catch (error) {
15
15
  if (error instanceof ZodError) {
16
- const { ...invalidEnvVars } = error.format();
16
+ const { _errors, ...invalidEnvVars } = error.format();
17
17
  console.error(`\nMissing or invalid environment variables:\n\n ${Object.keys(invalidEnvVars).join("\n ")}\n`);
18
18
  process.exit(1);
19
19
  }
package/src/runDeploy.ts CHANGED
@@ -2,7 +2,7 @@ import path from "node:path";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { InferredOptionTypes, Options } from "yargs";
4
4
  import { deploy } from "./deploy/deploy";
5
- import { createWalletClient, http, Hex, isHex } from "viem";
5
+ import { createWalletClient, http, Hex } from "viem";
6
6
  import { privateKeyToAccount } from "viem/accounts";
7
7
  import { loadConfig } from "@latticexyz/config/node";
8
8
  import { StoreConfig } from "@latticexyz/store";
@@ -12,7 +12,7 @@ import chalk from "chalk";
12
12
  import { MUDError } from "@latticexyz/common/errors";
13
13
  import { resolveConfig } from "./deploy/resolveConfig";
14
14
  import { getChainId } from "viem/actions";
15
- import { postDeploy } from "./utils/postDeploy";
15
+ import { postDeploy } from "./utils/utils/postDeploy";
16
16
  import { WorldDeploy } from "./deploy/common";
17
17
  import { build } from "./build";
18
18
 
@@ -22,14 +22,6 @@ export const deployOptions = {
22
22
  profile: { type: "string", desc: "The foundry profile to use" },
23
23
  saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true },
24
24
  rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" },
25
- rpcBatch: {
26
- type: "boolean",
27
- desc: "Enable batch processing of RPC requests in viem client (defaults to batch size of 100 and wait of 1s)",
28
- },
29
- deployerAddress: {
30
- type: "string",
31
- desc: "Deploy using an existing deterministic deployer (https://github.com/Arachnid/deterministic-deployment-proxy)",
32
- },
33
25
  worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" },
34
26
  srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." },
35
27
  skipBuild: { type: "boolean", desc: "Skip rebuilding the contracts before deploying" },
@@ -37,10 +29,6 @@ export const deployOptions = {
37
29
  type: "boolean",
38
30
  desc: "Always run PostDeploy.s.sol after each deploy (including during upgrades). By default, PostDeploy.s.sol is only run once after a new world is deployed.",
39
31
  },
40
- salt: {
41
- type: "string",
42
- desc: "The deployment salt to use. Defaults to a random salt.",
43
- },
44
32
  } as const satisfies Record<string, Options>;
45
33
 
46
34
  export type DeployOptions = InferredOptionTypes<typeof deployOptions>;
@@ -50,11 +38,6 @@ export type DeployOptions = InferredOptionTypes<typeof deployOptions>;
50
38
  * This is used by the deploy, test, and dev-contracts CLI commands.
51
39
  */
52
40
  export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
53
- const salt = opts.salt;
54
- if (salt != null && !isHex(salt)) {
55
- throw new MUDError("Expected hex string for salt");
56
- }
57
-
58
41
  const profile = opts.profile ?? process.env.FOUNDRY_PROFILE;
59
42
 
60
43
  const config = (await loadConfig(opts.configPath)) as StoreConfig & WorldConfig;
@@ -68,8 +51,8 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
68
51
  const rpc = opts.rpc ?? (await getRpcUrl(profile));
69
52
  console.log(
70
53
  chalk.bgBlue(
71
- chalk.whiteBright(`\n Deploying MUD contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`),
72
- ),
54
+ chalk.whiteBright(`\n Deploying MUD contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`)
55
+ )
73
56
  );
74
57
 
75
58
  // Run build
@@ -82,30 +65,20 @@ export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
82
65
  throw new MUDError(
83
66
  `Missing PRIVATE_KEY environment variable.
84
67
  Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
85
- in your contracts directory to use the default anvil private key.`,
68
+ in your contracts directory to use the default anvil private key.`
86
69
  );
87
70
  }
88
71
 
89
72
  const resolvedConfig = resolveConfig({ config, forgeSourceDir: srcDir, forgeOutDir: outDir });
90
73
 
91
74
  const client = createWalletClient({
92
- transport: http(rpc, {
93
- batch: opts.rpcBatch
94
- ? {
95
- batchSize: 100,
96
- wait: 1000,
97
- }
98
- : undefined,
99
- }),
75
+ transport: http(rpc),
100
76
  account: privateKeyToAccount(privateKey),
101
77
  });
102
-
103
78
  console.log("Deploying from", client.account.address);
104
79
 
105
80
  const startTime = Date.now();
106
81
  const worldDeploy = await deploy({
107
- deployerAddress: opts.deployerAddress as Hex | undefined,
108
- salt,
109
82
  worldAddress: opts.worldAddress as Hex | undefined,
110
83
  client,
111
84
  config: resolvedConfig,
@@ -138,7 +111,7 @@ in your contracts directory to use the default anvil private key.`,
138
111
  writeFileSync(config.worldsFile, JSON.stringify(deploys, null, 2));
139
112
 
140
113
  console.log(
141
- chalk.bgGreen(chalk.whiteBright(`\n Deployment result (written to ${config.worldsFile} and ${deploysDir}): \n`)),
114
+ chalk.bgGreen(chalk.whiteBright(`\n Deployment result (written to ${config.worldsFile} and ${deploysDir}): \n`))
142
115
  );
143
116
  }
144
117
 
@@ -2,7 +2,6 @@ import KeysWithValueModuleData from "@latticexyz/world-modules/out/KeysWithValue
2
2
  import KeysInTableModuleData from "@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json" assert { type: "json" };
3
3
  import UniqueEntityModuleData from "@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json" assert { type: "json" };
4
4
  import { Abi, Hex, size } from "viem";
5
- import { findPlaceholders } from "./findPlaceholders";
6
5
 
7
6
  // These modules are always deployed
8
7
  export const defaultModuleContracts = [
@@ -10,21 +9,18 @@ export const defaultModuleContracts = [
10
9
  name: "KeysWithValueModule",
11
10
  abi: KeysWithValueModuleData.abi as Abi,
12
11
  bytecode: KeysWithValueModuleData.bytecode.object as Hex,
13
- placeholders: findPlaceholders(KeysWithValueModuleData.bytecode.linkReferences),
14
12
  deployedBytecodeSize: size(KeysWithValueModuleData.deployedBytecode.object as Hex),
15
13
  },
16
14
  {
17
15
  name: "KeysInTableModule",
18
16
  abi: KeysInTableModuleData.abi as Abi,
19
17
  bytecode: KeysInTableModuleData.bytecode.object as Hex,
20
- placeholders: findPlaceholders(KeysInTableModuleData.bytecode.linkReferences),
21
18
  deployedBytecodeSize: size(KeysInTableModuleData.deployedBytecode.object as Hex),
22
19
  },
23
20
  {
24
21
  name: "UniqueEntityModule",
25
22
  abi: UniqueEntityModuleData.abi as Abi,
26
23
  bytecode: UniqueEntityModuleData.bytecode.object as Hex,
27
- placeholders: findPlaceholders(UniqueEntityModuleData.bytecode.linkReferences),
28
24
  deployedBytecodeSize: size(UniqueEntityModuleData.deployedBytecode.object as Hex),
29
25
  },
30
26
  ];
@@ -9,6 +9,6 @@ export function printMUD() {
9
9
  | :\\/: || :\\/: || (__) |
10
10
  | '--'M|| '--'U|| '--'D|
11
11
  '------''------''------'
12
- `),
12
+ `)
13
13
  );
14
14
  }
@@ -2,24 +2,20 @@ import { readFileSync } from "fs";
2
2
  import path from "path";
3
3
  import { MUDError } from "@latticexyz/common/errors";
4
4
  import { Abi, Hex, size } from "viem";
5
- import { LibraryPlaceholder } from "../deploy/common";
6
- import { findPlaceholders } from "./findPlaceholders";
7
5
 
8
6
  /**
9
7
  * Load the contract's abi and bytecode from the file system
10
8
  * @param contractName: Name of the contract to load
11
9
  */
12
10
  export function getContractData(
13
- filename: string,
14
11
  contractName: string,
15
- forgeOutDirectory: string,
16
- ): { bytecode: Hex; placeholders: readonly LibraryPlaceholder[]; abi: Abi; deployedBytecodeSize: number } {
17
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ forgeOutDirectory: string
13
+ ): { bytecode: Hex; abi: Abi; deployedBytecodeSize: number } {
18
14
  let data: any;
19
- const contractDataPath = path.join(forgeOutDirectory, filename, contractName + ".json");
15
+ const contractDataPath = path.join(forgeOutDirectory, contractName + ".sol", contractName + ".json");
20
16
  try {
21
17
  data = JSON.parse(readFileSync(contractDataPath, "utf8"));
22
- } catch (error) {
18
+ } catch (error: any) {
23
19
  throw new MUDError(`Error reading file at ${contractDataPath}`);
24
20
  }
25
21
 
@@ -32,7 +28,5 @@ export function getContractData(
32
28
  const abi = data?.abi;
33
29
  if (!abi) throw new MUDError(`No ABI found in ${contractDataPath}`);
34
30
 
35
- const placeholders = findPlaceholders(data?.bytecode?.linkReferences ?? {});
36
-
37
- return { abi, bytecode, placeholders, deployedBytecodeSize: size(deployedBytecode as Hex) };
31
+ return { abi, bytecode, deployedBytecodeSize: size(deployedBytecode as Hex) };
38
32
  }
@@ -7,7 +7,7 @@ export async function postDeploy(
7
7
  postDeployScript: string,
8
8
  worldAddress: string,
9
9
  rpc: string,
10
- profile: string | undefined,
10
+ profile: string | undefined
11
11
  ): Promise<void> {
12
12
  // Execute postDeploy forge script
13
13
  const postDeployPath = path.join(await getScriptDirectory(), postDeployScript + ".s.sol");
@@ -17,7 +17,7 @@ export async function postDeploy(
17
17
  ["script", postDeployScript, "--sig", "run(address)", worldAddress, "--broadcast", "--rpc-url", rpc, "-vvv"],
18
18
  {
19
19
  profile: profile,
20
- },
20
+ }
21
21
  );
22
22
  } else {
23
23
  console.log(`No script at ${postDeployPath}, skipping post deploy hook`);
@@ -1,36 +0,0 @@
1
- import{a as J}from"./chunk-22IIKR4S.js";import ps from"@latticexyz/gas-report";import fs from"@latticexyz/abi-ts";import{loadConfig as Jo}from"@latticexyz/config/node";import{getSrcDirectory as qo}from"@latticexyz/common/foundry";import{existsSync as Wo,readFileSync as Ho,writeFileSync as Eo}from"node:fs";import ae from"node:path";import{tablegen as No}from"@latticexyz/store/codegen";import{worldgen as zo}from"@latticexyz/world/node";import{forge as Lo,getForgeConfig as Uo,getRemappings as Vo}from"@latticexyz/common/foundry";import Mo from"glob";import{basename as Fo}from"path";function I(e){return Mo.sync(`${e}/**/*.sol`).map(o=>({path:o,basename:Fo(o,".sol")}))}import he from"debug";var M=he("mud:cli"),$o=he("mud:cli");M.log=console.debug.bind(console);$o.log=console.error.bind(console);import{execa as _o}from"execa";var Ko=M.extend("runDeploy");async function q({config:e,srcDir:o,foundryProfile:r=process.env.FOUNDRY_PROFILE}){let t=ae.join(o,e.codegenDirectory),n=await Vo(r);await Promise.all([No(e,t,n),zo(e,I(o),t)]);let s=await Uo(r);if(s.cache){let i=ae.join(s.cache_path,"solidity-files-cache.json");if(Wo(i)){Ko("Unsetting cached content hash of IWorld.sol to force it to regenerate");let a=JSON.parse(Ho(i,"utf8")),m=ae.join(t,"world","IWorld.sol");a.files[m].contentHash="",Eo(i,JSON.stringify(a,null,2))}}await Lo(["build"],{profile:r}),await _o("mud",["abi-ts"],{stdio:"inherit"})}var Yo={command:"build",describe:"Build contracts and generate MUD artifacts (table libraries, world interface, ABI)",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"},profile:{type:"string",desc:"The foundry profile to use"}})},async handler({configPath:e,profile:o}){let r=await Jo(e),t=await qo();await q({config:r,srcDir:t,foundryProfile:o}),process.exit(0)}},we=Yo;import{rmSync as Go}from"fs";import{homedir as Zo}from"os";import Qo from"path";import{execa as Xo}from"execa";var et={command:"devnode",describe:"Start a local Ethereum node for development",builder(e){return e.options({blocktime:{type:"number",default:1,decs:"Interval in which new blocks are produced"}})},async handler({blocktime:e}){console.log("Clearing devnode history");let o=Zo();Go(Qo.join(o,".foundry","anvil","tmp"),{recursive:!0,force:!0});let r=["-b",String(e),"--block-base-fee-per-gas","0"];console.log(`Running: anvil ${r.join(" ")}`);let t=Xo("anvil",r,{stdio:["inherit","inherit","inherit"]});process.on("SIGINT",()=>{console.log(`
2
- gracefully shutting down from SIGINT (Crtl-C)`),t.kill(),process.exit()}),await t}},xe=et;import{FaucetServiceDefinition as ot}from"@latticexyz/services/faucet";import{createChannel as tt,createClient as rt}from"nice-grpc-web";import Se from"chalk";import{NodeHttpTransport as nt}from"@improbable-eng/grpc-web-node-http-transport";function st(e){return rt(ot,tt(e,nt()))}var at={command:"faucet",describe:"Interact with a MUD faucet",builder(e){return e.options({dripDev:{type:"boolean",desc:"Request a drip from the dev endpoint (requires faucet to have dev mode enabled)",default:!0},faucetUrl:{type:"string",desc:"URL of the MUD faucet",default:"https://faucet.testnet-mud-services.linfra.xyz"},address:{type:"string",desc:"Ethereum address to fund",required:!0}})},async handler({dripDev:e,faucetUrl:o,address:r}){let t=st(o);e&&(console.log(Se.yellow("Dripping to",r)),await t.dripDev({address:r}),console.log(Se.yellow("Success"))),process.exit(0)}},Ce=at;var it={command:"hello <name>",describe:"Greet <name> with Hello",builder(e){return e.options({upper:{type:"boolean"}}).positional("name",{type:"string",demandOption:!0})},handler({name:e}){let o=`Gm, ${e}!`;console.log(o),process.exit(0)}},De=it;import ct from"path";import{loadConfig as dt}from"@latticexyz/config/node";import{tablegen as lt}from"@latticexyz/store/codegen";import{getRemappings as mt,getSrcDirectory as pt}from"@latticexyz/common/foundry";var ft={command:"tablegen",describe:"Autogenerate MUD Store table libraries based on the config file",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"}})},async handler({configPath:e}){let o=await dt(e),r=await pt(),t=await mt();await lt(o,ct.join(r,o.codegenDirectory),t),process.exit(0)}},ve=ft;import fe from"node:path";import{existsSync as Xr,mkdirSync as en,readFileSync as on,writeFileSync as ye}from"node:fs";import{getBalance as gt,getBytecode as bt,sendRawTransaction as ht,sendTransaction as Te,waitForTransactionReceipt as Ae}from"viem/actions";var A={gasPrice:1e11,gasLimit:1e5,signerAddress:"3fab184622dc19b6109349b94811493bf2a45362",transaction:"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",address:"4e59b44847b379578588920ca78fbf26c0b4956c",bytecode:"604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"};var l=M.extend("deploy"),ut=M.extend("deploy");l.log=console.debug.bind(console);ut.log=console.error.bind(console);var R=`0x${A.address}`,ke=`0x${A.bytecode}`;async function Ie(e){let o=await bt(e,{address:R});if(o)return l("found CREATE2 deployer at",R),o!==ke&&console.warn(`
3
- \u26A0\uFE0F Bytecode for deployer at ${R} did not match the expected CREATE2 bytecode. You may have unexpected results.
4
- `),R;let r=BigInt(A.gasLimit)*BigInt(A.gasPrice),t=await gt(e,{address:`0x${A.signerAddress}`}),n=r-t;if(n>0){l("sending gas for CREATE2 deployer to signer at",A.signerAddress);let a=await Te(e,{chain:e.chain??null,to:`0x${A.signerAddress}`,value:n}),m=await Ae(e,{hash:a});if(m.status!=="success")throw console.error("failed to send gas to deployer signer",m),new Error("failed to send gas to deployer signer")}l("deploying CREATE2 deployer at",R);let s=await ht(e,{serializedTransaction:`0x${A.transaction}`}).catch(a=>{if(String(a).includes("only replay-protected (EIP-155) transactions allowed over RPC"))return console.warn(`
5
- \u26A0\uFE0F Your chain or RPC does not allow for non EIP-155 signed transactions, so your deploys will not be determinstic and contract addresses may change between deploys.
6
-
7
- We recommend running your chain's node with \`--rpc.allow-unprotected-txs\` to enable determinstic deployments.
8
- `),l("deploying CREATE2 deployer"),Te(e,{chain:e.chain??null,data:ke});throw a}),i=await Ae(e,{hash:s});if(!i.contractAddress)throw new Error("Deploy receipt did not have contract address, was the deployer not deployed?");return i.contractAddress!==R&&console.warn(`
9
- \u26A0\uFE0F CREATE2 deployer created at ${i.contractAddress} does not match the CREATE2 determinstic deployer we expected (${R})`),i.contractAddress}import{waitForTransactionReceipt as zt}from"viem/actions";import Re from"@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json"assert{type:"json"};import Me from"@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json"assert{type:"json"};import Fe from"@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json"assert{type:"json"};import $e from"@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json"assert{type:"json"};import We from"@latticexyz/world/out/InitModule.sol/InitModule.json"assert{type:"json"};import Ft from"@latticexyz/world/out/InitModule.sol/InitModule.abi.json"assert{type:"json"};import He from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.json"assert{type:"json"};import $t from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{getCreate2Address as $,encodeDeployData as Ee,size as W}from"viem";import{padHex as xt}from"viem";import St from"@latticexyz/store/mud.config";import Ct from"@latticexyz/world/mud.config";import Dt from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import vt from"@latticexyz/world-modules/out/IModule.sol/IModule.abi.json"assert{type:"json"};import{resourceToHex as wt}from"@latticexyz/common";import{resolveUserTypes as Pe}from"@latticexyz/store";function L(e){let o={...e.userTypes,...Object.fromEntries(Object.entries(e.enums).map(([r])=>[r,{internalType:"uint8"}]))};return Object.fromEntries(Object.entries(e.tables).map(([r,t])=>[`${e.namespace}_${r}`,{namespace:e.namespace,name:t.name,tableId:wt({type:t.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:t.name}),keySchema:Pe(t.keySchema,o),valueSchema:Pe(t.valueSchema,o)}]))}import{helloStoreEvent as Tt}from"@latticexyz/store";import{helloWorldEvent as At}from"@latticexyz/world";var v=xt("0x",{size:32}),U=parseInt("6000",16),F=L(St),T=L(Ct),Y=[Tt,At],S=[...Dt,...vt],Be=["1.0.0-unaudited"],Oe=["1.0.0-unaudited"];import{waitForTransactionReceipt as Rt}from"viem/actions";import{concatHex as kt,getCreate2Address as It}from"viem";import{getBytecode as Pt}from"viem/actions";import{sendTransaction as Bt}from"@latticexyz/common";import Ot from"p-retry";import{wait as jt}from"@latticexyz/common/utils";async function je({client:e,deployerAddress:o,bytecode:r,deployedBytecodeSize:t,label:n="contract"}){if(r.includes("__$"))throw new Error(`Found unlinked public library in ${n} bytecode`);let s=It({from:o,salt:v,bytecode:r});return await Pt(e,{address:s,blockTag:"pending"})?(l("found",n,"at",s),[]):(t>U?console.warn(`
10
- Bytecode for ${n} (${t} bytes) is over the contract size limit (${U} bytes). Run \`forge build --sizes\` for more info.
11
- `):t>U*.95&&console.warn(`
12
- Bytecode for ${n} (${t} bytes) is almost over the contract size limit (${U} bytes). Run \`forge build --sizes\` for more info.
13
- `),l("deploying",n,"at",s),[await Ot(()=>Bt(e,{chain:e.chain??null,to:o,data:kt([v,r])}),{retries:3,onFailedAttempt:async a=>{let m=a.attemptNumber*500;l(`failed to deploy ${n}, retrying in ${m}ms...`),await jt(m)}})])}import{uniqueBy as Mt}from"@latticexyz/common/utils";async function P({client:e,deployerAddress:o,contracts:r}){let t=Mt(r,s=>s.bytecode),n=(await Promise.all(t.map(s=>je({client:e,deployerAddress:o,...s})))).flat();if(n.length){l("waiting for contracts");for(let s of n)await Rt(e,{hash:s})}return n}async function G(e,o){let r=W(Re.deployedBytecode.object),t=Re.bytecode.object,n=$({from:o,bytecode:t,salt:v}),s=W(Me.deployedBytecode.object),i=Me.bytecode.object,a=$({from:o,bytecode:i,salt:v}),m=W(Fe.deployedBytecode.object),c=Fe.bytecode.object,f=$({from:o,bytecode:c,salt:v}),y=W($e.deployedBytecode.object),x=$e.bytecode.object,C=$({from:o,bytecode:x,salt:v}),d=W(We.deployedBytecode.object),u=Ee({bytecode:We.bytecode.object,abi:Ft,args:[n,a,f,C]}),w=$({from:o,bytecode:u,salt:v}),g=W(He.deployedBytecode.object),D=Ee({bytecode:He.bytecode.object,abi:$t,args:[w]}),p=$({from:o,bytecode:D,salt:v});return await P({client:e,deployerAddress:o,contracts:[{bytecode:t,deployedBytecodeSize:r,label:"access management system"},{bytecode:i,deployedBytecodeSize:s,label:"balance transfer system"},{bytecode:c,deployedBytecodeSize:m,label:"batch call system"},{bytecode:x,deployedBytecodeSize:y,label:"core registration system"},{bytecode:u,deployedBytecodeSize:d,label:"core module"},{bytecode:D,deployedBytecodeSize:g,label:"world factory"}]}),p}import Lt from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{writeContract as Ut}from"@latticexyz/common";import{AbiEventSignatureNotFoundError as Wt,decodeEventLog as Ht,hexToString as Ne,parseAbi as Et,trim as ze}from"viem";import{isDefined as Nt}from"@latticexyz/common/utils";function Z(e){let o=e.map(i=>{try{return{...i,...Ht({strict:!0,abi:Et(Y),topics:i.topics,data:i.data})}}catch(a){if(a instanceof Wt)return;throw a}}).filter(Nt),{address:r,deployBlock:t,worldVersion:n,storeVersion:s}=o.reduce((i,a)=>({...i,address:a.address,deployBlock:a.blockNumber,...a.eventName==="HelloWorld"?{worldVersion:Ne(ze(a.args.worldVersion,{dir:"right"}))}:null,...a.eventName==="HelloStore"?{storeVersion:Ne(ze(a.args.storeVersion,{dir:"right"}))}:null}),{});if(r==null)throw new Error("could not find world address");if(t==null)throw new Error("could not find world deploy block number");if(n==null)throw new Error("could not find world version");if(s==null)throw new Error("could not find store version");return{address:r,deployBlock:t,worldVersion:n,storeVersion:s}}async function Le(e,o,r){let t=await G(e,o);l("deploying world");let n=await Ut(e,{chain:e.chain??null,address:t,abi:Lt,functionName:"deployWorld",args:[r]});l("waiting for world deploy");let s=await zt(e,{hash:n});if(s.status!=="success")throw console.error("world deploy failed",s),new Error("world deploy failed");let i=Z(s.logs.map(a=>a));return l("deployed world to",i.address,"at block",i.deployBlock),{...i,stateBlock:i.deployBlock}}import{resourceToLabel as ie,writeContract as Gt}from"@latticexyz/common";import{valueSchemaToFieldLayoutHex as Zt,keySchemaToHex as Qt,valueSchemaToHex as Xt}from"@latticexyz/protocol-parser";import{parseAbiItem as Vt,decodeAbiParameters as Ue,parseAbiParameters as Ve}from"viem";import{hexToResource as _t}from"@latticexyz/common";import{storeSetRecordEvent as Kt}from"@latticexyz/store";import{getLogs as Jt}from"viem/actions";import{decodeKey as qt,decodeValueArgs as Yt,hexToSchema as _e}from"@latticexyz/protocol-parser";async function Ke({client:e,worldDeploy:o}){l("looking up tables for",o.address);let t=(await Jt(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Vt(Kt),args:{tableId:F.store_Tables.tableId}})).map(n=>{let{tableId:s}=qt(F.store_Tables.keySchema,n.args.keyTuple),{namespace:i,name:a}=_t(s),m=Yt(F.store_Tables.valueSchema,n.args),c=_e(m.keySchema),f=_e(m.valueSchema),y=Ue(Ve("string[]"),m.abiEncodedKeyNames)[0],x=Ue(Ve("string[]"),m.abiEncodedFieldNames)[0],C=[...f.staticFields,...f.dynamicFields],d=Object.fromEntries(c.staticFields.map((w,g)=>[y[g],w])),u=Object.fromEntries(C.map((w,g)=>[x[g],w]));return{namespace:i,name:a,tableId:s,keySchema:d,valueSchema:u}});return l("found",t.length,"tables for",o.address),t}import er from"p-retry";import{wait as or}from"@latticexyz/common/utils";async function Je({client:e,worldDeploy:o,tables:r}){let n=(await Ke({client:e,worldDeploy:o})).map(a=>a.tableId),s=r.filter(a=>n.includes(a.tableId));s.length&&l("existing tables",s.map(ie).join(", "));let i=r.filter(a=>!n.includes(a.tableId));return i.length?(l("registering tables",i.map(ie).join(", ")),await Promise.all(i.map(a=>er(()=>Gt(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerTable",args:[a.tableId,Zt(a.valueSchema),Qt(a.keySchema),Xt(a.valueSchema),Object.keys(a.keySchema),Object.keys(a.valueSchema)]}),{retries:3,onFailedAttempt:async m=>{let c=m.attemptNumber*500;l(`failed to register table ${ie(a)}, retrying in ${c}ms...`),await or(c)}})))):[]}import{getAddress as O}from"viem";import{writeContract as ce,resourceToLabel as V}from"@latticexyz/common";import{parseAbiItem as tr}from"viem";import{getLogs as rr}from"viem/actions";import{storeSpliceStaticDataEvent as nr}from"@latticexyz/store";async function Q({client:e,worldDeploy:o}){l("looking up resource IDs for",o.address);let t=(await rr(e,{strict:!0,address:o.address,fromBlock:o.deployBlock,toBlock:o.stateBlock,event:tr(nr),args:{tableId:F.store_ResourceIds.tableId}})).map(n=>n.args.keyTuple[0]);return l("found",t.length,"resource IDs for",o.address),t}import{hexToResource as wr,resourceToLabel as xr}from"@latticexyz/common";import{decodeValueArgs as sr,encodeKey as ar}from"@latticexyz/protocol-parser";import{readContract as ir}from"viem/actions";async function B({client:e,worldDeploy:o,table:r,key:t}){let[n,s,i]=await ir(e,{blockNumber:o.stateBlock,address:o.address,abi:S,functionName:"getRecord",args:[r.tableId,ar(r.keySchema,t)]});return sr(r.valueSchema,{staticData:n,encodedLengths:s,dynamicData:i})}import{toFunctionSelector as cr,parseAbiItem as dr}from"viem";import{storeSetRecordEvent as lr}from"@latticexyz/store";import{getLogs as mr}from"viem/actions";import{decodeValueArgs as pr}from"@latticexyz/protocol-parser";import{hexToResource as fr}from"@latticexyz/common";async function X({client:e,worldDeploy:o}){l("looking up function signatures for",o.address);let t=(await mr(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:dr(lr),args:{tableId:T.world_FunctionSignatures.tableId}})).map(s=>pr(T.world_FunctionSignatures.valueSchema,s.args).functionSignature);return l("found",t.length,"function signatures for",o.address),await Promise.all(t.map(async s=>{let i=cr(s),{systemId:a,systemFunctionSelector:m}=await B({client:e,worldDeploy:o,table:T.world_FunctionSelectors,key:{worldFunctionSelector:i}}),{namespace:c,name:f}=fr(a),y=c===""?s:s.replace(`${c}_${f}_`,"");return{signature:s,selector:i,systemId:a,systemFunctionSignature:y,systemFunctionSelector:m}}))}import{parseAbiItem as yr,getAddress as ur}from"viem";import{storeSpliceStaticDataEvent as gr}from"@latticexyz/store";import{getLogs as br}from"viem/actions";import{decodeKey as hr}from"@latticexyz/protocol-parser";async function ee({client:e,worldDeploy:o}){l("looking up resource access for",o.address);let t=(await br(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:yr(gr),args:{tableId:T.world_ResourceAccess.tableId}})).map(s=>hr(T.world_ResourceAccess.keySchema,s.args.keyTuple)),n=(await Promise.all(t.map(async s=>[s,await B({client:e,worldDeploy:o,table:T.world_ResourceAccess,key:s})]))).filter(([,s])=>s.access).map(([s])=>({resourceId:s.resourceId,address:ur(s.caller)}));return l("found",n.length,"resource<>address access pairs"),n}async function qe({client:e,worldDeploy:o}){let[r,t,n]=await Promise.all([Q({client:e,worldDeploy:o}),X({client:e,worldDeploy:o}),ee({client:e,worldDeploy:o})]),s=r.map(wr).filter(i=>i.type==="system");return l("looking up systems",s.map(xr).join(", ")),await Promise.all(s.map(async i=>{let{system:a,publicAccess:m}=await B({client:e,worldDeploy:o,table:T.world_Systems,key:{systemId:i.resourceId}}),c=t.filter(f=>f.systemId===i.resourceId);return{address:a,namespace:i.namespace,name:i.name,systemId:i.resourceId,allowAll:m,allowedAddresses:n.filter(({resourceId:f})=>f===i.resourceId).map(({address:f})=>f),functions:c}}))}import{wait as de}from"@latticexyz/common/utils";import le from"p-retry";async function Ye({client:e,deployerAddress:o,libraries:r,worldDeploy:t,systems:n}){let[s,i]=await Promise.all([qe({client:e,worldDeploy:t}),ee({client:e,worldDeploy:t})]),a=n.filter(p=>s.some(b=>b.systemId===p.systemId&&O(b.address)===O(p.prepareDeploy(o,r).address)));a.length&&l("existing systems",a.map(V).join(", "));let m=a.map(p=>p.systemId),c=n.filter(p=>!m.includes(p.systemId));if(!c.length)return[];let f=c.filter(p=>s.some(b=>b.systemId===p.systemId&&O(b.address)!==O(p.prepareDeploy(o,r).address)));f.length&&l("upgrading systems",f.map(V).join(", "));let y=c.filter(p=>!s.some(b=>b.systemId===p.systemId));y.length&&l("registering new systems",y.map(V).join(", ")),await P({client:e,deployerAddress:o,contracts:c.map(p=>({bytecode:p.prepareDeploy(o,r).bytecode,deployedBytecodeSize:p.deployedBytecodeSize,label:`${V(p)} system`}))});let x=await Promise.all(c.map(p=>le(()=>ce(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"registerSystem",args:[p.systemId,p.prepareDeploy(o,r).address,p.allowAll]}),{retries:3,onFailedAttempt:async b=>{let h=b.attemptNumber*500;l(`failed to register system ${V(p)}, retrying in ${h}ms...`),await de(h)}}))),C=n.map(p=>p.systemId),d=i.filter(({resourceId:p})=>C.includes(p)),u=[...n.flatMap(p=>p.allowedAddresses.map(b=>({resourceId:p.systemId,address:b}))),...n.flatMap(p=>p.allowedSystemIds.map(b=>({resourceId:p.systemId,address:s.find(h=>h.systemId===b)?.address??n.find(h=>h.systemId===b)?.prepareDeploy(o,r).address})).filter(b=>b.address!=null))],w=u.filter(p=>!d.some(({resourceId:b,address:h})=>b===p.resourceId&&O(h)===O(p.address))),g=d.filter(p=>!u.some(({resourceId:b,address:h})=>b===p.resourceId&&O(h)===O(p.address)));g.length&&l("revoking",g.length,"access grants"),w.length&&l("adding",w.length,"access grants");let D=await Promise.all([...g.map(p=>le(()=>ce(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"revokeAccess",args:[p.resourceId,p.address]}),{retries:3,onFailedAttempt:async b=>{let h=b.attemptNumber*500;l(`failed to revoke access, retrying in ${h}ms...`),await de(h)}})),...w.map(p=>le(()=>ce(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"grantAccess",args:[p.resourceId,p.address]}),{retries:3,onFailedAttempt:async b=>{let h=b.attemptNumber*500;l(`failed to grant access, retrying in ${h}ms...`),await de(h)}}))]);return[...x,...D]}import{waitForTransactionReceipt as co}from"viem/actions";import{getAddress as Sr,parseAbi as Cr}from"viem";import{getBlockNumber as Dr,getLogs as vr}from"viem/actions";var Ge=new Map;async function Ze(e,o){let r=Sr(o),t=Ge.get(r);if(t!=null)return t;l("looking up world deploy for",r);let n=await Dr(e),s=await vr(e,{strict:!0,address:r,events:Cr(Y),fromBlock:"earliest",toBlock:n});return t={...Z(s),stateBlock:n},Ge.set(r,t),l("found world deploy for",r,"at block",t.deployBlock),t}import{hexToResource as Tr,writeContract as Qe}from"@latticexyz/common";import Xe from"p-retry";import{wait as eo}from"@latticexyz/common/utils";async function oo({client:e,worldDeploy:o,functions:r}){let t=await X({client:e,worldDeploy:o}),n=Object.fromEntries(t.map(a=>[a.selector,a])),s=r.filter(a=>n[a.selector]),i=r.filter(a=>!s.includes(a));if(s.length){l("functions already registered:",s.map(m=>m.signature).join(", "));let a=s.filter(m=>m.systemId!==n[m.selector]?.systemId);a.length&&console.warn("found",a.length,"functions already registered but pointing at a different system ID:",a.map(m=>m.signature).join(", "))}return i.length?(l("registering functions:",i.map(a=>a.signature).join(", ")),Promise.all(i.map(a=>{let{namespace:m}=Tr(a.systemId);return m===""?Xe(()=>Qe(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerRootFunctionSelector",args:[a.systemId,a.systemFunctionSignature,a.systemFunctionSignature]}),{retries:3,onFailedAttempt:async c=>{let f=c.attemptNumber*500;l(`failed to register function ${a.signature}, retrying in ${f}ms...`),await eo(f)}}):Xe(()=>Qe(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerFunctionSelector",args:[a.systemId,a.systemFunctionSignature]}),{retries:3,onFailedAttempt:async c=>{let f=c.attemptNumber*500;l(`failed to register function ${a.signature}, retrying in ${f}ms...`),await eo(f)}})}))):[]}import{BaseError as Ar}from"viem";import{writeContract as to}from"@latticexyz/common";import{isDefined as kr,wait as Ir}from"@latticexyz/common/utils";import Pr from"p-retry";async function ro({client:e,deployerAddress:o,libraries:r,worldDeploy:t,modules:n}){return n.length?(await P({client:e,deployerAddress:o,contracts:n.map(s=>({bytecode:s.prepareDeploy(o,r).bytecode,deployedBytecodeSize:s.deployedBytecodeSize,label:`${s.name} module`}))}),l("installing modules:",n.map(s=>s.name).join(", ")),(await Promise.all(n.map(s=>Pr(async()=>{try{let i=s.prepareDeploy(o,r).address;return s.installAsRoot?await to(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"installRootModule",args:[i,s.installData]}):await to(e,{chain:e.chain??null,address:t.address,abi:S,functionName:"installModule",args:[i,s.installData]})}catch(i){if(i instanceof Ar&&i.message.includes("Module_AlreadyInstalled")){l(`module ${s.name} already installed`);return}throw i}},{retries:3,onFailedAttempt:async i=>{let a=i.attemptNumber*500;l(`failed to install module ${s.name}, retrying in ${a}ms...`),await Ir(a)}})))).filter(kr)):[]}import{getAddress as no}from"viem";import{hexToResource as so,resourceToHex as ao,writeContract as Br}from"@latticexyz/common";async function io({client:e,worldDeploy:o,resourceIds:r}){let t=Array.from(new Set(r.map(y=>so(y).namespace))),n=await Q({client:e,worldDeploy:o}),s=new Set(n.map(y=>so(y).namespace));s.size&&l("found",s.size,"existing namespaces:",Array.from(s).map(y=>y===""?"<root>":y).join(", "));let i=t.filter(y=>s.has(y)),m=(await Promise.all(i.map(async y=>{let{owner:x}=await B({client:e,worldDeploy:o,table:T.world_NamespaceOwner,key:{namespaceId:ao({type:"namespace",namespace:y,name:""})}});return[y,x]}))).filter(([,y])=>no(y)!==no(e.account.address)).map(([y])=>y);if(m.length)throw new Error(`You are attempting to deploy to namespaces you do not own: ${m.join(", ")}`);let c=t.filter(y=>!s.has(y));return c.length>0&&l("registering namespaces",Array.from(c).join(", ")),Promise.all(c.map(y=>Br(e,{chain:e.chain??null,address:o.address,abi:S,functionName:"registerNamespace",args:[ao({namespace:y,type:"namespace",name:""})]})))}import{resourceToLabel as Or}from"@latticexyz/common";import{randomBytes as jr}from"crypto";async function lo({client:e,config:o,salt:r,worldAddress:t,deployerAddress:n}){let s=Object.values(o.tables),i=n??await Ie(e);await G(e,i),await P({client:e,deployerAddress:i,contracts:[...o.libraries.map(d=>({bytecode:d.prepareDeploy(i,o.libraries).bytecode,deployedBytecodeSize:d.deployedBytecodeSize,label:`${d.path}:${d.name} library`})),...o.systems.map(d=>({bytecode:d.prepareDeploy(i,o.libraries).bytecode,deployedBytecodeSize:d.deployedBytecodeSize,label:`${Or(d)} system`})),...o.modules.map(d=>({bytecode:d.prepareDeploy(i,o.libraries).bytecode,deployedBytecodeSize:d.deployedBytecodeSize,label:`${d.name} module`}))]});let a=t?await Ze(e,t):await Le(e,i,r??`0x${jr(32).toString("hex")}`);if(!Be.includes(a.storeVersion))throw new Error(`Unsupported Store version: ${a.storeVersion}`);if(!Oe.includes(a.worldVersion))throw new Error(`Unsupported World version: ${a.worldVersion}`);let m=await io({client:e,worldDeploy:a,resourceIds:[...s.map(d=>d.tableId),...o.systems.map(d=>d.systemId)]});l("waiting for all namespace registration transactions to confirm");for(let d of m)await co(e,{hash:d});let c=await Je({client:e,worldDeploy:a,tables:s}),f=await Ye({client:e,deployerAddress:i,libraries:o.libraries,worldDeploy:a,systems:o.systems}),y=await oo({client:e,worldDeploy:a,functions:o.systems.flatMap(d=>d.functions)}),x=await ro({client:e,deployerAddress:i,libraries:o.libraries,worldDeploy:a,modules:o.modules}),C=[...c,...f,...y,...x];l("waiting for all transactions to confirm");for(let d of C)await co(e,{hash:d});return l("deploy complete"),a}import{createWalletClient as tn,http as rn,isHex as nn}from"viem";import{privateKeyToAccount as sn}from"viem/accounts";import{loadConfig as an}from"@latticexyz/config/node";import{getOutDirectory as cn,getRpcUrl as dn,getSrcDirectory as ln}from"@latticexyz/common/foundry";import E from"chalk";import{MUDError as ho}from"@latticexyz/common/errors";import zr from"path";import{resolveWorldConfig as Lr}from"@latticexyz/world";import{resourceToHex as pe}from"@latticexyz/common";import{resolveWithContext as Ur}from"@latticexyz/config";import{encodeField as Vr}from"@latticexyz/protocol-parser";import{hexToBytes as _r,bytesToHex as Kr,toFunctionSelector as yo,toFunctionSignature as uo}from"viem";import oe from"@latticexyz/world-modules/out/KeysWithValueModule.sol/KeysWithValueModule.json"assert{type:"json"};import te from"@latticexyz/world-modules/out/KeysInTableModule.sol/KeysInTableModule.json"assert{type:"json"};import re from"@latticexyz/world-modules/out/UniqueEntityModule.sol/UniqueEntityModule.json"assert{type:"json"};import{size as me}from"viem";function H(e){return Object.entries(e).flatMap(([o,r])=>Object.entries(r).flatMap(([t,n])=>n.map(s=>({path:o,name:t,start:s.start,length:s.length}))))}var mo=[{name:"KeysWithValueModule",abi:oe.abi,bytecode:oe.bytecode.object,placeholders:H(oe.bytecode.linkReferences),deployedBytecodeSize:me(oe.deployedBytecode.object)},{name:"KeysInTableModule",abi:te.abi,bytecode:te.bytecode.object,placeholders:H(te.bytecode.linkReferences),deployedBytecodeSize:me(te.deployedBytecode.object)},{name:"UniqueEntityModule",abi:re.abi,bytecode:re.bytecode.object,placeholders:H(re.bytecode.linkReferences),deployedBytecodeSize:me(re.deployedBytecode.object)}];import{readFileSync as Rr}from"fs";import Mr from"path";import{MUDError as ne}from"@latticexyz/common/errors";import{size as Fr}from"viem";function _(e,o,r){let t,n=Mr.join(r,e,o+".json");try{t=JSON.parse(Rr(n,"utf8"))}catch{throw new ne(`Error reading file at ${n}`)}let s=t?.bytecode?.object;if(!s)throw new ne(`No bytecode found in ${n}`);let i=t?.deployedBytecode?.object;if(!i)throw new ne(`No deployed bytecode found in ${n}`);let a=t?.abi;if(!a)throw new ne(`No ABI found in ${n}`);let m=H(t?.bytecode?.linkReferences??{});return{abi:a,bytecode:s,placeholders:m,deployedBytecodeSize:Fr(i)}}import{groupBy as Jr}from"@latticexyz/common/utils";import{readFileSync as Wr}from"fs";import Hr from"glob";import $r from"toposort";function po(e,o,r){let t=$r(e.flatMap(n=>r(n).map(s=>[o(n),s])));return[...e].sort((n,s)=>t.indexOf(o(n))-t.indexOf(o(s)))}function fo(e){let r=Hr.sync(`${e}/**/*.json`,{ignore:"**/*.abi.json"}).map(t=>JSON.parse(Wr(t,"utf8"))).flatMap(t=>{if(!t.metadata)return[];let n=Object.keys(t.metadata.settings.compilationTarget)[0],s=t.metadata.settings.compilationTarget[n],i=t.bytecode.linkReferences;return Object.entries(i).flatMap(([a,m])=>Object.keys(m).map(c=>({path:a,name:c,dependentPath:n,dependentName:s})))});return po(r,t=>`${t.path}:${t.name}`,t=>[`${t.dependentPath}:${t.dependentName}`])}import{spliceHex as Er}from"@latticexyz/common";import{getCreate2Address as Nr}from"viem";function se(e,o){return function(t,n){let s=e;for(let i of o){let a=n.find(m=>m.path===i.path&&m.name===i.name);if(!a)throw new Error(`Could not find library for bytecode placeholder ${i.path}:${i.name}`);s=Er(s,i.start,i.length,a.prepareDeploy(t,n).address)}return{bytecode:s,address:Nr({from:t,bytecode:s,salt:v})}}}function go({config:e,forgeSourceDir:o,forgeOutDir:r}){let t=fo(r).map(d=>{let u=_(zr.basename(d.path),d.name,r);return{path:d.path,name:d.name,abi:u.abi,prepareDeploy:se(u.bytecode,u.placeholders),deployedBytecodeSize:u.deployedBytecodeSize}}),n=L(e),s=I(o).map(({basename:d})=>d),i=Lr(e,s),m=_("System.sol","System",r).abi.filter(d=>d.type==="function").map(uo),c=Object.entries(i.systems).map(([d,u])=>{let w=e.namespace,g=u.name,D=pe({type:"system",namespace:w,name:g}),p=_(`${d}.sol`,d,r),b=p.abi.filter(h=>h.type==="function").map(uo).filter(h=>!m.includes(h)).map(h=>{let be=w===""?h:`${w}__${h}`;return{signature:be,selector:yo(be),systemId:D,systemFunctionSignature:h,systemFunctionSelector:yo(h)}});return{namespace:w,name:g,systemId:D,allowAll:u.openAccess,allowedAddresses:u.accessListAddresses,allowedSystemIds:u.accessListSystems.map(h=>pe({type:"system",namespace:w,name:i.systems[h].name})),prepareDeploy:se(p.bytecode,p.placeholders),deployedBytecodeSize:p.deployedBytecodeSize,abi:p.abi,functions:b}}),f=Jr(c,d=>d.systemId),y=Array.from(f.values()).filter(d=>d.length>1).flat();if(y.length){let d=y.map(u=>u.name);throw new Error(`Found systems with overlapping system ID: ${d.join(", ")}.
14
-
15
- System IDs are generated from the first 16 bytes of the name, so you may need to rename them to avoid the overlap.`)}let x={tableIds:Object.fromEntries(Object.entries(e.tables).map(([d,u])=>[d,_r(pe({type:u.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:u.name}))]))},C=e.modules.map(d=>{let u=mo.find(g=>g.name===d.name)??_(`${d.name}.sol`,d.name,r),w=d.args.map(g=>Ur(g,x)).map(g=>{let D=g.value instanceof Uint8Array?Kr(g.value):g.value;return Vr(g.type,D)});if(w.length>1)throw new Error(`${d.name} module should only have 0-1 args, but had ${w.length} args.`);return{name:d.name,installAsRoot:d.root,installData:w.length===0?"0x":w[0],prepareDeploy:se(u.bytecode,u.placeholders),deployedBytecodeSize:u.deployedBytecodeSize,abi:u.abi}});return{tables:n,systems:c,modules:C,libraries:t}}import{getChainId as mn}from"viem/actions";import{existsSync as qr}from"fs";import Yr from"path";import Gr from"chalk";import{getScriptDirectory as Zr,forge as Qr}from"@latticexyz/common/foundry";async function bo(e,o,r,t){let n=Yr.join(await Zr(),e+".s.sol");qr(n)?(console.log(Gr.blue(`Executing post deploy script at ${n}`)),await Qr(["script",e,"--sig","run(address)",o,"--broadcast","--rpc-url",r,"-vvv"],{profile:t})):console.log(`No script at ${n}, skipping post deploy hook`)}var k={configPath:{type:"string",desc:"Path to the config file"},printConfig:{type:"boolean",desc:"Print the resolved config"},profile:{type:"string",desc:"The foundry profile to use"},saveDeployment:{type:"boolean",desc:"Save the deployment info to a file",default:!0},rpc:{type:"string",desc:"The RPC URL to use. Defaults to the RPC url from the local foundry.toml"},rpcBatch:{type:"boolean",desc:"Enable batch processing of RPC requests in viem client (defaults to batch size of 100 and wait of 1s)"},deployerAddress:{type:"string",desc:"Deploy using an existing deterministic deployer (https://github.com/Arachnid/deterministic-deployment-proxy)"},worldAddress:{type:"string",desc:"Deploy to an existing World at the given address"},srcDir:{type:"string",desc:"Source directory. Defaults to foundry src directory."},skipBuild:{type:"boolean",desc:"Skip rebuilding the contracts before deploying"},alwaysRunPostDeploy:{type:"boolean",desc:"Always run PostDeploy.s.sol after each deploy (including during upgrades). By default, PostDeploy.s.sol is only run once after a new world is deployed."},salt:{type:"string",desc:"The deployment salt to use. Defaults to a random salt."}};async function N(e){let o=e.salt;if(o!=null&&!nn(o))throw new ho("Expected hex string for salt");let r=e.profile??process.env.FOUNDRY_PROFILE,t=await an(e.configPath);e.printConfig&&console.log(E.green(`
16
- Resolved config:
17
- `),JSON.stringify(t,null,2));let n=e.srcDir??await ln(r),s=await cn(r),i=e.rpc??await dn(r);console.log(E.bgBlue(E.whiteBright(`
18
- Deploying MUD contracts${r?" with profile "+r:""} to RPC ${i}
19
- `))),e.skipBuild||await q({config:t,srcDir:n,foundryProfile:r});let a=process.env.PRIVATE_KEY;if(!a)throw new ho(`Missing PRIVATE_KEY environment variable.
20
- Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
21
- in your contracts directory to use the default anvil private key.`);let m=go({config:t,forgeSourceDir:n,forgeOutDir:s}),c=tn({transport:rn(i,{batch:e.rpcBatch?{batchSize:100,wait:1e3}:void 0}),account:sn(a)});console.log("Deploying from",c.account.address);let f=Date.now(),y=await lo({deployerAddress:e.deployerAddress,salt:o,worldAddress:e.worldAddress,client:c,config:m});(e.worldAddress==null||e.alwaysRunPostDeploy)&&await bo(t.postDeployScript,y.address,i,r),console.log(E.green("Deployment completed in",(Date.now()-f)/1e3,"seconds"));let x={worldAddress:y.address,blockNumber:Number(y.deployBlock)};if(e.saveDeployment){let C=await mn(c),d=fe.join(t.deploysDirectory,C.toString());en(d,{recursive:!0}),ye(fe.join(d,"latest.json"),JSON.stringify(x,null,2)),ye(fe.join(d,Date.now()+".json"),JSON.stringify(x,null,2));let u=[1337,31337],w=Xr(t.worldsFile)?JSON.parse(on(t.worldsFile,"utf-8")):{};w[C]={address:x.worldAddress,blockNumber:u.includes(C)?void 0:x.blockNumber},ye(t.worldsFile,JSON.stringify(w,null,2)),console.log(E.bgGreen(E.whiteBright(`
22
- Deployment result (written to ${t.worldsFile} and ${d}):
23
- `)))}return console.log(x),y}var pn={command:"deploy",describe:"Deploy MUD contracts",builder(e){return e.options(k)},async handler(e){try{await N(e)}catch(o){J(o),process.exit(1)}process.exit(0)}},wo=pn;import{loadConfig as fn}from"@latticexyz/config/node";import{worldgen as yn}from"@latticexyz/world/node";import{getSrcDirectory as un}from"@latticexyz/common/foundry";import xo from"path";import{rmSync as gn}from"fs";var bn={command:"worldgen",describe:"Autogenerate interfaces for Systems and World based on existing contracts and the config file",builder(e){return e.options({configPath:{type:"string",desc:"Path to the config file"},clean:{type:"boolean",desc:"Clear the worldgen directory before generating new interfaces (defaults to true)",default:!0}})},async handler(e){await hn(e),process.exit(0)}};async function hn(e){let o=e.srcDir??await un(),r=I(o),t=e.config??await fn(e.configPath),n=xo.join(o,t.codegenDirectory);e.clean&&gn(xo.join(n,t.worldgenDirectory),{recursive:!0,force:!0}),await yn(t,r,n)}var So=bn;import K from"chalk";import{readFileSync as Dn,writeFileSync as vn}from"fs";import ge from"path";import{MUDError as z}from"@latticexyz/common/errors";var Co={name:"@latticexyz/cli",version:"2.0.0-next.17",description:"Command line interface for mud",repository:{type:"git",url:"https://github.com/latticexyz/mud.git",directory:"packages/cli"},license:"MIT",type:"module",exports:{".":"./dist/index.js"},types:"src/index.ts",bin:{mud:"./dist/mud.js"},scripts:{build:"pnpm run build:js && pnpm run build:test-tables","build:js":"tsup && chmod +x ./dist/mud.js","build:test-tables":"tsx ./scripts/generate-test-tables.ts",clean:"pnpm run clean:js && pnpm run clean:test-tables","clean:js":"rimraf dist","clean:test-tables":"rimraf src/codegen",dev:"tsup --watch",lint:"eslint . --ext .ts",prepare:"mkdir -p ./dist && touch ./dist/mud.js",test:"tsc --noEmit && forge test","test:ci":"pnpm run test"},dependencies:{"@ethersproject/abi":"^5.7.0","@ethersproject/providers":"^5.7.2","@improbable-eng/grpc-web":"^0.15.0","@improbable-eng/grpc-web-node-http-transport":"^0.15.0","@latticexyz/abi-ts":"workspace:*","@latticexyz/common":"workspace:*","@latticexyz/config":"workspace:*","@latticexyz/gas-report":"workspace:*","@latticexyz/protocol-parser":"workspace:*","@latticexyz/schema-type":"workspace:*","@latticexyz/services":"workspace:*","@latticexyz/store":"workspace:*","@latticexyz/utils":"workspace:*","@latticexyz/world":"workspace:*","@latticexyz/world-modules":"workspace:*",chalk:"^5.0.1",chokidar:"^3.5.3",debug:"^4.3.4",dotenv:"^16.0.3",ejs:"^3.1.8",ethers:"^5.7.2",execa:"^7.0.0",glob:"^8.0.3","nice-grpc-web":"^2.0.1",openurl:"^1.1.1","p-retry":"^5.1.2",path:"^0.12.7",rxjs:"7.5.5","throttle-debounce":"^5.0.0",toposort:"^2.0.2",typescript:"5.4.2",viem:"2.7.12",yargs:"^17.7.1",zod:"^3.21.4","zod-validation-error":"^1.3.0"},devDependencies:{"@types/debug":"^4.1.7","@types/ejs":"^3.1.1","@types/glob":"^7.2.0","@types/node":"^18.15.11","@types/openurl":"^1.0.0","@types/throttle-debounce":"^5.0.0","@types/toposort":"^2.0.6","@types/yargs":"^17.0.10","ds-test":"https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0","forge-std":"https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1",tsup:"^6.7.0",tsx:"^3.12.6",vitest:"0.34.6"},gitHead:"914a1e0ae4a573d685841ca2ea921435057deb8f"};import Tn from"glob";import{ZodError as xn,z as Do}from"zod";var Sn=Do.object({MUD_PACKAGES:Do.string().transform(e=>JSON.parse(e))});function Cn(){try{return Sn.parse({MUD_PACKAGES:'{"@latticexyz/abi-ts":{"localPath":"packages/abi-ts"},"@latticexyz/block-logs-stream":{"localPath":"packages/block-logs-stream"},"@latticexyz/cli":{"localPath":"packages/cli"},"@latticexyz/common":{"localPath":"packages/common"},"@latticexyz/config":{"localPath":"packages/config"},"create-mud":{"localPath":"packages/create-mud"},"@latticexyz/dev-tools":{"localPath":"packages/dev-tools"},"@latticexyz/faucet":{"localPath":"packages/faucet"},"@latticexyz/gas-report":{"localPath":"packages/gas-report"},"@latticexyz/protocol-parser":{"localPath":"packages/protocol-parser"},"@latticexyz/react":{"localPath":"packages/react"},"@latticexyz/recs":{"localPath":"packages/recs"},"@latticexyz/schema-type":{"localPath":"packages/schema-type"},"@latticexyz/services":{"localPath":"packages/services"},"solhint-config-mud":{"localPath":"packages/solhint-config-mud"},"solhint-plugin-mud":{"localPath":"packages/solhint-plugin-mud"},"@latticexyz/store-indexer":{"localPath":"packages/store-indexer"},"@latticexyz/store-sync":{"localPath":"packages/store-sync"},"@latticexyz/store":{"localPath":"packages/store"},"@latticexyz/utils":{"localPath":"packages/utils"},"@latticexyz/world-modules":{"localPath":"packages/world-modules"},"@latticexyz/world":{"localPath":"packages/world"}}'})}catch(e){if(e instanceof xn){let{...o}=e.format();console.error(`
24
- Missing or invalid environment variables:
25
-
26
- ${Object.keys(o).join(`
27
- `)}
28
- `),process.exit(1)}throw e}}var ue=Cn().MUD_PACKAGES;var An={command:"set-version",describe:"Set MUD version in all package.json files and optionally backup the previously installed version",builder(e){return e.options({mudVersion:{alias:"v",type:"string",description:"Set MUD to the given version"},tag:{alias:"t",type:"string",description:"Set MUD to the latest version with the given tag from npm"},commit:{alias:"c",type:"string",description:"Set MUD to the version based on a given git commit hash from npm"},link:{alias:"l",type:"string",description:"Relative path to the local MUD root directory to link"}})},async handler(e){try{let o=["mudVersion","link","tag","commit","restore"],r=o.reduce((n,s)=>e[s]?n+1:n,0);if(r===0)throw new z(`You need to provide one these options: ${o.join(", ")}`);if(r>1)throw new z(`These options are mutually exclusive: ${o.join(", ")}`);e.link||(e.mudVersion=await kn(e));let t=Tn.sync("**/package.json").filter(n=>!n.includes("node_modules"));for(let n of t)In(n,e)}catch(o){J(o)}finally{process.exit(0)}}};async function kn(e){e.mudVersion==="canary"&&(e.tag="main");let o;try{console.log(K.blue("Fetching available versions")),o=await(await fetch(`https://registry.npmjs.org/${Co.name}`)).json()}catch{throw new z("Could not fetch available MUD versions")}if(e.tag){let r=o["dist-tags"][e.tag];if(!r)throw new z(`Could not find npm version with tag "${e.tag}"`);return console.log(K.green(`Latest version with tag ${e.tag}: ${r}`)),r}if(e.commit){let r=e.commit.substring(0,8),t=Object.keys(o.versions).find(n=>n.includes(r));if(!t)throw new z(`Could not find npm version based on commit "${e.commit}"`);return console.log(K.green(`Version from commit ${e.commit}: ${t}`)),t}return e.mudVersion}function In(e,o){let{link:r}=o,{mudVersion:t}=o,n=Pn(e),s=Object.keys(ue),i={};for(let c in n.dependencies)s.includes(c)&&(i[c]=n.dependencies[c]);let a={};for(let c in n.devDependencies)s.includes(c)&&(a[c]=n.devDependencies[c]);for(let c in n.dependencies)s.includes(c)&&(n.dependencies[c]=m(c,"dependencies"));for(let c in n.devDependencies)s.includes(c)&&(n.devDependencies[c]=m(c,"devDependencies"));return vn(e,JSON.stringify(n,null,2)+`
29
- `),console.log(`Updating ${e}`),vo(i,n.dependencies),vo(a,n.devDependencies),n;function m(c,f){return r&&(t=Bn(e,r,c)),t||n[f][c]}}function Pn(e){try{let o=Dn(e,"utf8");return JSON.parse(o)}catch{throw new z("Could not read JSON at "+e)}}function vo(e,o){for(let r in e)e[r]!==o[r]&&console.log(`${r}: ${K.red(e[r])} -> ${K.green(o[r])}`)}function Bn(e,o,r){let t=ge.relative(ge.dirname(e),process.cwd());return"link:"+ge.join(t,o,ue[r].localPath)}var To=An;import{anvil as On,forge as jn,getRpcUrl as Rn}from"@latticexyz/common/foundry";import Mn from"chalk";var Fn={...k,port:{type:"number",description:"Port to run internal node for fork testing on",default:4242},worldAddress:{type:"string",description:"Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing."},forgeOptions:{type:"string",description:"Options to pass to forge test"}},$n={command:"test",describe:"Run tests in MUD contracts",builder(e){return e.options(Fn)},async handler(e){if(!e.worldAddress){let n=["--block-base-fee-per-gas","0","--port",String(e.port)];On(n)}let o=e.worldAddress?await Rn(e.profile):`http://127.0.0.1:${e.port}`,r=e.worldAddress??(await N({...e,saveDeployment:!1,rpc:o})).address;console.log(Mn.blue("World address",r));let t=e.forgeOptions?.replaceAll("\\","").split(" ")??[];try{await jn(["test","--fork-url",o,...t],{profile:e.profile,env:{WORLD_ADDRESS:r}}),process.exit(0)}catch(n){console.error(n),process.exit(1)}}},Ao=$n;import{existsSync as Wn,readFileSync as Hn}from"fs";import{ethers as ko}from"ethers";import{loadConfig as En}from"@latticexyz/config/node";import{MUDError as Io}from"@latticexyz/common/errors";import{cast as Nn,getRpcUrl as zn,getSrcDirectory as Ln}from"@latticexyz/common/foundry";import{resolveWorldConfig as Un}from"@latticexyz/world";import Vn from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import Po from"@latticexyz/world/mud.config";import{resourceToHex as Oo}from"@latticexyz/common";import{createClient as _n,http as Kn}from"viem";import{getChainId as Jn}from"viem/actions";var Bo=Oo({type:"system",namespace:Po.namespace,name:Po.tables.Systems.name}),qn={command:"trace",describe:"Display the trace of a transaction",builder(e){return e.options({tx:{type:"string",required:!0,description:"Transaction hash to replay"},worldAddress:{type:"string",description:"World contract address. Defaults to the value from worlds.json, based on rpc's chainId"},configPath:{type:"string",description:"Path to the config file"},profile:{type:"string",description:"The foundry profile to use"},srcDir:{type:"string",description:"Source directory. Defaults to foundry src directory."},rpc:{type:"string",description:"json rpc endpoint. Defaults to foundry's configured eth_rpc_url"}})},async handler(e){e.profile??=process.env.FOUNDRY_PROFILE;let{profile:o}=e;e.srcDir??=await Ln(o),e.rpc??=await zn(o);let{tx:r,configPath:t,srcDir:n,rpc:s}=e,i=I(n),a=await En(t),m=Un(a,i.map(({basename:g})=>g)),c=e.worldAddress??await Yn(a.worldsFile,s),f=new ko.providers.StaticJsonRpcProvider(s),y=new ko.Contract(c,Vn,f),x=a.namespace,C=Object.values(m.systems).map(({name:g})=>g),d=await y.getFieldLayout(Bo),u=[];for(let g of C){let D=Oo({type:"system",namespace:x,name:g}),p=await y.getField(Bo,[D],0,d);u.push({name:g,address:p})}let w=await Nn(["run","--label",`${c}:World`,...u.map(({name:g,address:D})=>["--label",`${D}:${g}`]).flat(),`${r}`]);console.log(w),process.exit(0)}},jo=qn;async function Yn(e,o){if(Wn(e)){let r=_n({transport:Kn(o)}),t=await Jn(r),n=JSON.parse(Hn(e,"utf-8"));if(!n[t])throw new Io(`chainId ${t} is missing in worldsFile "${e}"`);return n[t].address}else throw new Io("worldAddress is not specified and worldsFile is missing")}import{anvil as Gn,getScriptDirectory as Zn,getSrcDirectory as Qn}from"@latticexyz/common/foundry";import j from"chalk";import Xn from"chokidar";import{loadConfig as es,resolveConfigPath as os}from"@latticexyz/config/node";import ts from"path";import{homedir as rs}from"os";import{rmSync as ns}from"fs";import{BehaviorSubject as ss,debounceTime as as,exhaustMap as is,filter as cs}from"rxjs";import{isDefined as ds}from"@latticexyz/common/utils";var ls={rpc:k.rpc,configPath:k.configPath,alwaysRunPostDeploy:k.alwaysRunPostDeploy,worldAddress:k.worldAddress},ms={command:"dev-contracts",describe:"Start a development server for MUD contracts",builder(e){return e.options(ls)},async handler(e){let o=e.rpc,r=e.configPath??await os(e.configPath),t=await Qn(),n=await Zn(),s=await es(r);if(!e.rpc){console.log(j.gray("Cleaning devnode cache"));let c=rs();ns(ts.join(c,".foundry","anvil","tmp"),{recursive:!0,force:!0}),Gn(["--block-time","1","--block-base-fee-per-gas","0"]),o="http://127.0.0.1:8545"}let i=new ss(Date.now());Xn.watch([r,t,n],{ignoreInitial:!0}).on("all",async(c,f)=>{f.includes(r)&&(console.log(j.blue("Config changed, queuing deploy\u2026")),i.next(Date.now())),(f.includes(t)||f.includes(n))&&(f.includes(s.codegenDirectory)||(console.log(j.blue("Contracts changed, queuing deploy\u2026")),i.next(Date.now())))});let a=e.worldAddress;i.pipe(as(200),is(async c=>{a&&console.log(j.blue("Rebuilding and upgrading world\u2026"));try{let f=await N({...e,configPath:r,rpc:o,rpcBatch:!1,skipBuild:!1,printConfig:!1,profile:void 0,saveDeployment:!0,deployerAddress:void 0,worldAddress:a,srcDir:t,salt:"0x"});return a=f.address,c<i.value?i.next(i.value):console.log(j.gray(`
30
- Waiting for file changes\u2026
31
- `)),f}catch(f){console.error(j.bgRed(j.whiteBright(`
32
- Error while attempting deploy
33
- `))),console.error(f),console.log(j.gray(`
34
- Waiting for file changes\u2026
35
- `))}}),cs(ds)).subscribe()}},Ro=ms;var Rp=[we,wo,xe,Ce,ps,De,ve,So,To,Ao,jo,Ro,fs];export{Rp as commands};
36
- //# sourceMappingURL=commands-22M65L4E.js.map