@latticexyz/cli 1.40.0 → 1.41.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-ATAWDHWC.js +67 -0
  3. package/dist/{chunk-6AQ6LFVZ.js → chunk-J4DJQNIC.js} +743 -103
  4. package/dist/chunk-KD354QKC.js +23039 -0
  5. package/dist/{chunk-S3V3XX7N.js → chunk-SLIMIO4Z.js} +1 -1
  6. package/dist/config/index.d.ts +746 -8
  7. package/dist/config/index.js +63 -17
  8. package/dist/index.d.ts +1 -2
  9. package/dist/index.js +14 -10
  10. package/dist/mud.js +1055 -49
  11. package/dist/utils/deprecated/index.js +2 -2
  12. package/dist/utils/index.d.ts +56 -7
  13. package/dist/utils/index.js +17 -3
  14. package/package.json +16 -11
  15. package/src/commands/deploy-v2.ts +96 -0
  16. package/src/commands/deprecated/call-system.ts +1 -1
  17. package/src/commands/deprecated/deploy-contracts.ts +1 -1
  18. package/src/commands/deprecated/test.ts +9 -6
  19. package/src/commands/deprecated/trace.ts +1 -1
  20. package/src/commands/gas-report.ts +1 -1
  21. package/src/commands/index.ts +4 -0
  22. package/src/commands/tablegen.ts +4 -18
  23. package/src/commands/worldgen.ts +55 -0
  24. package/src/config/commonSchemas.ts +19 -5
  25. package/src/config/dynamicResolution.ts +49 -0
  26. package/src/config/index.ts +20 -0
  27. package/src/config/loadStoreConfig.ts +3 -89
  28. package/src/config/parseStoreConfig.test-d.ts +40 -0
  29. package/src/config/parseStoreConfig.ts +314 -0
  30. package/src/config/validation.ts +71 -0
  31. package/src/config/world/index.ts +4 -0
  32. package/src/config/world/loadWorldConfig.test-d.ts +11 -0
  33. package/src/config/world/loadWorldConfig.ts +26 -0
  34. package/src/config/world/parseWorldConfig.ts +55 -0
  35. package/src/config/world/resolveWorldConfig.ts +80 -0
  36. package/src/config/world/userTypes.ts +72 -0
  37. package/src/index.ts +13 -5
  38. package/src/mud.ts +4 -0
  39. package/src/render-solidity/common.ts +138 -0
  40. package/src/render-solidity/field.ts +137 -0
  41. package/src/render-solidity/index.ts +10 -0
  42. package/src/render-solidity/record.ts +154 -0
  43. package/src/render-solidity/renderSystemInterface.ts +31 -0
  44. package/src/render-solidity/renderTable.ts +164 -0
  45. package/src/render-solidity/renderTypeHelpers.ts +99 -0
  46. package/src/render-solidity/renderTypes.ts +19 -0
  47. package/src/render-solidity/renderTypesFromConfig.ts +13 -0
  48. package/src/render-solidity/renderWorld.ts +24 -0
  49. package/src/{render-table/renderTablesFromConfig.ts → render-solidity/tableOptions.ts} +45 -37
  50. package/src/render-solidity/tablegen.ts +33 -0
  51. package/src/render-solidity/types.ts +110 -0
  52. package/src/render-solidity/userType.ts +132 -0
  53. package/src/render-solidity/worldgen.ts +60 -0
  54. package/src/utils/contractToInterface.ts +130 -0
  55. package/src/utils/deploy-v2.ts +512 -0
  56. package/src/utils/deprecated/build.ts +1 -1
  57. package/src/utils/deprecated/typegen.ts +1 -1
  58. package/src/utils/errors.ts +12 -2
  59. package/src/utils/execLog.ts +22 -0
  60. package/src/utils/formatAndWrite.ts +12 -0
  61. package/src/utils/foundry.ts +94 -0
  62. package/src/utils/getChainId.ts +10 -0
  63. package/src/utils/index.ts +2 -1
  64. package/src/utils/typeUtils.ts +17 -0
  65. package/dist/chunk-B6VWCGHZ.js +0 -199
  66. package/dist/chunk-JKAA3WMC.js +0 -55
  67. package/dist/chunk-JNGSW4AP.js +0 -493
  68. package/dist/chunk-PJ6GS2R4.js +0 -22
  69. package/dist/chunk-UC3QPOON.js +0 -35
  70. package/dist/loadStoreConfig-37f99136.d.ts +0 -164
  71. package/dist/render-table/index.d.ts +0 -29
  72. package/dist/render-table/index.js +0 -24
  73. package/dist/renderTable-9e6410c5.d.ts +0 -72
  74. package/src/config/loadStoreConfig.test-d.ts +0 -11
  75. package/src/render-table/common.ts +0 -67
  76. package/src/render-table/field.ts +0 -132
  77. package/src/render-table/index.ts +0 -6
  78. package/src/render-table/record.ts +0 -176
  79. package/src/render-table/renderTable.ts +0 -109
  80. package/src/render-table/types.ts +0 -51
  81. package/src/utils/forgeConfig.ts +0 -45
package/dist/mud.js CHANGED
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env -S TS_NODE_COMPILER_OPTIONS={\"module\":\"esnext\"} node --loader=ts-node/esm --no-warnings
2
2
  import {
3
- loadStoreConfig
4
- } from "./chunk-B6VWCGHZ.js";
5
- import {
6
- renderTablesFromConfig
7
- } from "./chunk-JNGSW4AP.js";
8
- import "./chunk-6AQ6LFVZ.js";
9
- import {
10
- formatSolidity
11
- } from "./chunk-UC3QPOON.js";
3
+ deploy,
4
+ formatSolidity,
5
+ getSchemaTypeInfo,
6
+ importForAbiOrUserType,
7
+ resolveAbiOrUserType
8
+ } from "./chunk-KD354QKC.js";
12
9
  import {
10
+ MUDError,
11
+ SchemaTypeArrayToElement,
12
+ loadStoreConfig,
13
+ loadWorldConfig,
13
14
  logError
14
- } from "./chunk-JKAA3WMC.js";
15
+ } from "./chunk-J4DJQNIC.js";
15
16
  import {
16
17
  JsonRpcProvider,
17
18
  componentsDir,
@@ -25,11 +26,13 @@ import {
25
26
  keccak256,
26
27
  resetLibDeploy,
27
28
  systemsDir
28
- } from "./chunk-S3V3XX7N.js";
29
+ } from "./chunk-SLIMIO4Z.js";
29
30
  import {
31
+ forge,
32
+ getRpcUrl,
30
33
  getSrcDirectory,
31
34
  getTestDirectory
32
- } from "./chunk-PJ6GS2R4.js";
35
+ } from "./chunk-ATAWDHWC.js";
33
36
  import {
34
37
  __commonJS,
35
38
  __toESM
@@ -1528,8 +1531,8 @@ var commandModule3 = {
1528
1531
  systems: { type: "string", desc: "Only generate deploy code for the given systems" }
1529
1532
  });
1530
1533
  },
1531
- async handler({ config, out, systems }) {
1532
- await generateLibDeploy(config, out, systems);
1534
+ async handler({ config: config2, out, systems }) {
1535
+ await generateLibDeploy(config2, out, systems);
1533
1536
  process.exit(0);
1534
1537
  }
1535
1538
  };
@@ -1559,7 +1562,7 @@ var commandModule4 = {
1559
1562
  });
1560
1563
  },
