@latticexyz/cli 2.0.0-march-19-skystrife-playtest-f0a343b1 → 2.0.0-next-17-awakening-9c07ab3a2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/cli",
3
- "version": "2.0.0-march-19-skystrife-playtest-f0a343b1",
3
+ "version": "2.0.0-next-17-awakening-9c07ab3a2",
4
4
  "description": "Command line interface for mud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,17 +40,17 @@
40
40
  "yargs": "^17.7.1",
41
41
  "zod": "^3.21.4",
42
42
  "zod-validation-error": "^1.3.0",
43
- "@latticexyz/abi-ts": "2.0.0-march-19-skystrife-playtest-f0a343b1",
44
- "@latticexyz/common": "2.0.0-march-19-skystrife-playtest-f0a343b1",
45
- "@latticexyz/config": "2.0.0-march-19-skystrife-playtest-f0a343b1",
46
- "@latticexyz/gas-report": "2.0.0-march-19-skystrife-playtest-f0a343b1",
47
- "@latticexyz/protocol-parser": "2.0.0-march-19-skystrife-playtest-f0a343b1",
48
- "@latticexyz/schema-type": "2.0.0-march-19-skystrife-playtest-f0a343b1",
49
- "@latticexyz/services": "2.0.0-march-19-skystrife-playtest-f0a343b1",
50
- "@latticexyz/store": "2.0.0-march-19-skystrife-playtest-f0a343b1",
51
- "@latticexyz/utils": "2.0.0-march-19-skystrife-playtest-f0a343b1",
52
- "@latticexyz/world": "2.0.0-march-19-skystrife-playtest-f0a343b1",
53
- "@latticexyz/world-modules": "2.0.0-march-19-skystrife-playtest-f0a343b1"
43
+ "@latticexyz/abi-ts": "2.0.0-next-17-awakening-9c07ab3a2",
44
+ "@latticexyz/common": "2.0.0-next-17-awakening-9c07ab3a2",
45
+ "@latticexyz/config": "2.0.0-next-17-awakening-9c07ab3a2",
46
+ "@latticexyz/gas-report": "2.0.0-next-17-awakening-9c07ab3a2",
47
+ "@latticexyz/protocol-parser": "2.0.0-next-17-awakening-9c07ab3a2",
48
+ "@latticexyz/schema-type": "2.0.0-next-17-awakening-9c07ab3a2",
49
+ "@latticexyz/services": "2.0.0-next-17-awakening-9c07ab3a2",
50
+ "@latticexyz/store": "2.0.0-next-17-awakening-9c07ab3a2",
51
+ "@latticexyz/utils": "2.0.0-next-17-awakening-9c07ab3a2",
52
+ "@latticexyz/world": "2.0.0-next-17-awakening-9c07ab3a2",
53
+ "@latticexyz/world-modules": "2.0.0-next-17-awakening-9c07ab3a2"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/debug": "^4.1.7",
@@ -64,7 +64,7 @@
64
64
  "forge-std": "https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1",
65
65
  "tsup": "^6.7.0",
66
66
  "tsx": "^3.12.6",
67
- "vitest": "0.31.4"
67
+ "vitest": "0.34.6"
68
68
  },
69
69
  "gitHead": "914a1e0ae4a573d685841ca2ea921435057deb8f",
70
70
  "scripts": {
@@ -89,6 +89,7 @@ const commandModule: CommandModule<typeof devOptions, InferredOptionTypes<typeof
89
89
  saveDeployment: true,
90
90
  worldAddress,
91
91
  srcDir,
92
+ salt: "0x",
92
93
  });
93
94
  worldAddress = deploy.address;
94
95
  // if there were changes while we were deploying, trigger it again
@@ -1,4 +1,4 @@
1
- import { Account, Address, Chain, Client, Transport, getAddress } from "viem";
1
+ import { Account, Address, Chain, Client, Hex, Transport, getAddress } from "viem";
2
2
  import { ensureDeployer } from "./ensureDeployer";
3
3
  import { deployWorld } from "./deployWorld";
4
4
  import { ensureTables } from "./ensureTables";
@@ -9,16 +9,18 @@ import { getWorldDeploy } from "./getWorldDeploy";
9
9
  import { ensureFunctions } from "./ensureFunctions";
10
10
  import { ensureModules } from "./ensureModules";
11
11
  import { Table } from "./configToTables";
12
- import { assertNamespaceOwner } from "./assertNamespaceOwner";
12
+ import { ensureNamespaceOwner } from "./ensureNamespaceOwner";
13
13
  import { debug } from "./debug";
14
14
  import { resourceLabel } from "./resourceLabel";
15
15
  import { uniqueBy } from "@latticexyz/common/utils";
16
16
  import { ensureContractsDeployed } from "./ensureContractsDeployed";
17
- import { coreModuleBytecode, worldFactoryBytecode, worldFactoryContracts } from "./ensureWorldFactory";
17
+ import { worldFactoryContracts } from "./ensureWorldFactory";
18
+ import { randomBytes } from "crypto";
18
19
 
19
20
  type DeployOptions<configInput extends ConfigInput> = {
20
21
  client: Client<Transport, Chain | undefined, Account>;
21
22
  config: Config<configInput>;
23
+ salt?: Hex;
22
24
  worldAddress?: Address;
23
25
  };
24
26
 
