@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.
- package/LICENSE +21 -0
- package/dist/chunk-ATAWDHWC.js +67 -0
- package/dist/{chunk-6AQ6LFVZ.js → chunk-J4DJQNIC.js} +743 -103
- package/dist/chunk-KD354QKC.js +23039 -0
- package/dist/{chunk-S3V3XX7N.js → chunk-SLIMIO4Z.js} +1 -1
- package/dist/config/index.d.ts +746 -8
- package/dist/config/index.js +63 -17
- package/dist/index.d.ts +1 -2
- package/dist/index.js +14 -10
- package/dist/mud.js +1055 -49
- package/dist/utils/deprecated/index.js +2 -2
- package/dist/utils/index.d.ts +56 -7
- package/dist/utils/index.js +17 -3
- package/package.json +16 -11
- package/src/commands/deploy-v2.ts +96 -0
- package/src/commands/deprecated/call-system.ts +1 -1
- package/src/commands/deprecated/deploy-contracts.ts +1 -1
- package/src/commands/deprecated/test.ts +9 -6
- package/src/commands/deprecated/trace.ts +1 -1
- package/src/commands/gas-report.ts +1 -1
- package/src/commands/index.ts +4 -0
- package/src/commands/tablegen.ts +4 -18
- package/src/commands/worldgen.ts +55 -0
- package/src/config/commonSchemas.ts +19 -5
- package/src/config/dynamicResolution.ts +49 -0
- package/src/config/index.ts +20 -0
- package/src/config/loadStoreConfig.ts +3 -89
- package/src/config/parseStoreConfig.test-d.ts +40 -0
- package/src/config/parseStoreConfig.ts +314 -0
- package/src/config/validation.ts +71 -0
- package/src/config/world/index.ts +4 -0
- package/src/config/world/loadWorldConfig.test-d.ts +11 -0
- 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 +13 -5
- package/src/mud.ts +4 -0
- package/src/render-solidity/common.ts +138 -0
- package/src/render-solidity/field.ts +137 -0
- package/src/render-solidity/index.ts +10 -0
- package/src/render-solidity/record.ts +154 -0
- package/src/render-solidity/renderSystemInterface.ts +31 -0
- package/src/render-solidity/renderTable.ts +164 -0
- package/src/render-solidity/renderTypeHelpers.ts +99 -0
- package/src/render-solidity/renderTypes.ts +19 -0
- package/src/render-solidity/renderTypesFromConfig.ts +13 -0
- package/src/render-solidity/renderWorld.ts +24 -0
- package/src/{render-table/renderTablesFromConfig.ts → render-solidity/tableOptions.ts} +45 -37
- package/src/render-solidity/tablegen.ts +33 -0
- package/src/render-solidity/types.ts +110 -0
- package/src/render-solidity/userType.ts +132 -0
- package/src/render-solidity/worldgen.ts +60 -0
- package/src/utils/contractToInterface.ts +130 -0
- package/src/utils/deploy-v2.ts +512 -0
- package/src/utils/deprecated/build.ts +1 -1
- package/src/utils/deprecated/typegen.ts +1 -1
- package/src/utils/errors.ts +12 -2
- package/src/utils/execLog.ts +22 -0
- package/src/utils/formatAndWrite.ts +12 -0
- package/src/utils/foundry.ts +94 -0
- package/src/utils/getChainId.ts +10 -0
- package/src/utils/index.ts +2 -1
- package/src/utils/typeUtils.ts +17 -0
- package/dist/chunk-B6VWCGHZ.js +0 -199
- package/dist/chunk-JKAA3WMC.js +0 -55
- package/dist/chunk-JNGSW4AP.js +0 -493
- package/dist/chunk-PJ6GS2R4.js +0 -22
- package/dist/chunk-UC3QPOON.js +0 -35
- package/dist/loadStoreConfig-37f99136.d.ts +0 -164
- package/dist/render-table/index.d.ts +0 -29
- package/dist/render-table/index.js +0 -24
- package/dist/renderTable-9e6410c5.d.ts +0 -72
- package/src/config/loadStoreConfig.test-d.ts +0 -11
- package/src/render-table/common.ts +0 -67
- package/src/render-table/field.ts +0 -132
- package/src/render-table/index.ts +0 -6
- package/src/render-table/record.ts +0 -176
- package/src/render-table/renderTable.ts +0 -109
- package/src/render-table/types.ts +0 -51
- package/src/utils/forgeConfig.ts +0 -45
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { AbiTypeToSchemaType, getStaticByteLength, SchemaType, SchemaTypeToAbiType } from "@latticexyz/schema-type";
|
|
2
|
+
import { StoreConfig } from "../config/index.js";
|
|
3
|
+
import { ImportDatum, RenderTableType } from "./types.js";
|
|
4
|
+
import { parseStaticArray } from "../config/validation.js";
|
|
5
|
+
|
|
6
|
+
export type UserTypeInfo = ReturnType<typeof getUserTypeInfo>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve an abi or user type into a SchemaType
|
|
10
|
+
*/
|
|
11
|
+
export function resolveAbiOrUserType(
|
|
12
|
+
abiOrUserType: string,
|
|
13
|
+
config: StoreConfig
|
|
14
|
+
): {
|
|
15
|
+
schemaType: SchemaType;
|
|
16
|
+
renderTableType: RenderTableType;
|
|
17
|
+
} {
|
|
18
|
+
// abi types which directly mirror a SchemaType
|
|
19
|
+
if (abiOrUserType in AbiTypeToSchemaType) {
|
|
20
|
+
const schemaType = AbiTypeToSchemaType[abiOrUserType];
|
|
21
|
+
return {
|
|
22
|
+
schemaType,
|
|
23
|
+
renderTableType: getSchemaTypeInfo(schemaType),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// static arrays
|
|
27
|
+
const staticArray = parseStaticArray(abiOrUserType);
|
|
28
|
+
if (staticArray) {
|
|
29
|
+
if (staticArray.elementType in AbiTypeToSchemaType) {
|
|
30
|
+
return getStaticArrayTypeInfo(abiOrUserType, staticArray.elementType, staticArray.staticLength);
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error("Static arrays of user types are not supported");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// user types
|
|
36
|
+
return getUserTypeInfo(abiOrUserType, config);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the required import for SchemaType|userType (`undefined` means that no import is required)
|
|
41
|
+
*/
|
|
42
|
+
export function importForAbiOrUserType(
|
|
43
|
+
abiOrUserType: string,
|
|
44
|
+
usedInDirectory: string,
|
|
45
|
+
config: StoreConfig
|
|
46
|
+
): ImportDatum | undefined {
|
|
47
|
+
// abi types which directly mirror a SchemaType
|
|
48
|
+
if (abiOrUserType in AbiTypeToSchemaType) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
// static arrays
|
|
52
|
+
const staticArray = parseStaticArray(abiOrUserType);
|
|
53
|
+
if (staticArray) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
// user types
|
|
57
|
+
return {
|
|
58
|
+
symbol: abiOrUserType,
|
|
59
|
+
fromPath: config.userTypesPath + ".sol",
|
|
60
|
+
usedInPath: usedInDirectory,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getSchemaTypeInfo(schemaType: SchemaType): RenderTableType {
|
|
65
|
+
const staticByteLength = getStaticByteLength(schemaType);
|
|
66
|
+
const isDynamic = staticByteLength === 0;
|
|
67
|
+
const typeId = SchemaTypeToAbiType[schemaType];
|
|
68
|
+
return {
|
|
69
|
+
typeId,
|
|
70
|
+
typeWithLocation: isDynamic ? typeId + " memory" : typeId,
|
|
71
|
+
enumName: SchemaType[schemaType],
|
|
72
|
+
staticByteLength,
|
|
73
|
+
isDynamic,
|
|
74
|
+
typeWrap: "",
|
|
75
|
+
typeUnwrap: "",
|
|
76
|
+
internalTypeId: typeId,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function getUserTypeInfo(
|
|
81
|
+
userType: string,
|
|
82
|
+
config: StoreConfig
|
|
83
|
+
): {
|
|
84
|
+
schemaType: SchemaType;
|
|
85
|
+
renderTableType: RenderTableType;
|
|
86
|
+
} {
|
|
87
|
+
// enums
|
|
88
|
+
if (userType in config.enums) {
|
|
89
|
+
const schemaType = SchemaType.UINT8;
|
|
90
|
+
const staticByteLength = getStaticByteLength(schemaType);
|
|
91
|
+
const isDynamic = staticByteLength === 0;
|
|
92
|
+
const typeId = userType;
|
|
93
|
+
return {
|
|
94
|
+
schemaType,
|
|
95
|
+
renderTableType: {
|
|
96
|
+
typeId,
|
|
97
|
+
typeWithLocation: typeId,
|
|
98
|
+
enumName: SchemaType[schemaType],
|
|
99
|
+
staticByteLength,
|
|
100
|
+
isDynamic,
|
|
101
|
+
typeWrap: `${userType}`,
|
|
102
|
+
typeUnwrap: `uint8`,
|
|
103
|
+
internalTypeId: `${SchemaTypeToAbiType[schemaType]}`,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// invalid
|
|
108
|
+
throw new Error(`User type "${userType}" does not exist`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getStaticArrayTypeInfo(abiType: string, elementType: string, staticLength: number) {
|
|
112
|
+
const internalTypeId = elementType + "[]";
|
|
113
|
+
const schemaType = AbiTypeToSchemaType[internalTypeId];
|
|
114
|
+
return {
|
|
115
|
+
schemaType,
|
|
116
|
+
renderTableType: {
|
|
117
|
+
typeId: abiType,
|
|
118
|
+
typeWithLocation: `${abiType} memory`,
|
|
119
|
+
enumName: SchemaType[schemaType],
|
|
120
|
+
staticByteLength: 0,
|
|
121
|
+
isDynamic: true,
|
|
122
|
+
typeWrap: `toStaticArray_${elementType}_${staticLength}`,
|
|
123
|
+
typeUnwrap: `fromStaticArray_${elementType}_${staticLength}`,
|
|
124
|
+
typeWrappingData: {
|
|
125
|
+
kind: "staticArray",
|
|
126
|
+
elementType,
|
|
127
|
+
staticLength,
|
|
128
|
+
},
|
|
129
|
+
internalTypeId,
|
|
130
|
+
},
|
|
131
|
+
} as const;
|
|
132
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { MUDConfig } from "../config/index.js";
|
|
4
|
+
import { contractToInterface } from "../utils/contractToInterface.js";
|
|
5
|
+
import { formatAndWrite } from "../utils/formatAndWrite.js";
|
|
6
|
+
import { renderSystemInterface } from "./renderSystemInterface.js";
|
|
7
|
+
import { renderWorld } from "./renderWorld.js";
|
|
8
|
+
import { ImportDatum } from "./types.js";
|
|
9
|
+
|
|
10
|
+
export async function worldgen(
|
|
11
|
+
config: MUDConfig,
|
|
12
|
+
existingContracts: { path: string; basename: string }[],
|
|
13
|
+
outputBaseDirectory: string
|
|
14
|
+
) {
|
|
15
|
+
const worldgenBaseDirectory = path.join(outputBaseDirectory, config.worldgenDirectory);
|
|
16
|
+
const systems = existingContracts.filter(({ basename }) => Object.keys(config.systems).includes(basename));
|
|
17
|
+
|
|
18
|
+
const systemInterfaceImports: ImportDatum[] = [];
|
|
19
|
+
for (const system of systems) {
|
|
20
|
+
const data = readFileSync(system.path, "utf8");
|
|
21
|
+
// get external funcions from a contract
|
|
22
|
+
const { functions, symbols } = contractToInterface(data, system.basename);
|
|
23
|
+
const imports = symbols.map((symbol) => ({
|
|
24
|
+
symbol,
|
|
25
|
+
fromPath: system.path,
|
|
26
|
+
usedInPath: worldgenBaseDirectory,
|
|
27
|
+
}));
|
|
28
|
+
const systemInterfaceName = `I${system.basename}`;
|
|
29
|
+
// create an interface using the external functions and imports
|
|
30
|
+
const { fileSelector } = config.systems[system.basename];
|
|
31
|
+
const output = renderSystemInterface({
|
|
32
|
+
name: systemInterfaceName,
|
|
33
|
+
functionPrefix: config.namespace === "" ? "" : `${config.namespace}_${fileSelector}_`,
|
|
34
|
+
functions,
|
|
35
|
+
imports,
|
|
36
|
+
});
|
|
37
|
+
// write to file
|
|
38
|
+
const fullOutputPath = path.join(worldgenBaseDirectory, systemInterfaceName + ".sol");
|
|
39
|
+
await formatAndWrite(output, fullOutputPath, "Generated system interface");
|
|
40
|
+
|
|
41
|
+
// prepare imports for IWorld
|
|
42
|
+
systemInterfaceImports.push({
|
|
43
|
+
symbol: systemInterfaceName,
|
|
44
|
+
fromPath: `${systemInterfaceName}.sol`,
|
|
45
|
+
usedInPath: "./",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// render IWorld
|
|
50
|
+
const worldInterfaceName = "IWorld";
|
|
51
|
+
const output = renderWorld({
|
|
52
|
+
interfaceName: worldInterfaceName,
|
|
53
|
+
imports: systemInterfaceImports,
|
|
54
|
+
storeImportPath: config.storeImportPath,
|
|
55
|
+
worldImportPath: config.worldImportPath,
|
|
56
|
+
});
|
|
57
|
+
// write to file
|
|
58
|
+
const fullOutputPath = path.join(worldgenBaseDirectory, worldInterfaceName + ".sol");
|
|
59
|
+
await formatAndWrite(output, fullOutputPath, "Generated system interface");
|
|
60
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { parse, visit } from "@solidity-parser/parser";
|
|
2
|
+
import { TypeName, VariableDeclaration } from "@solidity-parser/parser/dist/src/ast-types.js";
|
|
3
|
+
import { RenderSystemInterfaceFunction } from "../render-solidity/types.js";
|
|
4
|
+
import { MUDError } from "./errors.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parse the contract data to get the functions necessary to generate an interface,
|
|
8
|
+
* and symbols to import from the original contract.
|
|
9
|
+
* @param data contents of a file with the solidity contract
|
|
10
|
+
* @param contractName name of the contract
|
|
11
|
+
* @returns interface data
|
|
12
|
+
*/
|
|
13
|
+
export function contractToInterface(data: string, contractName: string) {
|
|
14
|
+
const ast = parse(data);
|
|
15
|
+
|
|
16
|
+
let withContract = false;
|
|
17
|
+
let symbols: string[] = [];
|
|
18
|
+
const functions: RenderSystemInterfaceFunction[] = [];
|
|
19
|
+
|
|
20
|
+
visit(ast, {
|
|
21
|
+
ContractDefinition({ name }) {
|
|
22
|
+
if (name === contractName) {
|
|
23
|
+
withContract = true;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
FunctionDefinition(
|
|
27
|
+
{ name, visibility, parameters, returnParameters, isConstructor, isFallback, isReceiveEther },
|
|
28
|
+
parent
|
|
29
|
+
) {
|
|
30
|
+
if (parent !== undefined && parent.type === "ContractDefinition" && parent.name === contractName) {
|
|
31
|
+
try {
|
|
32
|
+
// skip constructor and fallbacks
|
|
33
|
+
if (isConstructor || isFallback || isReceiveEther) return;
|
|
34
|
+
// forbid default visibility (this check might be unnecessary, modern solidity already disallows this)
|
|
35
|
+
if (visibility === "default") throw new MUDError(`Visibility is not specified`);
|
|
36
|
+
|
|
37
|
+
if (visibility === "external" || visibility === "public") {
|
|
38
|
+
functions.push({
|
|
39
|
+
name: name === null ? "" : name,
|
|
40
|
+
parameters: parameters.map(parseParameter),
|
|
41
|
+
returnParameters: returnParameters === null ? [] : returnParameters.map(parseParameter),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
for (const { typeName } of parameters.concat(returnParameters ?? [])) {
|
|
45
|
+
symbols = symbols.concat(typeNameToExternalSymbols(typeName));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (error: unknown) {
|
|
49
|
+
if (error instanceof MUDError) {
|
|
50
|
+
error.message = `Function "${name}" in contract "${contractName}": ${error.message}`;
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!withContract) {
|
|
59
|
+
throw new MUDError(`Contract not found: ${contractName}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
functions,
|
|
64
|
+
symbols,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function parseParameter({ name, typeName, storageLocation }: VariableDeclaration): string {
|
|
69
|
+
let typedNameWithLocation = "";
|
|
70
|
+
|
|
71
|
+
const { name: flattenedTypeName, stateMutability } = flattenTypeName(typeName);
|
|
72
|
+
// type name (e.g. uint256)
|
|
73
|
+
typedNameWithLocation += flattenedTypeName;
|
|
74
|
+
// optional mutability (e.g. address payable)
|
|
75
|
+
if (stateMutability !== null) {
|
|
76
|
+
typedNameWithLocation += ` ${stateMutability}`;
|
|
77
|
+
}
|
|
78
|
+
// location, when relevant (e.g. string memory)
|
|
79
|
+
if (storageLocation !== null) {
|
|
80
|
+
typedNameWithLocation += ` ${storageLocation}`;
|
|
81
|
+
}
|
|
82
|
+
// optional variable name
|
|
83
|
+
if (name !== null) {
|
|
84
|
+
typedNameWithLocation += ` ${name}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return typedNameWithLocation;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function flattenTypeName(typeName: TypeName | null): { name: string; stateMutability: string | null } {
|
|
91
|
+
if (typeName === null) {
|
|
92
|
+
return {
|
|
93
|
+
name: "",
|
|
94
|
+
stateMutability: null,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (typeName.type === "ElementaryTypeName") {
|
|
98
|
+
return {
|
|
99
|
+
name: typeName.name,
|
|
100
|
+
stateMutability: typeName.stateMutability,
|
|
101
|
+
};
|
|
102
|
+
} else if (typeName.type === "UserDefinedTypeName") {
|
|
103
|
+
return {
|
|
104
|
+
name: typeName.namePath,
|
|
105
|
+
stateMutability: null,
|
|
106
|
+
};
|
|
107
|
+
} else if (typeName.type === "ArrayTypeName") {
|
|
108
|
+
const { name, stateMutability } = flattenTypeName(typeName.baseTypeName);
|
|
109
|
+
return {
|
|
110
|
+
name: `${name}[]`,
|
|
111
|
+
stateMutability,
|
|
112
|
+
};
|
|
113
|
+
} else {
|
|
114
|
+
// TODO function types are unsupported but could be useful
|
|
115
|
+
throw new MUDError(`Invalid typeName.type ${typeName.type}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Get symbols that need to be imported for given typeName
|
|
120
|
+
function typeNameToExternalSymbols(typeName: TypeName | null): string[] {
|
|
121
|
+
if (typeName?.type === "UserDefinedTypeName") {
|
|
122
|
+
// split is needed to get a library, if types are internal to it
|
|
123
|
+
const symbol = typeName.namePath.split(".")[0];
|
|
124
|
+
return [symbol];
|
|
125
|
+
} else if (typeName?.type === "ArrayTypeName") {
|
|
126
|
+
return typeNameToExternalSymbols(typeName.baseTypeName);
|
|
127
|
+
} else {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
}
|