@latticexyz/cli 1.41.0 → 1.41.1-alpha.41
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-GR245KYP.js → chunk-J4DJQNIC.js} +679 -133
- package/dist/chunk-O57QENJ6.js +23039 -0
- package/dist/config/index.d.ts +610 -296
- package/dist/config/index.js +49 -26
- package/dist/index.d.ts +2 -110
- package/dist/index.js +9 -50
- package/dist/mud.js +937 -57
- package/dist/utils/index.d.ts +92 -4
- package/dist/utils/index.js +2 -3
- package/package.json +10 -9
- package/src/commands/deploy-v2.ts +11 -15
- package/src/commands/index.ts +2 -0
- package/src/commands/worldgen.ts +55 -0
- package/src/config/commonSchemas.ts +11 -13
- package/src/config/dynamicResolution.ts +49 -0
- package/src/config/index.ts +15 -3
- package/src/config/loadStoreConfig.ts +1 -1
- package/src/config/parseStoreConfig.test-d.ts +31 -5
- package/src/config/parseStoreConfig.ts +218 -78
- package/src/config/validation.ts +25 -0
- package/src/config/world/index.ts +4 -0
- package/src/config/{loadWorldConfig.test-d.ts → world/loadWorldConfig.test-d.ts} +3 -3
- package/src/config/world/loadWorldConfig.ts +26 -0
- package/src/config/world/parseWorldConfig.ts +55 -0
- package/src/config/world/resolveWorldConfig.ts +80 -0
- package/src/config/world/userTypes.ts +72 -0
- package/src/index.ts +4 -6
- package/src/render-solidity/common.ts +51 -6
- package/src/render-solidity/field.ts +40 -44
- package/src/render-solidity/index.ts +5 -1
- package/src/render-solidity/record.ts +56 -73
- package/src/render-solidity/renderSystemInterface.ts +31 -0
- package/src/render-solidity/renderTable.ts +98 -70
- package/src/render-solidity/renderTypeHelpers.ts +99 -0
- package/src/render-solidity/renderTypesFromConfig.ts +2 -2
- package/src/render-solidity/renderWorld.ts +24 -0
- package/src/render-solidity/{renderTablesFromConfig.ts → tableOptions.ts} +28 -30
- package/src/render-solidity/tablegen.ts +20 -22
- package/src/render-solidity/types.ts +39 -5
- package/src/render-solidity/userType.ts +80 -48
- package/src/render-solidity/worldgen.ts +60 -0
- package/src/utils/contractToInterface.ts +130 -0
- package/src/utils/deploy-v2.ts +268 -101
- package/src/utils/formatAndWrite.ts +12 -0
- package/src/utils/getChainId.ts +10 -0
- package/src/utils/typeUtils.ts +17 -0
- package/dist/chunk-AER7UDD4.js +0 -0
- package/dist/chunk-XRS7KWBZ.js +0 -547
- package/dist/chunk-YZATC2M3.js +0 -397
- package/dist/chunk-ZYDMYSTH.js +0 -1178
- package/dist/deploy-v2-b7b3207d.d.ts +0 -92
- package/src/config/loadWorldConfig.ts +0 -178
- package/src/constants.ts +0 -1
package/dist/mud.js
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env -S TS_NODE_COMPILER_OPTIONS={\"module\":\"esnext\"} node --loader=ts-node/esm --no-warnings
|
|
2
|
-
import {
|
|
3
|
-
deploymentInfoFilenamePrefix,
|
|
4
|
-
renderArguments,
|
|
5
|
-
renderList,
|
|
6
|
-
renderTablesFromConfig,
|
|
7
|
-
renderedSolidityHeader
|
|
8
|
-
} from "./chunk-XRS7KWBZ.js";
|
|
9
|
-
import {
|
|
10
|
-
loadStoreConfig,
|
|
11
|
-
loadWorldConfig
|
|
12
|
-
} from "./chunk-YZATC2M3.js";
|
|
13
2
|
import {
|
|
14
3
|
deploy,
|
|
15
|
-
formatSolidity
|
|
16
|
-
|
|
4
|
+
formatSolidity,
|
|
5
|
+
getSchemaTypeInfo,
|
|
6
|
+
importForAbiOrUserType,
|
|
7
|
+
resolveAbiOrUserType
|
|
8
|
+
} from "./chunk-O57QENJ6.js";
|
|
17
9
|
import {
|
|
18
10
|
MUDError,
|
|
11
|
+
SchemaTypeArrayToElement,
|
|
12
|
+
loadStoreConfig,
|
|
13
|
+
loadWorldConfig,
|
|
19
14
|
logError
|
|
20
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-J4DJQNIC.js";
|
|
21
16
|
import {
|
|
22
17
|
JsonRpcProvider,
|
|
23
18
|
componentsDir,
|
|
@@ -34,7 +29,6 @@ import {
|
|
|
34
29
|
} from "./chunk-SLIMIO4Z.js";
|
|
35
30
|
import {
|
|
36
31
|
forge,
|
|
37
|
-
getOutDirectory,
|
|
38
32
|
getRpcUrl,
|
|
39
33
|
getSrcDirectory,
|
|
40
34
|
getTestDirectory
|
|
@@ -11261,9 +11255,9 @@ var commandModule11 = {
|
|
|
11261
11255
|
compare: { type: "string", desc: "Compare to an existing gas report" }
|
|
11262
11256
|
});
|
|
11263
11257
|
},
|
|
11264
|
-
async handler({ path:
|
|
11258
|
+
async handler({ path: path11, save, compare: compare2 }) {
|
|
11265
11259
|
let gasReport = [];
|
|
11266
|
-
for (const file of
|
|
11260
|
+
for (const file of path11) {
|
|
11267
11261
|
gasReport = gasReport.concat(await runGasReport(file));
|
|
11268
11262
|
}
|
|
11269
11263
|
const compareGasReport = [];
|
|
@@ -11295,14 +11289,14 @@ var commandModule11 = {
|
|
|
11295
11289
|
}
|
|
11296
11290
|
};
|
|
11297
11291
|
var gas_report_default = commandModule11;
|
|
11298
|
-
async function runGasReport(
|
|
11299
|
-
if (!
|
|
11300
|
-
console.log("Skipping gas report for", chalk3.bold(
|
|
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)");
|
|
11301
11295
|
return [];
|
|
11302
11296
|
}
|
|
11303
|
-
console.log("Running gas report for", chalk3.bold(
|
|
11297
|
+
console.log("Running gas report for", chalk3.bold(path11));
|
|
11304
11298
|
const gasReport = [];
|
|
11305
|
-
const fileContents = readFileSync2(
|
|
11299
|
+
const fileContents = readFileSync2(path11, "utf8");
|
|
11306
11300
|
let newFile = fileContents;
|
|
11307
11301
|
const functionRegex = new RegExp(/function (.*){/g);
|
|
11308
11302
|
let functionMatch;
|
|
@@ -11326,7 +11320,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
|
|
|
11326
11320
|
);
|
|
11327
11321
|
}
|
|
11328
11322
|
newFile = newFile.replace(/pure/g, "view");
|
|
11329
|
-
const tempFileName =
|
|
11323
|
+
const tempFileName = path11.replace(/\.t\.sol$/, "MudGasReport.t.sol");
|
|
11330
11324
|
writeFileSync(tempFileName, newFile);
|
|
11331
11325
|
const child = execa2("forge", ["test", "--match-path", tempFileName, "-vvv"], {
|
|
11332
11326
|
stdio: ["inherit", "pipe", "inherit"]
|
|
@@ -11347,7 +11341,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
|
|
|
11347
11341
|
const name = gasReportMatch[1];
|
|
11348
11342
|
const functionCall = gasReportMatch[2].replace(";", "");
|
|
11349
11343
|
const gasUsed = gasReportMatch[3];
|
|
11350
|
-
gasReport.push({ source:
|
|
11344
|
+
gasReport.push({ source: path11, name, functionCall, gasUsed: parseInt(gasUsed) });
|
|
11351
11345
|
}
|
|
11352
11346
|
return gasReport;
|
|
11353
11347
|
}
|
|
@@ -11371,10 +11365,10 @@ function printGasReport(gasReport, compare2) {
|
|
|
11371
11365
|
const rows = [headers, ...values];
|
|
11372
11366
|
console.log(table(rows, { border: getBorderCharacters("norc") }));
|
|
11373
11367
|
}
|
|
11374
|
-
function saveGasReport(gasReport,
|
|
11375
|
-
console.log(chalk3.bold(`Saving gas report to ${
|
|
11368
|
+
function saveGasReport(gasReport, path11) {
|
|
11369
|
+
console.log(chalk3.bold(`Saving gas report to ${path11}`));
|
|
11376
11370
|
const serializedGasReport = gasReport.map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`).join("\n");
|
|
11377
|
-
writeFileSync(
|
|
11371
|
+
writeFileSync(path11, serializedGasReport);
|
|
11378
11372
|
}
|
|
11379
11373
|
|
|
11380
11374
|
// src/commands/hello.ts
|
|
@@ -11396,7 +11390,644 @@ var hello_default = commandModule12;
|
|
|
11396
11390
|
|
|
11397
11391
|
// src/render-solidity/tablegen.ts
|
|
11398
11392
|
import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
11393
|
+
import path7 from "path";
|
|
11394
|
+
|
|
11395
|
+
// src/render-solidity/tableOptions.ts
|
|
11399
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
|
+
}
|
|
11400
12031
|
|
|
11401
12032
|
// src/render-solidity/renderTypes.ts
|
|
11402
12033
|
function renderTypes(options) {
|
|
@@ -11417,9 +12048,9 @@ ${renderList(
|
|
|
11417
12048
|
|
|
11418
12049
|
// src/render-solidity/renderTypesFromConfig.ts
|
|
11419
12050
|
function renderTypesFromConfig(config2) {
|
|
11420
|
-
const enums = Object.keys(config2.
|
|
12051
|
+
const enums = Object.keys(config2.enums).map((name) => ({
|
|
11421
12052
|
name,
|
|
11422
|
-
memberNames: config2.
|
|
12053
|
+
memberNames: config2.enums[name]
|
|
11423
12054
|
}));
|
|
11424
12055
|
return renderTypes({
|
|
11425
12056
|
enums
|
|
@@ -11428,24 +12059,24 @@ function renderTypesFromConfig(config2) {
|
|
|
11428
12059
|
|
|
11429
12060
|
// src/render-solidity/tablegen.ts
|
|
11430
12061
|
async function tablegen(config2, outputBaseDirectory) {
|
|
11431
|
-
const
|
|
11432
|
-
for (const {
|
|
11433
|
-
const
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
writeFileSync2(outputPath, formattedOutput);
|
|
11437
|
-
console.log(`Generated table: ${outputPath}`);
|
|
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");
|
|
11438
12067
|
}
|
|
11439
|
-
if (Object.keys(config2.
|
|
11440
|
-
const
|
|
11441
|
-
const
|
|
11442
|
-
|
|
11443
|
-
const outputDirectory = path5.dirname(outputPath);
|
|
11444
|
-
mkdirSync(outputDirectory, { recursive: true });
|
|
11445
|
-
writeFileSync2(outputPath, formattedOutput);
|
|
11446
|
-
console.log(`Generated types file: ${outputPath}`);
|
|
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");
|
|
11447
12072
|
}
|
|
11448
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
|
+
}
|
|
11449
12080
|
|
|
11450
12081
|
// src/commands/tablegen.ts
|
|
11451
12082
|
var commandModule13 = {
|
|
@@ -11468,8 +12099,20 @@ var tablegen_default = commandModule13;
|
|
|
11468
12099
|
// src/commands/deploy-v2.ts
|
|
11469
12100
|
import chalk4 from "chalk";
|
|
11470
12101
|
import glob from "glob";
|
|
11471
|
-
import
|
|
12102
|
+
import path8, { basename } from "path";
|
|
11472
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
|
|
11473
12116
|
var commandModule14 = {
|
|
11474
12117
|
command: "deploy-v2",
|
|
11475
12118
|
describe: "Deploy MUD v2 contracts",
|
|
@@ -11479,6 +12122,7 @@ var commandModule14 = {
|
|
|
11479
12122
|
clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
|
|
11480
12123
|
printConfig: { type: "boolean", desc: "Print the resolved config" },
|
|
11481
12124
|
profile: { type: "string", desc: "The foundry profile to use" },
|
|
12125
|
+
debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
|
|
11482
12126
|
priorityFeeMultiplier: {
|
|
11483
12127
|
type: "number",
|
|
11484
12128
|
desc: "Multiply the estimated priority fee by the provided factor",
|
|
@@ -11500,8 +12144,8 @@ var commandModule14 = {
|
|
|
11500
12144
|
if (clean)
|
|
11501
12145
|
await forge(["clean"], { profile });
|
|
11502
12146
|
await forge(["build"], { profile });
|
|
11503
|
-
const
|
|
11504
|
-
const existingContracts = glob.sync(`${
|
|
12147
|
+
const srcDir = await getSrcDirectory();
|
|
12148
|
+
const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path11) => basename(path11, ".sol"));
|
|
11505
12149
|
const worldConfig = await loadWorldConfig(configPath, existingContracts);
|
|
11506
12150
|
const storeConfig = await loadStoreConfig(configPath);
|
|
11507
12151
|
const mudConfig = { ...worldConfig, ...storeConfig };
|
|
@@ -11512,16 +12156,11 @@ var commandModule14 = {
|
|
|
11512
12156
|
if (!privateKey)
|
|
11513
12157
|
throw new MUDError("Missing PRIVATE_KEY environment variable");
|
|
11514
12158
|
const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
|
|
11515
|
-
const
|
|
12159
|
+
const chainId = await getChainId(rpc);
|
|
12160
|
+
const outputDir = path8.join(mudConfig.deploysDirectory, chainId.toString());
|
|
11516
12161
|
mkdirSync2(outputDir, { recursive: true });
|
|
11517
|
-
writeFileSync3(
|
|
11518
|
-
|
|
11519
|
-
JSON.stringify(deploymentInfo, null, 2)
|
|
11520
|
-
);
|
|
11521
|
-
writeFileSync3(
|
|
11522
|
-
path6.join(outputDir, deploymentInfoFilenamePrefix + Date.now() + ".json"),
|
|
11523
|
-
JSON.stringify(deploymentInfo, null, 2)
|
|
11524
|
-
);
|
|
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));
|
|
11525
12164
|
console.log(chalk4.bgGreen(chalk4.whiteBright(`
|
|
11526
12165
|
Deployment result (written to ${outputDir}):
|
|
11527
12166
|
`)));
|
|
@@ -11535,6 +12174,246 @@ var commandModule14 = {
|
|
|
11535
12174
|
};
|
|
11536
12175
|
var deploy_v2_default = commandModule14;
|
|
11537
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;
|
|
12416
|
+
|
|
11538
12417
|
// src/commands/index.ts
|
|
11539
12418
|
var commands = [
|
|
11540
12419
|
bulkupload_default,
|
|
@@ -11550,7 +12429,8 @@ var commands = [
|
|
|
11550
12429
|
tablegen_default,
|
|
11551
12430
|
test_default,
|
|
11552
12431
|
trace_default,
|
|
11553
|
-
types_default
|
|
12432
|
+
types_default,
|
|
12433
|
+
worldgen_default
|
|
11554
12434
|
];
|
|
11555
12435
|
|
|
11556
12436
|
// src/mud.ts
|