@@ -31,6 +33,7 @@ type DeployOptions<configInput extends ConfigInput> = {
31
33
  export async function deploy<configInput extends ConfigInput>({
32
34
  client,
33
35
  config,
36
+ salt,
34
37
  worldAddress: existingWorldAddress,
35
38
  }: DeployOptions<configInput>): Promise<WorldDeploy> {
36
39
  const tables = Object.values(config.tables) as Table[];
@@ -58,7 +61,7 @@ export async function deploy<configInput extends ConfigInput>({
58
61
 
59
62
  const worldDeploy = existingWorldAddress
60
63
  ? await getWorldDeploy(client, existingWorldAddress)
61
- : await deployWorld(client);
64
+ : await deployWorld(client, salt ? salt : `0x${randomBytes(32).toString("hex")}`);
62
65
 
63
66
  if (!supportedStoreVersions.includes(worldDeploy.storeVersion)) {
64
67
  throw new Error(`Unsupported Store version: ${worldDeploy.storeVersion}`);
@@ -67,12 +70,17 @@ export async function deploy<configInput extends ConfigInput>({
67
70
  throw new Error(`Unsupported World version: ${worldDeploy.worldVersion}`);
68
71
  }
69
72
 
70
- await assertNamespaceOwner({
73
+ const namespaceTxs = await ensureNamespaceOwner({
71
74
  client,
72
75
  worldDeploy,
73
76
  resourceIds: [...tables.map((table) => table.tableId), ...systems.map((system) => system.systemId)],
74
77
  });
75
78
 
79
+ debug("waiting for all namespace registration transactions to confirm");
80
+ for (const tx of namespaceTxs) {
81
+ await waitForTransactionReceipt(client, { hash: tx });
82
+ }
83
+
76
84
  const tableTxs = await ensureTables({
77
85
  client,
78
86
  worldDeploy,
@@ -1,4 +1,4 @@
1
- import { Account, Chain, Client, Log, Transport } from "viem";
1
+ import { Account, Chain, Client, Hex, Log, Transport } from "viem";
2
2
  import { waitForTransactionReceipt } from "viem/actions";
3
3
  import { ensureWorldFactory, worldFactory } from "./ensureWorldFactory";
4
4
  import WorldFactoryAbi from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json" assert { type: "json" };
@@ -7,7 +7,10 @@ import { debug } from "./debug";
7
7
  import { logsToWorldDeploy } from "./logsToWorldDeploy";
8
8
  import { WorldDeploy } from "./common";
9
9
 
10
- export async function deployWorld(client: Client<Transport, Chain | undefined, Account>): Promise<WorldDeploy> {
10
+ export async function deployWorld(
11
+ client: Client<Transport, Chain | undefined, Account>,
12
+ salt: Hex
13
+ ): Promise<WorldDeploy> {
11
14
  await ensureWorldFactory(client);
12
15
 
13
16
  debug("deploying world");
@@ -16,6 +19,7 @@ export async function deployWorld(client: Client<Transport, Chain | undefined, A
16
19
  address: worldFactory,
17
20
  abi: WorldFactoryAbi,
18
21
  functionName: "deployWorld",
22
+ args: [salt],
19
23
  });
20
24
 
21
25
  debug("waiting for world deploy");
@@ -0,0 +1,71 @@
1
+ import { Account, Chain, Client, Hex, Transport, getAddress } from "viem";
2
+ import { WorldDeploy, worldAbi, worldTables } from "./common";
3
+ import { hexToResource, resourceToHex, writeContract } from "@latticexyz/common";
4
+ import { getResourceIds } from "./getResourceIds";
5
+ import { getTableValue } from "./getTableValue";
6
+ import { debug } from "./debug";
7
+
8
+ export async function ensureNamespaceOwner({
9
+ client,
10
+ worldDeploy,
11
+ resourceIds,
12
+ }: {
13
+ readonly client: Client<Transport, Chain | undefined, Account>;
14
+ readonly worldDeploy: WorldDeploy;
15
+ readonly resourceIds: readonly Hex[];
16
+ }): Promise<readonly Hex[]> {
17
+ const desiredNamespaces = Array.from(new Set(resourceIds.map((resourceId) => hexToResource(resourceId).namespace)));
18
+ const existingResourceIds = await getResourceIds({ client, worldDeploy });
19
+ const existingNamespaces = new Set(existingResourceIds.map((resourceId) => hexToResource(resourceId).namespace));
20
+ if (existingNamespaces.size) {
21
+ debug(
22
+ "found",
23
+ existingNamespaces.size,
24
+ "existing namespaces:",
25
+ Array.from(existingNamespaces)
26
+ .map((namespace) => (namespace === "" ? "<root>" : namespace))
27
+ .join(", ")
28
+ );
29
+ }
30
+
31
+ // Assert ownership of existing namespaces
32
+ const existingDesiredNamespaces = desiredNamespaces.filter((namespace) => existingNamespaces.has(namespace));
33
+ const namespaceOwners = await Promise.all(
34
+ existingDesiredNamespaces.map(async (namespace) => {
35
+ const { owner } = await getTableValue({
36
+ client,
37
+ worldDeploy,
38
+ table: worldTables.world_NamespaceOwner,
39
+ key: { namespaceId: resourceToHex({ type: "namespace", namespace, name: "" }) },
40
+ });
41
+ return [namespace, owner];
42
+ })
43
+ );
44
+
45
+ const unauthorizedNamespaces = namespaceOwners
46
+ .filter(([, owner]) => getAddress(owner) !== getAddress(client.account.address))
47
+ .map(([namespace]) => namespace);
48
+
49
+ if (unauthorizedNamespaces.length) {
50
+ throw new Error(`You are attempting to deploy to namespaces you do not own: ${unauthorizedNamespaces.join(", ")}`);
51
+ }
52
+
53
+ // Register missing namespaces
54
+ const missingNamespaces = desiredNamespaces.filter((namespace) => !existingNamespaces.has(namespace));
55
+ if (missingNamespaces.length > 0) {
56
+ debug("registering namespaces", Array.from(missingNamespaces).join(", "));
57
+ }
58
+ const registrationTxs = Promise.all(
59
+ missingNamespaces.map((namespace) =>
60
+ writeContract(client, {
61
+ chain: client.chain ?? null,
62
+ address: worldDeploy.address,
63
+ abi: worldAbi,
64
+ functionName: "registerNamespace",
65
+ args: [resourceToHex({ namespace, type: "namespace", name: "" })],
66
+ })
67
+ )
68
+ );
69
+
70
+ return registrationTxs;
71
+ }
@@ -1,32 +1,103 @@
1
- import coreModuleBuild from "@latticexyz/world/out/CoreModule.sol/CoreModule.json" assert { type: "json" };
1
+ import accessManagementSystemBuild from "@latticexyz/world/out/AccessManagementSystem.sol/AccessManagementSystem.json" assert { type: "json" };
2
+ import balanceTransferSystemBuild from "@latticexyz/world/out/BalanceTransferSystem.sol/BalanceTransferSystem.json" assert { type: "json" };
3
+ import batchCallSystemBuild from "@latticexyz/world/out/BatchCallSystem.sol/BatchCallSystem.json" assert { type: "json" };
4
+ import registrationSystemBuild from "@latticexyz/world/out/RegistrationSystem.sol/RegistrationSystem.json" assert { type: "json" };
5
+ import initModuleBuild from "@latticexyz/world/out/InitModule.sol/InitModule.json" assert { type: "json" };
6
+ import initModuleAbi from "@latticexyz/world/out/InitModule.sol/InitModule.abi.json" assert { type: "json" };
2
7
  import worldFactoryBuild from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.json" assert { type: "json" };
3
- import { Client, Transport, Chain, Account, Hex, parseAbi, getCreate2Address, encodeDeployData, size } from "viem";
8
+ import worldFactoryAbi from "@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json" assert { type: "json" };
9
+ import { Client, Transport, Chain, Account, Hex, getCreate2Address, encodeDeployData, size } from "viem";
4
10
  import { deployer } from "./ensureDeployer";
5
11
  import { salt } from "./common";
6
12
  import { ensureContractsDeployed } from "./ensureContractsDeployed";
7
13
  import { Contract } from "./ensureContract";
8
14
 
9
- export const coreModuleDeployedBytecodeSize = size(coreModuleBuild.deployedBytecode.object as Hex);
10
- export const coreModuleBytecode = encodeDeployData({
11
- bytecode: coreModuleBuild.bytecode.object as Hex,
15
+ export const accessManagementSystemDeployedBytecodeSize = size(
16
+ accessManagementSystemBuild.deployedBytecode.object as Hex
17
+ );
18
+ export const accessManagementSystemBytecode = encodeDeployData({
19
+ bytecode: accessManagementSystemBuild.bytecode.object as Hex,
12
20
  abi: [],
13
21
  });
22
+ export const accessManagementSystem = getCreate2Address({
23
+ from: deployer,
24
+ bytecode: accessManagementSystemBytecode,
25
+ salt,
26
+ });
27
+
28
+ export const balanceTransferSystemDeployedBytecodeSize = size(
29
+ balanceTransferSystemBuild.deployedBytecode.object as Hex
30
+ );
31
+ export const balanceTransferSystemBytecode = encodeDeployData({
32
+ bytecode: balanceTransferSystemBuild.bytecode.object as Hex,
33
+ abi: [],
34
+ });
35
+ export const balanceTransferSystem = getCreate2Address({
36
+ from: deployer,
37
+ bytecode: balanceTransferSystemBytecode,
38
+ salt,
39
+ });
40
+
41
+ export const batchCallSystemDeployedBytecodeSize = size(batchCallSystemBuild.deployedBytecode.object as Hex);
42
+ export const batchCallSystemBytecode = encodeDeployData({
43
+ bytecode: batchCallSystemBuild.bytecode.object as Hex,
44
+ abi: [],
45
+ });
46
+ export const batchCallSystem = getCreate2Address({ from: deployer, bytecode: batchCallSystemBytecode, salt });
47
+
48
+ export const registrationDeployedBytecodeSize = size(registrationSystemBuild.deployedBytecode.object as Hex);
49
+ export const registrationBytecode = encodeDeployData({
50
+ bytecode: registrationSystemBuild.bytecode.object as Hex,
51
+ abi: [],
52
+ });
53
+ export const registration = getCreate2Address({
54
+ from: deployer,
55
+ bytecode: registrationBytecode,
56
+ salt,
57
+ });
58
+
59
+ export const initModuleDeployedBytecodeSize = size(initModuleBuild.deployedBytecode.object as Hex);
60
+ export const initModuleBytecode = encodeDeployData({
61
+ bytecode: initModuleBuild.bytecode.object as Hex,
62
+ abi: initModuleAbi,
63
+ args: [accessManagementSystem, balanceTransferSystem, batchCallSystem, registration],
64
+ });
14
65
 
15
- export const coreModule = getCreate2Address({ from: deployer, bytecode: coreModuleBytecode, salt });
66
+ export const initModule = getCreate2Address({ from: deployer, bytecode: initModuleBytecode, salt });
16
67
 
17
68
  export const worldFactoryDeployedBytecodeSize = size(worldFactoryBuild.deployedBytecode.object as Hex);
18
69
  export const worldFactoryBytecode = encodeDeployData({
19
70
  bytecode: worldFactoryBuild.bytecode.object as Hex,
20
- abi: parseAbi(["constructor(address)"]),
21
- args: [coreModule],
71
+ abi: worldFactoryAbi,
72
+ args: [initModule],
22
73
  });
23
74
 
24
75
  export const worldFactory = getCreate2Address({ from: deployer, bytecode: worldFactoryBytecode, salt });
25
76
 
26
77
  export const worldFactoryContracts: readonly Contract[] = [
27
78
  {
28
- bytecode: coreModuleBytecode,
29
- deployedBytecodeSize: coreModuleDeployedBytecodeSize,
79
+ bytecode: accessManagementSystemBytecode,
80
+ deployedBytecodeSize: accessManagementSystemDeployedBytecodeSize,
81
+ label: "access management system",
82
+ },
83
+ {
84
+ bytecode: balanceTransferSystemBytecode,
85
+ deployedBytecodeSize: balanceTransferSystemDeployedBytecodeSize,
86
+ label: "balance transfer system",
87
+ },
88
+ {
89
+ bytecode: batchCallSystemBytecode,
90
+ deployedBytecodeSize: batchCallSystemDeployedBytecodeSize,
91
+ label: "batch call system",
92
+ },
93
+ {
94
+ bytecode: registrationBytecode,
95
+ deployedBytecodeSize: registrationDeployedBytecodeSize,
96
+ label: "core registration system",
97
+ },
98
+ {
99
+ bytecode: initModuleBytecode,
100
+ deployedBytecodeSize: initModuleDeployedBytecodeSize,
30
101
  label: "core module",
31
102
  },
32
103
  {
@@ -39,7 +110,7 @@ export const worldFactoryContracts: readonly Contract[] = [
39
110
  export async function ensureWorldFactory(
40
111
  client: Client<Transport, Chain | undefined, Account>
41
112
  ): Promise<readonly Hex[]> {
42
- // WorldFactory constructor doesn't call CoreModule, only sets its address, so we can do these in parallel since the address is deterministic
113
+ // WorldFactory constructor doesn't call InitModule, only sets its address, so we can do these in parallel since the address is deterministic
43
114
  return await ensureContractsDeployed({
44
115
  client,
45
116
  contracts: worldFactoryContracts,
@@ -1,11 +1,9 @@
1
- import { Client, getFunctionSelector, parseAbiItem } from "viem";
1
+ import { Client, parseAbiItem } from "viem";
2
2
  import { WorldDeploy, WorldFunction, worldTables } from "./common";
3
3
  import { debug } from "./debug";
4
4
  import { storeSetRecordEvent } from "@latticexyz/store";
5
5
  import { getLogs } from "viem/actions";
6
- import { decodeValueArgs } from "@latticexyz/protocol-parser";
7
- import { getTableValue } from "./getTableValue";
8
- import { hexToResource } from "@latticexyz/common";
6
+ import { decodeKey, decodeValueArgs } from "@latticexyz/protocol-parser";
9
7
 
10
8
  export async function getFunctions({
11
9
  client,
@@ -15,44 +13,52 @@ export async function getFunctions({
15
13
  readonly worldDeploy: WorldDeploy;
16
14
  }): Promise<readonly WorldFunction[]> {
17
15
  // This assumes we only use `FunctionSelectors._set(...)`, which is true as of this writing.
18
- debug("looking up function signatures for", worldDeploy.address);
19
- const logs = await getLogs(client, {
16
+ debug("looking up function selectors for", worldDeploy.address);
17
+ const selectorLogs = await getLogs(client, {
20
18
  strict: true,
21
19
  fromBlock: worldDeploy.deployBlock,
22
20
  toBlock: worldDeploy.stateBlock,
23
21
  address: worldDeploy.address,
24
22
  event: parseAbiItem(storeSetRecordEvent),
25
- args: { tableId: worldTables.world_FunctionSignatures.tableId },
23
+ args: { tableId: worldTables.world_FunctionSelectors.tableId },
24
+ });
25
+
26
+ const selectors = selectorLogs.map((log) => {
27
+ return {
28
+ ...decodeValueArgs(worldTables.world_FunctionSelectors.valueSchema, log.args),
29
+ ...decodeKey(worldTables.world_FunctionSelectors.keySchema, log.args.keyTuple),
30
+ };
26
31
  });
32
+ debug("found", selectors.length, "function selectors for", worldDeploy.address);
27
33
 
28
- const signatures = logs.map((log) => {
29
- const value = decodeValueArgs(worldTables.world_FunctionSignatures.valueSchema, log.args);
30
- return value.functionSignature;
34
+ // This assumes we only use `FunctionSignatures._set(...)`, which is true as of this writing.
35
+ debug("looking up function signatures for", worldDeploy.address);
36
+ const signatureLogs = await getLogs(client, {
37
+ strict: true,
38
+ fromBlock: worldDeploy.deployBlock,
39
+ toBlock: worldDeploy.stateBlock,
40
+ address: worldDeploy.address,
41
+ event: parseAbiItem(storeSetRecordEvent),
42
+ args: { tableId: worldTables.world_FunctionSignatures.tableId },
31
43
  });
32
- debug("found", signatures.length, "function signatures for", worldDeploy.address);
33
44
 
34
- // TODO: parallelize with a bulk getRecords
35
- const functions = await Promise.all(
36
- signatures.map(async (signature) => {
37
- const selector = getFunctionSelector(signature);
38
- const { systemId, systemFunctionSelector } = await getTableValue({
39
- client,
40
- worldDeploy,
41
- table: worldTables.world_FunctionSelectors,
42
- key: { functionSelector: selector },
43
- });
44
- const { namespace, name } = hexToResource(systemId);
45
- // TODO: find away around undoing contract logic (https://github.com/latticexyz/mud/issues/1708)
46
- const systemFunctionSignature = namespace === "" ? signature : signature.replace(`${namespace}_${name}_`, "");
47
- return {
48
- signature,
49
- selector,
50
- systemId,
51
- systemFunctionSignature,
52
- systemFunctionSelector,
53
- };
45
+ const selectorToSignature = Object.fromEntries(
46
+ signatureLogs.map((log) => {
47
+ return [
48
+ decodeKey(worldTables.world_FunctionSignatures.keySchema, log.args.keyTuple).functionSelector,
49
+ decodeValueArgs(worldTables.world_FunctionSignatures.valueSchema, log.args).functionSignature,
50
+ ];
54
51
  })
55
52
  );
53
+ debug("found", signatureLogs.length, "function signatures for", worldDeploy.address);
54
+
55
+ const functions = selectors.map(({ functionSelector: worldFunctionSelector, systemFunctionSelector, systemId }) => ({
56
+ selector: worldFunctionSelector,
57
+ signature: selectorToSignature[worldFunctionSelector],
58
+ systemFunctionSelector,
59
+ systemFunctionSignature: selectorToSignature[systemFunctionSelector],
60
+ systemId,
61
+ }));
56
62
 
57
63
  return functions;
58
64
  }
@@ -54,7 +54,7 @@ export function resolveConfig<config extends ConfigInput>({
54
54
  .filter((sig) => !baseSystemFunctions.includes(sig))
55
55
  .map((sig): WorldFunction => {
56
56
  // TODO: figure out how to not duplicate contract behavior (https://github.com/latticexyz/mud/issues/1708)
57
- const worldSignature = namespace === "" ? sig : `${namespace}_${name}_${sig}`;
57
+ const worldSignature = namespace === "" ? sig : `${namespace}__${sig}`;
58
58
  return {
59
59
  signature: worldSignature,
60
60
  selector: getFunctionSelector(worldSignature),
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 } from "viem";
5
+ import { createWalletClient, http, Hex, isHex } from "viem";
6
6
  import { privateKeyToAccount } from "viem/accounts";
7
7
  import { loadConfig } from "@latticexyz/config/node";
8
8
  import { StoreConfig } from "@latticexyz/store";
@@ -29,6 +29,10 @@ export const deployOptions = {
29
29
  type: "boolean",
30
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.",
31
31
  },
32
+ salt: {
33
+ type: "string",
34
+ desc: "The deployment salt to use. Defaults to a random salt.",
35
+ },
32
36
  } as const satisfies Record<string, Options>;
33
37
 
34
38
  export type DeployOptions = InferredOptionTypes<typeof deployOptions>;
@@ -38,6 +42,11 @@ export type DeployOptions = InferredOptionTypes<typeof deployOptions>;
38
42
  * This is used by the deploy, test, and dev-contracts CLI commands.
39
43
  */
40
44
  export async function runDeploy(opts: DeployOptions): Promise<WorldDeploy> {
45
+ const salt = opts.salt;
46
+ if (salt != null && !isHex(salt)) {
47
+ throw new MUDError("Expected hex string for salt");
48
+ }
49
+
41
50
  const profile = opts.profile ?? process.env.FOUNDRY_PROFILE;
42
51
 
43
52
  const config = (await loadConfig(opts.configPath)) as StoreConfig & WorldConfig;
@@ -79,6 +88,7 @@ in your contracts directory to use the default anvil private key.`
79
88
 
80
89
  const startTime = Date.now();
81
90
  const worldDeploy = await deploy({
91
+ salt,
82
92
  worldAddress: opts.worldAddress as Hex | undefined,
83
93
  client,
84
94
  config: resolvedConfig,
@@ -1,27 +0,0 @@
1
- import{a as z}from"./chunk-22IIKR4S.js";import es from"@latticexyz/gas-report";import os from"@latticexyz/abi-ts";import{loadConfig as Eo}from"@latticexyz/config/node";import{getSrcDirectory as Ho}from"@latticexyz/common/foundry";import{existsSync as Io,readFileSync as Oo,writeFileSync as Po}from"node:fs";import Y from"node:path";import{tablegen as jo}from"@latticexyz/store/codegen";import{worldgen as Fo}from"@latticexyz/world/node";import{forge as Wo,getForgeConfig as Bo,getRemappings as Mo}from"@latticexyz/common/foundry";import To from"glob";import{basename as Ao}from"path";function I(e){return To.sync(`${e}/**/*.sol`).map(o=>({path:o,basename:Ao(o,".sol")}))}import me from"debug";var W=me("mud:cli"),ko=me("mud:cli");W.log=console.debug.bind(console);ko.log=console.error.bind(console);import{execa as Ro}from"execa";var $o=W.extend("runDeploy");async function U({config:e,srcDir:o,foundryProfile:t=process.env.FOUNDRY_PROFILE}){let r=Y.join(o,e.codegenDirectory),n=await Mo(t);await Promise.all([jo(e,r,n),Fo(e,I(o),r)]);let s=await Bo(t);if(s.cache){let d=Y.join(s.cache_path,"solidity-files-cache.json");if(Io(d)){$o("Unsetting cached content hash of IWorld.sol to force it to regenerate");let i=JSON.parse(Oo(d,"utf8")),p=Y.join(r,"world","IWorld.sol");i.files[p].contentHash="",Po(d,JSON.stringify(i,null,2))}}await Wo(["build"],{profile:t}),await Ro("mud",["abi-ts"],{stdio:"inherit"})}var No={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 t=await Eo(e),r=await Ho();await U({config:t,srcDir:r,foundryProfile:o}),process.exit(0)}},pe=No;import{rmSync as zo}from"fs";import{homedir as Uo}from"os";import Vo from"path";import{execa as _o}from"execa";var Lo={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=Uo();zo(Vo.join(o,".foundry","anvil","tmp"),{recursive:!0,force:!0});let t=["-b",String(e),"--block-base-fee-per-gas","0"];console.log(`Running: anvil ${t.join(" ")}`);let r=_o("anvil",t,{stdio:["inherit","inherit","inherit"]});process.on("SIGINT",()=>{console.log(`
2
- gracefully shutting down from SIGINT (Crtl-C)`),r.kill(),process.exit()}),await r}},fe=Lo;import{FaucetServiceDefinition as Ko}from"@latticexyz/services/faucet";import{createChannel as Jo,createClient as qo}from"nice-grpc-web";import ue from"chalk";import{NodeHttpTransport as Go}from"@improbable-eng/grpc-web-node-http-transport";function Yo(e){return qo(Ko,Jo(e,Go()))}var Zo={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:t}){let r=Yo(o);e&&(console.log(ue.yellow("Dripping to",t)),await r.dripDev({address:t}),console.log(ue.yellow("Success"))),process.exit(0)}},ye=Zo;var Qo={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)}},ge=Qo;import Xo from"path";import{loadConfig as et}from"@latticexyz/config/node";import{tablegen as ot}from"@latticexyz/store/codegen";import{getRemappings as tt,getSrcDirectory as rt}from"@latticexyz/common/foundry";var nt={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 et(e),t=await rt(),r=await tt();await ot(o,Xo.join(t,o.codegenDirectory),r),process.exit(0)}},be=nt;import ie from"node:path";import{existsSync as zr,mkdirSync as Ur,readFileSync as Vr,writeFileSync as ae}from"node:fs";import{getAddress as eo}from"viem";import{getBytecode as at,sendRawTransaction as ct,sendTransaction as dt,waitForTransactionReceipt as he}from"viem/actions";var F={gasPrice:1e11,gasLimit:1e5,signerAddress:"3fab184622dc19b6109349b94811493bf2a45362",transaction:"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222",address:"4e59b44847b379578588920ca78fbf26c0b4956c"};var l=W.extend("deploy"),it=W.extend("deploy");l.log=console.debug.bind(console);it.log=console.error.bind(console);var v=`0x${F.address}`;async function we(e){if(await at(e,{address:v})){l("found create2 deployer at",v);return}l("sending gas for create2 deployer to signer at",F.signerAddress);let t=await dt(e,{chain:e.chain??null,to:`0x${F.signerAddress}`,value:BigInt(F.gasLimit)*BigInt(F.gasPrice)}),r=await he(e,{hash:t});if(r.status!=="success")throw console.error("failed to send gas to deployer signer",r),new Error("failed to send gas to deployer signer");l("deploying create2 deployer at",v);let n=await ct(e,{serializedTransaction:`0x${F.transaction}`}),s=await he(e,{hash:n});if(s.contractAddress!==v)throw console.error("unexpected contract address for deployer",s),new Error("unexpected contract address for deployer")}import{waitForTransactionReceipt as Wt}from"viem/actions";import De from"@latticexyz/world/out/CoreModule.sol/CoreModule.json"assert{type:"json"};import Te from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.json"assert{type:"json"};import{parseAbi as Tt,getCreate2Address as Ae,encodeDeployData as ke,size as Ie}from"viem";import{padHex as mt}from"viem";import pt from"@latticexyz/store/mud.config";import ft from"@latticexyz/world/mud.config";import ut from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import yt from"@latticexyz/world-modules/out/IModule.sol/IModule.abi.json"assert{type:"json"};import{resourceToHex as lt}from"@latticexyz/common";import{resolveUserTypes as xe}from"@latticexyz/store";function E(e){let o={...e.userTypes,...Object.fromEntries(Object.entries(e.enums).map(([t])=>[t,{internalType:"uint8"}]))};return Object.fromEntries(Object.entries(e.tables).map(([t,r])=>[`${e.namespace}_${t}`,{namespace:e.namespace,name:r.name,tableId:lt({type:r.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:r.name}),keySchema:xe(r.keySchema,o),valueSchema:xe(r.valueSchema,o)}]))}import{helloStoreEvent as gt}from"@latticexyz/store";import{helloWorldEvent as bt}from"@latticexyz/world";var T=mt("0x",{size:32}),H=parseInt("6000",16),B=E(pt),D=E(ft),V=[gt,bt],C=[...ut,...yt],Se=["1.0.0-unaudited"],Ce=["1.0.0-unaudited"];import{waitForTransactionReceipt as Dt}from"viem/actions";import{concatHex as ht,getCreate2Address as wt}from"viem";import{getBytecode as xt}from"viem/actions";import{sendTransaction as St}from"@latticexyz/common";import Ct from"p-retry";import{wait as vt}from"@latticexyz/common/utils";async function ve({client:e,bytecode:o,deployedBytecodeSize:t,label:r="contract"}){let n=wt({from:v,salt:T,bytecode:o});return await xt(e,{address:n,blockTag:"pending"})?(l("found",r,"at",n),[]):(t>H?console.warn(`
3
- Bytecode for ${r} (${t} bytes) is over the contract size limit (${H} bytes). Run \`forge build --sizes\` for more info.
4
- `):t>H*.95&&console.warn(`
5
- Bytecode for ${r} (${t} bytes) is almost over the contract size limit (${H} bytes). Run \`forge build --sizes\` for more info.
6
- `),l("deploying",r,"at",n),[await Ct(()=>St(e,{chain:e.chain??null,to:v,data:ht([T,o])}),{retries:3,onFailedAttempt:async d=>{let i=d.attemptNumber*500;l(`failed to deploy ${r}, retrying in ${i}ms...`),await vt(i)}})])}async function O({client:e,contracts:o}){let t=(await Promise.all(o.map(r=>ve({client:e,...r})))).flat();if(t.length){l("waiting for contracts");for(let r of t)await Dt(e,{hash:r})}return t}var At=Ie(De.deployedBytecode.object),Oe=ke({bytecode:De.bytecode.object,abi:[]}),kt=Ae({from:v,bytecode:Oe,salt:T}),It=Ie(Te.deployedBytecode.object),Pe=ke({bytecode:Te.bytecode.object,abi:Tt(["constructor(address)"]),args:[kt]}),je=Ae({from:v,bytecode:Pe,salt:T}),Z=[{bytecode:Oe,deployedBytecodeSize:At,label:"core module"},{bytecode:Pe,deployedBytecodeSize:It,label:"world factory"}];async function Fe(e){return await O({client:e,contracts:Z})}import Bt from"@latticexyz/world/out/WorldFactory.sol/WorldFactory.abi.json"assert{type:"json"};import{writeContract as Mt}from"@latticexyz/common";import{AbiEventSignatureNotFoundError as Ot,decodeEventLog as Pt,hexToString as We,parseAbi as jt,trim as Be}from"viem";import{isDefined as Ft}from"@latticexyz/common/utils";function _(e){let o=e.map(d=>{try{return{...d,...Pt({strict:!0,abi:jt(V),topics:d.topics,data:d.data})}}catch(i){if(i instanceof Ot)return;throw i}}).filter(Ft),{address:t,deployBlock:r,worldVersion:n,storeVersion:s}=o.reduce((d,i)=>({...d,address:i.address,deployBlock:i.blockNumber,...i.eventName==="HelloWorld"?{worldVersion:We(Be(i.args.worldVersion,{dir:"right"}))}:null,...i.eventName==="HelloStore"?{storeVersion:We(Be(i.args.storeVersion,{dir:"right"}))}:null}),{});if(t==null)throw new Error("could not find world address");if(r==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:t,deployBlock:r,worldVersion:n,storeVersion:s}}async function Me(e){await Fe(e),l("deploying world");let o=await Mt(e,{chain:e.chain??null,address:je,abi:Bt,functionName:"deployWorld"});l("waiting for world deploy");let t=await Wt(e,{hash:o});if(t.status!=="success")throw console.error("world deploy failed",t),new Error("world deploy failed");let r=_(t.logs.map(n=>n));return l("deployed world to",r.address,"at block",r.deployBlock),{...r,stateBlock:r.deployBlock}}import{writeContract as Ut}from"@latticexyz/common";import{valueSchemaToFieldLayoutHex as Vt,keySchemaToHex as _t,valueSchemaToHex as Lt}from"@latticexyz/protocol-parser";function S({namespace:e,name:o}){return`${e}:${o}`}import{parseAbiItem as Rt,decodeAbiParameters as Re,parseAbiParameters as $e}from"viem";import{hexToResource as $t}from"@latticexyz/common";import{storeSetRecordEvent as Et}from"@latticexyz/store";import{getLogs as Ht}from"viem/actions";import{decodeKey as Nt,decodeValueArgs as zt,hexToSchema as Ee}from"@latticexyz/protocol-parser";async function He({client:e,worldDeploy:o}){l("looking up tables for",o.address);let r=(await Ht(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:Rt(Et),args:{tableId:B.store_Tables.tableId}})).map(n=>{let{tableId:s}=Nt(B.store_Tables.keySchema,n.args.keyTuple),{namespace:d,name:i}=$t(s),p=zt(B.store_Tables.valueSchema,n.args),a=Ee(p.keySchema),m=Ee(p.valueSchema),f=Re($e("string[]"),p.abiEncodedKeyNames)[0],g=Re($e("string[]"),p.abiEncodedFieldNames)[0],u=[...m.staticFields,...m.dynamicFields],w=Object.fromEntries(a.staticFields.map((x,c)=>[f[c],x])),b=Object.fromEntries(u.map((x,c)=>[g[c],x]));return{namespace:d,name:i,tableId:s,keySchema:w,valueSchema:b}});return l("found",r.length,"tables for",o.address),r}import Kt from"p-retry";import{wait as Jt}from"@latticexyz/common/utils";async function Ne({client:e,worldDeploy:o,tables:t}){let n=(await He({client:e,worldDeploy:o})).map(i=>i.tableId),s=t.filter(i=>n.includes(i.tableId));s.length&&l("existing tables",s.map(S).join(", "));let d=t.filter(i=>!n.includes(i.tableId));return d.length?(l("registering tables",d.map(S).join(", ")),await Promise.all(d.map(i=>Kt(()=>Ut(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerTable",args:[i.tableId,Vt(i.valueSchema),_t(i.keySchema),Lt(i.valueSchema),Object.keys(i.keySchema),Object.keys(i.valueSchema)]}),{retries:3,onFailedAttempt:async p=>{let a=p.attemptNumber*500;l(`failed to register table ${S(i)}, retrying in ${a}ms...`),await Jt(a)}})))):[]}import{getAddress as A}from"viem";import{writeContract as Q}from"@latticexyz/common";import{parseAbiItem as qt}from"viem";import{getLogs as Gt}from"viem/actions";import{storeSpliceStaticDataEvent as Yt}from"@latticexyz/store";async function L({client:e,worldDeploy:o}){l("looking up resource IDs for",o.address);let r=(await Gt(e,{strict:!0,address:o.address,fromBlock:o.deployBlock,toBlock:o.stateBlock,event:qt(Yt),args:{tableId:B.store_ResourceIds.tableId}})).map(n=>n.args.keyTuple[0]);return l("found",r.length,"resource IDs for",o.address),r}import{hexToResource as mr}from"@latticexyz/common";import{decodeValueArgs as Zt,encodeKey as Qt}from"@latticexyz/protocol-parser";import{readContract as Xt}from"viem/actions";async function P({client:e,worldDeploy:o,table:t,key:r}){let[n,s,d]=await Xt(e,{blockNumber:o.stateBlock,address:o.address,abi:C,functionName:"getRecord",args:[t.tableId,Qt(t.keySchema,r)]});return Zt(t.valueSchema,{staticData:n,encodedLengths:s,dynamicData:d})}import{getFunctionSelector as er,parseAbiItem as or}from"viem";import{storeSetRecordEvent as tr}from"@latticexyz/store";import{getLogs as rr}from"viem/actions";import{decodeValueArgs as nr}from"@latticexyz/protocol-parser";import{hexToResource as sr}from"@latticexyz/common";async function K({client:e,worldDeploy:o}){l("looking up function signatures for",o.address);let r=(await rr(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:or(tr),args:{tableId:D.world_FunctionSignatures.tableId}})).map(s=>nr(D.world_FunctionSignatures.valueSchema,s.args).functionSignature);return l("found",r.length,"function signatures for",o.address),await Promise.all(r.map(async s=>{let d=er(s),{systemId:i,systemFunctionSelector:p}=await P({client:e,worldDeploy:o,table:D.world_FunctionSelectors,key:{functionSelector:d}}),{namespace:a,name:m}=sr(i),f=a===""?s:s.replace(`${a}_${m}_`,"");return{signature:s,selector:d,systemId:i,systemFunctionSignature:f,systemFunctionSelector:p}}))}import{parseAbiItem as ir,getAddress as ar}from"viem";import{storeSpliceStaticDataEvent as cr}from"@latticexyz/store";import{getLogs as dr}from"viem/actions";import{decodeKey as lr}from"@latticexyz/protocol-parser";async function J({client:e,worldDeploy:o}){l("looking up resource access for",o.address);let r=(await dr(e,{strict:!0,fromBlock:o.deployBlock,toBlock:o.stateBlock,address:o.address,event:ir(cr),args:{tableId:D.world_ResourceAccess.tableId}})).map(s=>lr(D.world_ResourceAccess.keySchema,s.args.keyTuple)),n=(await Promise.all(r.map(async s=>[s,await P({client:e,worldDeploy:o,table:D.world_ResourceAccess,key:s})]))).filter(([,s])=>s.access).map(([s])=>({resourceId:s.resourceId,address:ar(s.caller)}));return l("found",n.length,"resource<>address access pairs"),n}async function ze({client:e,worldDeploy:o}){let[t,r,n]=await Promise.all([L({client:e,worldDeploy:o}),K({client:e,worldDeploy:o}),J({client:e,worldDeploy:o})]),s=t.map(mr).filter(d=>d.type==="system");return l("looking up systems",s.map(S).join(", ")),await Promise.all(s.map(async d=>{let{system:i,publicAccess:p}=await P({client:e,worldDeploy:o,table:D.world_Systems,key:{systemId:d.resourceId}}),a=r.filter(m=>m.systemId===d.resourceId);return{address:i,namespace:d.namespace,name:d.name,systemId:d.resourceId,allowAll:p,allowedAddresses:n.filter(({resourceId:m})=>m===d.resourceId).map(({address:m})=>m),functions:a}}))}import{uniqueBy as pr,wait as X}from"@latticexyz/common/utils";import ee from"p-retry";async function Ue({client:e,worldDeploy:o,systems:t}){let[r,n]=await Promise.all([ze({client:e,worldDeploy:o}),J({client:e,worldDeploy:o})]),s=t.map(c=>c.systemId),d=n.filter(({resourceId:c})=>s.includes(c)),i=t.flatMap(c=>c.allowedAddresses.map(y=>({resourceId:c.systemId,address:y}))),p=i.filter(c=>!d.some(({resourceId:y,address:h})=>y===c.resourceId&&A(h)===A(c.address))),a=d.filter(c=>!i.some(({resourceId:y,address:h})=>y===c.resourceId&&A(h)===A(c.address)));a.length&&l("revoking",a.length,"access grants"),p.length&&l("adding",p.length,"access grants");let m=[...a.map(c=>ee(()=>Q(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"revokeAccess",args:[c.resourceId,c.address]}),{retries:3,onFailedAttempt:async y=>{let h=y.attemptNumber*500;l(`failed to revoke access, retrying in ${h}ms...`),await X(h)}})),...p.map(c=>ee(()=>Q(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"grantAccess",args:[c.resourceId,c.address]}),{retries:3,onFailedAttempt:async y=>{let h=y.attemptNumber*500;l(`failed to grant access, retrying in ${h}ms...`),await X(h)}}))],f=t.filter(c=>r.some(y=>y.systemId===c.systemId&&A(y.address)===A(c.address)));f.length&&l("existing systems",f.map(S).join(", "));let g=f.map(c=>c.systemId),u=t.filter(c=>!g.includes(c.systemId));if(!u.length)return[];let w=u.filter(c=>r.some(y=>y.systemId===c.systemId&&A(y.address)!==A(c.address)));w.length&&l("upgrading systems",w.map(S).join(", "));let b=u.filter(c=>!r.some(y=>y.systemId===c.systemId));b.length&&l("registering new systems",b.map(S).join(", ")),await O({client:e,contracts:pr(u,c=>A(c.address)).map(c=>({bytecode:c.bytecode,deployedBytecodeSize:c.deployedBytecodeSize,label:`${S(c)} system`}))});let x=u.map(c=>ee(()=>Q(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerSystem",args:[c.systemId,c.address,c.allowAll]}),{retries:3,onFailedAttempt:async y=>{let h=y.attemptNumber*500;l(`failed to register system ${S(c)}, retrying in ${h}ms...`),await X(h)}}));return await Promise.all([...m,...x])}import{waitForTransactionReceipt as Tr}from"viem/actions";import{getAddress as fr,parseAbi as ur}from"viem";import{getBlockNumber as yr,getLogs as gr}from"viem/actions";var Ve=new Map;async function _e(e,o){let t=fr(o),r=Ve.get(t);if(r!=null)return r;l("looking up world deploy for",t);let n=await yr(e),s=await gr(e,{strict:!0,address:t,events:ur(V),fromBlock:"earliest",toBlock:n});return r={..._(s),stateBlock:n},Ve.set(t,r),l("found world deploy for",t,"at block",r.deployBlock),r}import{hexToResource as br,writeContract as Le}from"@latticexyz/common";import Ke from"p-retry";import{wait as Je}from"@latticexyz/common/utils";async function qe({client:e,worldDeploy:o,functions:t}){let r=await K({client:e,worldDeploy:o}),n=Object.fromEntries(r.map(i=>[i.selector,i])),s=t.filter(i=>n[i.selector]),d=t.filter(i=>!s.includes(i));if(s.length){l("functions already registered:",s.map(p=>p.signature).join(", "));let i=s.filter(p=>p.systemId!==n[p.selector]?.systemId);i.length&&console.warn("found",i.length,"functions already registered but pointing at a different system ID:",i.map(p=>p.signature).join(", "))}return d.length?(l("registering functions:",d.map(i=>i.signature).join(", ")),Promise.all(d.map(i=>{let{namespace:p}=br(i.systemId);return p===""?Ke(()=>Le(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerRootFunctionSelector",args:[i.systemId,i.systemFunctionSignature,i.systemFunctionSelector]}),{retries:3,onFailedAttempt:async a=>{let m=a.attemptNumber*500;l(`failed to register function ${i.signature}, retrying in ${m}ms...`),await Je(m)}}):Ke(()=>Le(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"registerFunctionSelector",args:[i.systemId,i.systemFunctionSignature]}),{retries:3,onFailedAttempt:async a=>{let m=a.attemptNumber*500;l(`failed to register function ${i.signature}, retrying in ${m}ms...`),await Je(m)}})}))):[]}import{BaseError as hr,getAddress as wr}from"viem";import{writeContract as Ge}from"@latticexyz/common";import{isDefined as xr,uniqueBy as Sr,wait as Cr}from"@latticexyz/common/utils";import vr from"p-retry";async function Ye({client:e,worldDeploy:o,modules:t}){return t.length?(await O({client:e,contracts:Sr(t,r=>wr(r.address)).map(r=>({bytecode:r.bytecode,deployedBytecodeSize:r.deployedBytecodeSize,label:`${r.name} module`}))}),l("installing modules:",t.map(r=>r.name).join(", ")),(await Promise.all(t.map(r=>vr(async()=>{try{return r.installAsRoot?await Ge(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"installRootModule",args:[r.address,r.installData]}):await Ge(e,{chain:e.chain??null,address:o.address,abi:C,functionName:"installModule",args:[r.address,r.installData]})}catch(n){if(n instanceof hr&&n.message.includes("Module_AlreadyInstalled")){l(`module ${r.name} already installed`);return}throw n}},{retries:3,onFailedAttempt:async n=>{let s=n.attemptNumber*500;l(`failed to install module ${r.name}, retrying in ${s}ms...`),await Cr(s)}})))).filter(xr)):[]}import{getAddress as Ze}from"viem";import{hexToResource as Qe,resourceToHex as Dr}from"@latticexyz/common";async function Xe({client:e,worldDeploy:o,resourceIds:t}){let r=Array.from(new Set(t.map(a=>Qe(a).namespace))),n=await L({client:e,worldDeploy:o}),s=Array.from(new Set(n.map(a=>Qe(a).namespace))),d=r.filter(a=>s.includes(a)),p=(await Promise.all(d.map(async a=>{let{owner:m}=await P({client:e,worldDeploy:o,table:D.world_NamespaceOwner,key:{namespaceId:Dr({type:"namespace",namespace:a,name:""})}});return[a,m]}))).filter(([,a])=>Ze(a)!==Ze(e.account.address)).map(([a])=>a);if(p.length)throw new Error(`You are attempting to deploy to namespaces you do not own: ${p.join(", ")}`)}import{uniqueBy as oo}from"@latticexyz/common/utils";async function to({client:e,config:o,worldAddress:t}){let r=Object.values(o.tables),n=Object.values(o.systems);await we(e),await O({client:e,contracts:[...Z,...oo(n,f=>eo(f.address)).map(f=>({bytecode:f.bytecode,deployedBytecodeSize:f.deployedBytecodeSize,label:`${S(f)} system`})),...oo(o.modules,f=>eo(f.address)).map(f=>({bytecode:f.bytecode,deployedBytecodeSize:f.deployedBytecodeSize,label:`${f.name} module`}))]});let s=t?await _e(e,t):await Me(e);if(!Se.includes(s.storeVersion))throw new Error(`Unsupported Store version: ${s.storeVersion}`);if(!Ce.includes(s.worldVersion))throw new Error(`Unsupported World version: ${s.worldVersion}`);await Xe({client:e,worldDeploy:s,resourceIds:[...r.map(f=>f.tableId),...n.map(f=>f.systemId)]});let d=await Ne({client:e,worldDeploy:s,tables:r}),i=await Ue({client:e,worldDeploy:s,systems:n}),p=await qe({client:e,worldDeploy:s,functions:n.flatMap(f=>f.functions)}),a=await Ye({client:e,worldDeploy:s,modules:o.modules}),m=[...d,...i,...p,...a];l("waiting for all transactions to confirm");for(let f of m)await Tr(e,{hash:f});return l("deploy complete"),s}import{createWalletClient as _r,http as Lr}from"viem";import{privateKeyToAccount as Kr}from"viem/accounts";import{loadConfig as Jr}from"@latticexyz/config/node";import{getOutDirectory as qr,getRpcUrl as Gr,getSrcDirectory as Yr}from"@latticexyz/common/foundry";import M from"chalk";import{MUDError as Zr}from"@latticexyz/common/errors";import{resolveWorldConfig as Or}from"@latticexyz/world";import{resourceToHex as se,hexToResource as Pr}from"@latticexyz/common";import{resolveWithContext as jr}from"@latticexyz/config";import{encodeField as Fr}from"@latticexyz/protocol-parser";import{getFunctionSelector as no,getCreate2Address as so,getAddress as Wr,hexToBytes as Br,bytesToHex as Mr,getFunctionSignature as io}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 ne}from"viem";var ro=[{name:"KeysWithValueModule",abi:oe.abi,bytecode:oe.bytecode.object,deployedBytecodeSize:ne(oe.deployedBytecode.object)},{name:"KeysInTableModule",abi:te.abi,bytecode:te.bytecode.object,deployedBytecodeSize:ne(te.deployedBytecode.object)},{name:"UniqueEntityModule",abi:re.abi,bytecode:re.bytecode.object,deployedBytecodeSize:ne(re.deployedBytecode.object)}];import{readFileSync as Ar}from"fs";import kr from"path";import{MUDError as q}from"@latticexyz/common/errors";import{size as Ir}from"viem";function G(e,o){let t,r=kr.join(o,e+".sol",e+".json");try{t=JSON.parse(Ar(r,"utf8"))}catch{throw new q(`Error reading file at ${r}`)}let n=t?.bytecode?.object;if(!n)throw new q(`No bytecode found in ${r}`);let s=t?.deployedBytecode?.object;if(!s)throw new q(`No deployed bytecode found in ${r}`);let d=t?.abi;if(!d)throw new q(`No ABI found in ${r}`);return{abi:d,bytecode:n,deployedBytecodeSize:Ir(s)}}function ao({config:e,forgeSourceDir:o,forgeOutDir:t}){let r=E(e),n=I(o).map(({basename:g})=>g),s=Or(e,n),i=G("System",t).abi.filter(g=>g.type==="function").map(io),p=Object.entries(s.systems).map(([g,u])=>{let w=e.namespace,b=u.name,x=se({type:"system",namespace:w,name:b}),c=G(g,t),y=c.abi.filter(h=>h.type==="function").map(io).filter(h=>!i.includes(h)).map(h=>{let le=w===""?h:`${w}_${b}_${h}`;return{signature:le,selector:no(le),systemId:x,systemFunctionSignature:h,systemFunctionSelector:no(h)}});return{namespace:w,name:b,systemId:x,allowAll:u.openAccess,allowedAddresses:u.accessListAddresses,allowedSystemIds:u.accessListSystems.map(h=>se({type:"system",namespace:w,name:s.systems[h].name})),address:so({from:v,bytecode:c.bytecode,salt:T}),bytecode:c.bytecode,deployedBytecodeSize:c.deployedBytecodeSize,abi:c.abi,functions:y}}),a=p.map(({allowedAddresses:g,allowedSystemIds:u,...w})=>{let b=u.map(x=>{let c=p.find(y=>y.systemId===x);if(!c)throw new Error(`System ${S(w)} wanted access to ${S(Pr(x))}, but it wasn't found in the config.`);return c.address});return{...w,allowedAddresses:Array.from(new Set([...g,...b].map(x=>Wr(x))))}}),m={tableIds:Object.fromEntries(Object.entries(e.tables).map(([g,u])=>[g,Br(se({type:u.offchainOnly?"offchainTable":"table",namespace:e.namespace,name:u.name}))]))},f=e.modules.map(g=>{let u=ro.find(b=>b.name===g.name)??G(g.name,t),w=g.args.map(b=>jr(b,m)).map(b=>{let x=b.value instanceof Uint8Array?Mr(b.value):b.value;return Fr(b.type,x)});if(w.length>1)throw new Error(`${g.name} module should only have 0-1 args, but had ${w.length} args.`);return{name:g.name,installAsRoot:g.root,installData:w.length===0?"0x":w[0],address:so({from:v,bytecode:u.bytecode,salt:T}),bytecode:u.bytecode,deployedBytecodeSize:u.deployedBytecodeSize,abi:u.abi}});return{tables:r,systems:a,modules:f}}import{getChainId as Qr}from"viem/actions";import{existsSync as Rr}from"fs";import $r from"path";import Er from"chalk";import{getScriptDirectory as Hr,forge as Nr}from"@latticexyz/common/foundry";async function co(e,o,t,r){let n=$r.join(await Hr(),e+".s.sol");Rr(n)?(console.log(Er.blue(`Executing post deploy script at ${n}`)),await Nr(["script",e,"--sig","run(address)",o,"--broadcast","--rpc-url",t,"-vvv"],{profile:r})):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"},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."}};async function R(e){let o=e.profile??process.env.FOUNDRY_PROFILE,t=await Jr(e.configPath);e.printConfig&&console.log(M.green(`
7
- Resolved config:
8
- `),JSON.stringify(t,null,2));let r=e.srcDir??await Yr(o),n=await qr(o),s=e.rpc??await Gr(o);console.log(M.bgBlue(M.whiteBright(`
9
- Deploying MUD contracts${o?" with profile "+o:""} to RPC ${s}
10
- `))),e.skipBuild||await U({config:t,srcDir:r,foundryProfile:o});let d=process.env.PRIVATE_KEY;if(!d)throw new Zr(`Missing PRIVATE_KEY environment variable.
11
- Run 'echo "PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" > .env'
12
- in your contracts directory to use the default anvil private key.`);let i=ao({config:t,forgeSourceDir:r,forgeOutDir:n}),p=_r({transport:Lr(s),account:Kr(d)});console.log("Deploying from",p.account.address);let a=Date.now(),m=await to({worldAddress:e.worldAddress,client:p,config:i});(e.worldAddress==null||e.alwaysRunPostDeploy)&&await co(t.postDeployScript,m.address,s,o),console.log(M.green("Deployment completed in",(Date.now()-a)/1e3,"seconds"));let f={worldAddress:m.address,blockNumber:Number(m.deployBlock)};if(e.saveDeployment){let g=await Qr(p),u=ie.join(t.deploysDirectory,g.toString());Ur(u,{recursive:!0}),ae(ie.join(u,"latest.json"),JSON.stringify(f,null,2)),ae(ie.join(u,Date.now()+".json"),JSON.stringify(f,null,2));let w=[1337,31337],b=zr(t.worldsFile)?JSON.parse(Vr(t.worldsFile,"utf-8")):{};b[g]={address:f.worldAddress,blockNumber:w.includes(g)?void 0:f.blockNumber},ae(t.worldsFile,JSON.stringify(b,null,2)),console.log(M.bgGreen(M.whiteBright(`
13
- Deployment result (written to ${t.worldsFile} and ${u}):
14
- `)))}return console.log(f),m}var Xr={command:"deploy",describe:"Deploy MUD contracts",builder(e){return e.options(k)},async handler(e){try{await R(e)}catch(o){z(o),process.exit(1)}process.exit(0)}},lo=Xr;import{loadConfig as en}from"@latticexyz/config/node";import{worldgen as on}from"@latticexyz/world/node";import{getSrcDirectory as tn}from"@latticexyz/common/foundry";import mo from"path";import{rmSync as rn}from"fs";var nn={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 sn(e),process.exit(0)}};async function sn(e){let o=e.srcDir??await tn(),t=I(o),r=e.config??await en(e.configPath),n=mo.join(o,r.codegenDirectory);e.clean&&rn(mo.join(n,r.worldgenDirectory),{recursive:!0,force:!0}),await on(r,t,n)}var po=nn;import N from"chalk";import{readFileSync as mn,writeFileSync as pn}from"fs";import de from"path";import{MUDError as $}from"@latticexyz/common/errors";var fo={name:"@latticexyz/cli",version:"2.0.0-next.14",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",typescript:"5.1.6",viem:"1.14.0",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/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.31.4"},gitHead:"914a1e0ae4a573d685841ca2ea921435057deb8f"};import fn from"glob";import{ZodError as cn,z as uo}from"zod";var dn=uo.object({MUD_PACKAGES:uo.string().transform(e=>JSON.parse(e))});function ln(){try{return dn.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/noise":{"localPath":"packages/noise"},"@latticexyz/phaserx":{"localPath":"packages/phaserx"},"@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 cn){let{_errors:o,...t}=e.format();console.error(`
15
- Missing or invalid environment variables:
16
-
17
- ${Object.keys(t).join(`
18
- `)}
19
- `),process.exit(1)}throw e}}var ce=ln().MUD_PACKAGES;var un={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"],t=o.reduce((n,s)=>e[s]?n+1:n,0);if(t===0)throw new $(`You need to provide one these options: ${o.join(", ")}`);if(t>1)throw new $(`These options are mutually exclusive: ${o.join(", ")}`);e.link||(e.mudVersion=await yn(e));let r=fn.sync("**/package.json").filter(n=>!n.includes("node_modules"));for(let n of r)gn(n,e)}catch(o){z(o)}finally{process.exit(0)}}};async function yn(e){e.mudVersion==="canary"&&(e.tag="main");let o;try{console.log(N.blue("Fetching available versions")),o=await(await fetch(`https://registry.npmjs.org/${fo.name}`)).json()}catch{throw new $("Could not fetch available MUD versions")}if(e.tag){let t=o["dist-tags"][e.tag];if(!t)throw new $(`Could not find npm version with tag "${e.tag}"`);return console.log(N.green(`Latest version with tag ${e.tag}: ${t}`)),t}if(e.commit){let t=e.commit.substring(0,8),r=Object.keys(o.versions).find(n=>n.includes(t));if(!r)throw new $(`Could not find npm version based on commit "${e.commit}"`);return console.log(N.green(`Version from commit ${e.commit}: ${r}`)),r}return e.mudVersion}function gn(e,o){let{link:t}=o,{mudVersion:r}=o,n=bn(e),s=Object.keys(ce),d={};for(let a in n.dependencies)s.includes(a)&&(d[a]=n.dependencies[a]);let i={};for(let a in n.devDependencies)s.includes(a)&&(i[a]=n.devDependencies[a]);for(let a in n.dependencies)s.includes(a)&&(n.dependencies[a]=p(a,"dependencies"));for(let a in n.devDependencies)s.includes(a)&&(n.devDependencies[a]=p(a,"devDependencies"));return pn(e,JSON.stringify(n,null,2)+`
20
- `),console.log(`Updating ${e}`),yo(d,n.dependencies),yo(i,n.devDependencies),n;function p(a,m){return t&&(r=hn(e,t,a)),r||n[m][a]}}function bn(e){try{let o=mn(e,"utf8");return JSON.parse(o)}catch{throw new $("Could not read JSON at "+e)}}function yo(e,o){for(let t in e)e[t]!==o[t]&&console.log(`${t}: ${N.red(e[t])} -> ${N.green(o[t])}`)}function hn(e,o,t){let r=de.relative(de.dirname(e),process.cwd());return"link:"+de.join(r,o,ce[t].localPath)}var go=un;import{anvil as wn,forge as xn,getRpcUrl as Sn}from"@latticexyz/common/foundry";import Cn from"chalk";var vn={...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"}},Dn={command:"test",describe:"Run tests in MUD contracts",builder(e){return e.options(vn)},async handler(e){if(!e.worldAddress){let n=["--block-base-fee-per-gas","0","--port",String(e.port)];wn(n)}let o=e.worldAddress?await Sn(e.profile):`http://127.0.0.1:${e.port}`,t=e.worldAddress??(await R({...e,saveDeployment:!1,rpc:o})).address;console.log(Cn.blue("World address",t));let r=e.forgeOptions?.replaceAll("\\","").split(" ")??[];try{await xn(["test","--fork-url",o,...r],{profile:e.profile,env:{WORLD_ADDRESS:t}}),process.exit(0)}catch(n){console.error(n),process.exit(1)}}},bo=Dn;import{existsSync as Tn,readFileSync as An}from"fs";import{ethers as ho}from"ethers";import{loadConfig as kn}from"@latticexyz/config/node";import{MUDError as wo}from"@latticexyz/common/errors";import{cast as In,getRpcUrl as On,getSrcDirectory as Pn}from"@latticexyz/common/foundry";import{resolveWorldConfig as jn}from"@latticexyz/world";import Fn from"@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"assert{type:"json"};import xo from"@latticexyz/world/mud.config";import{resourceToHex as Co}from"@latticexyz/common";import{createClient as Wn,http as Bn}from"viem";import{getChainId as Mn}from"viem/actions";var So=Co({type:"system",namespace:xo.namespace,name:xo.tables.Systems.name}),Rn={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 Pn(o),e.rpc??=await On(o);let{tx:t,configPath:r,srcDir:n,rpc:s}=e,d=I(n),i=await kn(r),p=jn(i,d.map(({basename:c})=>c)),a=e.worldAddress??await $n(i.worldsFile,s),m=new ho.providers.StaticJsonRpcProvider(s),f=new ho.Contract(a,Fn,m),g=i.namespace,u=Object.values(p.systems).map(({name:c})=>c),w=await f.getFieldLayout(So),b=[];for(let c of u){let y=Co({type:"system",namespace:g,name:c}),h=await f.getField(So,[y],0,w);b.push({name:c,address:h})}let x=await In(["run","--label",`${a}:World`,...b.map(({name:c,address:y})=>["--label",`${y}:${c}`]).flat(),`${t}`]);console.log(x),process.exit(0)}},vo=Rn;async function $n(e,o){if(Tn(e)){let t=Wn({transport:Bn(o)}),r=await Mn(t),n=JSON.parse(An(e,"utf-8"));if(!n[r])throw new wo(`chainId ${r} is missing in worldsFile "${e}"`);return n[r].address}else throw new wo("worldAddress is not specified and worldsFile is missing")}import{anvil as En,getScriptDirectory as Hn,getSrcDirectory as Nn}from"@latticexyz/common/foundry";import j from"chalk";import zn from"chokidar";import{loadConfig as Un,resolveConfigPath as Vn}from"@latticexyz/config/node";import _n from"path";import{homedir as Ln}from"os";import{rmSync as Kn}from"fs";import{BehaviorSubject as Jn,debounceTime as qn,exhaustMap as Gn,filter as Yn}from"rxjs";import{isDefined as Zn}from"@latticexyz/common/utils";var Qn={rpc:k.rpc,configPath:k.configPath,alwaysRunPostDeploy:k.alwaysRunPostDeploy,worldAddress:k.worldAddress},Xn={command:"dev-contracts",describe:"Start a development server for MUD contracts",builder(e){return e.options(Qn)},async handler(e){let o=e.rpc,t=e.configPath??await Vn(e.configPath),r=await Nn(),n=await Hn(),s=await Un(t);if(!e.rpc){console.log(j.gray("Cleaning devnode cache"));let a=Ln();Kn(_n.join(a,".foundry","anvil","tmp"),{recursive:!0,force:!0}),En(["--block-time","1","--block-base-fee-per-gas","0"]),o="http://127.0.0.1:8545"}let d=new Jn(Date.now());zn.watch([t,r,n],{ignoreInitial:!0}).on("all",async(a,m)=>{m.includes(t)&&(console.log(j.blue("Config changed, queuing deploy\u2026")),d.next(Date.now())),(m.includes(r)||m.includes(n))&&(m.includes(s.codegenDirectory)||(console.log(j.blue("Contracts changed, queuing deploy\u2026")),d.next(Date.now())))});let i=e.worldAddress;d.pipe(qn(200),Gn(async a=>{i&&console.log(j.blue("Rebuilding and upgrading world\u2026"));try{let m=await R({...e,configPath:t,rpc:o,skipBuild:!1,printConfig:!1,profile:void 0,saveDeployment:!0,worldAddress:i,srcDir:r});return i=m.address,a<d.value?d.next(d.value):console.log(j.gray(`
21
- Waiting for file changes\u2026
22
- `)),m}catch(m){console.error(j.bgRed(j.whiteBright(`
23
- Error while attempting deploy
24
- `))),console.error(m),console.log(j.gray(`
25
- Waiting for file changes\u2026
26
- `))}}),Yn(Zn)).subscribe()}},Do=Xn;var dp=[pe,lo,fe,ye,es,ge,be,po,go,bo,vo,Do,os];export{dp as commands};
27
- //# sourceMappingURL=commands-RZOPG5RM.js.map