@latticexyz/cli 2.0.0-next.10 → 2.0.0-next.12
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/dist/index.js +0 -1
- package/dist/mud.js +23 -13
- package/dist/mud.js.map +1 -1
- package/package.json +17 -13
- package/src/commands/deploy.ts +7 -30
- package/src/commands/dev-contracts.ts +74 -138
- package/src/commands/set-version.ts +19 -60
- package/src/commands/test.ts +30 -36
- package/src/commands/trace.ts +7 -5
- package/src/common.ts +1 -0
- package/src/debug.ts +3 -0
- package/src/deploy/assertNamespaceOwner.ts +42 -0
- package/src/deploy/common.ts +72 -0
- package/src/deploy/configToTables.ts +68 -0
- package/src/deploy/create2/README.md +9 -0
- package/src/deploy/create2/deployment.json +7 -0
- package/src/deploy/debug.ts +3 -0
- package/src/deploy/deploy.ts +108 -0
- package/src/deploy/deployWorld.ts +33 -0
- package/src/deploy/ensureContract.ts +49 -0
- package/src/deploy/ensureContractsDeployed.ts +25 -0
- package/src/deploy/ensureDeployer.ts +36 -0
- package/src/deploy/ensureFunctions.ts +86 -0
- package/src/deploy/ensureModules.ts +72 -0
- package/src/deploy/ensureSystems.ts +161 -0
- package/src/deploy/ensureTables.ts +65 -0
- package/src/deploy/ensureWorldFactory.ts +34 -0
- package/src/deploy/getFunctions.ts +58 -0
- package/src/deploy/getResourceAccess.ts +51 -0
- package/src/deploy/getResourceIds.ts +31 -0
- package/src/deploy/getSystems.ts +48 -0
- package/src/deploy/getTableValue.ts +30 -0
- package/src/deploy/getTables.ts +59 -0
- package/src/deploy/getWorldDeploy.ts +39 -0
- package/src/deploy/logsToWorldDeploy.ts +49 -0
- package/src/deploy/resolveConfig.ts +154 -0
- package/src/deploy/resourceLabel.ts +3 -0
- package/src/index.ts +1 -1
- package/src/mudPackages.ts +24 -0
- package/src/runDeploy.ts +128 -0
- package/src/utils/modules/constants.ts +1 -2
- package/src/utils/utils/getContractData.ts +2 -5
- package/dist/chunk-TW3YGZ4D.js +0 -11
- package/dist/chunk-TW3YGZ4D.js.map +0 -1
- package/src/utils/deploy.ts +0 -254
- package/src/utils/deployHandler.ts +0 -93
- package/src/utils/modules/getInstallModuleCallData.ts +0 -27
- package/src/utils/modules/getUserModules.ts +0 -5
- package/src/utils/modules/types.ts +0 -14
- package/src/utils/systems/getGrantAccessCallData.ts +0 -29
- package/src/utils/systems/getRegisterFunctionSelectorsCallData.ts +0 -57
- package/src/utils/systems/getRegisterSystemCallData.ts +0 -17
- package/src/utils/systems/types.ts +0 -9
- package/src/utils/systems/utils.ts +0 -42
- package/src/utils/tables/getRegisterTableCallData.ts +0 -49
- package/src/utils/tables/getTableIds.ts +0 -18
- package/src/utils/tables/types.ts +0 -12
- package/src/utils/utils/confirmNonce.ts +0 -24
- package/src/utils/utils/deployContract.ts +0 -33
- package/src/utils/utils/fastTxExecute.ts +0 -56
- package/src/utils/utils/getChainId.ts +0 -10
- package/src/utils/utils/setInternalFeePerGas.ts +0 -49
- package/src/utils/utils/types.ts +0 -21
- package/src/utils/world.ts +0 -28
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@latticexyz/cli",
|
3
|
-
"version": "2.0.0-next.
|
3
|
+
"version": "2.0.0-next.12",
|
4
4
|
"description": "Command line interface for mud",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -23,6 +23,7 @@
|
|
23
23
|
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
|
24
24
|
"chalk": "^5.0.1",
|
25
25
|
"chokidar": "^3.5.3",
|
26
|
+
"debug": "^4.3.4",
|
26
27
|
"dotenv": "^16.0.3",
|
27
28
|
"ejs": "^3.1.8",
|
28
29
|
"ethers": "^5.7.2",
|
@@ -30,26 +31,29 @@
|
|
30
31
|
"glob": "^8.0.3",
|
31
32
|
"nice-grpc-web": "^2.0.1",
|
32
33
|
"openurl": "^1.1.1",
|
34
|
+
"p-retry": "^5.1.2",
|
33
35
|
"path": "^0.12.7",
|
36
|
+
"rxjs": "7.5.5",
|
34
37
|
"throttle-debounce": "^5.0.0",
|
35
38
|
"typescript": "5.1.6",
|
36
|
-
"viem": "1.
|
39
|
+
"viem": "1.14.0",
|
37
40
|
"yargs": "^17.7.1",
|
38
41
|
"zod": "^3.21.4",
|
39
42
|
"zod-validation-error": "^1.3.0",
|
40
|
-
"@latticexyz/abi-ts": "2.0.0-next.
|
41
|
-
"@latticexyz/common": "2.0.0-next.
|
42
|
-
"@latticexyz/config": "2.0.0-next.
|
43
|
-
"@latticexyz/gas-report": "2.0.0-next.
|
44
|
-
"@latticexyz/protocol-parser": "2.0.0-next.
|
45
|
-
"@latticexyz/schema-type": "2.0.0-next.
|
46
|
-
"@latticexyz/services": "2.0.0-next.
|
47
|
-
"@latticexyz/store": "2.0.0-next.
|
48
|
-
"@latticexyz/utils": "2.0.0-next.
|
49
|
-
"@latticexyz/world": "2.0.0-next.
|
50
|
-
"@latticexyz/world-modules": "2.0.0-next.
|
43
|
+
"@latticexyz/abi-ts": "2.0.0-next.12",
|
44
|
+
"@latticexyz/common": "2.0.0-next.12",
|
45
|
+
"@latticexyz/config": "2.0.0-next.12",
|
46
|
+
"@latticexyz/gas-report": "2.0.0-next.12",
|
47
|
+
"@latticexyz/protocol-parser": "2.0.0-next.12",
|
48
|
+
"@latticexyz/schema-type": "2.0.0-next.12",
|
49
|
+
"@latticexyz/services": "2.0.0-next.12",
|
50
|
+
"@latticexyz/store": "2.0.0-next.12",
|
51
|
+
"@latticexyz/utils": "2.0.0-next.12",
|
52
|
+
"@latticexyz/world": "2.0.0-next.12",
|
53
|
+
"@latticexyz/world-modules": "2.0.0-next.12"
|
51
54
|
},
|
52
55
|
"devDependencies": {
|
56
|
+
"@types/debug": "^4.1.7",
|
53
57
|
"@types/ejs": "^3.1.1",
|
54
58
|
"@types/glob": "^7.2.0",
|
55
59
|
"@types/node": "^18.15.11",
|
package/src/commands/deploy.ts
CHANGED
@@ -1,43 +1,20 @@
|
|
1
|
-
import type { CommandModule
|
1
|
+
import type { CommandModule } from "yargs";
|
2
2
|
import { logError } from "../utils/errors";
|
3
|
-
import { DeployOptions,
|
3
|
+
import { DeployOptions, deployOptions, runDeploy } from "../runDeploy";
|
4
4
|
|
5
|
-
|
6
|
-
configPath: { type: "string", desc: "Path to the config file" },
|
7
|
-
clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
|
8
|
-
printConfig: { type: "boolean", desc: "Print the resolved config" },
|
9
|
-
profile: { type: "string", desc: "The foundry profile to use" },
|
10
|
-
debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
|
11
|
-
priorityFeeMultiplier: {
|
12
|
-
type: "number",
|
13
|
-
desc: "Multiply the estimated priority fee by the provided factor",
|
14
|
-
default: 1,
|
15
|
-
},
|
16
|
-
saveDeployment: { type: "boolean", desc: "Save the deployment info to a file", default: true },
|
17
|
-
rpc: { type: "string", desc: "The RPC URL to use. Defaults to the RPC url from the local foundry.toml" },
|
18
|
-
worldAddress: { type: "string", desc: "Deploy to an existing World at the given address" },
|
19
|
-
srcDir: { type: "string", desc: "Source directory. Defaults to foundry src directory." },
|
20
|
-
disableTxWait: { type: "boolean", desc: "Disable waiting for transactions to be confirmed.", default: false },
|
21
|
-
pollInterval: {
|
22
|
-
type: "number",
|
23
|
-
desc: "Interval in miliseconds to use to poll for transaction receipts / block inclusion",
|
24
|
-
default: 1000,
|
25
|
-
},
|
26
|
-
skipBuild: { type: "boolean", desc: "Skip rebuilding the contracts before deploying" },
|
27
|
-
} satisfies Record<keyof DeployOptions, Options>;
|
28
|
-
|
29
|
-
const commandModule: CommandModule<DeployOptions, DeployOptions> = {
|
5
|
+
const commandModule: CommandModule<typeof deployOptions, DeployOptions> = {
|
30
6
|
command: "deploy",
|
31
7
|
|
32
8
|
describe: "Deploy MUD contracts",
|
33
9
|
|
34
10
|
builder(yargs) {
|
35
|
-
return yargs.options(
|
11
|
+
return yargs.options(deployOptions);
|
36
12
|
},
|
37
13
|
|
38
|
-
async handler(
|
14
|
+
async handler(opts) {
|
15
|
+
// Wrap in try/catch, because yargs seems to swallow errors
|
39
16
|
try {
|
40
|
-
await
|
17
|
+
await runDeploy(opts);
|
41
18
|
} catch (error: any) {
|
42
19
|
logError(error);
|
43
20
|
process.exit(1);
|
@@ -1,176 +1,112 @@
|
|
1
|
-
import type { CommandModule } from "yargs";
|
2
|
-
import {
|
3
|
-
anvil,
|
4
|
-
forge,
|
5
|
-
getRemappings,
|
6
|
-
getRpcUrl,
|
7
|
-
getScriptDirectory,
|
8
|
-
getSrcDirectory,
|
9
|
-
} from "@latticexyz/common/foundry";
|
1
|
+
import type { CommandModule, InferredOptionTypes } from "yargs";
|
2
|
+
import { anvil, getScriptDirectory, getSrcDirectory } from "@latticexyz/common/foundry";
|
10
3
|
import chalk from "chalk";
|
11
4
|
import chokidar from "chokidar";
|
12
5
|
import { loadConfig, resolveConfigPath } from "@latticexyz/config/node";
|
13
6
|
import { StoreConfig } from "@latticexyz/store";
|
14
|
-
import { tablegen } from "@latticexyz/store/codegen";
|
15
7
|
import path from "path";
|
16
|
-
import { debounce } from "throttle-debounce";
|
17
|
-
import { worldgenHandler } from "./worldgen";
|
18
8
|
import { WorldConfig } from "@latticexyz/world";
|
19
9
|
import { homedir } from "os";
|
20
10
|
import { rmSync } from "fs";
|
21
|
-
import {
|
22
|
-
import {
|
23
|
-
import {
|
24
|
-
import {
|
25
|
-
|
26
|
-
|
27
|
-
rpc
|
28
|
-
configPath
|
11
|
+
import { deployOptions, runDeploy } from "../runDeploy";
|
12
|
+
import { BehaviorSubject, debounceTime, exhaustMap, filter } from "rxjs";
|
13
|
+
import { Address } from "viem";
|
14
|
+
import { isDefined } from "@latticexyz/common/utils";
|
15
|
+
|
16
|
+
const devOptions = {
|
17
|
+
rpc: deployOptions.rpc,
|
18
|
+
configPath: deployOptions.configPath,
|
19
|
+
alwaysRunPostDeploy: deployOptions.alwaysRunPostDeploy,
|
29
20
|
};
|
30
21
|
|
31
|
-
const commandModule: CommandModule<
|
22
|
+
const commandModule: CommandModule<typeof devOptions, InferredOptionTypes<typeof devOptions>> = {
|
32
23
|
command: "dev-contracts",
|
33
24
|
|
34
25
|
describe: "Start a development server for MUD contracts",
|
35
26
|
|
36
27
|
builder(yargs) {
|
37
|
-
return yargs.options(
|
38
|
-
rpc: {
|
39
|
-
type: "string",
|
40
|
-
decs: "RPC endpoint of the development node. If none is provided, an anvil instance is spawned in the background on port 8545.",
|
41
|
-
},
|
42
|
-
configPath: {
|
43
|
-
type: "string",
|
44
|
-
decs: "Path to MUD config",
|
45
|
-
},
|
46
|
-
});
|
28
|
+
return yargs.options(devOptions);
|
47
29
|
},
|
48
30
|
|
49
|
-
async handler(
|
50
|
-
|
51
|
-
await
|
52
|
-
|
53
|
-
const
|
54
|
-
const configPath = args.configPath ?? (await resolveConfigPath(args.configPath));
|
55
|
-
const srcDirectory = await getSrcDirectory();
|
56
|
-
const scriptDirectory = await getScriptDirectory();
|
57
|
-
const remappings = await getRemappings();
|
31
|
+
async handler(opts) {
|
32
|
+
let rpc = opts.rpc;
|
33
|
+
const configPath = opts.configPath ?? (await resolveConfigPath(opts.configPath));
|
34
|
+
const srcDir = await getSrcDirectory();
|
35
|
+
const scriptDir = await getScriptDirectory();
|
58
36
|
const initialConfig = (await loadConfig(configPath)) as StoreConfig & WorldConfig;
|
59
37
|
|
60
|
-
// Initial run of all codegen steps before starting anvil
|
61
|
-
// (so clients can wait for everything to be ready before starting)
|
62
|
-
await handleConfigChange(initialConfig);
|
63
|
-
await handleContractsChange(initialConfig);
|
64
|
-
|
65
38
|
// Start an anvil instance in the background if no RPC url is provided
|
66
|
-
if (!
|
39
|
+
if (!opts.rpc) {
|
40
|
+
// Clean anvil cache as 1s block times can fill up the disk
|
41
|
+
// - https://github.com/foundry-rs/foundry/issues/3623
|
42
|
+
// - https://github.com/foundry-rs/foundry/issues/4989
|
43
|
+
// - https://github.com/foundry-rs/foundry/issues/3699
|
44
|
+
// - https://github.com/foundry-rs/foundry/issues/3512
|
67
45
|
console.log(chalk.gray("Cleaning devnode cache"));
|
68
46
|
const userHomeDir = homedir();
|
69
47
|
rmSync(path.join(userHomeDir, ".foundry", "anvil", "tmp"), { recursive: true, force: true });
|
70
48
|
|
71
49
|
const anvilArgs = ["--block-time", "1", "--block-base-fee-per-gas", "0"];
|
72
50
|
anvil(anvilArgs);
|
51
|
+
rpc = "http://127.0.0.1:8545";
|
73
52
|
}
|
74
53
|
|
75
|
-
const changedSinceLastHandled = {
|
76
|
-
config: false,
|
77
|
-
contracts: false,
|
78
|
-
};
|
79
|
-
|
80
|
-
const changeInProgress = {
|
81
|
-
current: false,
|
82
|
-
};
|
83
|
-
|
84
54
|
// Watch for changes
|
85
|
-
const
|
86
|
-
|
55
|
+
const lastChange$ = new BehaviorSubject<number>(Date.now());
|
56
|
+
chokidar.watch([configPath, srcDir, scriptDir], { ignoreInitial: true }).on("all", async (_, updatePath) => {
|
87
57
|
if (updatePath.includes(configPath)) {
|
88
|
-
|
89
|
-
|
90
|
-
// listening to changes in the codegen directory to avoid an infinite loop
|
91
|
-
changedSinceLastHandled.contracts = true;
|
58
|
+
console.log(chalk.blue("Config changed, queuing deploy…"));
|
59
|
+
lastChange$.next(Date.now());
|
92
60
|
}
|
93
|
-
|
94
|
-
if (updatePath.includes(srcDirectory) || updatePath.includes(scriptDirectory)) {
|
61
|
+
if (updatePath.includes(srcDir) || updatePath.includes(scriptDir)) {
|
95
62
|
// Ignore changes to codegen files to avoid an infinite loop
|
96
|
-
if (updatePath.includes(initialConfig.codegenDirectory))
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
// Trigger debounced onChange
|
101
|
-
handleChange();
|
102
|
-
});
|
103
|
-
|
104
|
-
const handleChange = debounce(100, async () => {
|
105
|
-
// Avoid handling changes multiple times in parallel
|
106
|
-
if (changeInProgress.current) return;
|
107
|
-
changeInProgress.current = true;
|
108
|
-
|
109
|
-
// Reset dirty flags
|
110
|
-
const { config, contracts } = changedSinceLastHandled;
|
111
|
-
changedSinceLastHandled.config = false;
|
112
|
-
changedSinceLastHandled.contracts = false;
|
113
|
-
|
114
|
-
try {
|
115
|
-
// Load latest config
|
116
|
-
const mudConfig = (await loadConfig(configPath)) as StoreConfig & WorldConfig;
|
117
|
-
|
118
|
-
// Handle changes
|
119
|
-
if (config) await handleConfigChange(mudConfig);
|
120
|
-
if (contracts) await handleContractsChange(mudConfig);
|
121
|
-
|
122
|
-
await deploy();
|
123
|
-
} catch (error) {
|
124
|
-
console.error(chalk.red("MUD dev-contracts watcher failed to deploy config or contracts changes\n"));
|
125
|
-
logError(error);
|
126
|
-
}
|
127
|
-
|
128
|
-
changeInProgress.current = false;
|
129
|
-
if (changedSinceLastHandled.config || changedSinceLastHandled.contracts) {
|
130
|
-
console.log("Detected change while handling the previous change");
|
131
|
-
handleChange();
|
63
|
+
if (!updatePath.includes(initialConfig.codegenDirectory)) {
|
64
|
+
console.log(chalk.blue("Contracts changed, queuing deploy…"));
|
65
|
+
lastChange$.next(Date.now());
|
66
|
+
}
|
132
67
|
}
|
133
|
-
|
134
|
-
printMUD();
|
135
|
-
console.log("MUD watching for changes...");
|
136
68
|
});
|
137
69
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
//
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
70
|
+
let worldAddress: Address | undefined;
|
71
|
+
|
72
|
+
const deploys$ = lastChange$.pipe(
|
73
|
+
// debounce so that a large batch of file changes only triggers a deploy after it settles down, rather than the first change it sees (and then redeploying immediately after)
|
74
|
+
debounceTime(200),
|
75
|
+
exhaustMap(async (lastChange) => {
|
76
|
+
if (worldAddress) {
|
77
|
+
console.log(chalk.blue("Rebuilding and upgrading world…"));
|
78
|
+
}
|
79
|
+
|
80
|
+
try {
|
81
|
+
const deploy = await runDeploy({
|
82
|
+
...opts,
|
83
|
+
configPath,
|
84
|
+
rpc,
|
85
|
+
skipBuild: false,
|
86
|
+
printConfig: false,
|
87
|
+
profile: undefined,
|
88
|
+
saveDeployment: true,
|
89
|
+
worldAddress,
|
90
|
+
srcDir,
|
91
|
+
});
|
92
|
+
worldAddress = deploy.address;
|
93
|
+
// if there were changes while we were deploying, trigger it again
|
94
|
+
if (lastChange < lastChange$.value) {
|
95
|
+
lastChange$.next(lastChange$.value);
|
96
|
+
} else {
|
97
|
+
console.log(chalk.gray("\nWaiting for file changes…\n"));
|
98
|
+
}
|
99
|
+
return deploy;
|
100
|
+
} catch (error) {
|
101
|
+
console.error(chalk.bgRed(chalk.whiteBright("\n Error while attempting deploy \n")));
|
102
|
+
console.error(error);
|
103
|
+
console.log(chalk.gray("\nWaiting for file changes…\n"));
|
104
|
+
}
|
105
|
+
}),
|
106
|
+
filter(isDefined)
|
107
|
+
);
|
108
|
+
|
109
|
+
deploys$.subscribe();
|
174
110
|
},
|
175
111
|
};
|
176
112
|
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import chalk from "chalk";
|
2
|
-
import {
|
2
|
+
import { readFileSync, writeFileSync } from "fs";
|
3
3
|
import path from "path";
|
4
4
|
import type { CommandModule } from "yargs";
|
5
5
|
import { MUDError } from "@latticexyz/common/errors";
|
6
6
|
import { logError } from "../utils/errors";
|
7
7
|
import localPackageJson from "../../package.json" assert { type: "json" };
|
8
8
|
import glob from "glob";
|
9
|
+
import { mudPackages } from "../mudPackages";
|
9
10
|
|
10
11
|
type Options = {
|
11
12
|
backup?: boolean;
|
@@ -17,9 +18,6 @@ type Options = {
|
|
17
18
|
link?: string;
|
18
19
|
};
|
19
20
|
|
20
|
-
const BACKUP_FILE = ".mudbackup";
|
21
|
-
const MUD_PREFIX = "@latticexyz";
|
22
|
-
|
23
21
|
const commandModule: CommandModule<Options, Options> = {
|
24
22
|
command: "set-version",
|
25
23
|
|
@@ -27,12 +25,6 @@ const commandModule: CommandModule<Options, Options> = {
|
|
27
25
|
|
28
26
|
builder(yargs) {
|
29
27
|
return yargs.options({
|
30
|
-
backup: { type: "boolean", description: `Back up the current MUD versions to "${BACKUP_FILE}"` },
|
31
|
-
force: {
|
32
|
-
type: "boolean",
|
33
|
-
description: `Backup fails if a "${BACKUP_FILE}" file is found, unless --force is provided`,
|
34
|
-
},
|
35
|
-
restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
|
36
28
|
mudVersion: { alias: "v", type: "string", description: "Set MUD to the given version" },
|
37
29
|
tag: {
|
38
30
|
alias: "t",
|
@@ -117,63 +109,39 @@ async function resolveVersion(options: Options) {
|
|
117
109
|
}
|
118
110
|
|
119
111
|
function updatePackageJson(filePath: string, options: Options): { workspaces?: string[] } {
|
120
|
-
const {
|
121
|
-
let {
|
122
|
-
|
123
|
-
const backupFilePath = path.join(path.dirname(filePath), BACKUP_FILE);
|
124
|
-
const backupFileExists = existsSync(backupFilePath);
|
125
|
-
|
126
|
-
// Create a backup file for previous MUD versions by default if linking to local MUD
|
127
|
-
if (link && !backupFileExists) backup = true;
|
128
|
-
|
129
|
-
// If `backup` is true and force not set, check if a backup file already exists and throw an error if it does
|
130
|
-
if (backup && !force && backupFileExists) {
|
131
|
-
throw new MUDError(
|
132
|
-
`A backup file already exists at ${backupFilePath}.\nUse --force to overwrite it or --restore to restore it.`
|
133
|
-
);
|
134
|
-
}
|
112
|
+
const { link } = options;
|
113
|
+
let { mudVersion } = options;
|
135
114
|
|
136
115
|
const packageJson = readPackageJson(filePath);
|
137
|
-
|
138
|
-
// Load .mudbackup if `restore` is true
|
139
|
-
const backupJson = restore ? readPackageJson(backupFilePath) : undefined;
|
116
|
+
const mudPackageNames = Object.keys(mudPackages);
|
140
117
|
|
141
118
|
// Find all MUD dependencies
|
142
119
|
const mudDependencies: Record<string, string> = {};
|
143
|
-
for (const
|
144
|
-
if (
|
145
|
-
mudDependencies[
|
120
|
+
for (const packageName in packageJson.dependencies) {
|
121
|
+
if (mudPackageNames.includes(packageName)) {
|
122
|
+
mudDependencies[packageName] = packageJson.dependencies[packageName];
|
146
123
|
}
|
147
124
|
}
|
148
125
|
|
149
126
|
// Find all MUD devDependencies
|
150
127
|
const mudDevDependencies: Record<string, string> = {};
|
151
|
-
for (const
|
152
|
-
if (
|
153
|
-
mudDevDependencies[
|
128
|
+
for (const packageName in packageJson.devDependencies) {
|
129
|
+
if (mudPackageNames.includes(packageName)) {
|
130
|
+
mudDevDependencies[packageName] = packageJson.devDependencies[packageName];
|
154
131
|
}
|
155
132
|
}
|
156
133
|
|
157
|
-
// Back up the current dependencies if `backup` is true
|
158
|
-
if (backup) {
|
159
|
-
writeFileSync(
|
160
|
-
backupFilePath,
|
161
|
-
JSON.stringify({ dependencies: mudDependencies, devDependencies: mudDevDependencies }, null, 2)
|
162
|
-
);
|
163
|
-
console.log(chalk.green(`Backed up MUD dependencies from ${filePath} to ${backupFilePath}`));
|
164
|
-
}
|
165
|
-
|
166
134
|
// Update the dependencies
|
167
|
-
for (const
|
168
|
-
if (
|
169
|
-
packageJson.dependencies[
|
135
|
+
for (const packageName in packageJson.dependencies) {
|
136
|
+
if (mudPackageNames.includes(packageName)) {
|
137
|
+
packageJson.dependencies[packageName] = resolveMudVersion(packageName, "dependencies");
|
170
138
|
}
|
171
139
|
}
|
172
140
|
|
173
141
|
// Update the devDependencies
|
174
|
-
for (const
|
175
|
-
if (
|
176
|
-
packageJson.devDependencies[
|
142
|
+
for (const packageName in packageJson.devDependencies) {
|
143
|
+
if (mudPackageNames.includes(packageName)) {
|
144
|
+
packageJson.devDependencies[packageName] = resolveMudVersion(packageName, "devDependencies");
|
177
145
|
}
|
178
146
|
}
|
179
147
|
|
@@ -184,17 +152,9 @@ function updatePackageJson(filePath: string, options: Options): { workspaces?: s
|
|
184
152
|
logComparison(mudDependencies, packageJson.dependencies);
|
185
153
|
logComparison(mudDevDependencies, packageJson.devDependencies);
|
186
154
|
|
187
|
-
// Remove the backup file if `restore` is true and `backup` is false
|
188
|
-
// because the old backup file is no longer needed
|
189
|
-
if (restore && !backup) {
|
190
|
-
rmSync(backupFilePath);
|
191
|
-
console.log(chalk.green(`Cleaned up ${backupFilePath}`));
|
192
|
-
}
|
193
|
-
|
194
155
|
return packageJson;
|
195
156
|
|
196
157
|
function resolveMudVersion(key: string, type: "dependencies" | "devDependencies") {
|
197
|
-
if (restore && backupJson) return backupJson[type][key];
|
198
158
|
if (link) mudVersion = resolveLinkPath(filePath, link, key);
|
199
159
|
if (!mudVersion) return packageJson[type][key];
|
200
160
|
return mudVersion;
|
@@ -225,10 +185,9 @@ function logComparison(prev: Record<string, string>, curr: Record<string, string
|
|
225
185
|
/**
|
226
186
|
* Returns path of the package to link, given a path to a local MUD clone and a package
|
227
187
|
*/
|
228
|
-
function resolveLinkPath(packageJsonPath: string, mudLinkPath: string,
|
229
|
-
const pkgName = pkg.replace(MUD_PREFIX, "");
|
188
|
+
function resolveLinkPath(packageJsonPath: string, mudLinkPath: string, packageName: string) {
|
230
189
|
const packageJsonToRootPath = path.relative(path.dirname(packageJsonPath), process.cwd());
|
231
|
-
const linkPath = path.join(packageJsonToRootPath, mudLinkPath,
|
190
|
+
const linkPath = path.join(packageJsonToRootPath, mudLinkPath, mudPackages[packageName].localPath);
|
232
191
|
return "link:" + linkPath;
|
233
192
|
}
|
234
193
|
|
package/src/commands/test.ts
CHANGED
@@ -1,70 +1,64 @@
|
|
1
|
-
import type { CommandModule } from "yargs";
|
1
|
+
import type { CommandModule, InferredOptionTypes, Options } from "yargs";
|
2
2
|
import { anvil, forge, getRpcUrl } from "@latticexyz/common/foundry";
|
3
3
|
import chalk from "chalk";
|
4
|
-
import {
|
5
|
-
import { yDeployOptions } from "./deploy";
|
6
|
-
import { DeployOptions, deployHandler } from "../utils/deployHandler";
|
4
|
+
import { deployOptions, runDeploy } from "../runDeploy";
|
7
5
|
|
8
|
-
|
6
|
+
const testOptions = {
|
7
|
+
...deployOptions,
|
8
|
+
port: { type: "number", description: "Port to run internal node for fork testing on", default: 4242 },
|
9
|
+
worldAddress: {
|
10
|
+
type: "string",
|
11
|
+
description:
|
12
|
+
"Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing.",
|
13
|
+
},
|
14
|
+
forgeOptions: { type: "string", description: "Options to pass to forge test" },
|
15
|
+
} as const satisfies Record<string, Options>;
|
9
16
|
|
10
|
-
|
17
|
+
type TestOptions = InferredOptionTypes<typeof testOptions>;
|
11
18
|
|
12
|
-
const commandModule: CommandModule<
|
19
|
+
const commandModule: CommandModule<typeof testOptions, TestOptions> = {
|
13
20
|
command: "test",
|
14
21
|
|
15
22
|
describe: "Run tests in MUD contracts",
|
16
23
|
|
17
24
|
builder(yargs) {
|
18
|
-
return yargs.options(
|
19
|
-
...yDeployOptions,
|
20
|
-
port: { type: "number", description: "Port to run internal node for fork testing on", default: 4242 },
|
21
|
-
worldAddress: {
|
22
|
-
type: "string",
|
23
|
-
description:
|
24
|
-
"Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing.",
|
25
|
-
},
|
26
|
-
forgeOptions: { type: "string", description: "Options to pass to forge test" },
|
27
|
-
});
|
25
|
+
return yargs.options(testOptions);
|
28
26
|
},
|
29
27
|
|
30
|
-
async handler(
|
28
|
+
async handler(opts) {
|
31
29
|
// Start an internal anvil process if no world address is provided
|
32
|
-
if (!
|
33
|
-
const anvilArgs = ["--block-base-fee-per-gas", "0", "--port", String(
|
30
|
+
if (!opts.worldAddress) {
|
31
|
+
const anvilArgs = ["--block-base-fee-per-gas", "0", "--port", String(opts.port)];
|
34
32
|
anvil(anvilArgs);
|
35
33
|
}
|
36
34
|
|
37
|
-
const forkRpc =
|
35
|
+
const forkRpc = opts.worldAddress ? await getRpcUrl(opts.profile) : `http://127.0.0.1:${opts.port}`;
|
38
36
|
|
39
37
|
const worldAddress =
|
40
|
-
|
38
|
+
opts.worldAddress ??
|
41
39
|
(
|
42
|
-
await
|
43
|
-
...
|
40
|
+
await runDeploy({
|
41
|
+
...opts,
|
44
42
|
saveDeployment: false,
|
45
43
|
rpc: forkRpc,
|
46
44
|
})
|
47
|
-
).
|
45
|
+
).address;
|
48
46
|
|
49
47
|
console.log(chalk.blue("World address", worldAddress));
|
50
48
|
|
51
|
-
|
52
|
-
writeFileSync(WORLD_ADDRESS_FILE, worldAddress);
|
53
|
-
|
54
|
-
const userOptions = args.forgeOptions?.replaceAll("\\", "").split(" ") ?? [];
|
49
|
+
const userOptions = opts.forgeOptions?.replaceAll("\\", "").split(" ") ?? [];
|
55
50
|
try {
|
56
|
-
|
57
|
-
profile:
|
51
|
+
await forge(["test", "--fork-url", forkRpc, ...userOptions], {
|
52
|
+
profile: opts.profile,
|
53
|
+
env: {
|
54
|
+
WORLD_ADDRESS: worldAddress,
|
55
|
+
},
|
58
56
|
});
|
59
|
-
|
57
|
+
process.exit(0);
|
60
58
|
} catch (e) {
|
61
59
|
console.error(e);
|
62
|
-
rmSync(WORLD_ADDRESS_FILE);
|
63
60
|
process.exit(1);
|
64
61
|
}
|
65
|
-
|
66
|
-
rmSync(WORLD_ADDRESS_FILE);
|
67
|
-
process.exit(0);
|
68
62
|
},
|
69
63
|
};
|
70
64
|
|
package/src/commands/trace.ts
CHANGED
@@ -9,12 +9,13 @@ import { StoreConfig } from "@latticexyz/store";
|
|
9
9
|
import { resolveWorldConfig, WorldConfig } from "@latticexyz/world";
|
10
10
|
import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json" assert { type: "json" };
|
11
11
|
import worldConfig from "@latticexyz/world/mud.config.js";
|
12
|
-
import {
|
12
|
+
import { resourceToHex } from "@latticexyz/common";
|
13
13
|
import { getExistingContracts } from "../utils/getExistingContracts";
|
14
|
-
import {
|
14
|
+
import { createClient, http } from "viem";
|
15
|
+
import { getChainId } from "viem/actions";
|
15
16
|
|
16
17
|
// TODO account for multiple namespaces (https://github.com/latticexyz/mud/issues/994)
|
17
|
-
const systemsTableId =
|
18
|
+
const systemsTableId = resourceToHex({
|
18
19
|
type: "system",
|
19
20
|
namespace: worldConfig.namespace,
|
20
21
|
name: worldConfig.tables.Systems.name,
|
@@ -80,7 +81,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
80
81
|
const systemTableFieldLayout = await WorldContract.getFieldLayout(systemsTableId);
|
81
82
|
const labels: { name: string; address: string }[] = [];
|
82
83
|
for (const name of names) {
|
83
|
-
const systemSelector =
|
84
|
+
const systemSelector = resourceToHex({ type: "system", namespace, name });
|
84
85
|
// Get the first field of `Systems` table (the table maps system name to its address and other data)
|
85
86
|
const address = await WorldContract.getField(systemsTableId, [systemSelector], 0, systemTableFieldLayout);
|
86
87
|
labels.push({ name, address });
|
@@ -103,7 +104,8 @@ export default commandModule;
|
|
103
104
|
|
104
105
|
async function getWorldAddress(worldsFile: string, rpc: string) {
|
105
106
|
if (existsSync(worldsFile)) {
|
106
|
-
const
|
107
|
+
const client = createClient({ transport: http(rpc) });
|
108
|
+
const chainId = await getChainId(client);
|
107
109
|
const deploys = JSON.parse(readFileSync(worldsFile, "utf-8"));
|
108
110
|
|
109
111
|
if (!deploys[chainId]) {
|
package/src/common.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export type MudPackages = Record<string, { localPath: string }>;
|
package/src/debug.ts
ADDED