@0xobelisk/sui-common 0.4.9
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 +92 -0
- package/README.md +3 -0
- package/dist/index.js +370 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
- package/src/codegen/index.ts +3 -0
- package/src/codegen/modules.d.ts +1 -0
- package/src/codegen/types/index.ts +82 -0
- package/src/codegen/utils/config.ts +68 -0
- package/src/codegen/utils/errors.ts +5 -0
- package/src/codegen/utils/format.ts +42 -0
- package/src/codegen/utils/formatAndWrite.ts +31 -0
- package/src/codegen/utils/index.ts +6 -0
- package/src/codegen/utils/posixPath.ts +8 -0
- package/src/codegen/utils/renderMove/common.ts +473 -0
- package/src/codegen/utils/renderMove/generateEntityKey.ts +53 -0
- package/src/codegen/utils/renderMove/generateEps.ts +159 -0
- package/src/codegen/utils/renderMove/generateInit.ts +40 -0
- package/src/codegen/utils/renderMove/generateSchema.ts +219 -0
- package/src/codegen/utils/renderMove/generateScript.ts +37 -0
- package/src/codegen/utils/renderMove/generateSystem.ts +53 -0
- package/src/codegen/utils/renderMove/generateToml.ts +21 -0
- package/src/codegen/utils/renderMove/worldgen.ts +34 -0
- package/src/index.ts +1 -0
- package/src/modules.d.ts +11 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import { BaseType, SchemaMapType, BaseValueType, MoveType } from "../../types";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
|
|
4
|
+
export function deleteFolderRecursive(path: string) {
|
|
5
|
+
if (fs.existsSync(path)) {
|
|
6
|
+
fs.readdirSync(path).forEach((file) => {
|
|
7
|
+
const curPath = `${path}/${file}`;
|
|
8
|
+
if (fs.lstatSync(curPath).isDirectory()) {
|
|
9
|
+
deleteFolderRecursive(curPath);
|
|
10
|
+
} else {
|
|
11
|
+
fs.unlinkSync(curPath);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
fs.rmdirSync(path);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function capitalizeFirstLetter(input: string): string {
|
|
19
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Convert snake_case to camelCase
|
|
24
|
+
* @param str
|
|
25
|
+
*/
|
|
26
|
+
export function convertToCamelCase(str: string): string {
|
|
27
|
+
str = str.charAt(0).toUpperCase() + str.slice(1);
|
|
28
|
+
let result = str.replace(/(_\w)/g, (match) => match[1].toUpperCase());
|
|
29
|
+
return result + "Data";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param name
|
|
35
|
+
* @param values
|
|
36
|
+
* @return [use name::name_schema, use name::info_schema]
|
|
37
|
+
*/
|
|
38
|
+
export function getUseSchema(
|
|
39
|
+
name: string,
|
|
40
|
+
values: Record<string, SchemaMapType>
|
|
41
|
+
): string[] {
|
|
42
|
+
let schema: string[] = [];
|
|
43
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
44
|
+
if (typeof value === "object" && value.ephemeral) {
|
|
45
|
+
} else {
|
|
46
|
+
schema.push(`\tuse ${name}::${key}_schema;`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return schema;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param values
|
|
54
|
+
* @return [ name_schema::register(&mut _obelisk_world, ctx) ,info_schema::register(&mut _obelisk_world, ctx) ]
|
|
55
|
+
*/
|
|
56
|
+
export function getRegisterSchema(
|
|
57
|
+
values: Record<string, SchemaMapType>
|
|
58
|
+
): string[] {
|
|
59
|
+
let registers: string[] = [];
|
|
60
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
61
|
+
if (typeof value === "object" && value.ephemeral) {
|
|
62
|
+
} else {
|
|
63
|
+
registers.push(`\t\t${key}_schema::register(&mut _obelisk_world, &admin_cap, ctx);`);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return registers;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
*
|
|
71
|
+
* @param name
|
|
72
|
+
* @param values
|
|
73
|
+
* @return [ friend name::name_system, friend name::info_system ]
|
|
74
|
+
*/
|
|
75
|
+
export function getFriendSystem(name: string, values: string[]): string {
|
|
76
|
+
return values.map((key) => `\tfriend ${name}::${key};`).join("\n") + `\n\tfriend ${name}::deploy_hook;`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @param values
|
|
82
|
+
* @param prefixArgs
|
|
83
|
+
* @return [ name, age, birth_time ]
|
|
84
|
+
*/
|
|
85
|
+
export function getStructAttrs(
|
|
86
|
+
values: Record<string, string> | string,
|
|
87
|
+
prefixArgs: string
|
|
88
|
+
): string[] {
|
|
89
|
+
return typeof values === "string"
|
|
90
|
+
? [`${prefixArgs}value`]
|
|
91
|
+
: Object.entries(values).map(([key, _]) => `${prefixArgs}${key}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isAddress(str: string): boolean {
|
|
95
|
+
const regex = /^0x[a-fA-F0-9]+$/;
|
|
96
|
+
return regex.test(str);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function getStructInitValue(
|
|
100
|
+
keys: BaseType | Record<string, BaseType>,
|
|
101
|
+
values: BaseValueType | Record<string, BaseValueType>
|
|
102
|
+
) {
|
|
103
|
+
if (
|
|
104
|
+
typeof values === "string" ||
|
|
105
|
+
typeof values === "boolean" ||
|
|
106
|
+
typeof values === "number"
|
|
107
|
+
) {
|
|
108
|
+
if (keys === "string") {
|
|
109
|
+
return [`string(b"${values}")`];
|
|
110
|
+
}
|
|
111
|
+
if (typeof values === "string") {
|
|
112
|
+
if (isAddress(values)) {
|
|
113
|
+
return [`@${values}`];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return [`${values}`];
|
|
117
|
+
} else if (Array.isArray(values)) {
|
|
118
|
+
// Check the array element type
|
|
119
|
+
if (values.length > 0) {
|
|
120
|
+
if (
|
|
121
|
+
typeof values[0] === "string" ||
|
|
122
|
+
typeof values[0] === "boolean" ||
|
|
123
|
+
typeof values[0] === "number"
|
|
124
|
+
) {
|
|
125
|
+
if (keys === "vector<string>") {
|
|
126
|
+
return [`vector[${values.map((item) => `string(b"${item}")`)}]`];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (typeof values[0] === "string") {
|
|
130
|
+
if (isAddress(values[0])) {
|
|
131
|
+
return [`vector[${values.map((item) => `@${item}`)}]`];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return [`vector[${values.map((item) => `${item}`)}]`];
|
|
135
|
+
} else if (typeof values === "object") {
|
|
136
|
+
let res = `vector[${values.map((item: any) => {
|
|
137
|
+
return `vector[${item.map((data: any) => {
|
|
138
|
+
return `${data}`;
|
|
139
|
+
})}]`;
|
|
140
|
+
})}]`;
|
|
141
|
+
|
|
142
|
+
return [res];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} else if (typeof values === "object") {
|
|
146
|
+
// It's an object, handle accordingly
|
|
147
|
+
let res = Object.entries(values).map(([key, value]) => {
|
|
148
|
+
if (
|
|
149
|
+
typeof value === "string" ||
|
|
150
|
+
typeof value === "boolean" ||
|
|
151
|
+
typeof value === "number"
|
|
152
|
+
) {
|
|
153
|
+
if (typeof keys === "string") {
|
|
154
|
+
if (keys === "string") {
|
|
155
|
+
return `string(b"${value}")`;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
if (keys[key] === "string") {
|
|
159
|
+
return `string(b"${value}")`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (typeof value === "string") {
|
|
164
|
+
if (isAddress(value)) {
|
|
165
|
+
return `@${value}`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return `${value}`;
|
|
169
|
+
} else if (Array.isArray(value)) {
|
|
170
|
+
// Check the array element type
|
|
171
|
+
if (value.length > 0) {
|
|
172
|
+
if (
|
|
173
|
+
typeof value[0] === "string" ||
|
|
174
|
+
typeof value[0] === "boolean" ||
|
|
175
|
+
typeof value[0] === "number"
|
|
176
|
+
) {
|
|
177
|
+
if (typeof keys === "string") {
|
|
178
|
+
if (keys === "vector<string>") {
|
|
179
|
+
return `vector[${value.map((item) => `string(b"${item}")`)}]`;
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
if (keys[key] === "vector<string>") {
|
|
183
|
+
return `vector[${value.map((item) => `string(b"${item}")`)}]`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (typeof value[0] === "string") {
|
|
188
|
+
if (isAddress(value[0])) {
|
|
189
|
+
return `vector[${value.map((item) => `@${item}`)}]`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return `vector[${value.map((item) => `${item}`)}]`;
|
|
193
|
+
} else if (typeof value === "object") {
|
|
194
|
+
let res = `vector[${value.map((item: any) => {
|
|
195
|
+
return `vector[${item.map((data: any) => {
|
|
196
|
+
return `${data}`;
|
|
197
|
+
})}]`;
|
|
198
|
+
})}]`;
|
|
199
|
+
|
|
200
|
+
return res;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return res;
|
|
206
|
+
}
|
|
207
|
+
// Handle other cases or return an empty array if type not recognized
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
*
|
|
213
|
+
* @param values
|
|
214
|
+
* @return ( bool , u64 , u64)
|
|
215
|
+
*/
|
|
216
|
+
// export function getStructTypes(values: SchemaMapType): string {
|
|
217
|
+
export function getStructTypes(
|
|
218
|
+
values: MoveType | Record<string, MoveType>
|
|
219
|
+
): string {
|
|
220
|
+
return typeof values === "string"
|
|
221
|
+
? values
|
|
222
|
+
: `(${Object.entries(values).map(([_, type]) => `${type}`)})`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
*
|
|
227
|
+
* @param values
|
|
228
|
+
* @return Attributes and types of the struct. [ name: string, age: u64 ]
|
|
229
|
+
*/
|
|
230
|
+
export function getStructAttrsWithType(
|
|
231
|
+
values: Record<string, string> | string,
|
|
232
|
+
prefix: string
|
|
233
|
+
): string[] {
|
|
234
|
+
return typeof values === "string"
|
|
235
|
+
? [`${prefix}value: ${values}`]
|
|
236
|
+
: Object.entries(values).map(([key, type]) => `${prefix}${key}: ${type}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @param values
|
|
241
|
+
* @param prefixArgs
|
|
242
|
+
* @return [ data.name, data.age ]
|
|
243
|
+
*/
|
|
244
|
+
export function getStructAttrsQuery(
|
|
245
|
+
values: MoveType | Record<string, MoveType>,
|
|
246
|
+
prefixArgs: string
|
|
247
|
+
): string[] {
|
|
248
|
+
return typeof values === "string"
|
|
249
|
+
? [`${prefixArgs}_obelisk_data.value`]
|
|
250
|
+
: Object.entries(values).map(
|
|
251
|
+
([key, _]) => `${prefixArgs}_obelisk_data.${key}`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function renderKeyName(values: Record<string, string> | string): string {
|
|
256
|
+
return `\t${getStructAttrs(values, "// ").join("\n\t")}`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function renderStruct(
|
|
260
|
+
structName: string,
|
|
261
|
+
values: Record<string, string> | string,
|
|
262
|
+
isEphemeral: boolean = false
|
|
263
|
+
): string {
|
|
264
|
+
return `\tstruct ${structName} has copy, drop ${
|
|
265
|
+
isEphemeral ? "" : ", store"
|
|
266
|
+
} {
|
|
267
|
+
${getStructAttrsWithType(values, "\t\t").join(",\n")}
|
|
268
|
+
\t}\n`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function renderNewStructFunc(
|
|
272
|
+
structName: string,
|
|
273
|
+
values: Record<string, string> | string
|
|
274
|
+
): string {
|
|
275
|
+
return `\tpublic fun new(${getStructAttrsWithType(values, "").join(
|
|
276
|
+
", "
|
|
277
|
+
)}): ${structName} {
|
|
278
|
+
\t\t${structName} {
|
|
279
|
+
${getStructAttrs(values, "\t\t\t").join(", \n")}
|
|
280
|
+
\t\t}
|
|
281
|
+
\t}\n`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function renderRegisterFunc(structName: string): string {
|
|
285
|
+
return `\tpublic fun register(_obelisk_world: &mut World, admin_cap: &AdminCap, ctx: &mut TxContext) {
|
|
286
|
+
\t\tworld::add_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID, table::new<address, ${structName}>(ctx), admin_cap);
|
|
287
|
+
\t}`;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function renderSetFunc(
|
|
291
|
+
structName: string,
|
|
292
|
+
values: Record<string, string> | string
|
|
293
|
+
): string {
|
|
294
|
+
return `\tpublic(friend) fun set(_obelisk_world: &mut World, _obelisk_entity_key: address, ${getStructAttrsWithType(
|
|
295
|
+
values,
|
|
296
|
+
" "
|
|
297
|
+
)}) {
|
|
298
|
+
\t\tlet _obelisk_schema = world::get_mut_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID);
|
|
299
|
+
\t\tlet _obelisk_data = new(${getStructAttrs(values, " ")});
|
|
300
|
+
\t\tif(table::contains<address, ${structName}>(_obelisk_schema, _obelisk_entity_key)) {
|
|
301
|
+
\t\t\t*table::borrow_mut<address, ${structName}>(_obelisk_schema, _obelisk_entity_key) = _obelisk_data;
|
|
302
|
+
\t\t} else {
|
|
303
|
+
\t\t\ttable::add(_obelisk_schema, _obelisk_entity_key, _obelisk_data);
|
|
304
|
+
\t\t};
|
|
305
|
+
\t\tevents::emit_set(SCHEMA_ID, SCHEMA_TYPE, some(_obelisk_entity_key), _obelisk_data)
|
|
306
|
+
\t}
|
|
307
|
+
`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function renderRemoveFunc(structName: string): string {
|
|
311
|
+
return `\tpublic(friend) fun remove(_obelisk_world: &mut World, _obelisk_entity_key: address) {
|
|
312
|
+
\t\tlet _obelisk_schema = world::get_mut_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID);
|
|
313
|
+
\t\tassert!(table::contains<address, ${structName}>(_obelisk_schema, _obelisk_entity_key), EEntityDoesNotExist);
|
|
314
|
+
\t\ttable::remove(_obelisk_schema, _obelisk_entity_key);
|
|
315
|
+
\t\tevents::emit_remove(SCHEMA_ID, _obelisk_entity_key)
|
|
316
|
+
\t}
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function renderSetAttrsFunc(
|
|
321
|
+
structName: string,
|
|
322
|
+
struct: MoveType | Record<string, MoveType>
|
|
323
|
+
): string {
|
|
324
|
+
return typeof struct === "string"
|
|
325
|
+
? ""
|
|
326
|
+
: "\n" +
|
|
327
|
+
Object.entries(struct)
|
|
328
|
+
.map(
|
|
329
|
+
([key, type]) =>
|
|
330
|
+
`\tpublic(friend) fun set_${key}(_obelisk_world: &mut World, _obelisk_entity_key: address, ${key}: ${type}) {
|
|
331
|
+
\t\tlet _obelisk_schema = world::get_mut_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID);
|
|
332
|
+
\t\tassert!(table::contains<address, ${structName}>(_obelisk_schema, _obelisk_entity_key), EEntityDoesNotExist);
|
|
333
|
+
\t\tlet _obelisk_data = table::borrow_mut<address, ${structName}>(_obelisk_schema, _obelisk_entity_key);
|
|
334
|
+
\t\t_obelisk_data.${key} = ${key};
|
|
335
|
+
\t\tevents::emit_set(SCHEMA_ID, SCHEMA_TYPE, some(_obelisk_entity_key), *_obelisk_data)
|
|
336
|
+
\t}
|
|
337
|
+
`
|
|
338
|
+
)
|
|
339
|
+
.join("\n");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export function renderGetAllFunc(
|
|
343
|
+
structName: string,
|
|
344
|
+
struct: MoveType | Record<string, MoveType>
|
|
345
|
+
): string {
|
|
346
|
+
return `\tpublic fun get(_obelisk_world: &World, _obelisk_entity_key: address): ${getStructTypes(
|
|
347
|
+
struct
|
|
348
|
+
)} {
|
|
349
|
+
\t\tlet _obelisk_schema = world::get_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID);
|
|
350
|
+
\t\tassert!(table::contains<address, ${structName}>(_obelisk_schema, _obelisk_entity_key), EEntityDoesNotExist);
|
|
351
|
+
\t\tlet _obelisk_data = table::borrow<address, ${structName}>(_obelisk_schema, _obelisk_entity_key);
|
|
352
|
+
\t\t(
|
|
353
|
+
${getStructAttrsQuery(struct, "\t\t\t").join(",\n")}
|
|
354
|
+
\t\t)
|
|
355
|
+
\t}
|
|
356
|
+
`;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function renderGetAttrsFunc(
|
|
360
|
+
structName: string,
|
|
361
|
+
struct: MoveType | Record<string, MoveType>
|
|
362
|
+
): string {
|
|
363
|
+
return typeof struct === "string"
|
|
364
|
+
? ""
|
|
365
|
+
: "\n" +
|
|
366
|
+
Object.entries(struct)
|
|
367
|
+
.map(
|
|
368
|
+
([
|
|
369
|
+
key,
|
|
370
|
+
type,
|
|
371
|
+
]) => `\tpublic fun get_${key}(_obelisk_world: &World, _obelisk_entity_key: address): ${type} {
|
|
372
|
+
\t\tlet _obelisk_schema = world::get_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID);
|
|
373
|
+
\t\tassert!(table::contains<address, ${structName}>(_obelisk_schema, _obelisk_entity_key), EEntityDoesNotExist);
|
|
374
|
+
\t\tlet _obelisk_data = table::borrow<address, ${structName}>(_obelisk_schema, _obelisk_entity_key);
|
|
375
|
+
\t\t_obelisk_data.${key}
|
|
376
|
+
\t}
|
|
377
|
+
`
|
|
378
|
+
)
|
|
379
|
+
.join("\n");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export function renderContainFunc(structName: string): string {
|
|
383
|
+
return `\tpublic fun contains(_obelisk_world: &World, _obelisk_entity_key: address): bool {
|
|
384
|
+
\t\tlet _obelisk_schema = world::get_schema<Table<address,${structName}>>(_obelisk_world, SCHEMA_ID);
|
|
385
|
+
\t\ttable::contains<address, ${structName}>(_obelisk_schema, _obelisk_entity_key)
|
|
386
|
+
\t}`;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function renderRegisterFuncWithInit(
|
|
390
|
+
structName: string,
|
|
391
|
+
valueType: BaseType | Record<string, BaseType>,
|
|
392
|
+
defaultValue: BaseValueType | Record<string, BaseValueType>
|
|
393
|
+
): string {
|
|
394
|
+
return `\tpublic fun register(_obelisk_world: &mut World, admin_cap: &AdminCap, _ctx: &mut TxContext) {
|
|
395
|
+
\t\tlet _obelisk_schema = new(${getStructInitValue(valueType, defaultValue)});
|
|
396
|
+
\t\tworld::add_schema<${structName}>(_obelisk_world, SCHEMA_ID, _obelisk_schema, admin_cap);
|
|
397
|
+
\t\tevents::emit_set(SCHEMA_ID, SCHEMA_TYPE, none(), _obelisk_schema);
|
|
398
|
+
\t}`;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function renderSingleSetFunc(
|
|
402
|
+
structName: string,
|
|
403
|
+
values: Record<string, string> | string
|
|
404
|
+
): string {
|
|
405
|
+
return `\tpublic(friend) fun set(_obelisk_world: &mut World, ${getStructAttrsWithType(
|
|
406
|
+
values,
|
|
407
|
+
" "
|
|
408
|
+
)}) {
|
|
409
|
+
\t\tlet _obelisk_schema = world::get_mut_schema<${structName}>(_obelisk_world, SCHEMA_ID);
|
|
410
|
+
${
|
|
411
|
+
typeof values === "string"
|
|
412
|
+
? `\t\t_obelisk_schema.value = value;`
|
|
413
|
+
: Object.entries(values)
|
|
414
|
+
.map(([key, _]) => `\t\t_obelisk_schema.${key} = ${key};`)
|
|
415
|
+
.join("\n")
|
|
416
|
+
}
|
|
417
|
+
\t}`;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export function renderSingleSetAttrsFunc(
|
|
421
|
+
structName: string,
|
|
422
|
+
struct: MoveType | Record<string, MoveType>
|
|
423
|
+
): string {
|
|
424
|
+
return typeof struct === "string"
|
|
425
|
+
? ""
|
|
426
|
+
: "\n" +
|
|
427
|
+
Object.entries(struct)
|
|
428
|
+
.map(
|
|
429
|
+
([key, type]) => `
|
|
430
|
+
\tpublic(friend) fun set_${key}(_obelisk_world: &mut World, ${key}: ${type}) {
|
|
431
|
+
\t\tlet _obelisk_schema = world::get_mut_schema<${structName}>(_obelisk_world, SCHEMA_ID);
|
|
432
|
+
\t\t_obelisk_schema.${key} = ${key};
|
|
433
|
+
\t\tevents::emit_set(SCHEMA_ID, SCHEMA_TYPE, none(), *_obelisk_schema)
|
|
434
|
+
\t}`
|
|
435
|
+
)
|
|
436
|
+
.join("\n");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export function renderSingleGetAllFunc(
|
|
440
|
+
structName: string,
|
|
441
|
+
values: MoveType | Record<string, MoveType>
|
|
442
|
+
): string {
|
|
443
|
+
return `\tpublic fun get(_obelisk_world: &World): ${getStructTypes(values)} {
|
|
444
|
+
\t\tlet _obelisk_schema = world::get_schema<${structName}>(_obelisk_world, SCHEMA_ID);
|
|
445
|
+
\t\t(
|
|
446
|
+
${
|
|
447
|
+
typeof values === "string"
|
|
448
|
+
? `\t\t\t_obelisk_schema.value`
|
|
449
|
+
: Object.entries(values)
|
|
450
|
+
.map(([key, _]) => `\t\t\t_obelisk_schema.${key},`)
|
|
451
|
+
.join("\n")
|
|
452
|
+
}
|
|
453
|
+
\t\t)
|
|
454
|
+
\t}`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function renderSingleGetAttrsFunc(
|
|
458
|
+
structName: string,
|
|
459
|
+
struct: MoveType | Record<string, MoveType>
|
|
460
|
+
): string {
|
|
461
|
+
return typeof struct === "string"
|
|
462
|
+
? ""
|
|
463
|
+
: "\n" +
|
|
464
|
+
Object.entries(struct)
|
|
465
|
+
.map(
|
|
466
|
+
([key, type]) => `
|
|
467
|
+
\tpublic fun get_${key}(_obelisk_world: &World): ${type} {
|
|
468
|
+
\t\tlet _obelisk_schema = world::get_schema<${structName}>(_obelisk_world, SCHEMA_ID);
|
|
469
|
+
\t\t_obelisk_schema.${key}
|
|
470
|
+
\t}`
|
|
471
|
+
)
|
|
472
|
+
.join("\n");
|
|
473
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ObeliskConfig } from "../../types";
|
|
2
|
+
import { formatAndWriteMove } from "../formatAndWrite";
|
|
3
|
+
|
|
4
|
+
export function generateEntityKey(config: ObeliskConfig, srcPrefix: string) {
|
|
5
|
+
let code = `module ${config.name}::entity_key {
|
|
6
|
+
use sui::hash::keccak256;
|
|
7
|
+
use sui::address;
|
|
8
|
+
use sui::object;
|
|
9
|
+
use std::vector;
|
|
10
|
+
|
|
11
|
+
public fun from_object<T: key + store>(object: &T): address {
|
|
12
|
+
object::id_address(object)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public fun from_bytes(bytes: vector<u8>): address {
|
|
16
|
+
address::from_bytes(keccak256(&bytes))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public fun from_u256(x: u256): address {
|
|
20
|
+
address::from_u256(x)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public fun from_address_with_seed(addr: address, seed: vector<u8>): address {
|
|
24
|
+
let data = address::to_bytes(addr);
|
|
25
|
+
vector::append(&mut data, seed);
|
|
26
|
+
from_bytes(data)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public fun from_address_with_u256(addr: address, x: u256): address {
|
|
30
|
+
let data = address::to_bytes(addr);
|
|
31
|
+
vector::append(&mut data, bcs::to_bytes<u256>(&x));
|
|
32
|
+
from_bytes(data)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public fun from_object_with_seed<T: key + store>(object: &T, seed: vector<u8>): address {
|
|
36
|
+
let data = address::to_bytes(object::id_address(object));
|
|
37
|
+
vector::append(&mut data, seed);
|
|
38
|
+
from_bytes(data)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public fun from_object_with_u256<T: key + store>(object: &T, x: u256): address {
|
|
42
|
+
let data = address::to_bytes(object::id_address(object));
|
|
43
|
+
vector::append(&mut data, bcs::to_bytes<u256>(&x));
|
|
44
|
+
from_bytes(data)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
formatAndWriteMove(
|
|
49
|
+
code,
|
|
50
|
+
`${srcPrefix}/contracts/${config.name}/sources/entity_key.move`,
|
|
51
|
+
"formatAndWriteMove"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { formatAndWriteMove } from "../formatAndWrite";
|
|
2
|
+
|
|
3
|
+
export function generateEps(
|
|
4
|
+
projectName: string,
|
|
5
|
+
srcPrefix: string,
|
|
6
|
+
version?: number
|
|
7
|
+
) {
|
|
8
|
+
generateWorld(projectName, srcPrefix, version);
|
|
9
|
+
generateEvents(projectName, srcPrefix);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function generateWorld(
|
|
13
|
+
projectName: string,
|
|
14
|
+
srcPrefix: string,
|
|
15
|
+
version?: number
|
|
16
|
+
) {
|
|
17
|
+
if (version === undefined) {
|
|
18
|
+
version = 1;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let code = `module ${projectName}::world {
|
|
22
|
+
use std::ascii::{String, string};
|
|
23
|
+
use std::vector;
|
|
24
|
+
use sui::tx_context::TxContext;
|
|
25
|
+
use sui::bag::{Self, Bag};
|
|
26
|
+
use sui::object::{Self, UID, ID};
|
|
27
|
+
|
|
28
|
+
const VERSION: u64 = ${version};
|
|
29
|
+
|
|
30
|
+
/// Schema does not exist
|
|
31
|
+
const ESchemaDoesNotExist: u64 = 0;
|
|
32
|
+
/// Schema already exists
|
|
33
|
+
const ESchemaAlreadyExists: u64 = 1;
|
|
34
|
+
/// Not the right admin for this world
|
|
35
|
+
const ENotAdmin: u64 = 2;
|
|
36
|
+
/// Migration is not an upgrade
|
|
37
|
+
const ENotUpgrade: u64 = 3;
|
|
38
|
+
/// Calling functions from the wrong package version
|
|
39
|
+
const EWrongVersion: u64 = 4;
|
|
40
|
+
|
|
41
|
+
struct AdminCap has key, store {
|
|
42
|
+
id: UID,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
struct World has key, store {
|
|
46
|
+
id: UID,
|
|
47
|
+
/// Name of the world
|
|
48
|
+
name: String,
|
|
49
|
+
/// Description of the world
|
|
50
|
+
description: String,
|
|
51
|
+
/// Schemas of the world
|
|
52
|
+
schemas: Bag,
|
|
53
|
+
/// Schema names of the world
|
|
54
|
+
schema_names: vector<String>,
|
|
55
|
+
/// admin of the world
|
|
56
|
+
admin: ID,
|
|
57
|
+
/// Version of the world
|
|
58
|
+
version: u64
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public fun create(name: String, description: String, ctx: &mut TxContext): (World, AdminCap) {
|
|
62
|
+
let admin_cap = AdminCap {
|
|
63
|
+
id: object::new(ctx),
|
|
64
|
+
};
|
|
65
|
+
let _obelisk_world = World {
|
|
66
|
+
id: object::new(ctx),
|
|
67
|
+
name,
|
|
68
|
+
description,
|
|
69
|
+
schemas: bag::new(ctx),
|
|
70
|
+
schema_names: vector::empty(),
|
|
71
|
+
admin: object::id(&admin_cap),
|
|
72
|
+
version: VERSION
|
|
73
|
+
};
|
|
74
|
+
(_obelisk_world, admin_cap)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public fun get_admin(_obelisk_world: &World): ID {
|
|
78
|
+
_obelisk_world.admin
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public fun info(_obelisk_world: &World): (String, String, u64) {
|
|
82
|
+
(_obelisk_world.name, _obelisk_world.description, _obelisk_world.version)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public fun schema_names(_obelisk_world: &World): vector<String> {
|
|
86
|
+
_obelisk_world.schema_names
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public fun get_schema<T : store>(_obelisk_world: &World, _obelisk_schema_id: vector<u8>): &T {
|
|
90
|
+
assert!(_obelisk_world.version == VERSION, EWrongVersion);
|
|
91
|
+
assert!(bag::contains(&_obelisk_world.schemas, _obelisk_schema_id), ESchemaDoesNotExist);
|
|
92
|
+
bag::borrow<vector<u8>, T>(&_obelisk_world.schemas, _obelisk_schema_id)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public fun get_mut_schema<T : store>(_obelisk_world: &mut World, _obelisk_schema_id: vector<u8>): &mut T {
|
|
96
|
+
assert!(_obelisk_world.version == VERSION, EWrongVersion);
|
|
97
|
+
assert!(bag::contains(&_obelisk_world.schemas, _obelisk_schema_id), ESchemaDoesNotExist);
|
|
98
|
+
bag::borrow_mut<vector<u8>, T>(&mut _obelisk_world.schemas, _obelisk_schema_id)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public fun add_schema<T : store>(_obelisk_world: &mut World, _obelisk_schema_id: vector<u8>, schema: T, admin_cap: &AdminCap){
|
|
102
|
+
assert!(_obelisk_world.admin == object::id(admin_cap), ENotAdmin);
|
|
103
|
+
assert!(_obelisk_world.version == VERSION, EWrongVersion);
|
|
104
|
+
assert!(!bag::contains(&_obelisk_world.schemas, _obelisk_schema_id), ESchemaAlreadyExists);
|
|
105
|
+
vector::push_back(&mut _obelisk_world.schema_names, string(_obelisk_schema_id));
|
|
106
|
+
bag::add<vector<u8>,T>(&mut _obelisk_world.schemas, _obelisk_schema_id, schema);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public fun contains(_obelisk_world: &mut World, _obelisk_schema_id: vector<u8>): bool {
|
|
110
|
+
assert!(_obelisk_world.version == VERSION, EWrongVersion);
|
|
111
|
+
bag::contains(&mut _obelisk_world.schemas, _obelisk_schema_id)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
entry fun migrate(_obelisk_world: &mut World, admin_cap: &AdminCap) {
|
|
115
|
+
assert!(_obelisk_world.admin == object::id(admin_cap), ENotAdmin);
|
|
116
|
+
assert!(_obelisk_world.version < VERSION, ENotUpgrade);
|
|
117
|
+
_obelisk_world.version = VERSION;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
formatAndWriteMove(
|
|
122
|
+
code,
|
|
123
|
+
`${srcPrefix}/contracts/${projectName}/sources/codegen/eps/world.move`,
|
|
124
|
+
"formatAndWriteMove"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function generateEvents(projectName: string, srcPrefix: string) {
|
|
129
|
+
let code = `module ${projectName}::events {
|
|
130
|
+
use sui::event;
|
|
131
|
+
use std::option::Option;
|
|
132
|
+
|
|
133
|
+
struct SchemaSetRecord<T: copy + drop> has copy, drop {
|
|
134
|
+
_obelisk_schema_id: vector<u8>,
|
|
135
|
+
_obelisk_schema_type: u8, // obelisk_schema_type_enum => { 0: common, 1: singleton, 2: ephemeral }
|
|
136
|
+
_obelisk_entity_key: Option<address>,
|
|
137
|
+
data: T
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
struct SchemaRemoveRecord has copy, drop {
|
|
141
|
+
_obelisk_schema_id: vector<u8>,
|
|
142
|
+
_obelisk_entity_key: address
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public fun emit_set<T: copy + drop>(_obelisk_schema_id: vector<u8>, _obelisk_schema_type: u8, _obelisk_entity_key: Option<address>, data: T) {
|
|
146
|
+
event::emit(SchemaSetRecord { _obelisk_schema_id, _obelisk_schema_type, _obelisk_entity_key, data})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public fun emit_remove(_obelisk_schema_id: vector<u8>, _obelisk_entity_key: address) {
|
|
150
|
+
event::emit(SchemaRemoveRecord { _obelisk_schema_id, _obelisk_entity_key })
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
formatAndWriteMove(
|
|
155
|
+
code,
|
|
156
|
+
`${srcPrefix}/contracts/${projectName}/sources/codegen/eps/events.move`,
|
|
157
|
+
"formatAndWriteMove"
|
|
158
|
+
);
|
|
159
|
+
}
|