1561
1564
  async handler({
1562
- config,
1565
+ config: config2,
1563
1566
  deployerPrivateKey,
1564
1567
  worldAddress,
1565
1568
  rpc,
@@ -1578,7 +1581,7 @@ var commandModule4 = {
1578
1581
  let genDeployResult;
1579
1582
  try {
1580
1583
  genDeployResult = await generateAndDeploy({
1581
- config,
1584
+ config: config2,
1582
1585
  deployerPrivateKey,
1583
1586
  worldAddress,
1584
1587
  rpc,
@@ -1609,7 +1612,7 @@ var commandModule4 = {
1609
1612
  hsr(srcDir, async (systems2) => {
1610
1613
  try {
1611
1614
  return await generateAndDeploy({
1612
- config,
1615
+ config: config2,
1613
1616
  deployerPrivateKey,
1614
1617
  worldAddress,
1615
1618
  rpc,
@@ -1661,22 +1664,24 @@ var commandModule6 = {
1661
1664
  v: { type: "number", default: 2, desc: "Verbosity for forge test" }
1662
1665
  });
1663
1666
  },
1664
- async handler({ forgeOpts, config, v }) {
1667
+ async handler({ forgeOpts, config: config2, v }) {
1665
1668
  const testDir = await getTestDirectory();
1666
1669
  console.log("Generate LibDeploy.sol");
1667
- await generateLibDeploy(config, testDir);
1670
+ await generateLibDeploy(config2, testDir);
1668
1671
  const child = execLog("forge", [
1669
1672
  "test",
1670
1673
  ...v ? ["-" + [...new Array(v)].map(() => "v").join("")] : [],
1671
1674
  ...forgeOpts?.split(" ") || []
1672
1675
  ]);
1673
- console.log("Reset LibDeploy.sol");
1674
- await resetLibDeploy(testDir);
1675
- process.on("SIGINT", () => {
1676
+ process.on("SIGINT", async () => {
1676
1677
  console.log("\ngracefully shutting down from SIGINT (Crtl-C)");
1677
1678
  child.kill();
1679
+ await resetLibDeploy(testDir);
1678
1680
  process.exit();
1679
1681
  });
1682
+ await child;
1683
+ console.log("Reset LibDeploy.sol");
1684
+ await resetLibDeploy(testDir);
1680
1685
  }
1681
1686
  };
1682
1687
  var test_default = commandModule6;
@@ -9652,9 +9657,9 @@ var commandModule7 = {
9652
9657
  debug: { type: "boolean", description: "open debugger" }
9653
9658
  });
9654
9659
  },
9655
- async handler({ config, world, rpc, tx, debug }) {
9660
+ async handler({ config: config2, world, rpc, tx, debug }) {
9656
9661
  const wd = process.cwd();
9657
- const deployData = config && JSON.parse(readFileSync(config, { encoding: "utf8" }));
9662
+ const deployData = config2 && JSON.parse(readFileSync(config2, { encoding: "utf8" }));
9658
9663
  const labels = [];
9659
9664
  const rpcUrl = rpc || "http://localhost:8545";
9660
9665
  const provider = new JsonRpcProvider(rpcUrl);
@@ -11250,9 +11255,9 @@ var commandModule11 = {
11250
11255
  compare: { type: "string", desc: "Compare to an existing gas report" }
11251
11256
  });
11252
11257
  },
11253
- async handler({ path: path6, save, compare: compare2 }) {
11258
+ async handler({ path: path11, save, compare: compare2 }) {
11254
11259
  let gasReport = [];
11255
- for (const file of path6) {
11260
+ for (const file of path11) {
11256
11261
  gasReport = gasReport.concat(await runGasReport(file));
11257
11262
  }
11258
11263
  const compareGasReport = [];
@@ -11284,14 +11289,14 @@ var commandModule11 = {
11284
11289
  }
11285
11290
  };
11286
11291
  var gas_report_default = commandModule11;
11287
- async function runGasReport(path6) {
11288
- if (!path6.endsWith(".t.sol")) {
11289
- console.log("Skipping gas report for", chalk3.bold(path6), "(not a test file)");
11292
+ async function runGasReport(path11) {
11293
+ if (!path11.endsWith(".t.sol")) {
11294
+ console.log("Skipping gas report for", chalk3.bold(path11), "(not a test file)");
11290
11295
  return [];
11291
11296
  }
11292
- console.log("Running gas report for", chalk3.bold(path6));
11297
+ console.log("Running gas report for", chalk3.bold(path11));
11293
11298
  const gasReport = [];
11294
- const fileContents = readFileSync2(path6, "utf8");
11299
+ const fileContents = readFileSync2(path11, "utf8");
11295
11300
  let newFile = fileContents;
11296
11301
  const functionRegex = new RegExp(/function (.*){/g);
11297
11302
  let functionMatch;
@@ -11315,7 +11320,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
11315
11320
  );
11316
11321
  }
11317
11322
  newFile = newFile.replace(/pure/g, "view");
11318
- const tempFileName = path6.replace(/\.t\.sol$/, "MudGasReport.t.sol");
11323
+ const tempFileName = path11.replace(/\.t\.sol$/, "MudGasReport.t.sol");
11319
11324
  writeFileSync(tempFileName, newFile);
11320
11325
  const child = execa2("forge", ["test", "--match-path", tempFileName, "-vvv"], {
11321
11326
  stdio: ["inherit", "pipe", "inherit"]
@@ -11336,7 +11341,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
11336
11341
  const name = gasReportMatch[1];
11337
11342
  const functionCall = gasReportMatch[2].replace(";", "");
11338
11343
  const gasUsed = gasReportMatch[3];
11339
- gasReport.push({ source: path6, name, functionCall, gasUsed: parseInt(gasUsed) });
11344
+ gasReport.push({ source: path11, name, functionCall, gasUsed: parseInt(gasUsed) });
11340
11345
  }
11341
11346
  return gasReport;
11342
11347
  }
@@ -11360,10 +11365,10 @@ function printGasReport(gasReport, compare2) {
11360
11365
  const rows = [headers, ...values];
11361
11366
  console.log(table(rows, { border: getBorderCharacters("norc") }));
11362
11367
  }
11363
- function saveGasReport(gasReport, path6) {
11364
- console.log(chalk3.bold(`Saving gas report to ${path6}`));
11368
+ function saveGasReport(gasReport, path11) {
11369
+ console.log(chalk3.bold(`Saving gas report to ${path11}`));
11365
11370
  const serializedGasReport = gasReport.map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`).join("\n");
11366
- writeFileSync(path6, serializedGasReport);
11371
+ writeFileSync(path11, serializedGasReport);
11367
11372
  }
11368
11373
 
11369
11374
  // src/commands/hello.ts
@@ -11383,9 +11388,697 @@ var commandModule12 = {
11383
11388
  };
11384
11389
  var hello_default = commandModule12;
11385
11390
 
11386
- // src/commands/tablegen.ts
11391
+ // src/render-solidity/tablegen.ts
11387
11392
  import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
11393
+ import path7 from "path";
11394
+
11395
+ // src/render-solidity/tableOptions.ts
11388
11396
  import path5 from "path";
11397
+ function getTableOptions(config2) {
11398
+ const storeImportPath = config2.storeImportPath;
11399
+ const options = [];
11400
+ for (const tableName of Object.keys(config2.tables)) {
11401
+ const tableData = config2.tables[tableName];
11402
+ const withStruct = tableData.dataStruct;
11403
+ const withRecordMethods = withStruct || Object.keys(tableData.schema).length > 1;
11404
+ const noFieldMethodSuffix = !withRecordMethods && Object.keys(tableData.schema).length === 1;
11405
+ const imports = [];
11406
+ const primaryKeys = Object.keys(tableData.primaryKeys).map((name) => {
11407
+ const abiOrUserType = tableData.primaryKeys[name];
11408
+ const { renderTableType } = resolveAbiOrUserType(abiOrUserType, config2);
11409
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config2);
11410
+ if (importDatum)
11411
+ imports.push(importDatum);
11412
+ if (renderTableType.isDynamic)
11413
+ throw new Error(`Parsing error: found dynamic primary key ${name} in table ${tableName}`);
11414
+ const primaryKey = {
11415
+ ...renderTableType,
11416
+ name,
11417
+ isDynamic: false
11418
+ };
11419
+ return primaryKey;
11420
+ });
11421
+ const fields = Object.keys(tableData.schema).map((name) => {
11422
+ const abiOrUserType = tableData.schema[name];
11423
+ const { renderTableType, schemaType } = resolveAbiOrUserType(abiOrUserType, config2);
11424
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config2);
11425
+ if (importDatum)
11426
+ imports.push(importDatum);
11427
+ const elementType = SchemaTypeArrayToElement[schemaType];
11428
+ const field = {
11429
+ ...renderTableType,
11430
+ arrayElement: elementType !== void 0 ? getSchemaTypeInfo(elementType) : void 0,
11431
+ name,
11432
+ methodNameSuffix: noFieldMethodSuffix ? "" : `${name[0].toUpperCase()}${name.slice(1)}`
11433
+ };
11434
+ return field;
11435
+ });
11436
+ const staticFields = fields.filter(({ isDynamic }) => !isDynamic);
11437
+ const dynamicFields = fields.filter(({ isDynamic }) => isDynamic);
11438
+ const staticResourceData = (() => {
11439
+ if (tableData.tableIdArgument) {
11440
+ return;
11441
+ } else {
11442
+ return {
11443
+ tableIdName: tableName + "TableId",
11444
+ namespace: config2.namespace,
11445
+ fileSelector: tableData.fileSelector
11446
+ };
11447
+ }
11448
+ })();
11449
+ options.push({
11450
+ outputPath: path5.join(tableData.directory, `${tableName}.sol`),
11451
+ tableName,
11452
+ renderOptions: {
11453
+ imports,
11454
+ libraryName: tableName,
11455
+ structName: withStruct ? tableName + "Data" : void 0,
11456
+ staticResourceData,
11457
+ storeImportPath,
11458
+ primaryKeys,
11459
+ fields,
11460
+ staticFields,
11461
+ dynamicFields,
11462
+ withRecordMethods,
11463
+ storeArgument: tableData.storeArgument
11464
+ }
11465
+ });
11466
+ }
11467
+ return options;
11468
+ }
11469
+
11470
+ // src/render-solidity/common.ts
11471
+ import path6 from "path";
11472
+ var renderedSolidityHeader = `// SPDX-License-Identifier: MIT
11473
+ pragma solidity >=0.8.0;
11474
+
11475
+ /* Autogenerated file. Do not edit manually. */`;
11476
+ function renderList(list, renderItem) {
11477
+ return internalRenderList("", list, renderItem);
11478
+ }
11479
+ function renderArguments(args) {
11480
+ const filteredArgs = args.filter((arg) => arg !== void 0 && arg !== "");
11481
+ return internalRenderList(",", filteredArgs, (arg) => arg);
11482
+ }
11483
+ function renderCommonData({
11484
+ staticResourceData,
11485
+ primaryKeys
11486
+ }) {
11487
+ const _tableId = staticResourceData ? "" : "_tableId";
11488
+ const _typedTableId = staticResourceData ? "" : "uint256 _tableId";
11489
+ const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
11490
+ const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
11491
+ const _primaryKeysDefinition = `
11492
+ bytes32[] memory _primaryKeys = new bytes32[](${primaryKeys.length});
11493
+ ${renderList(
11494
+ primaryKeys,
11495
+ (primaryKey, index) => `_primaryKeys[${index}] = ${renderValueTypeToBytes32(primaryKey.name, primaryKey)};`
11496
+ )}
11497
+ `;
11498
+ return {
11499
+ _tableId,
11500
+ _typedTableId,
11501
+ _keyArgs,
11502
+ _typedKeyArgs,
11503
+ _primaryKeysDefinition
11504
+ };
11505
+ }
11506
+ function solidityRelativeImportPath(fromPath, usedInPath) {
11507
+ return "./" + path6.relative("./" + usedInPath, "./" + fromPath);
11508
+ }
11509
+ function renderImports(imports) {
11510
+ const aggregatedImports = /* @__PURE__ */ new Map();
11511
+ for (const { symbol, fromPath, usedInPath } of imports) {
11512
+ const path11 = solidityRelativeImportPath(fromPath, usedInPath);
11513
+ if (!aggregatedImports.has(path11)) {
11514
+ aggregatedImports.set(path11, /* @__PURE__ */ new Set());
11515
+ }
11516
+ aggregatedImports.get(path11)?.add(symbol);
11517
+ }
11518
+ const renderedImports = [];
11519
+ for (const [path11, symbols] of aggregatedImports) {
11520
+ const renderedSymbols = [...symbols].join(", ");
11521
+ renderedImports.push(`import { ${renderedSymbols} } from "${path11}";`);
11522
+ }
11523
+ return renderedImports.join("\n");
11524
+ }
11525
+ function renderWithStore(storeArgument, callback) {
11526
+ let result = "";
11527
+ result += callback(void 0, "StoreSwitch", "", void 0);
11528
+ if (storeArgument) {
11529
+ result += "\n" + callback("IStore _store", "_store", " (using the specified store)", "_store");
11530
+ }
11531
+ return result;
11532
+ }
11533
+ function renderTableId(staticResourceData) {
11534
+ const hardcodedTableId = `uint256(bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.fileSelector}"))))`;
11535
+ const tableIdDefinition = `
11536
+ uint256 constant _tableId = ${hardcodedTableId};
11537
+ uint256 constant ${staticResourceData.tableIdName} = _tableId;
11538
+ `;
11539
+ return {
11540
+ hardcodedTableId,
11541
+ tableIdDefinition
11542
+ };
11543
+ }
11544
+ function renderValueTypeToBytes32(name, { staticByteLength, typeUnwrap, internalTypeId }) {
11545
+ const bits = staticByteLength * 8;
11546
+ const innerText = `${typeUnwrap}(${name})`;
11547
+ if (internalTypeId.match(/^uint\d{1,3}$/)) {
11548
+ return `bytes32(uint256(${innerText}))`;
11549
+ } else if (internalTypeId.match(/^int\d{1,3}$/)) {
11550
+ return `bytes32(uint256(uint${bits}(${innerText})))`;
11551
+ } else if (internalTypeId.match(/^bytes\d{1,2}$/)) {
11552
+ return `bytes32(${innerText})`;
11553
+ } else if (internalTypeId === "address") {
11554
+ return `bytes32(bytes20(${innerText}))`;
11555
+ } else if (internalTypeId === "bool") {
11556
+ return `_boolToBytes32(${innerText})`;
11557
+ } else {
11558
+ throw new Error(`Unknown value type id ${internalTypeId}`);
11559
+ }
11560
+ }
11561
+ function internalRenderList(lineTerminator, list, renderItem) {
11562
+ return list.map((item, index) => renderItem(item, index) + (index === list.length - 1 ? "" : lineTerminator)).join("\n");
11563
+ }
11564
+
11565
+ // src/render-solidity/field.ts
11566
+ function renderFieldMethods(options) {
11567
+ const storeArgument = options.storeArgument;
11568
+ const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
11569
+ let result = "";
11570
+ for (const [index, field] of options.fields.entries()) {
11571
+ const _typedFieldName = `${field.typeWithLocation} ${field.name}`;
11572
+ result += renderWithStore(
11573
+ storeArgument,
11574
+ (_typedStore, _store, _commentSuffix) => `
11575
+ /** Get ${field.name}${_commentSuffix} */
11576
+ function get${field.methodNameSuffix}(${renderArguments([
11577
+ _typedStore,
11578
+ _typedTableId,
11579
+ _typedKeyArgs
11580
+ ])}) internal view returns (${_typedFieldName}) {
11581
+ ${_primaryKeysDefinition}
11582
+ bytes memory _blob = ${_store}.getField(_tableId, _primaryKeys, ${index});
11583
+ return ${renderDecodeFieldSingle(field)};
11584
+ }
11585
+ `
11586
+ );
11587
+ result += renderWithStore(
11588
+ storeArgument,
11589
+ (_typedStore, _store, _commentSuffix) => `
11590
+ /** Set ${field.name}${_commentSuffix} */
11591
+ function set${field.methodNameSuffix}(${renderArguments([
11592
+ _typedStore,
11593
+ _typedTableId,
11594
+ _typedKeyArgs,
11595
+ _typedFieldName
11596
+ ])}) internal {
11597
+ ${_primaryKeysDefinition}
11598
+ ${_store}.setField(_tableId, _primaryKeys, ${index}, ${renderEncodeField(field)});
11599
+ }
11600
+ `
11601
+ );
11602
+ if (field.isDynamic) {
11603
+ const portionData = fieldPortionData(field);
11604
+ result += renderWithStore(
11605
+ storeArgument,
11606
+ (_typedStore, _store, _commentSuffix) => `
11607
+ /** Push ${portionData.title} to ${field.name}${_commentSuffix} */
11608
+ function push${field.methodNameSuffix}(${renderArguments([
11609
+ _typedStore,
11610
+ _typedTableId,
11611
+ _typedKeyArgs,
11612
+ `${portionData.typeWithLocation} ${portionData.name}`
11613
+ ])}) internal {
11614
+ ${_primaryKeysDefinition}
11615
+ ${_store}.pushToField(_tableId, _primaryKeys, ${index}, ${portionData.encoded});
11616
+ }
11617
+ `
11618
+ );
11619
+ }
11620
+ }
11621
+ return result;
11622
+ }
11623
+ function renderEncodeField(field) {
11624
+ let func;
11625
+ if (field.arrayElement) {
11626
+ func = "EncodeArray.encode";
11627
+ } else if (field.isDynamic) {
11628
+ func = "bytes";
11629
+ } else {
11630
+ func = "abi.encodePacked";
11631
+ }
11632
+ return `${func}(${field.typeUnwrap}(${field.name}))`;
11633
+ }
11634
+ function renderDecodeValueType(field, offset) {
11635
+ const { staticByteLength, internalTypeId } = field;
11636
+ const innerSlice = `Bytes.slice${staticByteLength}(_blob, ${offset})`;
11637
+ const bits = staticByteLength * 8;
11638
+ let result;
11639
+ if (internalTypeId.match(/^uint\d{1,3}$/) || internalTypeId === "address") {
11640
+ result = `${internalTypeId}(${innerSlice})`;
11641
+ } else if (internalTypeId.match(/^int\d{1,3}$/)) {
11642
+ result = `${internalTypeId}(uint${bits}(${innerSlice}))`;
11643
+ } else if (internalTypeId.match(/^bytes\d{1,2}$/)) {
11644
+ result = innerSlice;
11645
+ } else if (internalTypeId === "bool") {
11646
+ result = `_toBool(uint8(${innerSlice}))`;
11647
+ } else {
11648
+ throw new Error(`Unknown value type id ${internalTypeId}`);
11649
+ }
11650
+ return `${field.typeWrap}(${result})`;
11651
+ }
11652
+ function fieldPortionData(field) {
11653
+ const methodNameSuffix = "";
11654
+ if (field.arrayElement) {
11655
+ const name = "_element";
11656
+ return {
11657
+ typeWithLocation: field.arrayElement.typeWithLocation,
11658
+ name: "_element",
11659
+ encoded: renderEncodeField({ ...field.arrayElement, arrayElement: void 0, name, methodNameSuffix }),
11660
+ title: "an element"
11661
+ };
11662
+ } else {
11663
+ const name = "_slice";
11664
+ return {
11665
+ typeWithLocation: `${field.typeId} memory`,
11666
+ name,
11667
+ encoded: renderEncodeField({ ...field, name, methodNameSuffix }),
11668
+ title: "a slice"
11669
+ };
11670
+ }
11671
+ }
11672
+ function renderDecodeFieldSingle(field) {
11673
+ const { isDynamic, arrayElement } = field;
11674
+ if (arrayElement) {
11675
+ return `${field.typeWrap}(
11676
+ SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_${arrayElement.internalTypeId}()
11677
+ )`;
11678
+ } else if (isDynamic) {
11679
+ return `${field.typeWrap}(${field.internalTypeId}(_blob))`;
11680
+ } else {
11681
+ return renderDecodeValueType(field, 0);
11682
+ }
11683
+ }
11684
+
11685
+ // src/render-solidity/record.ts
11686
+ function renderRecordMethods(options) {
11687
+ const { structName, storeArgument } = options;
11688
+ const { _tableId, _typedTableId, _keyArgs, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
11689
+ let result = renderWithStore(
11690
+ storeArgument,
11691
+ (_typedStore, _store, _commentSuffix) => `
11692
+ /** Get the full data${_commentSuffix} */
11693
+ function get(${renderArguments([
11694
+ _typedStore,
11695
+ _typedTableId,
11696
+ _typedKeyArgs
11697
+ ])}) internal view returns (${renderDecodedRecord(options)}) {
11698
+ ${_primaryKeysDefinition}
11699
+ bytes memory _blob = ${_store}.getRecord(_tableId, _primaryKeys, getSchema());
11700
+ return decode(_blob);
11701
+ }
11702
+ `
11703
+ );
11704
+ result += renderWithStore(
11705
+ storeArgument,
11706
+ (_typedStore, _store, _commentSuffix) => `
11707
+ /** Set the full data using individual values${_commentSuffix} */
11708
+ function set(${renderArguments([
11709
+ _typedStore,
11710
+ _typedTableId,
11711
+ _typedKeyArgs,
11712
+ renderArguments(options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`))
11713
+ ])}) internal {
11714
+ bytes memory _data = encode(${renderArguments(options.fields.map(({ name }) => name))});
11715
+
11716
+ ${_primaryKeysDefinition}
11717
+
11718
+ ${_store}.setRecord(_tableId, _primaryKeys, _data);
11719
+ }
11720
+ `
11721
+ );
11722
+ if (structName !== void 0) {
11723
+ result += renderWithStore(
11724
+ storeArgument,
11725
+ (_typedStore, _store, _commentSuffix, _untypedStore) => `
11726
+ /** Set the full data using the data struct${_commentSuffix} */
11727
+ function set(${renderArguments([
11728
+ _typedStore,
11729
+ _typedTableId,
11730
+ _typedKeyArgs,
11731
+ `${structName} memory _table`
11732
+ ])}) internal {
11733
+ set(${renderArguments([
11734
+ _untypedStore,
11735
+ _tableId,
11736
+ _keyArgs,
11737
+ renderArguments(options.fields.map(({ name }) => `_table.${name}`))
11738
+ ])});
11739
+ }
11740
+ `
11741
+ );
11742
+ }
11743
+ result += renderDecodeFunction(options);
11744
+ return result;
11745
+ }
11746
+ function renderDecodeFunction({ structName, fields, staticFields, dynamicFields }) {
11747
+ const renderedDecodedRecord = structName ? `${structName} memory _table` : renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
11748
+ const fieldNamePrefix = structName ? "_table." : "";
11749
+ const staticOffsets = staticFields.map(() => 0);
11750
+ let _acc = 0;
11751
+ for (const [index, field] of staticFields.entries()) {
11752
+ staticOffsets[index] = _acc;
11753
+ _acc += field.staticByteLength;
11754
+ }
11755
+ if (dynamicFields.length > 0) {
11756
+ const totalStaticLength = staticFields.reduce((acc, { staticByteLength }) => acc + staticByteLength, 0);
11757
+ return `
11758
+ /** Decode the tightly packed blob using this table's schema */
11759
+ function decode(bytes memory _blob) internal view returns (${renderedDecodedRecord}) {
11760
+ // ${totalStaticLength} is the total byte length of static data
11761
+ PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, ${totalStaticLength}));
11762
+
11763
+ ${renderList(
11764
+ staticFields,
11765
+ (field, index) => `
11766
+ ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
11767
+ `
11768
+ )}
11769
+ uint256 _start;
11770
+ uint256 _end = ${totalStaticLength + 32};
11771
+ ${renderList(
11772
+ dynamicFields,
11773
+ (field, index) => `
11774
+ _start = _end;
11775
+ _end += _encodedLengths.atIndex(${index});
11776
+ ${fieldNamePrefix}${field.name} = ${renderDecodeDynamicFieldPartial(field)};
11777
+ `
11778
+ )}
11779
+ }
11780
+ `;
11781
+ } else {
11782
+ return `
11783
+ /** Decode the tightly packed blob using this table's schema */
11784
+ function decode(bytes memory _blob) internal pure returns (${renderedDecodedRecord}) {
11785
+ ${renderList(
11786
+ staticFields,
11787
+ (field, index) => `
11788
+ ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
11789
+ `
11790
+ )}
11791
+ }
11792
+ `;
11793
+ }
11794
+ }
11795
+ function renderDecodedRecord({ structName, fields }) {
11796
+ if (structName) {
11797
+ return `${structName} memory _table`;
11798
+ } else {
11799
+ return renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
11800
+ }
11801
+ }
11802
+ function renderDecodeDynamicFieldPartial(field) {
11803
+ const { typeId, arrayElement, typeWrap } = field;
11804
+ if (arrayElement) {
11805
+ return `${typeWrap}(
11806
+ SliceLib.getSubslice(_blob, _start, _end).decodeArray_${arrayElement.typeId}()
11807
+ )`;
11808
+ } else {
11809
+ return `${typeWrap}(
11810
+ ${typeId}(
11811
+ SliceLib.getSubslice(_blob, _start, _end).toBytes()
11812
+ )
11813
+ )`;
11814
+ }
11815
+ }
11816
+
11817
+ // src/render-solidity/renderTypeHelpers.ts
11818
+ function renderTypeHelpers(options) {
11819
+ const { fields, primaryKeys } = options;
11820
+ let result = "";
11821
+ for (const wrappingHelper of getWrappingHelpers([...fields, ...primaryKeys])) {
11822
+ result += wrappingHelper;
11823
+ }
11824
+ if (fields.some(({ typeId }) => typeId === "bool")) {
11825
+ result += `
11826
+ function _toBool(uint8 value) pure returns (bool result) {
11827
+ assembly {
11828
+ result := value
11829
+ }
11830
+ }
11831
+ `;
11832
+ }
11833
+ if (primaryKeys.some(({ typeId }) => typeId === "bool")) {
11834
+ result += `
11835
+ function _boolToBytes32(bool value) pure returns (bytes32 result) {
11836
+ assembly {
11837
+ result := value
11838
+ }
11839
+ }
11840
+ `;
11841
+ }
11842
+ return result;
11843
+ }
11844
+ function getWrappingHelpers(array) {
11845
+ const wrappers = /* @__PURE__ */ new Map();
11846
+ const unwrappers = /* @__PURE__ */ new Map();
11847
+ for (const { typeWrappingData, typeWrap, typeUnwrap, internalTypeId } of array) {
11848
+ if (!typeWrappingData)
11849
+ continue;
11850
+ const { kind } = typeWrappingData;
11851
+ if (kind === "staticArray") {
11852
+ const { elementType, staticLength } = typeWrappingData;
11853
+ wrappers.set(typeWrap, renderWrapperStaticArray(typeWrap, elementType, staticLength, internalTypeId));
11854
+ unwrappers.set(typeUnwrap, renderUnwrapperStaticArray(typeUnwrap, elementType, staticLength, internalTypeId));
11855
+ }
11856
+ }
11857
+ return [...wrappers.values(), ...unwrappers.values()];
11858
+ }
11859
+ function renderWrapperStaticArray(functionName, elementType, staticLength, internalTypeId) {
11860
+ return `
11861
+ function ${functionName}(
11862
+ ${internalTypeId} memory _value
11863
+ ) pure returns (
11864
+ ${elementType}[${staticLength}] memory _result
11865
+ ) {
11866
+ // in memory static arrays are just dynamic arrays without the length byte
11867
+ assembly {
11868
+ _result := add(_value, 0x20)
11869
+ }
11870
+ }
11871
+ `;
11872
+ }
11873
+ function renderUnwrapperStaticArray(functionName, elementType, staticLength, internalTypeId) {
11874
+ const byteLength = staticLength * 32;
11875
+ return `
11876
+ function ${functionName}(
11877
+ ${elementType}[${staticLength}] memory _value
11878
+ ) view returns (
11879
+ ${internalTypeId} memory _result
11880
+ ) {
11881
+ _result = new ${internalTypeId}(${staticLength});
11882
+ uint256 fromPointer;
11883
+ uint256 toPointer;
11884
+ assembly {
11885
+ fromPointer := _value
11886
+ toPointer := add(_result, 0x20)
11887
+ }
11888
+ Memory.copy(fromPointer, toPointer, ${byteLength});
11889
+ }
11890
+ `;
11891
+ }
11892
+
11893
+ // src/render-solidity/renderTable.ts
11894
+ function renderTable(options) {
11895
+ const {
11896
+ imports,
11897
+ libraryName,
11898
+ structName,
11899
+ staticResourceData,
11900
+ storeImportPath,
11901
+ fields,
11902
+ staticFields,
11903
+ dynamicFields,
11904
+ withRecordMethods,
11905
+ storeArgument,
11906
+ primaryKeys
11907
+ } = options;
11908
+ const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
11909
+ return `${renderedSolidityHeader}
11910
+
11911
+ // Import schema type
11912
+ import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol";
11913
+
11914
+ // Import store internals
11915
+ import { IStore } from "${storeImportPath}IStore.sol";
11916
+ import { StoreSwitch } from "${storeImportPath}StoreSwitch.sol";
11917
+ import { StoreCore } from "${storeImportPath}StoreCore.sol";
11918
+ import { Bytes } from "${storeImportPath}Bytes.sol";
11919
+ import { Memory } from "${storeImportPath}Memory.sol";
11920
+ import { SliceLib } from "${storeImportPath}Slice.sol";
11921
+ import { EncodeArray } from "${storeImportPath}tightcoder/EncodeArray.sol";
11922
+ import { Schema, SchemaLib } from "${storeImportPath}Schema.sol";
11923
+ import { PackedCounter, PackedCounterLib } from "${storeImportPath}PackedCounter.sol";
11924
+
11925
+ ${imports.length > 0 ? `
11926
+ // Import user types
11927
+ ${renderImports(imports)}
11928
+ ` : ""}
11929
+
11930
+ ${staticResourceData ? renderTableId(staticResourceData).tableIdDefinition : ""}
11931
+
11932
+ ${!structName ? "" : `
11933
+ struct ${structName} {
11934
+ ${renderList(fields, ({ name, typeId }) => `${typeId} ${name};`)}
11935
+ }
11936
+ `}
11937
+
11938
+ library ${libraryName} {
11939
+ /** Get the table's schema */
11940
+ function getSchema() internal pure returns (Schema) {
11941
+ SchemaType[] memory _schema = new SchemaType[](${fields.length});
11942
+ ${renderList(fields, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
11943
+
11944
+ return SchemaLib.encode(_schema);
11945
+ }
11946
+
11947
+ function getKeySchema() internal pure returns (Schema) {
11948
+ SchemaType[] memory _schema = new SchemaType[](${primaryKeys.length});
11949
+ ${renderList(primaryKeys, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
11950
+
11951
+ return SchemaLib.encode(_schema);
11952
+ }
11953
+
11954
+ /** Get the table's metadata */
11955
+ function getMetadata() internal pure returns (string memory, string[] memory) {
11956
+ string[] memory _fieldNames = new string[](${fields.length});
11957
+ ${renderList(fields, (field, index) => `_fieldNames[${index}] = "${field.name}";`)}
11958
+ return ("${libraryName}", _fieldNames);
11959
+ }
11960
+
11961
+ ${renderWithStore(
11962
+ storeArgument,
11963
+ (_typedStore, _store, _commentSuffix) => `
11964
+ /** Register the table's schema${_commentSuffix} */
11965
+ function registerSchema(${renderArguments([_typedStore, _typedTableId])}) internal {
11966
+ ${_store}.registerSchema(_tableId, getSchema(), getKeySchema());
11967
+ }
11968
+ `
11969
+ )}
11970
+ ${renderWithStore(
11971
+ storeArgument,
11972
+ (_typedStore, _store, _commentSuffix) => `
11973
+ /** Set the table's metadata${_commentSuffix} */
11974
+ function setMetadata(${renderArguments([_typedStore, _typedTableId])}) internal {
11975
+ (string memory _tableName, string[] memory _fieldNames) = getMetadata();
11976
+ ${_store}.setMetadata(_tableId, _tableName, _fieldNames);
11977
+ }
11978
+ `
11979
+ )}
11980
+
11981
+ ${renderFieldMethods(options)}
11982
+
11983
+ ${withRecordMethods ? renderRecordMethods(options) : ""}
11984
+
11985
+ /** Tightly pack full data using this table's schema */
11986
+ function encode(${renderArguments(
11987
+ options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)
11988
+ )}) internal view returns (bytes memory) {
11989
+ ${renderEncodedLengths(dynamicFields)}
11990
+ return abi.encodePacked(${renderArguments([
11991
+ renderArguments(staticFields.map(({ name }) => name)),
11992
+ // TODO try gas optimization (preallocate for all, encodePacked statics, and direct encode dynamics)
11993
+ // (see https://github.com/latticexyz/mud/issues/444)
11994
+ ...dynamicFields.length === 0 ? [] : ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]
11995
+ ])});
11996
+ }
11997
+
11998
+ ${renderWithStore(
11999
+ storeArgument,
12000
+ (_typedStore, _store, _commentSuffix) => `
12001
+ /* Delete all data for given keys${_commentSuffix} */
12002
+ function deleteRecord(${renderArguments([_typedStore, _typedTableId, _typedKeyArgs])}) internal {
12003
+ ${_primaryKeysDefinition}
12004
+ ${_store}.deleteRecord(_tableId, _primaryKeys);
12005
+ }
12006
+ `
12007
+ )}
12008
+ }
12009
+
12010
+ ${renderTypeHelpers(options)}
12011
+
12012
+ `;
12013
+ }
12014
+ function renderEncodedLengths(dynamicFields) {
12015
+ if (dynamicFields.length > 0) {
12016
+ return `
12017
+ uint16[] memory _counters = new uint16[](${dynamicFields.length});
12018
+ ${renderList(dynamicFields, ({ name, arrayElement }, index) => {
12019
+ if (arrayElement) {
12020
+ return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
12021
+ } else {
12022
+ return `_counters[${index}] = uint16(bytes(${name}).length);`;
12023
+ }
12024
+ })}
12025
+ PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
12026
+ `;
12027
+ } else {
12028
+ return "";
12029
+ }
12030
+ }
12031
+
12032
+ // src/render-solidity/renderTypes.ts
12033
+ function renderTypes(options) {
12034
+ const { enums } = options;
12035
+ return `${renderedSolidityHeader}
12036
+
12037
+ ${renderList(
12038
+ enums,
12039
+ ({ name, memberNames }) => `
12040
+ enum ${name} {
12041
+ ${renderArguments(memberNames)}
12042
+ }
12043
+ `
12044
+ )}
12045
+
12046
+ `;
12047
+ }
12048
+
12049
+ // src/render-solidity/renderTypesFromConfig.ts
12050
+ function renderTypesFromConfig(config2) {
12051
+ const enums = Object.keys(config2.enums).map((name) => ({
12052
+ name,
12053
+ memberNames: config2.enums[name]
12054
+ }));
12055
+ return renderTypes({
12056
+ enums
12057
+ });
12058
+ }
12059
+
12060
+ // src/render-solidity/tablegen.ts
12061
+ async function tablegen(config2, outputBaseDirectory) {
12062
+ const allTableOptions = getTableOptions(config2);
12063
+ for (const { outputPath, renderOptions } of allTableOptions) {
12064
+ const fullOutputPath = path7.join(outputBaseDirectory, outputPath);
12065
+ const output = renderTable(renderOptions);
12066
+ formatAndWrite(output, fullOutputPath, "Generated table");
12067
+ }
12068
+ if (Object.keys(config2.enums).length > 0) {
12069
+ const fullOutputPath = path7.join(outputBaseDirectory, `${config2.userTypesPath}.sol`);
12070
+ const output = renderTypesFromConfig(config2);
12071
+ formatAndWrite(output, fullOutputPath, "Generated types file");
12072
+ }
12073
+ }
12074
+ async function formatAndWrite(output, fullOutputPath, logPrefix) {
12075
+ const formattedOutput = await formatSolidity(output);
12076
+ mkdirSync(path7.dirname(fullOutputPath), { recursive: true });
12077
+ writeFileSync2(fullOutputPath, formattedOutput);
12078
+ console.log(`${logPrefix}: ${fullOutputPath}`);
12079
+ }
12080
+
12081
+ // src/commands/tablegen.ts
11389
12082
  var commandModule13 = {
11390
12083
  command: "tablegen",
11391
12084
  describe: "Autogenerate MUD Store table libraries based on the config file",
@@ -11395,22 +12088,331 @@ var commandModule13 = {
11395
12088
  });
11396
12089
  },
11397
12090
  async handler({ configPath }) {
12091
+ const srcDirectory = await getSrcDirectory();
12092
+ const config2 = await loadStoreConfig(configPath);
12093
+ await tablegen(config2, srcDirectory);
12094
+ process.exit(0);
12095
+ }
12096
+ };
12097
+ var tablegen_default = commandModule13;
12098
+
12099
+ // src/commands/deploy-v2.ts
12100
+ import chalk4 from "chalk";
12101
+ import glob from "glob";
12102
+ import path8, { basename } from "path";
12103
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
12104
+
12105
+ // src/utils/getChainId.ts
12106
+ import { ethers } from "ethers";
12107
+ async function getChainId(rpc) {
12108
+ const { result: chainId } = await ethers.utils.fetchJson(
12109
+ rpc,
12110
+ '{ "id": 42, "jsonrpc": "2.0", "method": "eth_chainId", "params": [ ] }'
12111
+ );
12112
+ return Number(chainId);
12113
+ }
12114
+
12115
+ // src/commands/deploy-v2.ts
12116
+ var commandModule14 = {
12117
+ command: "deploy-v2",
12118
+ describe: "Deploy MUD v2 contracts",
12119
+ builder(yargs2) {
12120
+ return yargs2.options({
12121
+ configPath: { type: "string", desc: "Path to the config file" },
12122
+ clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
12123
+ printConfig: { type: "boolean", desc: "Print the resolved config" },
12124
+ profile: { type: "string", desc: "The foundry profile to use" },
12125
+ debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
12126
+ priorityFeeMultiplier: {
12127
+ type: "number",
12128
+ desc: "Multiply the estimated priority fee by the provided factor",
12129
+ default: 1
12130
+ }
12131
+ });
12132
+ },
12133
+ async handler(args) {
12134
+ args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
12135
+ const { configPath, printConfig, profile, clean } = args;
12136
+ const rpc = await getRpcUrl(profile);
12137
+ console.log(
12138
+ chalk4.bgBlue(
12139
+ chalk4.whiteBright(`
12140
+ Deploying MUD v2 contracts${profile ? " with profile " + profile : ""} to RPC ${rpc}
12141
+ `)
12142
+ )
12143
+ );
12144
+ if (clean)
12145
+ await forge(["clean"], { profile });
12146
+ await forge(["build"], { profile });
11398
12147
  const srcDir = await getSrcDirectory();
11399
- const config = await loadStoreConfig(configPath);
11400
- const renderedTables = renderTablesFromConfig(config);
11401
- for (const { output, tableName } of renderedTables) {
11402
- const formattedOutput = await formatSolidity(output);
11403
- const tablePath = config.tables[tableName].route;
11404
- const outputDirectory = path5.join(srcDir, tablePath);
11405
- mkdirSync(outputDirectory, { recursive: true });
11406
- const outputPath = path5.join(outputDirectory, `${tableName}.sol`);
11407
- writeFileSync2(outputPath, formattedOutput);
11408
- console.log(`Generated schema: ${outputPath}`);
12148
+ const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path11) => basename(path11, ".sol"));
12149
+ const worldConfig = await loadWorldConfig(configPath, existingContracts);
12150
+ const storeConfig = await loadStoreConfig(configPath);
12151
+ const mudConfig = { ...worldConfig, ...storeConfig };
12152
+ if (printConfig)
12153
+ console.log(chalk4.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
12154
+ try {
12155
+ const privateKey = process.env.PRIVATE_KEY;
12156
+ if (!privateKey)
12157
+ throw new MUDError("Missing PRIVATE_KEY environment variable");
12158
+ const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
12159
+ const chainId = await getChainId(rpc);
12160
+ const outputDir = path8.join(mudConfig.deploysDirectory, chainId.toString());
12161
+ mkdirSync2(outputDir, { recursive: true });
12162
+ writeFileSync3(path8.join(outputDir, "latest.json"), JSON.stringify(deploymentInfo, null, 2));
12163
+ writeFileSync3(path8.join(outputDir, Date.now() + ".json"), JSON.stringify(deploymentInfo, null, 2));
12164
+ console.log(chalk4.bgGreen(chalk4.whiteBright(`
12165
+ Deployment result (written to ${outputDir}):
12166
+ `)));
12167
+ console.log(deploymentInfo);
12168
+ } catch (error) {
12169
+ logError(error);
12170
+ process.exit(1);
11409
12171
  }
11410
12172
  process.exit(0);
11411
12173
  }
11412
12174
  };
11413
- var tablegen_default = commandModule13;
12175
+ var deploy_v2_default = commandModule14;
12176
+
12177
+ // src/commands/worldgen.ts
12178
+ import glob2 from "glob";
12179
+ import path10, { basename as basename2 } from "path";
12180
+
12181
+ // src/render-solidity/worldgen.ts
12182
+ import { readFileSync as readFileSync3 } from "fs";
12183
+ import path9 from "path";
12184
+
12185
+ // src/utils/contractToInterface.ts
12186
+ import { parse, visit } from "@solidity-parser/parser";
12187
+ function contractToInterface(data, contractName) {
12188
+ const ast = parse(data);
12189
+ let withContract = false;
12190
+ let symbols = [];
12191
+ const functions = [];
12192
+ visit(ast, {
12193
+ ContractDefinition({ name }) {
12194
+ if (name === contractName) {
12195
+ withContract = true;
12196
+ }
12197
+ },
12198
+ FunctionDefinition({ name, visibility, parameters, returnParameters, isConstructor, isFallback, isReceiveEther }, parent) {
12199
+ if (parent !== void 0 && parent.type === "ContractDefinition" && parent.name === contractName) {
12200
+ try {
12201
+ if (isConstructor || isFallback || isReceiveEther)
12202
+ return;
12203
+ if (visibility === "default")
12204
+ throw new MUDError(`Visibility is not specified`);
12205
+ if (visibility === "external" || visibility === "public") {
12206
+ functions.push({
12207
+ name: name === null ? "" : name,
12208
+ parameters: parameters.map(parseParameter),
12209
+ returnParameters: returnParameters === null ? [] : returnParameters.map(parseParameter)
12210
+ });
12211
+ for (const { typeName } of parameters.concat(returnParameters ?? [])) {
12212
+ symbols = symbols.concat(typeNameToExternalSymbols(typeName));
12213
+ }
12214
+ }
12215
+ } catch (error) {
12216
+ if (error instanceof MUDError) {
12217
+ error.message = `Function "${name}" in contract "${contractName}": ${error.message}`;
12218
+ }
12219
+ throw error;
12220
+ }
12221
+ }
12222
+ }
12223
+ });
12224
+ if (!withContract) {
12225
+ throw new MUDError(`Contract not found: ${contractName}`);
12226
+ }
12227
+ return {
12228
+ functions,
12229
+ symbols
12230
+ };
12231
+ }
12232
+ function parseParameter({ name, typeName, storageLocation }) {
12233
+ let typedNameWithLocation = "";
12234
+ const { name: flattenedTypeName, stateMutability } = flattenTypeName(typeName);
12235
+ typedNameWithLocation += flattenedTypeName;
12236
+ if (stateMutability !== null) {
12237
+ typedNameWithLocation += ` ${stateMutability}`;
12238
+ }
12239
+ if (storageLocation !== null) {
12240
+ typedNameWithLocation += ` ${storageLocation}`;
12241
+ }
12242
+ if (name !== null) {
12243
+ typedNameWithLocation += ` ${name}`;
12244
+ }
12245
+ return typedNameWithLocation;
12246
+ }
12247
+ function flattenTypeName(typeName) {
12248
+ if (typeName === null) {
12249
+ return {
12250
+ name: "",
12251
+ stateMutability: null
12252
+ };
12253
+ }
12254
+ if (typeName.type === "ElementaryTypeName") {
12255
+ return {
12256
+ name: typeName.name,
12257
+ stateMutability: typeName.stateMutability
12258
+ };
12259
+ } else if (typeName.type === "UserDefinedTypeName") {
12260
+ return {
12261
+ name: typeName.namePath,
12262
+ stateMutability: null
12263
+ };
12264
+ } else if (typeName.type === "ArrayTypeName") {
12265
+ const { name, stateMutability } = flattenTypeName(typeName.baseTypeName);
12266
+ return {
12267
+ name: `${name}[]`,
12268
+ stateMutability
12269
+ };
12270
+ } else {
12271
+ throw new MUDError(`Invalid typeName.type ${typeName.type}`);
12272
+ }
12273
+ }
12274
+ function typeNameToExternalSymbols(typeName) {
12275
+ if (typeName?.type === "UserDefinedTypeName") {
12276
+ const symbol = typeName.namePath.split(".")[0];
12277
+ return [symbol];
12278
+ } else if (typeName?.type === "ArrayTypeName") {
12279
+ return typeNameToExternalSymbols(typeName.baseTypeName);
12280
+ } else {
12281
+ return [];
12282
+ }
12283
+ }
12284
+
12285
+ // src/utils/formatAndWrite.ts
12286
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
12287
+ import { dirname } from "path";
12288
+ async function formatAndWrite2(output, fullOutputPath, logPrefix) {
12289
+ const formattedOutput = await formatSolidity(output);
12290
+ mkdirSync3(dirname(fullOutputPath), { recursive: true });
12291
+ writeFileSync4(fullOutputPath, formattedOutput);
12292
+ console.log(`${logPrefix}: ${fullOutputPath}`);
12293
+ }
12294
+
12295
+ // src/render-solidity/renderSystemInterface.ts
12296
+ function renderSystemInterface(options) {
12297
+ const { imports, name, functionPrefix, functions } = options;
12298
+ return `${renderedSolidityHeader}
12299
+
12300
+ ${renderImports(imports)}
12301
+
12302
+ interface ${name} {
12303
+ ${renderList(
12304
+ functions,
12305
+ ({ name: name2, parameters, returnParameters }) => `
12306
+ function ${functionPrefix}${name2}(${renderArguments(parameters)}) external ${renderReturnParameters(
12307
+ returnParameters
12308
+ )};
12309
+ `
12310
+ )}
12311
+ }
12312
+
12313
+ `;
12314
+ }
12315
+ function renderReturnParameters(returnParameters) {
12316
+ if (returnParameters.length > 0) {
12317
+ return `returns (${renderArguments(returnParameters)})`;
12318
+ } else {
12319
+ return "";
12320
+ }
12321
+ }
12322
+
12323
+ // src/render-solidity/renderWorld.ts
12324
+ function renderWorld(options) {
12325
+ const { interfaceName, storeImportPath, worldImportPath, imports } = options;
12326
+ return `${renderedSolidityHeader}
12327
+
12328
+ import { IStore } from "${storeImportPath}IStore.sol";
12329
+
12330
+ import { IWorldCore } from "${worldImportPath}interfaces/IWorldCore.sol";
12331
+
12332
+ ${renderImports(imports)}
12333
+
12334
+ /**
12335
+ * The ${interfaceName} interface includes all systems dynamically added to the World
12336
+ * during the deploy process.
12337
+ */
12338
+ interface ${interfaceName} is ${renderArguments(["IStore", "IWorldCore", ...imports.map(({ symbol }) => symbol)])} {
12339
+
12340
+ }
12341
+
12342
+ `;
12343
+ }
12344
+
12345
+ // src/render-solidity/worldgen.ts
12346
+ async function worldgen(config2, existingContracts, outputBaseDirectory) {
12347
+ const worldgenBaseDirectory = path9.join(outputBaseDirectory, config2.worldgenDirectory);
12348
+ const systems = existingContracts.filter(({ basename: basename3 }) => Object.keys(config2.systems).includes(basename3));
12349
+ const systemInterfaceImports = [];
12350
+ for (const system of systems) {
12351
+ const data = readFileSync3(system.path, "utf8");
12352
+ const { functions, symbols } = contractToInterface(data, system.basename);
12353
+ const imports = symbols.map((symbol) => ({
12354
+ symbol,
12355
+ fromPath: system.path,
12356
+ usedInPath: worldgenBaseDirectory
12357
+ }));
12358
+ const systemInterfaceName = `I${system.basename}`;
12359
+ const { fileSelector } = config2.systems[system.basename];
12360
+ const output2 = renderSystemInterface({
12361
+ name: systemInterfaceName,
12362
+ functionPrefix: config2.namespace === "" ? "" : `${config2.namespace}_${fileSelector}_`,
12363
+ functions,
12364
+ imports
12365
+ });
12366
+ const fullOutputPath2 = path9.join(worldgenBaseDirectory, systemInterfaceName + ".sol");
12367
+ await formatAndWrite2(output2, fullOutputPath2, "Generated system interface");
12368
+ systemInterfaceImports.push({
12369
+ symbol: systemInterfaceName,
12370
+ fromPath: `${systemInterfaceName}.sol`,
12371
+ usedInPath: "./"
12372
+ });
12373
+ }
12374
+ const worldInterfaceName = "IWorld";
12375
+ const output = renderWorld({
12376
+ interfaceName: worldInterfaceName,
12377
+ imports: systemInterfaceImports,
12378
+ storeImportPath: config2.storeImportPath,
12379
+ worldImportPath: config2.worldImportPath
12380
+ });
12381
+ const fullOutputPath = path9.join(worldgenBaseDirectory, worldInterfaceName + ".sol");
12382
+ await formatAndWrite2(output, fullOutputPath, "Generated system interface");
12383
+ }
12384
+
12385
+ // src/commands/worldgen.ts
12386
+ import { rmSync as rmSync3 } from "fs";
12387
+ var commandModule15 = {
12388
+ command: "worldgen",
12389
+ describe: "Autogenerate interfaces for Systems and World based on existing contracts and the config file",
12390
+ builder(yargs2) {
12391
+ return yargs2.options({
12392
+ configPath: { type: "string", desc: "Path to the config file" },
12393
+ clean: { type: "boolean", desc: "Clear the worldgen directory before generating new interfaces" }
12394
+ });
12395
+ },
12396
+ async handler(args) {
12397
+ const { configPath, clean } = args;
12398
+ const srcDir = await getSrcDirectory();
12399
+ const existingContracts = glob2.sync(`${srcDir}/**/*.sol`).map((path11) => ({
12400
+ path: path11,
12401
+ basename: basename2(path11, ".sol")
12402
+ }));
12403
+ const worldConfig = await loadWorldConfig(
12404
+ configPath,
12405
+ existingContracts.map(({ basename: basename3 }) => basename3)
12406
+ );
12407
+ const storeConfig = await loadStoreConfig(configPath);
12408
+ const mudConfig = { ...worldConfig, ...storeConfig };
12409
+ if (clean)
12410
+ rmSync3(path10.join(srcDir, worldConfig.worldgenDirectory), { recursive: true, force: true });
12411
+ await worldgen(mudConfig, existingContracts, srcDir);
12412
+ process.exit(0);
12413
+ }
12414
+ };
12415
+ var worldgen_default = commandModule15;
11414
12416
 
11415
12417
  // src/commands/index.ts
11416
12418
  var commands = [
@@ -11418,6 +12420,7 @@ var commands = [
11418
12420
  call_system_default,
11419
12421
  codegen_libdeploy_default,
11420
12422
  deploy_contracts_default,
12423
+ deploy_v2_default,
11421
12424
  devnode_default,
11422
12425
  faucet_default,
11423
12426
  gas_report_default,
@@ -11426,10 +12429,13 @@ var commands = [
11426
12429
  tablegen_default,
11427
12430
  test_default,
11428
12431
  trace_default,
11429
- types_default
12432
+ types_default,
12433
+ worldgen_default
11430
12434
  ];
11431
12435
 
11432
12436
  // src/mud.ts
12437
+ import * as dotenv from "dotenv";
12438
+ dotenv.config();
11433
12439
  yargs(hideBin(process.argv)).scriptName("mud").command(commands).strict().fail((msg, err) => {
11434
12440
  console.log("");
11435
12441
  logError(err);