@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.
@@ -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
+ }