@latticexyz/cli 1.41.0 → 2.0.0-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/dist/{chunk-GR245KYP.js → chunk-J4DJQNIC.js} +679 -133
- package/dist/chunk-O57QENJ6.js +23039 -0
- package/dist/config/index.d.ts +606 -292
- 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/src/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
export { parseStoreConfig } from "./config/parseStoreConfig.js";
|
|
2
1
|
export { loadStoreConfig } from "./config/loadStoreConfig.js";
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
2
|
+
export { parseStoreConfig } from "./config/parseStoreConfig.js";
|
|
3
|
+
export { loadWorldConfig, resolveWorldConfig, parseWorldConfig } from "./config/world/index.js";
|
|
4
|
+
export { resolveTableId } from "./config/dynamicResolution.js";
|
|
6
5
|
|
|
7
6
|
export type {
|
|
8
7
|
StoreUserConfig,
|
|
@@ -13,5 +12,4 @@ export type {
|
|
|
13
12
|
MUDConfig,
|
|
14
13
|
} from "./config/index.js";
|
|
15
14
|
|
|
16
|
-
export
|
|
17
|
-
export * from "./utils/index.js";
|
|
15
|
+
export { storeConfig, mudConfig } from "./config/index.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { ImportDatum, RenderTableOptions, RenderTableType, StaticResourceData } from "./types.js";
|
|
2
3
|
|
|
3
4
|
export const renderedSolidityHeader = `// SPDX-License-Identifier: MIT
|
|
4
5
|
pragma solidity >=0.8.0;
|
|
@@ -20,10 +21,13 @@ export function renderArguments(args: (string | undefined)[]) {
|
|
|
20
21
|
return internalRenderList(",", filteredArgs, (arg) => arg);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export function renderCommonData({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
export function renderCommonData({
|
|
25
|
+
staticResourceData,
|
|
26
|
+
primaryKeys,
|
|
27
|
+
}: Pick<RenderTableOptions, "staticResourceData" | "primaryKeys">) {
|
|
28
|
+
// static resource means static tableId as well, and no tableId arguments
|
|
29
|
+
const _tableId = staticResourceData ? "" : "_tableId";
|
|
30
|
+
const _typedTableId = staticResourceData ? "" : "uint256 _tableId";
|
|
27
31
|
|
|
28
32
|
const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
|
|
29
33
|
const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
|
|
@@ -45,6 +49,14 @@ export function renderCommonData({ staticRouteData, primaryKeys }: RenderTableOp
|
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
51
|
|
|
52
|
+
/** For 2 paths which are relative to a common root, create a relative import path from one to another */
|
|
53
|
+
export function solidityRelativeImportPath(fromPath: string, usedInPath: string) {
|
|
54
|
+
// 1st "./" must be added because path strips it,
|
|
55
|
+
// but solidity expects it unless there's "../" ("./../" is fine).
|
|
56
|
+
// 2nd and 3rd "./" forcefully avoid absolute paths (everything is relative to `src`).
|
|
57
|
+
return "./" + path.relative("./" + usedInPath, "./" + fromPath);
|
|
58
|
+
}
|
|
59
|
+
|
|
48
60
|
/**
|
|
49
61
|
* Aggregates, deduplicates and renders imports for symbols per path.
|
|
50
62
|
* Identical symbols from different paths are NOT handled, they should be checked before rendering.
|
|
@@ -52,7 +64,8 @@ export function renderCommonData({ staticRouteData, primaryKeys }: RenderTableOp
|
|
|
52
64
|
export function renderImports(imports: ImportDatum[]) {
|
|
53
65
|
// Aggregate symbols by import path, also deduplicating them
|
|
54
66
|
const aggregatedImports = new Map<string, Set<string>>();
|
|
55
|
-
for (const { symbol,
|
|
67
|
+
for (const { symbol, fromPath, usedInPath } of imports) {
|
|
68
|
+
const path = solidityRelativeImportPath(fromPath, usedInPath);
|
|
56
69
|
if (!aggregatedImports.has(path)) {
|
|
57
70
|
aggregatedImports.set(path, new Set());
|
|
58
71
|
}
|
|
@@ -67,6 +80,38 @@ export function renderImports(imports: ImportDatum[]) {
|
|
|
67
80
|
return renderedImports.join("\n");
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
export function renderWithStore(
|
|
84
|
+
storeArgument: boolean,
|
|
85
|
+
callback: (
|
|
86
|
+
_typedStore: string | undefined,
|
|
87
|
+
_store: string,
|
|
88
|
+
_commentSuffix: string,
|
|
89
|
+
_untypedStore: string | undefined
|
|
90
|
+
) => string
|
|
91
|
+
) {
|
|
92
|
+
let result = "";
|
|
93
|
+
result += callback(undefined, "StoreSwitch", "", undefined);
|
|
94
|
+
|
|
95
|
+
if (storeArgument) {
|
|
96
|
+
result += "\n" + callback("IStore _store", "_store", " (using the specified store)", "_store");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function renderTableId(staticResourceData: StaticResourceData) {
|
|
103
|
+
const hardcodedTableId = `uint256(bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.fileSelector}"))))`;
|
|
104
|
+
|
|
105
|
+
const tableIdDefinition = `
|
|
106
|
+
uint256 constant _tableId = ${hardcodedTableId};
|
|
107
|
+
uint256 constant ${staticResourceData.tableIdName} = _tableId;
|
|
108
|
+
`;
|
|
109
|
+
return {
|
|
110
|
+
hardcodedTableId,
|
|
111
|
+
tableIdDefinition,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
70
115
|
function renderValueTypeToBytes32(name: string, { staticByteLength, typeUnwrap, internalTypeId }: RenderTableType) {
|
|
71
116
|
const bits = staticByteLength * 8;
|
|
72
117
|
const innerText = `${typeUnwrap}(${name})`;
|
|
@@ -1,70 +1,66 @@
|
|
|
1
|
-
import { renderArguments, renderCommonData } from "./common.js";
|
|
1
|
+
import { renderArguments, renderCommonData, renderWithStore } from "./common.js";
|
|
2
2
|
import { RenderTableField, RenderTableOptions, RenderTableType } from "./types.js";
|
|
3
3
|
|
|
4
4
|
export function renderFieldMethods(options: RenderTableOptions) {
|
|
5
|
+
const storeArgument = options.storeArgument;
|
|
5
6
|
const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
|
|
6
7
|
|
|
7
8
|
let result = "";
|
|
8
9
|
for (const [index, field] of options.fields.entries()) {
|
|
9
10
|
const _typedFieldName = `${field.typeWithLocation} ${field.name}`;
|
|
10
11
|
|
|
11
|
-
result +=
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
_typedKeyArgs,
|
|
16
|
-
])}) internal view returns (${_typedFieldName}) {
|
|
17
|
-
${_primaryKeysDefinition}
|
|
18
|
-
bytes memory _blob = StoreSwitch.getField(_tableId, _primaryKeys, ${index});
|
|
19
|
-
return ${renderDecodeFieldSingle(field)};
|
|
20
|
-
}
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
|
-
if (options.storeArgument) {
|
|
24
|
-
result += `
|
|
25
|
-
/** Get ${field.name} from the specified store */
|
|
12
|
+
result += renderWithStore(
|
|
13
|
+
storeArgument,
|
|
14
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
15
|
+
/** Get ${field.name}${_commentSuffix} */
|
|
26
16
|
function get${field.methodNameSuffix}(${renderArguments([
|
|
17
|
+
_typedStore,
|
|
27
18
|
_typedTableId,
|
|
28
|
-
`IStore _store`,
|
|
29
19
|
_typedKeyArgs,
|
|
30
20
|
])}) internal view returns (${_typedFieldName}) {
|
|
31
21
|
${_primaryKeysDefinition}
|
|
32
|
-
bytes memory _blob = _store.getField(_tableId, _primaryKeys, ${index});
|
|
22
|
+
bytes memory _blob = ${_store}.getField(_tableId, _primaryKeys, ${index});
|
|
33
23
|
return ${renderDecodeFieldSingle(field)};
|
|
34
24
|
}
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
`
|
|
26
|
+
);
|
|
37
27
|
|
|
38
|
-
result +=
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
28
|
+
result += renderWithStore(
|
|
29
|
+
storeArgument,
|
|
30
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
31
|
+
/** Set ${field.name}${_commentSuffix} */
|
|
32
|
+
function set${field.methodNameSuffix}(${renderArguments([
|
|
33
|
+
_typedStore,
|
|
34
|
+
_typedTableId,
|
|
35
|
+
_typedKeyArgs,
|
|
36
|
+
_typedFieldName,
|
|
37
|
+
])}) internal {
|
|
38
|
+
${_primaryKeysDefinition}
|
|
39
|
+
${_store}.setField(_tableId, _primaryKeys, ${index}, ${renderEncodeField(field)});
|
|
40
|
+
}
|
|
41
|
+
`
|
|
42
|
+
);
|
|
49
43
|
|
|
50
44
|
// TODO: this is super inefficient right now, need to add support for pushing to arrays to the store core library to avoid reading/writing the entire array
|
|
51
45
|
// (see https://github.com/latticexyz/mud/issues/438)
|
|
52
46
|
if (field.isDynamic) {
|
|
53
47
|
const portionData = fieldPortionData(field);
|
|
54
48
|
|
|
55
|
-
result +=
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
49
|
+
result += renderWithStore(
|
|
50
|
+
storeArgument,
|
|
51
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
52
|
+
/** Push ${portionData.title} to ${field.name}${_commentSuffix} */
|
|
53
|
+
function push${field.methodNameSuffix}(${renderArguments([
|
|
54
|
+
_typedStore,
|
|
55
|
+
_typedTableId,
|
|
56
|
+
_typedKeyArgs,
|
|
57
|
+
`${portionData.typeWithLocation} ${portionData.name}`,
|
|
58
|
+
])}) internal {
|
|
59
|
+
${_primaryKeysDefinition}
|
|
60
|
+
${_store}.pushToField(_tableId, _primaryKeys, ${index}, ${portionData.encoded});
|
|
61
|
+
}
|
|
62
|
+
`
|
|
63
|
+
);
|
|
68
64
|
}
|
|
69
65
|
}
|
|
70
66
|
return result;
|
|
@@ -2,5 +2,9 @@ export * from "./common.js";
|
|
|
2
2
|
export * from "./field.js";
|
|
3
3
|
export * from "./record.js";
|
|
4
4
|
export * from "./renderTable.js";
|
|
5
|
-
export * from "./
|
|
5
|
+
export * from "./renderTypes.js";
|
|
6
|
+
export * from "./renderTypesFromConfig.js";
|
|
7
|
+
export * from "./tablegen.js";
|
|
8
|
+
export * from "./tableOptions.js";
|
|
6
9
|
export * from "./types.js";
|
|
10
|
+
export * from "./userType.js";
|
|
@@ -1,71 +1,66 @@
|
|
|
1
|
-
import { renderList, renderArguments, renderCommonData } from "./common.js";
|
|
2
|
-
import { renderDecodeValueType
|
|
1
|
+
import { renderList, renderArguments, renderCommonData, renderWithStore } from "./common.js";
|
|
2
|
+
import { renderDecodeValueType } from "./field.js";
|
|
3
3
|
import { RenderTableDynamicField, RenderTableOptions } from "./types.js";
|
|
4
4
|
|
|
5
5
|
export function renderRecordMethods(options: RenderTableOptions) {
|
|
6
|
-
const {
|
|
6
|
+
const { structName, storeArgument } = options;
|
|
7
7
|
const { _tableId, _typedTableId, _keyArgs, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
|
|
8
8
|
|
|
9
|
-
let result =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)}) {
|
|
14
|
-
${_primaryKeysDefinition}
|
|
15
|
-
bytes memory _blob = StoreSwitch.getRecord(_tableId, _primaryKeys, getSchema());
|
|
16
|
-
return decode(_blob);
|
|
17
|
-
}
|
|
18
|
-
`;
|
|
19
|
-
|
|
20
|
-
if (storeArgument) {
|
|
21
|
-
result += `
|
|
22
|
-
/** Get the full data from the specified store */
|
|
9
|
+
let result = renderWithStore(
|
|
10
|
+
storeArgument,
|
|
11
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
12
|
+
/** Get the full data${_commentSuffix} */
|
|
23
13
|
function get(${renderArguments([
|
|
14
|
+
_typedStore,
|
|
24
15
|
_typedTableId,
|
|
25
|
-
`IStore _store`,
|
|
26
16
|
_typedKeyArgs,
|
|
27
17
|
])}) internal view returns (${renderDecodedRecord(options)}) {
|
|
28
18
|
${_primaryKeysDefinition}
|
|
29
|
-
bytes memory _blob = _store.getRecord(_tableId, _primaryKeys);
|
|
19
|
+
bytes memory _blob = ${_store}.getRecord(_tableId, _primaryKeys, getSchema());
|
|
30
20
|
return decode(_blob);
|
|
31
21
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
result +=
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// (see https://github.com/latticexyz/mud/issues/444)
|
|
47
|
-
...(dynamicFields.length === 0
|
|
48
|
-
? []
|
|
49
|
-
: ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]),
|
|
50
|
-
])});
|
|
22
|
+
`
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
result += renderWithStore(
|
|
26
|
+
storeArgument,
|
|
27
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
28
|
+
/** Set the full data using individual values${_commentSuffix} */
|
|
29
|
+
function set(${renderArguments([
|
|
30
|
+
_typedStore,
|
|
31
|
+
_typedTableId,
|
|
32
|
+
_typedKeyArgs,
|
|
33
|
+
renderArguments(options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)),
|
|
34
|
+
])}) internal {
|
|
35
|
+
bytes memory _data = encode(${renderArguments(options.fields.map(({ name }) => name))});
|
|
51
36
|
|
|
52
|
-
|
|
37
|
+
${_primaryKeysDefinition}
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
${_store}.setRecord(_tableId, _primaryKeys, _data);
|
|
40
|
+
}
|
|
41
|
+
`
|
|
42
|
+
);
|
|
57
43
|
|
|
58
44
|
if (structName !== undefined) {
|
|
59
|
-
result +=
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
45
|
+
result += renderWithStore(
|
|
46
|
+
storeArgument,
|
|
47
|
+
(_typedStore, _store, _commentSuffix, _untypedStore) => `
|
|
48
|
+
/** Set the full data using the data struct${_commentSuffix} */
|
|
49
|
+
function set(${renderArguments([
|
|
50
|
+
_typedStore,
|
|
51
|
+
_typedTableId,
|
|
52
|
+
_typedKeyArgs,
|
|
53
|
+
`${structName} memory _table`,
|
|
54
|
+
])}) internal {
|
|
55
|
+
set(${renderArguments([
|
|
56
|
+
_untypedStore,
|
|
57
|
+
_tableId,
|
|
58
|
+
_keyArgs,
|
|
59
|
+
renderArguments(options.fields.map(({ name }) => `_table.${name}`)),
|
|
60
|
+
])});
|
|
61
|
+
}
|
|
62
|
+
`
|
|
63
|
+
);
|
|
69
64
|
}
|
|
70
65
|
|
|
71
66
|
result += renderDecodeFunction(options);
|
|
@@ -142,30 +137,18 @@ function renderDecodedRecord({ structName, fields }: RenderTableOptions) {
|
|
|
142
137
|
}
|
|
143
138
|
|
|
144
139
|
function renderDecodeDynamicFieldPartial(field: RenderTableDynamicField) {
|
|
145
|
-
const { typeId, arrayElement } = field;
|
|
140
|
+
const { typeId, arrayElement, typeWrap } = field;
|
|
146
141
|
if (arrayElement) {
|
|
147
142
|
// arrays
|
|
148
|
-
return
|
|
143
|
+
return `${typeWrap}(
|
|
144
|
+
SliceLib.getSubslice(_blob, _start, _end).decodeArray_${arrayElement.typeId}()
|
|
145
|
+
)`;
|
|
149
146
|
} else {
|
|
150
147
|
// bytes/string
|
|
151
|
-
return `${
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (dynamicFields.length > 0) {
|
|
157
|
-
return `
|
|
158
|
-
uint16[] memory _counters = new uint16[](${dynamicFields.length});
|
|
159
|
-
${renderList(dynamicFields, ({ name, arrayElement }, index) => {
|
|
160
|
-
if (arrayElement) {
|
|
161
|
-
return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
|
|
162
|
-
} else {
|
|
163
|
-
return `_counters[${index}] = uint16(bytes(${name}).length);`;
|
|
164
|
-
}
|
|
165
|
-
})}
|
|
166
|
-
PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
|
|
167
|
-
`;
|
|
168
|
-
} else {
|
|
169
|
-
return "";
|
|
148
|
+
return `${typeWrap}(
|
|
149
|
+
${typeId}(
|
|
150
|
+
SliceLib.getSubslice(_blob, _start, _end).toBytes()
|
|
151
|
+
)
|
|
152
|
+
)`;
|
|
170
153
|
}
|
|
171
154
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { renderArguments, renderList, renderedSolidityHeader, renderImports } from "./common.js";
|
|
2
|
+
import { RenderSystemInterfaceOptions } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export function renderSystemInterface(options: RenderSystemInterfaceOptions) {
|
|
5
|
+
const { imports, name, functionPrefix, functions } = options;
|
|
6
|
+
|
|
7
|
+
return `${renderedSolidityHeader}
|
|
8
|
+
|
|
9
|
+
${renderImports(imports)}
|
|
10
|
+
|
|
11
|
+
interface ${name} {
|
|
12
|
+
${renderList(
|
|
13
|
+
functions,
|
|
14
|
+
({ name, parameters, returnParameters }) => `
|
|
15
|
+
function ${functionPrefix}${name}(${renderArguments(parameters)}) external ${renderReturnParameters(
|
|
16
|
+
returnParameters
|
|
17
|
+
)};
|
|
18
|
+
`
|
|
19
|
+
)}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function renderReturnParameters(returnParameters: string[]) {
|
|
26
|
+
if (returnParameters.length > 0) {
|
|
27
|
+
return `returns (${renderArguments(returnParameters)})`;
|
|
28
|
+
} else {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
renderArguments,
|
|
3
|
+
renderCommonData,
|
|
4
|
+
renderList,
|
|
5
|
+
renderedSolidityHeader,
|
|
6
|
+
renderImports,
|
|
7
|
+
renderTableId,
|
|
8
|
+
renderWithStore,
|
|
9
|
+
} from "./common.js";
|
|
10
|
+
import { renderEncodeField, renderFieldMethods } from "./field.js";
|
|
3
11
|
import { renderRecordMethods } from "./record.js";
|
|
4
|
-
import {
|
|
12
|
+
import { renderTypeHelpers } from "./renderTypeHelpers.js";
|
|
13
|
+
import { RenderTableDynamicField, RenderTableOptions } from "./types.js";
|
|
5
14
|
|
|
6
15
|
export function renderTable(options: RenderTableOptions) {
|
|
7
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
imports,
|
|
18
|
+
libraryName,
|
|
19
|
+
structName,
|
|
20
|
+
staticResourceData,
|
|
21
|
+
storeImportPath,
|
|
22
|
+
fields,
|
|
23
|
+
staticFields,
|
|
24
|
+
dynamicFields,
|
|
25
|
+
withRecordMethods,
|
|
26
|
+
storeArgument,
|
|
27
|
+
primaryKeys,
|
|
28
|
+
} = options;
|
|
8
29
|
|
|
9
30
|
const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
|
|
10
31
|
|
|
@@ -18,6 +39,7 @@ import { IStore } from "${storeImportPath}IStore.sol";
|
|
|
18
39
|
import { StoreSwitch } from "${storeImportPath}StoreSwitch.sol";
|
|
19
40
|
import { StoreCore } from "${storeImportPath}StoreCore.sol";
|
|
20
41
|
import { Bytes } from "${storeImportPath}Bytes.sol";
|
|
42
|
+
import { Memory } from "${storeImportPath}Memory.sol";
|
|
21
43
|
import { SliceLib } from "${storeImportPath}Slice.sol";
|
|
22
44
|
import { EncodeArray } from "${storeImportPath}tightcoder/EncodeArray.sol";
|
|
23
45
|
import { Schema, SchemaLib } from "${storeImportPath}Schema.sol";
|
|
@@ -32,14 +54,7 @@ ${
|
|
|
32
54
|
: ""
|
|
33
55
|
}
|
|
34
56
|
|
|
35
|
-
${
|
|
36
|
-
!staticRouteData
|
|
37
|
-
? ""
|
|
38
|
-
: `
|
|
39
|
-
uint256 constant _tableId = uint256(keccak256("${staticRouteData.baseRoute + staticRouteData.subRoute}"));
|
|
40
|
-
uint256 constant ${staticRouteData.tableIdName} = _tableId;
|
|
41
|
-
`
|
|
42
|
-
}
|
|
57
|
+
${staticResourceData ? renderTableId(staticResourceData).tableIdDefinition : ""}
|
|
43
58
|
|
|
44
59
|
${
|
|
45
60
|
!structName
|
|
@@ -60,6 +75,13 @@ library ${libraryName} {
|
|
|
60
75
|
return SchemaLib.encode(_schema);
|
|
61
76
|
}
|
|
62
77
|
|
|
78
|
+
function getKeySchema() internal pure returns (Schema) {
|
|
79
|
+
SchemaType[] memory _schema = new SchemaType[](${primaryKeys.length});
|
|
80
|
+
${renderList(primaryKeys, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
|
|
81
|
+
|
|
82
|
+
return SchemaLib.encode(_schema);
|
|
83
|
+
}
|
|
84
|
+
|
|
63
85
|
/** Get the table's metadata */
|
|
64
86
|
function getMetadata() internal pure returns (string memory, string[] memory) {
|
|
65
87
|
string[] memory _fieldNames = new string[](${fields.length});
|
|
@@ -67,70 +89,76 @@ library ${libraryName} {
|
|
|
67
89
|
return ("${libraryName}", _fieldNames);
|
|
68
90
|
}
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
${renderWithStore(
|
|
93
|
+
storeArgument,
|
|
94
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
95
|
+
/** Register the table's schema${_commentSuffix} */
|
|
96
|
+
function registerSchema(${renderArguments([_typedStore, _typedTableId])}) internal {
|
|
97
|
+
${_store}.registerSchema(_tableId, getSchema(), getKeySchema());
|
|
98
|
+
}
|
|
99
|
+
`
|
|
100
|
+
)}
|
|
101
|
+
${renderWithStore(
|
|
102
|
+
storeArgument,
|
|
103
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
104
|
+
/** Set the table's metadata${_commentSuffix} */
|
|
105
|
+
function setMetadata(${renderArguments([_typedStore, _typedTableId])}) internal {
|
|
106
|
+
(string memory _tableName, string[] memory _fieldNames) = getMetadata();
|
|
107
|
+
${_store}.setMetadata(_tableId, _tableName, _fieldNames);
|
|
108
|
+
}
|
|
109
|
+
`
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
${renderFieldMethods(options)}
|
|
113
|
+
|
|
114
|
+
${withRecordMethods ? renderRecordMethods(options) : ""}
|
|
115
|
+
|
|
116
|
+
/** Tightly pack full data using this table's schema */
|
|
117
|
+
function encode(${renderArguments(
|
|
118
|
+
options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)
|
|
119
|
+
)}) internal view returns (bytes memory) {
|
|
120
|
+
${renderEncodedLengths(dynamicFields)}
|
|
121
|
+
return abi.encodePacked(${renderArguments([
|
|
122
|
+
renderArguments(staticFields.map(({ name }) => name)),
|
|
123
|
+
// TODO try gas optimization (preallocate for all, encodePacked statics, and direct encode dynamics)
|
|
124
|
+
// (see https://github.com/latticexyz/mud/issues/444)
|
|
125
|
+
...(dynamicFields.length === 0
|
|
126
|
+
? []
|
|
127
|
+
: ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]),
|
|
128
|
+
])});
|
|
88
129
|
}
|
|
89
130
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
131
|
+
${renderWithStore(
|
|
132
|
+
storeArgument,
|
|
133
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
134
|
+
/* Delete all data for given keys${_commentSuffix} */
|
|
135
|
+
function deleteRecord(${renderArguments([_typedStore, _typedTableId, _typedKeyArgs])}) internal {
|
|
136
|
+
${_primaryKeysDefinition}
|
|
137
|
+
${_store}.deleteRecord(_tableId, _primaryKeys);
|
|
138
|
+
}
|
|
139
|
+
`
|
|
140
|
+
)}
|
|
96
141
|
}
|
|
97
142
|
|
|
98
|
-
${
|
|
143
|
+
${renderTypeHelpers(options)}
|
|
99
144
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
/* Delete all data for given keys */
|
|
103
|
-
function deleteRecord(${renderArguments([_typedTableId, _typedKeyArgs])}) internal {
|
|
104
|
-
${_primaryKeysDefinition}
|
|
105
|
-
StoreSwitch.deleteRecord(_tableId, _primaryKeys);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
${
|
|
110
|
-
// nothing can be cast to bool, so an assembly helper is required
|
|
111
|
-
!fields.some(({ typeId }) => typeId === "bool")
|
|
112
|
-
? ""
|
|
113
|
-
: `
|
|
114
|
-
function _toBool(uint8 value) pure returns (bool result) {
|
|
115
|
-
assembly {
|
|
116
|
-
result := value
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
`
|
|
145
|
+
`;
|
|
120
146
|
}
|
|
121
147
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
148
|
+
function renderEncodedLengths(dynamicFields: RenderTableDynamicField[]) {
|
|
149
|
+
if (dynamicFields.length > 0) {
|
|
150
|
+
return `
|
|
151
|
+
uint16[] memory _counters = new uint16[](${dynamicFields.length});
|
|
152
|
+
${renderList(dynamicFields, ({ name, arrayElement }, index) => {
|
|
153
|
+
if (arrayElement) {
|
|
154
|
+
return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
|
|
155
|
+
} else {
|
|
156
|
+
return `_counters[${index}] = uint16(bytes(${name}).length);`;
|
|
157
|
+
}
|
|
158
|
+
})}
|
|
159
|
+
PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
|
|
160
|
+
`;
|
|
161
|
+
} else {
|
|
162
|
+
return "";
|
|
131
163
|
}
|
|
132
|
-
`
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
`;
|
|
136
164
|
}
|