@latticexyz/cli 2.0.0-alpha.49 → 2.0.0-alpha.50

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.
@@ -7,7 +7,7 @@ import {
7
7
  forge,
8
8
  getOutDirectory,
9
9
  getScriptDirectory
10
- } from "./chunk-ATAWDHWC.js";
10
+ } from "./chunk-FPG73MVN.js";
11
11
  import {
12
12
  resolveAbiOrUserType
13
13
  } from "./chunk-5NC2OON2.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getOutDirectory,
3
3
  getSrcDirectory
4
- } from "./chunk-ATAWDHWC.js";
4
+ } from "./chunk-FPG73MVN.js";
5
5
  import {
6
6
  __commonJS,
7
7
  __require,
@@ -54,6 +54,9 @@ async function cast(args, options) {
54
54
  env: { FOUNDRY_PROFILE: options?.profile }
55
55
  });
56
56
  }
57
+ async function anvil(args) {
58
+ return execLog("anvil", args);
59
+ }
57
60
 
58
61
  export {
59
62
  getForgeConfig,
@@ -63,5 +66,6 @@ export {
63
66
  getOutDirectory,
64
67
  getRpcUrl,
65
68
  forge,
66
- cast
69
+ cast,
70
+ anvil
67
71
  };
package/dist/mud.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env -S TS_NODE_COMPILER_OPTIONS={\"module\":\"esnext\"} node --loader=ts-node/esm --no-warnings
2
2
  import {
3
3
  deploy
4
- } from "./chunk-Q7D3SKYJ.js";
4
+ } from "./chunk-5SNB3NQM.js";
5
5
  import {
6
6
  MUDError,
7
7
  loadStoreConfig,
@@ -21,13 +21,14 @@ import {
21
21
  keccak256,
22
22
  resetLibDeploy,
23
23
  systemsDir
24
- } from "./chunk-SLIMIO4Z.js";
24
+ } from "./chunk-FFY7VTYB.js";
25
25
  import {
26
+ anvil,
26
27
  forge,
27
28
  getRpcUrl,
28
29
  getSrcDirectory,
29
30
  getTestDirectory
30
- } from "./chunk-ATAWDHWC.js";
31
+ } from "./chunk-FPG73MVN.js";
31
32
  import {
32
33
  renderArguments,
33
34
  renderImports,
@@ -11451,49 +11452,47 @@ async function getChainId(rpc) {
11451
11452
  }
11452
11453
 
11453
11454
  // src/commands/deploy-v2.ts
11454
- var commandModule15 = {
11455
- command: "deploy-v2",
11456
- describe: "Deploy MUD v2 contracts",
11457
- builder(yargs2) {
11458
- return yargs2.options({
11459
- configPath: { type: "string", desc: "Path to the config file" },
11460
- clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
11461
- printConfig: { type: "boolean", desc: "Print the resolved config" },
11462
- profile: { type: "string", desc: "The foundry profile to use" },
11463
- debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
11464
- priorityFeeMultiplier: {
11465
- type: "number",
11466
- desc: "Multiply the estimated priority fee by the provided factor",
11467
- default: 1
11468
- }
11469
- });
11455
+ var yDeployOptions = {
11456
+ configPath: { type: "string", desc: "Path to the config file" },
11457
+ clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
11458
+ printConfig: { type: "boolean", desc: "Print the resolved config" },
11459
+ profile: { type: "string", desc: "The foundry profile to use" },
11460
+ debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
11461
+ priorityFeeMultiplier: {
11462
+ type: "number",
11463
+ desc: "Multiply the estimated priority fee by the provided factor",
11464
+ default: 1
11470
11465
  },
11471
- async handler(args) {
11472
- args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
11473
- const { configPath, printConfig, profile, clean } = args;
11474
- const rpc = await getRpcUrl(profile);
11475
- console.log(
11476
- chalk4.bgBlue(
11477
- chalk4.whiteBright(`
11466
+ saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true },
11467
+ rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" }
11468
+ };
11469
+ async function deployHandler(args) {
11470
+ args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
11471
+ const { configPath, printConfig, profile, clean } = args;
11472
+ const rpc = args.rpc ?? await getRpcUrl(profile);
11473
+ console.log(
11474
+ chalk4.bgBlue(
11475
+ chalk4.whiteBright(`
11478
11476
  Deploying MUD v2 contracts${profile ? " with profile " + profile : ""} to RPC ${rpc}
11479
11477
  `)
11480
- )
11481
- );
11482
- if (clean)
11483
- await forge(["clean"], { profile });
11484
- await forge(["build"], { profile });
11485
- const srcDir = await getSrcDirectory();
11486
- const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path9) => basename(path9, ".sol"));
11487
- const worldConfig = await loadWorldConfig(configPath, existingContracts);
11488
- const storeConfig = await loadStoreConfig(configPath);
11489
- const mudConfig = { ...worldConfig, ...storeConfig };
11490
- if (printConfig)
11491
- console.log(chalk4.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
11492
- try {
11493
- const privateKey = process.env.PRIVATE_KEY;
11494
- if (!privateKey)
11495
- throw new MUDError("Missing PRIVATE_KEY environment variable");
11496
- const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
11478
+ )
11479
+ );
11480
+ if (clean)
11481
+ await forge(["clean"], { profile });
11482
+ await forge(["build"], { profile });
11483
+ const srcDir = await getSrcDirectory();
11484
+ const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path9) => basename(path9, ".sol"));
11485
+ const worldConfig = await loadWorldConfig(configPath, existingContracts);
11486
+ const storeConfig = await loadStoreConfig(configPath);
11487
+ const mudConfig = { ...worldConfig, ...storeConfig };
11488
+ if (printConfig)
11489
+ console.log(chalk4.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
11490
+ try {
11491
+ const privateKey = process.env.PRIVATE_KEY;
11492
+ if (!privateKey)
11493
+ throw new MUDError("Missing PRIVATE_KEY environment variable");
11494
+ const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
11495
+ if (args.saveDeployment) {
11497
11496
  const chainId = await getChainId(rpc);
11498
11497
  const outputDir = path5.join(mudConfig.deploysDirectory, chainId.toString());
11499
11498
  mkdirSync(outputDir, { recursive: true });
@@ -11502,11 +11501,22 @@ var commandModule15 = {
11502
11501
  console.log(chalk4.bgGreen(chalk4.whiteBright(`
11503
11502
  Deployment result (written to ${outputDir}):
11504
11503
  `)));
11505
- console.log(deploymentInfo);
11506
- } catch (error) {
11507
- logError(error);
11508
- process.exit(1);
11509
11504
  }
11505
+ console.log(deploymentInfo);
11506
+ return deploymentInfo;
11507
+ } catch (error) {
11508
+ logError(error);
11509
+ process.exit(1);
11510
+ }
11511
+ }
11512
+ var commandModule15 = {
11513
+ command: "deploy-v2",
11514
+ describe: "Deploy MUD v2 contracts",
11515
+ builder(yargs2) {
11516
+ return yargs2.options(yDeployOptions);
11517
+ },
11518
+ async handler(args) {
11519
+ await deployHandler(args);
11510
11520
  process.exit(0);
11511
11521
  }
11512
11522
  };
@@ -11749,7 +11759,7 @@ import path8 from "path";
11749
11759
  // package.json
11750
11760
  var package_default = {
11751
11761
  name: "@latticexyz/cli",
11752
- version: "2.0.0-alpha.49+7d06c1b5",
11762
+ version: "2.0.0-alpha.50+d6be8b08",
11753
11763
  description: "Command line interface for mud",
11754
11764
  main: "dist/index.js",
11755
11765
  types: "dist/index.d.ts",
@@ -11776,7 +11786,7 @@ var package_default = {
11776
11786
  release: "npm publish --access=public"
11777
11787
  },
11778
11788
  devDependencies: {
11779
- "@latticexyz/store": "^2.0.0-alpha.49+7d06c1b5",
11789
+ "@latticexyz/store": "^2.0.0-alpha.50+d6be8b08",
11780
11790
  "@types/ejs": "^3.1.1",
11781
11791
  "@types/glob": "^7.2.0",
11782
11792
  "@types/node": "^17.0.34",
@@ -11789,10 +11799,10 @@ var package_default = {
11789
11799
  dependencies: {
11790
11800
  "@improbable-eng/grpc-web": "^0.15.0",
11791
11801
  "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
11792
- "@latticexyz/schema-type": "^2.0.0-alpha.49+7d06c1b5",
11793
- "@latticexyz/services": "^2.0.0-alpha.49+7d06c1b5",
11794
- "@latticexyz/solecs": "^2.0.0-alpha.49+7d06c1b5",
11795
- "@latticexyz/std-contracts": "^2.0.0-alpha.49+7d06c1b5",
11802
+ "@latticexyz/schema-type": "^2.0.0-alpha.50+d6be8b08",
11803
+ "@latticexyz/services": "^2.0.0-alpha.50+d6be8b08",
11804
+ "@latticexyz/solecs": "^2.0.0-alpha.50+d6be8b08",
11805
+ "@latticexyz/std-contracts": "^2.0.0-alpha.50+d6be8b08",
11796
11806
  "@solidity-parser/parser": "^0.16.0",
11797
11807
  "@typechain/ethers-v5": "^10.1.1",
11798
11808
  chalk: "^5.0.1",
@@ -11819,7 +11829,7 @@ var package_default = {
11819
11829
  zod: "^3.21.4",
11820
11830
  "zod-validation-error": "^1.0.1"
11821
11831
  },
11822
- gitHead: "7d06c1b5cf00df627000c907e78f60d3cd2415cd"
11832
+ gitHead: "d6be8b08d0eeae3b10eb9e7bffb6d4dd2fc58aa0"
11823
11833
  };
11824
11834
 
11825
11835
  // src/commands/set-version.ts
@@ -11938,6 +11948,52 @@ function logComparison(prev, curr) {
11938
11948
  }
11939
11949
  var set_version_default = commandModule17;
11940
11950
 
11951
+ // src/commands/test-v2.ts
11952
+ import chalk6 from "chalk";
11953
+ import { rmSync as rmSync5, writeFileSync as writeFileSync4 } from "fs";
11954
+ var WORLD_ADDRESS_FILE = ".mudtest";
11955
+ var commandModule18 = {
11956
+ command: "test-v2",
11957
+ describe: "Run tests in MUD v2 contracts",
11958
+ builder(yargs2) {
11959
+ return yargs2.options({
11960
+ ...yDeployOptions,
11961
+ port: { type: "number", description: "Port to run internal node for fork testing on", default: 4242 },
11962
+ worldAddress: {
11963
+ type: "string",
11964
+ 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."
11965
+ },
11966
+ forgeOptions: { type: "string", description: "Options to pass to forge test" }
11967
+ });
11968
+ },
11969
+ async handler(args) {
11970
+ if (!args.worldAddress) {
11971
+ const anvilArgs = ["--block-base-fee-per-gas", "0", "--port", String(args.port)];
11972
+ anvil(anvilArgs);
11973
+ }
11974
+ const forkRpc = args.worldAddress ? await getRpcUrl(args.profile) : `http://127.0.0.1:${args.port}`;
11975
+ const worldAddress = args.worldAddress ?? (await deployHandler({
11976
+ ...args,
11977
+ saveDeployment: false,
11978
+ rpc: forkRpc
11979
+ })).worldAddress;
11980
+ console.log(chalk6.blue("World address", worldAddress));
11981
+ writeFileSync4(WORLD_ADDRESS_FILE, worldAddress);
11982
+ const userOptions = args.forgeOptions?.replaceAll("\\", "").split(" ") ?? [];
11983
+ try {
11984
+ const testResult = await forge(["test", "--fork-url", forkRpc, ...userOptions], {
11985
+ profile: args.profile
11986
+ });
11987
+ console.log(testResult);
11988
+ } catch (e) {
11989
+ console.error(e);
11990
+ }
11991
+ rmSync5(WORLD_ADDRESS_FILE);
11992
+ process.exit(0);
11993
+ }
11994
+ };
11995
+ var test_v2_default = commandModule18;
11996
+
11941
11997
  // src/commands/index.ts
11942
11998
  var commands = [
11943
11999
  bulkupload_default,
@@ -11956,7 +12012,8 @@ var commands = [
11956
12012
  trace_default,
11957
12013
  types_default,
11958
12014
  worldgen_default,
11959
- set_version_default
12015
+ set_version_default,
12016
+ test_v2_default
11960
12017
  ];
11961
12018
 
11962
12019
  // src/mud.ts
@@ -14,8 +14,8 @@ import {
14
14
  hsr,
15
15
  keccak256,
16
16
  resetLibDeploy
17
- } from "../../chunk-SLIMIO4Z.js";
18
- import "../../chunk-ATAWDHWC.js";
17
+ } from "../../chunk-FFY7VTYB.js";
18
+ import "../../chunk-FPG73MVN.js";
19
19
  import "../../chunk-O6HOO6WA.js";
20
20
  export {
21
21
  IDregex,
@@ -75,6 +75,12 @@ declare function forge(args: string[], options?: {
75
75
  declare function cast(args: string[], options?: {
76
76
  profile?: string;
77
77
  }): Promise<string>;
78
+ /**
79
+ * Start an anvil chain
80
+ * @param args The arguments to pass to anvil
81
+ * @returns Stdout of the command
82
+ */
83
+ declare function anvil(args: string[]): Promise<string>;
78
84
 
79
85
  declare function formatSolidity(content: string, prettierConfigPath?: string): Promise<string>;
80
86
  declare function formatTypescript(content: string): Promise<string>;
@@ -95,4 +101,4 @@ interface DeploymentInfo {
95
101
  }
96
102
  declare function deploy(mudConfig: MUDConfig, deployConfig: DeployConfig): Promise<DeploymentInfo>;
97
103
 
98
- export { DeployConfig, DeploymentInfo, ForgeConfig, MUDError, NotESMConfigError, NotInsideProjectError, UnrecognizedSystemErrorFactory, cast, deploy, forge, formatAndWriteSolidity, formatAndWriteTypescript, formatSolidity, formatTypescript, fromZodErrorCustom, getForgeConfig, getOutDirectory, getRpcUrl, getScriptDirectory, getSrcDirectory, getTestDirectory, logError };
104
+ export { DeployConfig, DeploymentInfo, ForgeConfig, MUDError, NotESMConfigError, NotInsideProjectError, UnrecognizedSystemErrorFactory, anvil, cast, deploy, forge, formatAndWriteSolidity, formatAndWriteTypescript, formatSolidity, formatTypescript, fromZodErrorCustom, getForgeConfig, getOutDirectory, getRpcUrl, getScriptDirectory, getSrcDirectory, getTestDirectory, logError };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  deploy
3
- } from "../chunk-Q7D3SKYJ.js";
3
+ } from "../chunk-5SNB3NQM.js";
4
4
  import {
5
5
  MUDError,
6
6
  NotESMConfigError,
@@ -10,6 +10,7 @@ import {
10
10
  logError
11
11
  } from "../chunk-LPWKZQUI.js";
12
12
  import {
13
+ anvil,
13
14
  cast,
14
15
  forge,
15
16
  getForgeConfig,
@@ -18,7 +19,7 @@ import {
18
19
  getScriptDirectory,
19
20
  getSrcDirectory,
20
21
  getTestDirectory
21
- } from "../chunk-ATAWDHWC.js";
22
+ } from "../chunk-FPG73MVN.js";
22
23
  import {
23
24
  formatAndWriteSolidity,
24
25
  formatAndWriteTypescript,
@@ -32,6 +33,7 @@ export {
32
33
  NotESMConfigError,
33
34
  NotInsideProjectError,
34
35
  UnrecognizedSystemErrorFactory,
36
+ anvil,
35
37
  cast,
36
38
  deploy,
37
39
  forge,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/cli",
3
- "version": "2.0.0-alpha.49+7d06c1b5",
3
+ "version": "2.0.0-alpha.50+d6be8b08",
4
4
  "description": "Command line interface for mud",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,7 +27,7 @@
27
27
  "release": "npm publish --access=public"
28
28
  },
29
29
  "devDependencies": {
30
- "@latticexyz/store": "^2.0.0-alpha.49+7d06c1b5",
30
+ "@latticexyz/store": "^2.0.0-alpha.50+d6be8b08",
31
31
  "@types/ejs": "^3.1.1",
32
32
  "@types/glob": "^7.2.0",
33
33
  "@types/node": "^17.0.34",
@@ -40,10 +40,10 @@
40
40
  "dependencies": {
41
41
  "@improbable-eng/grpc-web": "^0.15.0",
42
42
  "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
43
- "@latticexyz/schema-type": "^2.0.0-alpha.49+7d06c1b5",
44
- "@latticexyz/services": "^2.0.0-alpha.49+7d06c1b5",
45
- "@latticexyz/solecs": "^2.0.0-alpha.49+7d06c1b5",
46
- "@latticexyz/std-contracts": "^2.0.0-alpha.49+7d06c1b5",
43
+ "@latticexyz/schema-type": "^2.0.0-alpha.50+d6be8b08",
44
+ "@latticexyz/services": "^2.0.0-alpha.50+d6be8b08",
45
+ "@latticexyz/solecs": "^2.0.0-alpha.50+d6be8b08",
46
+ "@latticexyz/std-contracts": "^2.0.0-alpha.50+d6be8b08",
47
47
  "@solidity-parser/parser": "^0.16.0",
48
48
  "@typechain/ethers-v5": "^10.1.1",
49
49
  "chalk": "^5.0.1",
@@ -70,5 +70,5 @@
70
70
  "zod": "^3.21.4",
71
71
  "zod-validation-error": "^1.0.1"
72
72
  },
73
- "gitHead": "7d06c1b5cf00df627000c907e78f60d3cd2415cd"
73
+ "gitHead": "d6be8b08d0eeae3b10eb9e7bffb6d4dd2fc58aa0"
74
74
  }
@@ -1,7 +1,7 @@
1
1
  import chalk from "chalk";
2
2
  import glob from "glob";
3
3
  import path, { basename } from "path";
4
- import type { CommandModule } from "yargs";
4
+ import type { CommandModule, Options } from "yargs";
5
5
  import { loadWorldConfig } from "../config/world/index.js";
6
6
  import { deploy } from "../utils/deploy-v2.js";
7
7
  import { logError, MUDError } from "../utils/errors.js";
@@ -10,71 +10,68 @@ import { mkdirSync, writeFileSync } from "fs";
10
10
  import { loadStoreConfig } from "../config/loadStoreConfig.js";
11
11
  import { getChainId } from "../utils/getChainId.js";
12
12
 
13
- type Options = {
13
+ export type DeployOptions = {
14
14
  configPath?: string;
15
15
  printConfig?: boolean;
16
16
  profile?: string;
17
- privateKey: string;
18
17
  priorityFeeMultiplier: number;
19
18
  clean?: boolean;
20
19
  debug?: boolean;
20
+ saveDeployment?: boolean;
21
+ rpc?: string;
21
22
  };
22
23
 
23
- const commandModule: CommandModule<Options, Options> = {
24
- command: "deploy-v2",
25
-
26
- describe: "Deploy MUD v2 contracts",
27
-
28
- builder(yargs) {
29
- return yargs.options({
30
- configPath: { type: "string", desc: "Path to the config file" },
31
- clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
32
- printConfig: { type: "boolean", desc: "Print the resolved config" },
33
- profile: { type: "string", desc: "The foundry profile to use" },
34
- debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
35
- priorityFeeMultiplier: {
36
- type: "number",
37
- desc: "Multiply the estimated priority fee by the provided factor",
38
- default: 1,
39
- },
40
- });
24
+ export const yDeployOptions = {
25
+ configPath: { type: "string", desc: "Path to the config file" },
26
+ clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
27
+ printConfig: { type: "boolean", desc: "Print the resolved config" },
28
+ profile: { type: "string", desc: "The foundry profile to use" },
29
+ debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
30
+ priorityFeeMultiplier: {
31
+ type: "number",
32
+ desc: "Multiply the estimated priority fee by the provided factor",
33
+ default: 1,
41
34
  },
42
-
43
- async handler(args) {
44
- args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
45
- const { configPath, printConfig, profile, clean } = args;
46
-
47
- const rpc = await getRpcUrl(profile);
48
- console.log(
49
- chalk.bgBlue(
50
- chalk.whiteBright(`\n Deploying MUD v2 contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`)
51
- )
52
- );
53
-
54
- if (clean) await forge(["clean"], { profile });
55
-
56
- // Run forge build
57
- await forge(["build"], { profile });
58
-
59
- // Get a list of all contract names
60
- const srcDir = await getSrcDirectory();
61
- const existingContracts = glob
62
- .sync(`${srcDir}/**/*.sol`)
63
- // Get the basename of the file
64
- .map((path) => basename(path, ".sol"));
65
-
66
- // Load and resolve the config
67
- const worldConfig = await loadWorldConfig(configPath, existingContracts);
68
- const storeConfig = await loadStoreConfig(configPath);
69
- const mudConfig = { ...worldConfig, ...storeConfig };
70
-
71
- if (printConfig) console.log(chalk.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
72
-
73
- try {
74
- const privateKey = process.env.PRIVATE_KEY;
75
- if (!privateKey) throw new MUDError("Missing PRIVATE_KEY environment variable");
76
- const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
77
-
35
+ saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true },
36
+ rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" },
37
+ } satisfies Record<keyof DeployOptions, Options>;
38
+
39
+ export async function deployHandler(args: Parameters<(typeof commandModule)["handler"]>[0]) {
40
+ args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
41
+ const { configPath, printConfig, profile, clean } = args;
42
+
43
+ const rpc = args.rpc ?? (await getRpcUrl(profile));
44
+ console.log(
45
+ chalk.bgBlue(
46
+ chalk.whiteBright(`\n Deploying MUD v2 contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`)
47
+ )
48
+ );
49
+
50
+ if (clean) await forge(["clean"], { profile });
51
+
52
+ // Run forge build
53
+ await forge(["build"], { profile });
54
+
55
+ // Get a list of all contract names
56
+ const srcDir = await getSrcDirectory();
57
+ const existingContracts = glob
58
+ .sync(`${srcDir}/**/*.sol`)
59
+ // Get the basename of the file
60
+ .map((path) => basename(path, ".sol"));
61
+
62
+ // Load and resolve the config
63
+ const worldConfig = await loadWorldConfig(configPath, existingContracts);
64
+ const storeConfig = await loadStoreConfig(configPath);
65
+ const mudConfig = { ...worldConfig, ...storeConfig };
66
+
67
+ if (printConfig) console.log(chalk.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
68
+
69
+ try {
70
+ const privateKey = process.env.PRIVATE_KEY;
71
+ if (!privateKey) throw new MUDError("Missing PRIVATE_KEY environment variable");
72
+ const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
73
+
74
+ if (args.saveDeployment) {
78
75
  // Write deployment result to file (latest and timestamp)
79
76
  const chainId = await getChainId(rpc);
80
77
  const outputDir = path.join(mudConfig.deploysDirectory, chainId.toString());
@@ -83,12 +80,27 @@ const commandModule: CommandModule<Options, Options> = {
83
80
  writeFileSync(path.join(outputDir, Date.now() + ".json"), JSON.stringify(deploymentInfo, null, 2));
84
81
 
85
82
  console.log(chalk.bgGreen(chalk.whiteBright(`\n Deployment result (written to ${outputDir}): \n`)));
86
- console.log(deploymentInfo);
87
- } catch (error: any) {
88
- logError(error);
89
- process.exit(1);
90
83
  }
91
84
 
85
+ console.log(deploymentInfo);
86
+ return deploymentInfo;
87
+ } catch (error: any) {
88
+ logError(error);
89
+ process.exit(1);
90
+ }
91
+ }
92
+
93
+ const commandModule: CommandModule<DeployOptions, DeployOptions> = {
94
+ command: "deploy-v2",
95
+
96
+ describe: "Deploy MUD v2 contracts",
97
+
98
+ builder(yargs) {
99
+ return yargs.options(yDeployOptions);
100
+ },
101
+
102
+ async handler(args) {
103
+ await deployHandler(args);
92
104
  process.exit(0);
93
105
  },
94
106
  };
@@ -18,6 +18,7 @@ import tsgen from "./tsgen.js";
18
18
  import deployV2 from "./deploy-v2.js";
19
19
  import worldgen from "./worldgen.js";
20
20
  import setVersion from "./set-version.js";
21
+ import testV2 from "./test-v2.js";
21
22
 
22
23
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
23
24
  export const commands: CommandModule<any, any>[] = [
@@ -38,4 +39,5 @@ export const commands: CommandModule<any, any>[] = [
38
39
  types,
39
40
  worldgen,
40
41
  setVersion,
42
+ testV2,
41
43
  ];
@@ -0,0 +1,71 @@
1
+ import type { CommandModule } from "yargs";
2
+ import { deployHandler, DeployOptions } from "./deploy-v2.js";
3
+ import { yDeployOptions } from "./deploy-v2.js";
4
+ import { anvil, forge, getRpcUrl, getTestDirectory } from "../utils/foundry.js";
5
+ import chalk from "chalk";
6
+ import { rmSync, writeFileSync } from "fs";
7
+ import path from "path";
8
+
9
+ type Options = DeployOptions & { port?: number; worldAddress?: string; forgeOptions?: string };
10
+
11
+ const WORLD_ADDRESS_FILE = ".mudtest";
12
+
13
+ const commandModule: CommandModule<Options, Options> = {
14
+ command: "test-v2",
15
+
16
+ describe: "Run tests in MUD v2 contracts",
17
+
18
+ builder(yargs) {
19
+ return yargs.options({
20
+ ...yDeployOptions,
21
+ port: { type: "number", description: "Port to run internal node for fork testing on", default: 4242 },
22
+ worldAddress: {
23
+ type: "string",
24
+ description:
25
+ "Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing.",
26
+ },
27
+ forgeOptions: { type: "string", description: "Options to pass to forge test" },
28
+ });
29
+ },
30
+
31
+ async handler(args) {
32
+ // Start an internal anvil process if no world address is provided
33
+ if (!args.worldAddress) {
34
+ const anvilArgs = ["--block-base-fee-per-gas", "0", "--port", String(args.port)];
35
+ anvil(anvilArgs);
36
+ }
37
+
38
+ const forkRpc = args.worldAddress ? await getRpcUrl(args.profile) : `http://127.0.0.1:${args.port}`;
39
+
40
+ const worldAddress =
41
+ args.worldAddress ??
42
+ (
43
+ await deployHandler({
44
+ ...args,
45
+ saveDeployment: false,
46
+ rpc: forkRpc,
47
+ })
48
+ ).worldAddress;
49
+
50
+ console.log(chalk.blue("World address", worldAddress));
51
+
52
+ // Create a temporary file to pass the world address to the tests
53
+ writeFileSync(WORLD_ADDRESS_FILE, worldAddress);
54
+
55
+ const userOptions = args.forgeOptions?.replaceAll("\\", "").split(" ") ?? [];
56
+ try {
57
+ const testResult = await forge(["test", "--fork-url", forkRpc, ...userOptions], {
58
+ profile: args.profile,
59
+ });
60
+ console.log(testResult);
61
+ } catch (e) {
62
+ console.error(e);
63
+ }
64
+
65
+ rmSync(WORLD_ADDRESS_FILE);
66
+
67
+ process.exit(0);
68
+ },
69
+ };
70
+
71
+ export default commandModule;
@@ -92,3 +92,12 @@ export async function cast(args: string[], options?: { profile?: string }): Prom
92
92
  env: { FOUNDRY_PROFILE: options?.profile },
93
93
  });
94
94
  }
95
+
96
+ /**
97
+ * Start an anvil chain
98
+ * @param args The arguments to pass to anvil
99
+ * @returns Stdout of the command
100
+ */
101
+ export async function anvil(args: string[]): Promise<string> {
102
+ return execLog("anvil", args);
103
+ }