@latticexyz/cli 2.0.0-alpha.49 → 2.0.0-alpha.5
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/chunk-6V563IAZ.js +283 -0
- package/dist/{chunk-ATAWDHWC.js → chunk-FPG73MVN.js} +5 -1
- package/dist/chunk-KJTPZOUH.js +3864 -0
- package/dist/{chunk-O6HOO6WA.js → chunk-L4YLJHLJ.js} +1 -9
- package/dist/{chunk-KPBNUPK6.js → chunk-SKNB74MT.js} +155 -159
- package/dist/chunk-VQTZJIFF.js +353 -0
- package/dist/{chunk-MXDV47JM.js → chunk-WZFXLDPK.js} +75 -24
- package/dist/chunk-YL4GJLLL.js +26139 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +0 -22
- package/dist/mud.d.ts +1 -1
- package/dist/mud.js +319 -3971
- package/dist/mud2.d.ts +1 -0
- package/dist/mud2.js +25 -0
- package/dist/render-solidity/index.d.ts +3 -3
- package/dist/render-solidity/index.js +3 -4
- package/dist/render-ts/index.d.ts +2 -3
- package/dist/render-ts/index.js +3 -4
- package/dist/utils/deprecated/index.js +3 -3
- package/dist/utils/index.d.ts +9 -19
- package/dist/utils/index.js +7 -18
- package/package.json +19 -20
- package/src/commands/deploy-v2.ts +80 -64
- package/src/commands/deprecated/index.ts +22 -0
- package/src/commands/deprecated/test.ts +1 -1
- package/src/commands/gas-report.ts +54 -55
- package/src/commands/index.ts +2 -17
- package/src/commands/set-version.ts +39 -10
- package/src/commands/tablegen.ts +5 -5
- package/src/commands/test-v2.ts +71 -0
- package/src/commands/tsgen.ts +1 -1
- package/src/commands/worldgen.ts +5 -4
- package/src/contracts/BulkUpload.sol +13 -20
- package/src/contracts/Deploy.sol +3 -3
- package/src/contracts/LibDeploy.sol +1 -1
- package/src/contracts/LibDeployStub.sol +1 -1
- package/src/index.ts +1 -15
- package/src/mud.ts +4 -3
- package/src/mud2.ts +29 -0
- package/src/render-solidity/common.ts +4 -4
- package/src/render-solidity/field.ts +25 -2
- package/src/render-solidity/record.ts +14 -10
- package/src/render-solidity/renderSystemInterface.ts +4 -4
- package/src/render-solidity/renderTableIndex.ts +15 -0
- package/src/render-solidity/renderTypesFromConfig.ts +1 -1
- package/src/render-solidity/tableOptions.ts +2 -2
- package/src/render-solidity/tablegen.ts +13 -1
- package/src/render-solidity/types.ts +2 -1
- package/src/render-solidity/userType.ts +1 -2
- package/src/render-solidity/worldgen.ts +3 -3
- package/src/render-ts/recsV1TableOptions.ts +2 -2
- package/src/render-ts/renderRecsV1Tables.ts +2 -2
- package/src/render-ts/schemaTypesToRecsTypeStrings.ts +136 -136
- package/src/render-ts/tsgen.ts +1 -1
- package/src/render-ts/types.ts +1 -1
- package/src/utils/contractToInterface.ts +5 -3
- package/src/utils/deploy-v2.ts +85 -78
- package/src/utils/errors.ts +3 -34
- package/src/utils/foundry.ts +9 -0
- package/dist/chunk-5NC2OON2.js +0 -164
- package/dist/chunk-7GA2K5A6.js +0 -283
- package/dist/chunk-LPWKZQUI.js +0 -454
- package/dist/chunk-Q7D3SKYJ.js +0 -22908
- package/dist/chunk-SLIMIO4Z.js +0 -14358
- package/dist/config/index.d.ts +0 -408
- package/dist/config/index.js +0 -85
- package/dist/parseStoreConfig-899f574e.d.ts +0 -369
- package/src/config/commonSchemas.ts +0 -34
- package/src/config/dynamicResolution.ts +0 -49
- package/src/config/index.ts +0 -24
- package/src/config/loadConfig.ts +0 -39
- package/src/config/loadStoreConfig.ts +0 -18
- package/src/config/parseStoreConfig.test-d.ts +0 -40
- package/src/config/parseStoreConfig.ts +0 -314
- package/src/config/validation.ts +0 -163
- package/src/config/world/index.ts +0 -4
- package/src/config/world/loadWorldConfig.test-d.ts +0 -11
- package/src/config/world/loadWorldConfig.ts +0 -26
- package/src/config/world/parseWorldConfig.ts +0 -56
- package/src/config/world/resolveWorldConfig.ts +0 -80
- package/src/config/world/userTypes.ts +0 -74
- package/src/utils/typeUtils.ts +0 -17
|
@@ -39,6 +39,8 @@ type GasReportEntry = {
|
|
|
39
39
|
|
|
40
40
|
type GasReport = GasReportEntry[];
|
|
41
41
|
|
|
42
|
+
const tempFileSuffix = "MudGasReport";
|
|
43
|
+
|
|
42
44
|
const commandModule: CommandModule<Options, Options> = {
|
|
43
45
|
command: "gas-report",
|
|
44
46
|
|
|
@@ -52,43 +54,43 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
52
54
|
});
|
|
53
55
|
},
|
|
54
56
|
|
|
55
|
-
async handler({ path, save, compare }) {
|
|
56
|
-
|
|
57
|
+
async handler({ path: files, save, compare }) {
|
|
58
|
+
const validFiles = files.filter((file) => file.endsWith(".t.sol"));
|
|
59
|
+
const tempFiles = await Promise.all(validFiles.map((file) => createGasReport(file)));
|
|
60
|
+
|
|
61
|
+
process.once("SIGINT", () => {
|
|
62
|
+
console.log("caught sigint, deleting temp files");
|
|
63
|
+
tempFiles.forEach((file) => rmSync(file));
|
|
64
|
+
});
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
gasReport =
|
|
66
|
+
let gasReport: GasReport;
|
|
67
|
+
try {
|
|
68
|
+
gasReport = await runGasReport();
|
|
69
|
+
} catch {
|
|
70
|
+
setTimeout(() => process.exit());
|
|
71
|
+
return;
|
|
72
|
+
} finally {
|
|
73
|
+
// Delete the temporary files
|
|
74
|
+
tempFiles.forEach((file) => rmSync(file));
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
// If this gas report should be compared to an existing one, load the existing one
|
|
64
|
-
const compareGasReport: GasReport = [];
|
|
65
78
|
if (compare) {
|
|
66
79
|
try {
|
|
67
|
-
const
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const functionCall = compareGasReportMatch[3];
|
|
76
|
-
const gasUsed = compareGasReportMatch[4];
|
|
77
|
-
|
|
78
|
-
compareGasReport.push({ source, name, functionCall, gasUsed: parseInt(gasUsed) });
|
|
79
|
-
}
|
|
80
|
+
const compareGasReport: GasReport = JSON.parse(readFileSync(compare, "utf8"));
|
|
81
|
+
// Merge the previous gas report with the new one
|
|
82
|
+
gasReport = gasReport.map((entry) => {
|
|
83
|
+
const prevEntry = compareGasReport.find(
|
|
84
|
+
(e) => e.name === entry.name && e.functionCall === entry.functionCall
|
|
85
|
+
);
|
|
86
|
+
return { ...entry, prevGasUsed: prevEntry?.gasUsed };
|
|
87
|
+
});
|
|
80
88
|
} catch {
|
|
81
89
|
console.log(chalk.red(`Gas report to compare not found: ${compare}`));
|
|
82
90
|
compare = undefined;
|
|
83
91
|
}
|
|
84
92
|
}
|
|
85
93
|
|
|
86
|
-
// Merge the previous gas report with the new one
|
|
87
|
-
gasReport = gasReport.map((entry) => {
|
|
88
|
-
const prevEntry = compareGasReport.find((e) => e.name === entry.name && e.functionCall === entry.functionCall);
|
|
89
|
-
return { ...entry, prevGasUsed: prevEntry?.gasUsed };
|
|
90
|
-
});
|
|
91
|
-
|
|
92
94
|
// Print gas report
|
|
93
95
|
printGasReport(gasReport, compare);
|
|
94
96
|
|
|
@@ -101,16 +103,11 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
101
103
|
|
|
102
104
|
export default commandModule;
|
|
103
105
|
|
|
104
|
-
async function
|
|
105
|
-
|
|
106
|
-
console.log("Skipping gas report for", chalk.bold(path), "(not a test file)");
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
console.log("Running gas report for", chalk.bold(path));
|
|
110
|
-
const gasReport: GasReport = [];
|
|
106
|
+
async function createGasReport(filename: string): Promise<string> {
|
|
107
|
+
console.log("Creating gas report for", chalk.bold(filename));
|
|
111
108
|
|
|
112
109
|
// Parse the given test file, and add gas reporting wherever requested by a `// !gasreport` comment
|
|
113
|
-
const fileContents = readFileSync(
|
|
110
|
+
const fileContents = readFileSync(filename, "utf8");
|
|
114
111
|
let newFile = fileContents;
|
|
115
112
|
|
|
116
113
|
// Use a regex to find first line of each function
|
|
@@ -139,7 +136,7 @@ async function runGasReport(path: string): Promise<GasReport> {
|
|
|
139
136
|
_gasreport = gasleft();
|
|
140
137
|
${functionCall}
|
|
141
138
|
_gasreport = _gasreport - gasleft();
|
|
142
|
-
console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);`
|
|
139
|
+
console.log("GAS REPORT(${filename}): ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);`
|
|
143
140
|
);
|
|
144
141
|
}
|
|
145
142
|
|
|
@@ -148,41 +145,47 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
|
|
|
148
145
|
|
|
149
146
|
// Write the new file to disk (temporarily)
|
|
150
147
|
// Create the temp file by replacing the previous file name with MudGasReport
|
|
151
|
-
const tempFileName =
|
|
148
|
+
const tempFileName = filename.replace(/\.t\.sol$/, `${tempFileSuffix}.t.sol`);
|
|
152
149
|
writeFileSync(tempFileName, newFile);
|
|
153
150
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
return tempFileName;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function runGasReport(): Promise<GasReport> {
|
|
155
|
+
console.log("Running gas report");
|
|
156
|
+
const gasReport: GasReport = [];
|
|
158
157
|
|
|
159
158
|
// Extract the logs from the child process
|
|
160
159
|
let logs = "";
|
|
161
160
|
try {
|
|
161
|
+
// Run the generated file using forge
|
|
162
|
+
const child = execa("forge", ["test", "--match-path", `*${tempFileSuffix}*`, "-vvv"], {
|
|
163
|
+
stdio: ["inherit", "pipe", "inherit"],
|
|
164
|
+
});
|
|
162
165
|
logs = (await child).stdout;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
console.log(e.stdout ?? e);
|
|
166
|
+
} catch (error: any) {
|
|
167
|
+
console.log(error.stdout ?? error);
|
|
166
168
|
console.log(chalk.red("\n-----------\nError while running the gas report (see above)"));
|
|
167
|
-
|
|
168
|
-
process.exit();
|
|
169
|
+
throw error;
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
// Extract the gas reports from the logs
|
|
172
173
|
|
|
173
174
|
// Create a regex to find all lines starting with `GAS REPORT:` and extract the name, function call and gas used
|
|
174
|
-
const gasReportRegex = new RegExp(/GAS REPORT: (.*) \[(.*)\]: (.*)/g);
|
|
175
|
+
const gasReportRegex = new RegExp(/GAS REPORT\((.*)\): (.*) \[(.*)\]: (.*)/g);
|
|
175
176
|
|
|
176
177
|
// Loop through the matches and print the gas report
|
|
177
178
|
let gasReportMatch;
|
|
178
179
|
while ((gasReportMatch = gasReportRegex.exec(logs)) !== null) {
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
gasReport.push({ source
|
|
180
|
+
const source = gasReportMatch[1];
|
|
181
|
+
const name = gasReportMatch[2];
|
|
182
|
+
const functionCall = gasReportMatch[3].replace(";", "");
|
|
183
|
+
const gasUsed = parseInt(gasReportMatch[4]);
|
|
184
|
+
gasReport.push({ source, name, functionCall, gasUsed });
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
gasReport.sort((a, b) => a.source.localeCompare(b.source));
|
|
188
|
+
|
|
186
189
|
return gasReport;
|
|
187
190
|
}
|
|
188
191
|
|
|
@@ -212,9 +215,5 @@ function printGasReport(gasReport: GasReport, compare?: string) {
|
|
|
212
215
|
|
|
213
216
|
function saveGasReport(gasReport: GasReport, path: string) {
|
|
214
217
|
console.log(chalk.bold(`Saving gas report to ${path}`));
|
|
215
|
-
|
|
216
|
-
.map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`)
|
|
217
|
-
.join("\n");
|
|
218
|
-
|
|
219
|
-
writeFileSync(path, serializedGasReport);
|
|
218
|
+
writeFileSync(path, `${JSON.stringify(gasReport, null, 2)}\n`);
|
|
220
219
|
}
|
package/src/commands/index.ts
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { CommandModule } from "yargs";
|
|
2
2
|
|
|
3
|
-
import bulkupload from "./deprecated/bulkupload.js";
|
|
4
|
-
import callSystem from "./deprecated/call-system.js";
|
|
5
|
-
import codegenLibdeploy from "./deprecated/codegen-libdeploy.js";
|
|
6
|
-
import deployContracts from "./deprecated/deploy-contracts.js";
|
|
7
|
-
import systemTypes from "./deprecated/system-types.js";
|
|
8
|
-
import test from "./deprecated/test.js";
|
|
9
|
-
import trace from "./deprecated/trace.js";
|
|
10
|
-
import types from "./deprecated/types.js";
|
|
11
|
-
|
|
12
3
|
import devnode from "./devnode.js";
|
|
13
4
|
import faucet from "./faucet.js";
|
|
14
5
|
import gasReport from "./gas-report.js";
|
|
@@ -18,24 +9,18 @@ import tsgen from "./tsgen.js";
|
|
|
18
9
|
import deployV2 from "./deploy-v2.js";
|
|
19
10
|
import worldgen from "./worldgen.js";
|
|
20
11
|
import setVersion from "./set-version.js";
|
|
12
|
+
import testV2 from "./test-v2.js";
|
|
21
13
|
|
|
22
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
|
|
23
15
|
export const commands: CommandModule<any, any>[] = [
|
|
24
|
-
bulkupload,
|
|
25
|
-
callSystem,
|
|
26
|
-
codegenLibdeploy,
|
|
27
|
-
deployContracts,
|
|
28
16
|
deployV2,
|
|
29
17
|
devnode,
|
|
30
18
|
faucet,
|
|
31
19
|
gasReport,
|
|
32
20
|
hello,
|
|
33
|
-
systemTypes,
|
|
34
21
|
tablegen,
|
|
35
22
|
tsgen,
|
|
36
|
-
test,
|
|
37
|
-
trace,
|
|
38
|
-
types,
|
|
39
23
|
worldgen,
|
|
40
24
|
setVersion,
|
|
25
|
+
testV2,
|
|
41
26
|
];
|
|
@@ -2,14 +2,16 @@ import chalk from "chalk";
|
|
|
2
2
|
import { existsSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import type { CommandModule } from "yargs";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { MUDError } from "@latticexyz/config";
|
|
6
|
+
import { logError } from "../utils/errors.js";
|
|
7
|
+
import localPackageJson from "../../package.json" assert { type: "json" };
|
|
7
8
|
|
|
8
9
|
type Options = {
|
|
9
10
|
backup?: boolean;
|
|
10
11
|
force?: boolean;
|
|
11
12
|
restore?: boolean;
|
|
12
13
|
mudVersion?: string;
|
|
14
|
+
link?: string;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
const BACKUP_FILE = ".mudbackup";
|
|
@@ -29,13 +31,19 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
29
31
|
},
|
|
30
32
|
restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
|
|
31
33
|
mudVersion: { alias: "v", type: "string", description: "The MUD version to install" },
|
|
34
|
+
link: { alias: "l", type: "string", description: "Relative path to the local MUD root directory to link" },
|
|
32
35
|
});
|
|
33
36
|
},
|
|
34
37
|
|
|
35
38
|
async handler(options) {
|
|
36
39
|
try {
|
|
37
|
-
if (!options.mudVersion && !options.restore) {
|
|
38
|
-
throw new MUDError(`
|
|
40
|
+
if (!options.mudVersion && !options.link && !options.restore) {
|
|
41
|
+
throw new MUDError("`--mudVersion` or `--link` is required unless --restore is provided.");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// `link` and `mudVersion` are mutually exclusive
|
|
45
|
+
if (options.link && options.mudVersion) {
|
|
46
|
+
throw new MUDError("Options `--link` and `--mudVersion` are mutually exclusive");
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
// Resolve the `canary` version number if needed
|
|
@@ -62,11 +70,17 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
62
70
|
};
|
|
63
71
|
|
|
64
72
|
function updatePackageJson(filePath: string, options: Options): { workspaces?: string[] } {
|
|
65
|
-
const {
|
|
73
|
+
const { restore, force, link } = options;
|
|
74
|
+
let { backup, mudVersion } = options;
|
|
75
|
+
|
|
66
76
|
const backupFilePath = path.join(path.dirname(filePath), BACKUP_FILE);
|
|
77
|
+
const backupFileExists = existsSync(backupFilePath);
|
|
78
|
+
|
|
79
|
+
// Create a backup file for previous MUD versions by default if linking to local MUD
|
|
80
|
+
if (link && !backupFileExists) backup = true;
|
|
67
81
|
|
|
68
82
|
// If `backup` is true and force not set, check if a backup file already exists and throw an error if it does
|
|
69
|
-
if (backup && !force &&
|
|
83
|
+
if (backup && !force && backupFileExists) {
|
|
70
84
|
throw new MUDError(
|
|
71
85
|
`A backup file already exists at ${backupFilePath}.\nUse --force to overwrite it or --restore to restore it.`
|
|
72
86
|
);
|
|
@@ -105,16 +119,14 @@ function updatePackageJson(filePath: string, options: Options): { workspaces?: s
|
|
|
105
119
|
// Update the dependencies
|
|
106
120
|
for (const key in packageJson.dependencies) {
|
|
107
121
|
if (key.startsWith(MUD_PREFIX)) {
|
|
108
|
-
packageJson.dependencies[key] =
|
|
109
|
-
restore && backupJson ? backupJson.dependencies[key] : mudVersion || packageJson.dependencies[key];
|
|
122
|
+
packageJson.dependencies[key] = resolveMudVersion(key, "dependencies");
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
// Update the devDependencies
|
|
114
127
|
for (const key in packageJson.devDependencies) {
|
|
115
128
|
if (key.startsWith(MUD_PREFIX)) {
|
|
116
|
-
packageJson.devDependencies[key] =
|
|
117
|
-
restore && backupJson ? backupJson.devDependencies[key] : mudVersion || packageJson.devDependencies[key];
|
|
129
|
+
packageJson.devDependencies[key] = resolveMudVersion(key, "devDependencies");
|
|
118
130
|
}
|
|
119
131
|
}
|
|
120
132
|
|
|
@@ -133,6 +145,13 @@ function updatePackageJson(filePath: string, options: Options): { workspaces?: s
|
|
|
133
145
|
}
|
|
134
146
|
|
|
135
147
|
return packageJson;
|
|
148
|
+
|
|
149
|
+
function resolveMudVersion(key: string, type: "dependencies" | "devDependencies") {
|
|
150
|
+
if (restore && backupJson) return backupJson[type][key];
|
|
151
|
+
if (link) mudVersion = resolveLinkPath(filePath, link, key);
|
|
152
|
+
if (!mudVersion) return packageJson[type][key];
|
|
153
|
+
return mudVersion;
|
|
154
|
+
}
|
|
136
155
|
}
|
|
137
156
|
|
|
138
157
|
function readPackageJson(path: string): {
|
|
@@ -168,4 +187,14 @@ function logComparison(prev: Record<string, string>, curr: Record<string, string
|
|
|
168
187
|
}
|
|
169
188
|
}
|
|
170
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Returns path of the package to link, given a path to a local MUD clone and a package
|
|
192
|
+
*/
|
|
193
|
+
function resolveLinkPath(packageJsonPath: string, mudLinkPath: string, pkg: string) {
|
|
194
|
+
const pkgName = pkg.replace(MUD_PREFIX, "");
|
|
195
|
+
const packageJsonToRootPath = path.relative(path.dirname(packageJsonPath), process.cwd());
|
|
196
|
+
const linkPath = path.join(packageJsonToRootPath, mudLinkPath, "packages", pkgName);
|
|
197
|
+
return "link:" + linkPath;
|
|
198
|
+
}
|
|
199
|
+
|
|
171
200
|
export default commandModule;
|
package/src/commands/tablegen.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import path from "path";
|
|
1
2
|
import type { CommandModule } from "yargs";
|
|
2
|
-
import { loadStoreConfig } from "
|
|
3
|
-
import { getSrcDirectory } from "../utils/foundry.js";
|
|
3
|
+
import { loadStoreConfig } from "@latticexyz/config";
|
|
4
4
|
import { tablegen } from "../render-solidity/tablegen.js";
|
|
5
|
+
import { getSrcDirectory } from "../utils/index.js";
|
|
5
6
|
|
|
6
7
|
type Options = {
|
|
7
8
|
configPath?: string;
|
|
@@ -19,11 +20,10 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
19
20
|
},
|
|
20
21
|
|
|
21
22
|
async handler({ configPath }) {
|
|
22
|
-
const srcDirectory = await getSrcDirectory();
|
|
23
|
-
|
|
24
23
|
const config = await loadStoreConfig(configPath);
|
|
24
|
+
const srcDir = await getSrcDirectory();
|
|
25
25
|
|
|
26
|
-
await tablegen(config,
|
|
26
|
+
await tablegen(config, path.join(srcDir, config.codegenDirectory));
|
|
27
27
|
|
|
28
28
|
process.exit(0);
|
|
29
29
|
},
|
|
@@ -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;
|
package/src/commands/tsgen.ts
CHANGED
package/src/commands/worldgen.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CommandModule } from "yargs";
|
|
2
|
-
import { loadStoreConfig } from "
|
|
3
|
-
import { loadWorldConfig } from "../config/index.js";
|
|
2
|
+
import { loadStoreConfig, loadWorldConfig } from "@latticexyz/config";
|
|
4
3
|
import { getSrcDirectory } from "../utils/foundry.js";
|
|
5
4
|
import glob from "glob";
|
|
6
5
|
import path, { basename } from "path";
|
|
@@ -42,11 +41,13 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
42
41
|
const storeConfig = await loadStoreConfig(configPath);
|
|
43
42
|
const mudConfig = { ...worldConfig, ...storeConfig };
|
|
44
43
|
|
|
44
|
+
const outputBaseDirectory = path.join(srcDir, mudConfig.codegenDirectory);
|
|
45
|
+
|
|
45
46
|
// clear the worldgen directory
|
|
46
|
-
if (clean) rmSync(path.join(
|
|
47
|
+
if (clean) rmSync(path.join(outputBaseDirectory, mudConfig.worldgenDirectory), { recursive: true, force: true });
|
|
47
48
|
|
|
48
49
|
// generate new interfaces
|
|
49
|
-
await worldgen(mudConfig, existingContracts,
|
|
50
|
+
await worldgen(mudConfig, existingContracts, outputBaseDirectory);
|
|
50
51
|
|
|
51
52
|
process.exit(0);
|
|
52
53
|
},
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity >=0.8.0;
|
|
3
3
|
|
|
4
|
-
import {Script} from "forge-std/Script.sol";
|
|
5
|
-
import {console} from "forge-std/console.sol";
|
|
4
|
+
import { Script } from "forge-std/Script.sol";
|
|
5
|
+
import { console } from "forge-std/console.sol";
|
|
6
6
|
|
|
7
|
-
import {BulkSetStateSystem, ID as BulkSetStateSystemID, ECSEvent} from "std-contracts/systems/BulkSetStateSystem.sol";
|
|
8
|
-
import {World} from "solecs/World.sol";
|
|
9
|
-
import {System} from "solecs/System.sol";
|
|
10
|
-
import {getAddressById} from "solecs/utils.sol";
|
|
11
|
-
import {Set} from "solecs/Set.sol";
|
|
7
|
+
import { BulkSetStateSystem, ID as BulkSetStateSystemID, ECSEvent } from "std-contracts/systems/BulkSetStateSystem.sol";
|
|
8
|
+
import { World } from "solecs/World.sol";
|
|
9
|
+
import { System } from "solecs/System.sol";
|
|
10
|
+
import { getAddressById } from "solecs/utils.sol";
|
|
11
|
+
import { Set } from "solecs/Set.sol";
|
|
12
12
|
|
|
13
13
|
struct ParsedState {
|
|
14
14
|
string[] componentIds;
|
|
@@ -33,11 +33,7 @@ struct State {
|
|
|
33
33
|
* forge script --sig "run(string, address)" --rpc-url http://localhost:8545 src/contracts/BulkUpload.sol:BulkUpload path/to/ecs-map-test.json <WORLD_ADDRESS>
|
|
34
34
|
*/
|
|
35
35
|
contract BulkUpload is Script {
|
|
36
|
-
function run(
|
|
37
|
-
string memory path,
|
|
38
|
-
address worldAddress,
|
|
39
|
-
uint256 eventsPerTx
|
|
40
|
-
) public {
|
|
36
|
+
function run(string memory path, address worldAddress, uint256 eventsPerTx) public {
|
|
41
37
|
vmSafe.startBroadcast();
|
|
42
38
|
|
|
43
39
|
// Read JSON
|
|
@@ -108,9 +104,10 @@ contract BulkUpload is Script {
|
|
|
108
104
|
}
|
|
109
105
|
}
|
|
110
106
|
|
|
111
|
-
function transformEventsToOnlyUseNeededEntities(
|
|
112
|
-
|
|
113
|
-
|
|
107
|
+
function transformEventsToOnlyUseNeededEntities(
|
|
108
|
+
uint256[] memory entities,
|
|
109
|
+
ECSEvent[] memory events
|
|
110
|
+
) returns (uint256[] memory, ECSEvent[] memory) {
|
|
114
111
|
Set uniqueEntityIndices = new Set();
|
|
115
112
|
|
|
116
113
|
// Find unique entity indices
|
|
@@ -167,11 +164,7 @@ function hexToBytes(string memory s) pure returns (bytes memory) {
|
|
|
167
164
|
return r;
|
|
168
165
|
}
|
|
169
166
|
|
|
170
|
-
function substring(
|
|
171
|
-
string memory str,
|
|
172
|
-
uint256 start,
|
|
173
|
-
uint256 end
|
|
174
|
-
) pure returns (string memory) {
|
|
167
|
+
function substring(string memory str, uint256 start, uint256 end) pure returns (string memory) {
|
|
175
168
|
bytes memory strBytes = bytes(str);
|
|
176
169
|
bytes memory result = new bytes(end - start);
|
|
177
170
|
for (uint256 i = start; i < end; i++) {
|
package/src/contracts/Deploy.sol
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
pragma solidity >=0.8.0;
|
|
3
3
|
|
|
4
4
|
// Foundry
|
|
5
|
-
import {Script} from "forge-std/Script.sol";
|
|
6
|
-
import {console} from "forge-std/console.sol";
|
|
5
|
+
import { Script } from "forge-std/Script.sol";
|
|
6
|
+
import { console } from "forge-std/console.sol";
|
|
7
7
|
|
|
8
8
|
// Libraries
|
|
9
|
-
import {LibDeploy, DeployResult} from "./LibDeploy.sol";
|
|
9
|
+
import { LibDeploy, DeployResult } from "./LibDeploy.sol";
|
|
10
10
|
|
|
11
11
|
contract Deploy is Script {
|
|
12
12
|
function broadcastDeploy(
|
|
@@ -7,7 +7,7 @@ pragma solidity >=0.8.0;
|
|
|
7
7
|
// To manually generate the real LibDeploy.sol use
|
|
8
8
|
// `mud codegen-libdeploy`.
|
|
9
9
|
|
|
10
|
-
import {IWorld} from "solecs/interfaces/IWorld.sol";
|
|
10
|
+
import { IWorld } from "solecs/interfaces/IWorld.sol";
|
|
11
11
|
|
|
12
12
|
struct DeployResult {
|
|
13
13
|
IWorld world;
|
|
@@ -7,7 +7,7 @@ pragma solidity >=0.8.0;
|
|
|
7
7
|
// To manually generate the real LibDeploy.sol use
|
|
8
8
|
// `mud codegen-libdeploy`.
|
|
9
9
|
|
|
10
|
-
import {IWorld} from "solecs/interfaces/IWorld.sol";
|
|
10
|
+
import { IWorld } from "solecs/interfaces/IWorld.sol";
|
|
11
11
|
|
|
12
12
|
struct DeployResult {
|
|
13
13
|
IWorld world;
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { parseStoreConfig } from "./config/parseStoreConfig.js";
|
|
3
|
-
export { loadWorldConfig, resolveWorldConfig, parseWorldConfig } from "./config/world/index.js";
|
|
4
|
-
export { resolveTableId } from "./config/dynamicResolution.js";
|
|
5
|
-
|
|
6
|
-
export type {
|
|
7
|
-
StoreUserConfig,
|
|
8
|
-
StoreConfig,
|
|
9
|
-
WorldUserConfig,
|
|
10
|
-
ResolvedWorldConfig,
|
|
11
|
-
MUDUserConfig,
|
|
12
|
-
MUDConfig,
|
|
13
|
-
} from "./config/index.js";
|
|
14
|
-
|
|
15
|
-
export { storeConfig, mudConfig } from "./config/index.js";
|
|
1
|
+
export {};
|
package/src/mud.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import yargs from "yargs";
|
|
4
4
|
import { hideBin } from "yargs/helpers";
|
|
5
|
-
import { commands } from "./commands/index.js";
|
|
5
|
+
import { commands as v2 } from "./commands/index.js";
|
|
6
|
+
import { commands as v1 } from "./commands/deprecated/index.js";
|
|
6
7
|
import { logError } from "./utils/errors.js";
|
|
7
8
|
|
|
8
9
|
// Load .env file into process.env
|
|
@@ -14,7 +15,7 @@ yargs(hideBin(process.argv))
|
|
|
14
15
|
.scriptName("mud")
|
|
15
16
|
// Use the commands directory to scaffold
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- command array overload isn't typed, see https://github.com/yargs/yargs/blob/main/docs/advanced.md#esm-hierarchy
|
|
17
|
-
.command(
|
|
18
|
+
.command([...v1, ...v2] as any)
|
|
18
19
|
// Enable strict mode.
|
|
19
20
|
.strict()
|
|
20
21
|
// Custom error handler
|
package/src/mud2.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import yargs from "yargs";
|
|
4
|
+
import { hideBin } from "yargs/helpers";
|
|
5
|
+
import { commands } from "./commands/index.js";
|
|
6
|
+
import { logError } from "./utils/errors.js";
|
|
7
|
+
|
|
8
|
+
// Load .env file into process.env
|
|
9
|
+
import * as dotenv from "dotenv";
|
|
10
|
+
dotenv.config();
|
|
11
|
+
|
|
12
|
+
yargs(hideBin(process.argv))
|
|
13
|
+
// Explicit name to display in help (by default it's the entry file, which may not be "mud" for e.g. ts-node)
|
|
14
|
+
.scriptName("mud")
|
|
15
|
+
// Use the commands directory to scaffold
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- command array overload isn't typed, see https://github.com/yargs/yargs/blob/main/docs/advanced.md#esm-hierarchy
|
|
17
|
+
.command(commands as any)
|
|
18
|
+
// Enable strict mode.
|
|
19
|
+
.strict()
|
|
20
|
+
// Custom error handler
|
|
21
|
+
.fail((msg, err) => {
|
|
22
|
+
console.log("");
|
|
23
|
+
logError(err);
|
|
24
|
+
console.log("");
|
|
25
|
+
|
|
26
|
+
process.exit(1);
|
|
27
|
+
})
|
|
28
|
+
// Useful aliases.
|
|
29
|
+
.alias({ h: "help" }).argv;
|
|
@@ -27,7 +27,7 @@ export function renderCommonData({
|
|
|
27
27
|
}: Pick<RenderTableOptions, "staticResourceData" | "primaryKeys">) {
|
|
28
28
|
// static resource means static tableId as well, and no tableId arguments
|
|
29
29
|
const _tableId = staticResourceData ? "" : "_tableId";
|
|
30
|
-
const _typedTableId = staticResourceData ? "" : "
|
|
30
|
+
const _typedTableId = staticResourceData ? "" : "bytes32 _tableId";
|
|
31
31
|
|
|
32
32
|
const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
|
|
33
33
|
const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
|
|
@@ -100,11 +100,11 @@ export function renderWithStore(
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
export function renderTableId(staticResourceData: StaticResourceData) {
|
|
103
|
-
const hardcodedTableId = `
|
|
103
|
+
const hardcodedTableId = `bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.name}")))`;
|
|
104
104
|
|
|
105
105
|
const tableIdDefinition = `
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
bytes32 constant _tableId = ${hardcodedTableId};
|
|
107
|
+
bytes32 constant ${staticResourceData.tableIdName} = _tableId;
|
|
108
108
|
`;
|
|
109
109
|
return {
|
|
110
110
|
hardcodedTableId,
|