@0xobelisk/sui-common 1.2.0-pre.99 → 2.0.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 +92 -0
- package/README.md +670 -1
- package/dist/index.d.ts +61 -27
- package/dist/index.js +1078 -461
- package/dist/index.js.map +1 -1
- package/package.json +15 -17
- package/src/codegen/debug.ts +0 -4
- package/src/codegen/types/index.ts +46 -10
- package/src/codegen/utils/config.ts +1 -1
- package/src/codegen/utils/format.ts +0 -6
- package/src/codegen/utils/formatAndWrite.ts +10 -31
- package/src/codegen/utils/generateLock.ts +122 -0
- package/src/codegen/utils/index.ts +4 -2
- package/src/codegen/utils/renderMove/{schemaGen.ts → codegen.ts} +40 -28
- package/src/codegen/utils/renderMove/common.ts +0 -65
- package/src/codegen/utils/renderMove/dapp.ts +2 -14
- package/src/codegen/utils/renderMove/generateDappKey.ts +33 -18
- package/src/codegen/utils/renderMove/generateError.ts +32 -15
- package/src/codegen/utils/renderMove/generateGenesis.ts +55 -22
- package/src/codegen/utils/renderMove/generateInitTest.ts +26 -14
- package/src/codegen/utils/renderMove/generateObjects.ts +377 -0
- package/src/codegen/utils/renderMove/generatePermits.ts +151 -0
- package/src/codegen/utils/renderMove/generateResources.ts +894 -242
- package/src/codegen/utils/renderMove/generateScenes.ts +467 -0
- package/src/codegen/utils/renderMove/generateScript.ts +18 -13
- package/src/codegen/utils/renderMove/generateSystem.ts +0 -2
- package/src/codegen/utils/renderMove/generateUserStorageInit.ts +37 -0
- package/src/codegen/utils/validateConfig.ts +237 -0
- package/src/index.ts +0 -1
- package/src/modules.d.ts +0 -10
- package/src/codegen/modules.d.ts +0 -1
- package/src/codegen/utils/posixPath.ts +0 -8
- package/src/codegen/utils/renderMove/generateComponents.ts +0 -802
- package/src/codegen/utils/renderMove/generateDefaultSchema.ts +0 -216
- package/src/codegen/utils/renderMove/generateEvent.ts +0 -99
- package/src/codegen/utils/renderMove/generateSchema.ts +0 -287
- package/src/codegen/utils/renderMove/generateSchemaHub.ts +0 -60
- package/src/parseData/index.ts +0 -1
- package/src/parseData/parser/index.ts +0 -47
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { DubheConfig, SceneConfig, Component } from '../../types';
|
|
2
|
+
import { formatAndWriteMove } from '../formatAndWrite';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
function toPascalCase(str: string): string {
|
|
6
|
+
return str
|
|
7
|
+
.split('_')
|
|
8
|
+
.map((word) => {
|
|
9
|
+
if (/^\d+$/.test(word)) return word;
|
|
10
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
11
|
+
})
|
|
12
|
+
.join('');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getMoveType(t: string): string {
|
|
16
|
+
return t === 'string' || t === 'String' ? 'String' : t;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function sceneStorageType(markerName: string): string {
|
|
20
|
+
return `dubhe::dapp_service::SceneStorage<${markerName}>`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function permitMarker(config: DubheConfig, cfg: SceneConfig): string | undefined {
|
|
24
|
+
if (cfg.authorization.kind !== 'permit') return undefined;
|
|
25
|
+
return `${config.name}::${cfg.authorization.permit}::${toPascalCase(cfg.authorization.permit)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function permitType(config: DubheConfig, cfg: SceneConfig): string | undefined {
|
|
29
|
+
if (cfg.authorization.kind !== 'permit') return undefined;
|
|
30
|
+
return `dubhe::dapp_service::ScenePermit<${permitMarker(config, cfg)}>`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function generateFieldAccessors(config: DubheConfig, sceneKey: string, cfg: SceneConfig): string {
|
|
34
|
+
const markerName = toPascalCase(sceneKey);
|
|
35
|
+
const storageType = sceneStorageType(markerName);
|
|
36
|
+
const permit = permitMarker(config, cfg);
|
|
37
|
+
const permitStorageType = permitType(config, cfg);
|
|
38
|
+
const lines: string[] = [];
|
|
39
|
+
|
|
40
|
+
for (const [fieldName, fieldType] of Object.entries(cfg.fields)) {
|
|
41
|
+
const moveType = getMoveType(fieldType as string);
|
|
42
|
+
|
|
43
|
+
if (cfg.authorization.kind === 'permit' && permit && permitStorageType) {
|
|
44
|
+
lines.push(`
|
|
45
|
+
public fun get_${fieldName}(storage: &${storageType}): ${moveType} {
|
|
46
|
+
dubhe::dapp_system::get_scene_field<${markerName}, ${moveType}>(storage, b"${fieldName}")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public(package) fun set_${fieldName}(
|
|
50
|
+
permit: &${permitStorageType},
|
|
51
|
+
storage: &mut ${storageType},
|
|
52
|
+
user_storage: &dubhe::dapp_service::UserStorage,
|
|
53
|
+
value: ${moveType},
|
|
54
|
+
ctx: &TxContext,
|
|
55
|
+
) {
|
|
56
|
+
dubhe::dapp_system::set_scene_field<DappKey, ${permit}, ${markerName}, ${moveType}>(
|
|
57
|
+
dapp_key::new(), permit, storage, user_storage, b"${fieldName}", value, ctx
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public(package) fun remove_${fieldName}_system_maintenance(storage: &mut ${storageType}): ${moveType} {
|
|
62
|
+
dubhe::dapp_system::remove_scene_field_system_maintenance<DappKey, ${markerName}, ${moveType}>(
|
|
63
|
+
dapp_key::new(), storage, b"${fieldName}"
|
|
64
|
+
)
|
|
65
|
+
}`);
|
|
66
|
+
} else {
|
|
67
|
+
lines.push(`
|
|
68
|
+
public fun get_${fieldName}(storage: &${storageType}): ${moveType} {
|
|
69
|
+
dubhe::dapp_system::get_scene_field<${markerName}, ${moveType}>(storage, b"${fieldName}")
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public(package) fun set_${fieldName}(storage: &mut ${storageType}, value: ${moveType}) {
|
|
73
|
+
dubhe::dapp_system::set_scene_field_system<DappKey, ${markerName}, ${moveType}>(
|
|
74
|
+
dapp_key::new(), storage, b"${fieldName}", value
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public(package) fun remove_${fieldName}(storage: &mut ${storageType}): ${moveType} {
|
|
79
|
+
dubhe::dapp_system::remove_scene_field_system_maintenance<DappKey, ${markerName}, ${moveType}>(
|
|
80
|
+
dapp_key::new(), storage, b"${fieldName}"
|
|
81
|
+
)
|
|
82
|
+
}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return lines.join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function writeArgs(config: DubheConfig, cfg: SceneConfig): string {
|
|
90
|
+
const type = permitType(config, cfg);
|
|
91
|
+
if (cfg.authorization.kind !== 'permit' || !type) return '';
|
|
92
|
+
return ` permit: &${type},\n`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/// Permit-authorized writes identify the caller by user_storage's canonical owner.
|
|
96
|
+
function userStorageArg(cfg: SceneConfig): string {
|
|
97
|
+
if (cfg.authorization.kind !== 'permit') return '';
|
|
98
|
+
return ` user_storage: &dubhe::dapp_service::UserStorage,\n`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function writeCtxArg(cfg: SceneConfig): string {
|
|
102
|
+
return cfg.authorization.kind === 'permit' ? ' ctx: &TxContext,\n' : '';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function setFieldCall(
|
|
106
|
+
config: DubheConfig,
|
|
107
|
+
cfg: SceneConfig,
|
|
108
|
+
markerName: string,
|
|
109
|
+
moveType: string,
|
|
110
|
+
fieldExpr: string,
|
|
111
|
+
valueExpr: string
|
|
112
|
+
): string {
|
|
113
|
+
const permit = permitMarker(config, cfg);
|
|
114
|
+
if (cfg.authorization.kind === 'permit' && permit) {
|
|
115
|
+
return `dubhe::dapp_system::set_scene_field<DappKey, ${permit}, ${markerName}, ${moveType}>(
|
|
116
|
+
dapp_key::new(), permit, storage, user_storage, ${fieldExpr}, ${valueExpr}, ctx
|
|
117
|
+
);`;
|
|
118
|
+
}
|
|
119
|
+
return `dubhe::dapp_system::set_scene_field_system<DappKey, ${markerName}, ${moveType}>(
|
|
120
|
+
dapp_key::new(), storage, ${fieldExpr}, ${valueExpr}
|
|
121
|
+
);`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function removeFieldCall(
|
|
125
|
+
config: DubheConfig,
|
|
126
|
+
cfg: SceneConfig,
|
|
127
|
+
markerName: string,
|
|
128
|
+
moveType: string,
|
|
129
|
+
fieldExpr: string
|
|
130
|
+
): string {
|
|
131
|
+
const permit = permitMarker(config, cfg);
|
|
132
|
+
if (cfg.authorization.kind === 'permit' && permit) {
|
|
133
|
+
return `dubhe::dapp_system::remove_scene_field<DappKey, ${permit}, ${markerName}, ${moveType}>(
|
|
134
|
+
dapp_key::new(), permit, storage, user_storage, ${fieldExpr}, ctx
|
|
135
|
+
)`;
|
|
136
|
+
}
|
|
137
|
+
return `dubhe::dapp_system::remove_scene_field_system_maintenance<DappKey, ${markerName}, ${moveType}>(
|
|
138
|
+
dapp_key::new(), storage, ${fieldExpr}
|
|
139
|
+
)`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function generateFungibleBagAccessors(
|
|
143
|
+
config: DubheConfig,
|
|
144
|
+
sceneKey: string,
|
|
145
|
+
cfg: SceneConfig,
|
|
146
|
+
resourceName: string
|
|
147
|
+
): string {
|
|
148
|
+
const markerName = toPascalCase(sceneKey);
|
|
149
|
+
const storageType = sceneStorageType(markerName);
|
|
150
|
+
|
|
151
|
+
return `
|
|
152
|
+
public fun get_${resourceName}(storage: &${storageType}): u64 {
|
|
153
|
+
if (dubhe::dapp_system::has_scene_field<${markerName}, u64>(storage, b"${resourceName}")) {
|
|
154
|
+
dubhe::dapp_system::get_scene_field<${markerName}, u64>(storage, b"${resourceName}")
|
|
155
|
+
} else { 0 }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public(package) fun add_${resourceName}(
|
|
159
|
+
${writeArgs(config, cfg)} storage: &mut ${storageType},
|
|
160
|
+
${userStorageArg(cfg)} amount: u64,
|
|
161
|
+
${writeCtxArg(cfg)} ) {
|
|
162
|
+
let current = get_${resourceName}(storage);
|
|
163
|
+
${setFieldCall(config, cfg, markerName, 'u64', `b"${resourceName}"`, 'current + amount')}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public(package) fun sub_${resourceName}(
|
|
167
|
+
${writeArgs(config, cfg)} storage: &mut ${storageType},
|
|
168
|
+
${userStorageArg(cfg)} amount: u64,
|
|
169
|
+
${writeCtxArg(cfg)} ) {
|
|
170
|
+
let current = get_${resourceName}(storage);
|
|
171
|
+
assert!(current >= amount, EInsufficientAmount);
|
|
172
|
+
${setFieldCall(config, cfg, markerName, 'u64', `b"${resourceName}"`, 'current - amount')}
|
|
173
|
+
}`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function generateKeyedBagAccessors(
|
|
177
|
+
config: DubheConfig,
|
|
178
|
+
sceneKey: string,
|
|
179
|
+
cfg: SceneConfig,
|
|
180
|
+
resourceName: string,
|
|
181
|
+
idField: string
|
|
182
|
+
): string {
|
|
183
|
+
const markerName = toPascalCase(sceneKey);
|
|
184
|
+
const storageType = sceneStorageType(markerName);
|
|
185
|
+
|
|
186
|
+
return `
|
|
187
|
+
public fun has_${resourceName}(storage: &${storageType}, ${idField}: u64): bool {
|
|
188
|
+
let key = sui::bcs::to_bytes(&${idField});
|
|
189
|
+
dubhe::dapp_system::has_scene_field<${markerName}, vector<u8>>(storage, key)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public fun get_${resourceName}_data(storage: &${storageType}, ${idField}: u64): vector<u8> {
|
|
193
|
+
let key = sui::bcs::to_bytes(&${idField});
|
|
194
|
+
dubhe::dapp_system::get_scene_field<${markerName}, vector<u8>>(storage, key)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public(package) fun set_${resourceName}_data(
|
|
198
|
+
${writeArgs(config, cfg)} storage: &mut ${storageType},
|
|
199
|
+
${userStorageArg(cfg)} ${idField}: u64,
|
|
200
|
+
data: vector<u8>,
|
|
201
|
+
${writeCtxArg(cfg)} ) {
|
|
202
|
+
let key = sui::bcs::to_bytes(&${idField});
|
|
203
|
+
assert!(!dubhe::dapp_system::has_scene_field<${markerName}, vector<u8>>(storage, key), EDuplicateItemId);
|
|
204
|
+
${setFieldCall(config, cfg, markerName, 'vector<u8>', 'key', 'data')}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public(package) fun remove_${resourceName}_data(
|
|
208
|
+
${writeArgs(config, cfg)} storage: &mut ${storageType},
|
|
209
|
+
${userStorageArg(cfg)} ${idField}: u64,
|
|
210
|
+
${writeCtxArg(cfg)} ): vector<u8> {
|
|
211
|
+
let key = sui::bcs::to_bytes(&${idField});
|
|
212
|
+
assert!(dubhe::dapp_system::has_scene_field<${markerName}, vector<u8>>(storage, key), EFieldNotFound);
|
|
213
|
+
${removeFieldCall(config, cfg, markerName, 'vector<u8>', 'key')}
|
|
214
|
+
}`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function generateAcceptsFromTransfers(
|
|
218
|
+
projectName: string,
|
|
219
|
+
destKey: string,
|
|
220
|
+
destCfg: SceneConfig,
|
|
221
|
+
destAccepts: string[],
|
|
222
|
+
acceptsFrom: string[],
|
|
223
|
+
config: DubheConfig
|
|
224
|
+
): { imports: string[]; functions: string[] } {
|
|
225
|
+
const resources = config.resources ?? {};
|
|
226
|
+
const allObjects = config.objects ?? {};
|
|
227
|
+
const allScenes = config.scenes ?? {};
|
|
228
|
+
const destMarker = toPascalCase(destKey);
|
|
229
|
+
const destStorageType = sceneStorageType(destMarker);
|
|
230
|
+
const imports: string[] = [];
|
|
231
|
+
const functions: string[] = [];
|
|
232
|
+
const destPermit = permitType(config, destCfg);
|
|
233
|
+
const destPermitArg =
|
|
234
|
+
destCfg.authorization.kind === 'permit' && destPermit
|
|
235
|
+
? ` dest_permit: &${destPermit},\n`
|
|
236
|
+
: '';
|
|
237
|
+
const destCallPrefix = destCfg.authorization.kind === 'permit' ? 'dest_permit, ' : '';
|
|
238
|
+
const destCtxCall = destCfg.authorization.kind === 'permit' ? ', ctx' : '';
|
|
239
|
+
|
|
240
|
+
for (const sourceName of acceptsFrom) {
|
|
241
|
+
const sourceCfg = allObjects[sourceName] ?? allScenes[sourceName];
|
|
242
|
+
if (!sourceCfg) continue;
|
|
243
|
+
|
|
244
|
+
const sourceAccepts = sourceCfg.accepts ?? [];
|
|
245
|
+
const sourceMarker = toPascalCase(sourceName);
|
|
246
|
+
imports.push(` use ${projectName}::${sourceName};`);
|
|
247
|
+
|
|
248
|
+
const isSourceScene = !!allScenes[sourceName];
|
|
249
|
+
const qualifiedSourceMarker = `${projectName}::${sourceName}::${sourceMarker}`;
|
|
250
|
+
const sourceStorageType = isSourceScene
|
|
251
|
+
? `dubhe::dapp_service::SceneStorage<${qualifiedSourceMarker}>`
|
|
252
|
+
: `dubhe::dapp_service::ObjectStorage<${qualifiedSourceMarker}>`;
|
|
253
|
+
const sceneSourceCfg = isSourceScene ? (sourceCfg as SceneConfig) : undefined;
|
|
254
|
+
const sourcePermit = sceneSourceCfg ? permitType(config, sceneSourceCfg) : undefined;
|
|
255
|
+
const sourceIsPermitScene = sceneSourceCfg?.authorization.kind === 'permit' && !!sourcePermit;
|
|
256
|
+
const sourcePermitArg = sourceIsPermitScene ? ` source_permit: &${sourcePermit},\n` : '';
|
|
257
|
+
const sourceCallPrefix = sourceIsPermitScene ? 'source_permit, ' : '';
|
|
258
|
+
const sourceUserStorageCall = sourceIsPermitScene ? 'user_storage, ' : '';
|
|
259
|
+
const sourceCtxCall = sourceIsPermitScene ? ', ctx' : '';
|
|
260
|
+
|
|
261
|
+
const destIsPermitScene = destCfg.authorization.kind === 'permit';
|
|
262
|
+
const destUserStorageCall = destIsPermitScene ? 'user_storage, ' : '';
|
|
263
|
+
// Permit-authorized writes resolve the caller identity from user_storage.
|
|
264
|
+
const userStorageParam =
|
|
265
|
+
sourceIsPermitScene || destIsPermitScene
|
|
266
|
+
? ` user_storage: &dubhe::dapp_service::UserStorage,\n`
|
|
267
|
+
: '';
|
|
268
|
+
const ctxParam =
|
|
269
|
+
sourceIsPermitScene || destIsPermitScene ? ' ctx: &TxContext,\n' : '';
|
|
270
|
+
|
|
271
|
+
const commonResources = sourceAccepts.filter((r) => destAccepts.includes(r));
|
|
272
|
+
for (const resourceName of commonResources) {
|
|
273
|
+
const resCfg = resources[resourceName];
|
|
274
|
+
if (!resCfg || typeof resCfg === 'string') continue;
|
|
275
|
+
const comp = resCfg as Component;
|
|
276
|
+
|
|
277
|
+
if (!comp.fungible && comp.keys?.length) {
|
|
278
|
+
const idField = comp.keys[0];
|
|
279
|
+
functions.push(`
|
|
280
|
+
public(package) fun transfer_${sourceName}_to_${destKey}_${resourceName}(
|
|
281
|
+
${sourcePermitArg}${destPermitArg} from: &mut ${sourceStorageType},
|
|
282
|
+
to: &mut ${destStorageType},
|
|
283
|
+
${userStorageParam} ${idField}: u64,
|
|
284
|
+
${ctxParam} ) {
|
|
285
|
+
let data = ${sourceName}::remove_${resourceName}_data(${sourceCallPrefix}from, ${sourceUserStorageCall}${idField}${sourceCtxCall});
|
|
286
|
+
set_${resourceName}_data(${destCallPrefix}to, ${destUserStorageCall}${idField}, data${destCtxCall});
|
|
287
|
+
}`);
|
|
288
|
+
} else {
|
|
289
|
+
functions.push(`
|
|
290
|
+
public(package) fun transfer_${sourceName}_to_${destKey}_${resourceName}(
|
|
291
|
+
${sourcePermitArg}${destPermitArg} from: &mut ${sourceStorageType},
|
|
292
|
+
to: &mut ${destStorageType},
|
|
293
|
+
${userStorageParam} amount: u64,
|
|
294
|
+
${ctxParam} ) {
|
|
295
|
+
${sourceName}::sub_${resourceName}(${sourceCallPrefix}from, ${sourceUserStorageCall}amount${sourceCtxCall});
|
|
296
|
+
add_${resourceName}(${destCallPrefix}to, ${destUserStorageCall}amount${destCtxCall});
|
|
297
|
+
}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return { imports, functions };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export async function generateScenes(config: DubheConfig, outputDir: string) {
|
|
306
|
+
if (!config.scenes || Object.keys(config.scenes).length === 0) return;
|
|
307
|
+
console.log('\n📦 Starting Scene Storage Generation...');
|
|
308
|
+
|
|
309
|
+
const projectName = config.name;
|
|
310
|
+
const resources = config.resources ?? {};
|
|
311
|
+
|
|
312
|
+
for (const [sceneKey, sceneCfg] of Object.entries(config.scenes)) {
|
|
313
|
+
console.log(` └─ ${sceneKey}`);
|
|
314
|
+
const markerName = toPascalCase(sceneKey);
|
|
315
|
+
const sceneTypeTag = `b"${sceneKey}"`;
|
|
316
|
+
const fullSceneType = sceneStorageType(markerName);
|
|
317
|
+
const fieldAccessors = generateFieldAccessors(config, sceneKey, sceneCfg);
|
|
318
|
+
const acceptedResources = sceneCfg.accepts ?? [];
|
|
319
|
+
|
|
320
|
+
const bagAccessorParts: string[] = [];
|
|
321
|
+
for (const resourceName of acceptedResources) {
|
|
322
|
+
const resCfg = resources[resourceName];
|
|
323
|
+
if (!resCfg || typeof resCfg === 'string') continue;
|
|
324
|
+
const comp = resCfg as Component;
|
|
325
|
+
if (!comp.fungible && comp.keys?.length) {
|
|
326
|
+
bagAccessorParts.push(
|
|
327
|
+
generateKeyedBagAccessors(config, sceneKey, sceneCfg, resourceName, comp.keys[0])
|
|
328
|
+
);
|
|
329
|
+
} else {
|
|
330
|
+
bagAccessorParts.push(
|
|
331
|
+
generateFungibleBagAccessors(config, sceneKey, sceneCfg, resourceName)
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const { imports: afImports, functions: afFunctions } = generateAcceptsFromTransfers(
|
|
337
|
+
projectName,
|
|
338
|
+
sceneKey,
|
|
339
|
+
sceneCfg,
|
|
340
|
+
acceptedResources,
|
|
341
|
+
sceneCfg.acceptsFrom ?? [],
|
|
342
|
+
config
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const sceneFieldTypes = Object.values(sceneCfg.fields) as string[];
|
|
346
|
+
const sceneNeedsStringImport = sceneFieldTypes.some(
|
|
347
|
+
(t) => t === 'string' || t === 'String' || t === 'vector<String>'
|
|
348
|
+
);
|
|
349
|
+
const sceneStringImport = sceneNeedsStringImport ? `\n use std::ascii::String;` : '';
|
|
350
|
+
|
|
351
|
+
const hasKeyedBagAccessors = acceptedResources.some((resourceName) => {
|
|
352
|
+
const resCfg = resources[resourceName];
|
|
353
|
+
if (!resCfg || typeof resCfg === 'string') return false;
|
|
354
|
+
return !!(resCfg as Component).keys?.length && !(resCfg as Component).fungible;
|
|
355
|
+
});
|
|
356
|
+
const hasFungibleBagAccessors = acceptedResources.some((resourceName) => {
|
|
357
|
+
const resCfg = resources[resourceName];
|
|
358
|
+
if (!resCfg || typeof resCfg === 'string') return false;
|
|
359
|
+
return !!(resCfg as Component).fungible;
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const errorConstants = [
|
|
363
|
+
hasKeyedBagAccessors
|
|
364
|
+
? ` #[error]\n const EFieldNotFound: vector<u8> = b"Field not found";`
|
|
365
|
+
: '',
|
|
366
|
+
hasFungibleBagAccessors
|
|
367
|
+
? ` #[error]\n const EInsufficientAmount: vector<u8> = b"Insufficient amount";`
|
|
368
|
+
: '',
|
|
369
|
+
hasKeyedBagAccessors
|
|
370
|
+
? ` #[error]\n const EDuplicateItemId: vector<u8> = b"Duplicate item id";`
|
|
371
|
+
: ''
|
|
372
|
+
]
|
|
373
|
+
.filter(Boolean)
|
|
374
|
+
.join('\n');
|
|
375
|
+
const errorBlock =
|
|
376
|
+
errorConstants.length > 0
|
|
377
|
+
? `\n // ─── Error constants ───────────────────────────────────────────────────\n${errorConstants}\n`
|
|
378
|
+
: '';
|
|
379
|
+
|
|
380
|
+
const afImportBlock = afImports.length > 0 ? '\n' + afImports.join('\n') : '';
|
|
381
|
+
const permit = permitType(config, sceneCfg);
|
|
382
|
+
const createFns =
|
|
383
|
+
sceneCfg.authorization.kind === 'permit' && permit
|
|
384
|
+
? `
|
|
385
|
+
public(package) fun new_${sceneKey}_with_permit(
|
|
386
|
+
dapp_storage: &DappStorage,
|
|
387
|
+
permit: &${permit},
|
|
388
|
+
ctx: &mut TxContext,
|
|
389
|
+
): ${fullSceneType} {
|
|
390
|
+
dubhe::dapp_system::new_typed_scene_with_permit<DappKey, ${permitMarker(
|
|
391
|
+
config,
|
|
392
|
+
sceneCfg
|
|
393
|
+
)}, ${markerName}>(
|
|
394
|
+
dapp_key::new(), dapp_storage, permit, SCENE_TYPE, ctx
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
public(package) fun create_${sceneKey}_with_permit(
|
|
399
|
+
dapp_storage: &DappStorage,
|
|
400
|
+
permit: &${permit},
|
|
401
|
+
ctx: &mut TxContext,
|
|
402
|
+
) {
|
|
403
|
+
dubhe::dapp_system::create_and_share_typed_scene_with_permit<DappKey, ${permitMarker(
|
|
404
|
+
config,
|
|
405
|
+
sceneCfg
|
|
406
|
+
)}, ${markerName}>(
|
|
407
|
+
dapp_key::new(), dapp_storage, permit, SCENE_TYPE, ctx
|
|
408
|
+
);
|
|
409
|
+
}`
|
|
410
|
+
: `
|
|
411
|
+
public(package) fun new_${sceneKey}_system(
|
|
412
|
+
dapp_storage: &DappStorage,
|
|
413
|
+
ctx: &mut TxContext,
|
|
414
|
+
): ${fullSceneType} {
|
|
415
|
+
dubhe::dapp_system::new_typed_scene_system<DappKey, ${markerName}>(
|
|
416
|
+
dapp_key::new(), dapp_storage, SCENE_TYPE, ctx
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
public(package) fun create_${sceneKey}_system(
|
|
421
|
+
dapp_storage: &DappStorage,
|
|
422
|
+
ctx: &mut TxContext,
|
|
423
|
+
) {
|
|
424
|
+
dubhe::dapp_system::create_and_share_typed_scene_system<DappKey, ${markerName}>(
|
|
425
|
+
dapp_key::new(), dapp_storage, SCENE_TYPE, ctx
|
|
426
|
+
);
|
|
427
|
+
}`;
|
|
428
|
+
|
|
429
|
+
const code = `module ${projectName}::${sceneKey} {
|
|
430
|
+
use dubhe::dapp_service::DappStorage;
|
|
431
|
+
use ${projectName}::dapp_key;
|
|
432
|
+
use ${projectName}::dapp_key::DappKey;${sceneStringImport}${afImportBlock}
|
|
433
|
+
${errorBlock}
|
|
434
|
+
const SCENE_TYPE: vector<u8> = ${sceneTypeTag};
|
|
435
|
+
|
|
436
|
+
/// Phantom type that distinguishes this scene storage at compile time.
|
|
437
|
+
public struct ${markerName} has copy, drop {}
|
|
438
|
+
|
|
439
|
+
// ─── Field accessors (own fields) ──────────────────────────────────────
|
|
440
|
+
${fieldAccessors}
|
|
441
|
+
|
|
442
|
+
// ─── Bag accessors for accepted resources ─────────────────────────────
|
|
443
|
+
${bagAccessorParts.join('\n')}
|
|
444
|
+
|
|
445
|
+
// ─── acceptsFrom: cross-storage transfer functions ─────────────────────
|
|
446
|
+
${afFunctions.join('\n')}
|
|
447
|
+
|
|
448
|
+
// ─── SceneStorage lifecycle wrappers ──────────────────────────────────
|
|
449
|
+
${createFns}
|
|
450
|
+
|
|
451
|
+
public(package) fun share_${sceneKey}(storage: ${fullSceneType}) {
|
|
452
|
+
dubhe::dapp_system::share_scene_storage<DappKey, ${markerName}>(
|
|
453
|
+
dapp_key::new(), storage
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
public(package) fun destroy_${sceneKey}(storage: ${fullSceneType}) {
|
|
458
|
+
dubhe::dapp_system::destroy_typed_scene<DappKey, ${markerName}>(
|
|
459
|
+
dapp_key::new(), storage
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
`;
|
|
464
|
+
|
|
465
|
+
await formatAndWriteMove(code, path.join(outputDir, `${sceneKey}.move`), 'formatAndWriteMove');
|
|
466
|
+
}
|
|
467
|
+
}
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { DubheConfig } from '../../types';
|
|
2
2
|
import { formatAndWriteMove } from '../formatAndWrite';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
|
-
// import { capitalizeAndRemoveUnderscores } from // Unused './generateSchema';
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export async function generateDeployHook(config: DubheConfig, path: string) {
|
|
5
|
+
export async function generateDeployHook(
|
|
6
|
+
config: DubheConfig,
|
|
7
|
+
path: string,
|
|
8
|
+
initialMode: 0 | 1 = 1
|
|
9
|
+
) {
|
|
14
10
|
if (!existsSync(path)) {
|
|
15
|
-
const
|
|
16
|
-
|
|
11
|
+
const modeComment =
|
|
12
|
+
initialMode === 1
|
|
13
|
+
? `// Settlement mode: USER_PAYS — users pay transaction fees at settlement time.
|
|
14
|
+
// The framework admin sets the revenue share via set_dapp_revenue_share.
|
|
15
|
+
// Initialise any DappStorage-level defaults here (e.g. resource starting values).`
|
|
16
|
+
: `// Settlement mode: DAPP_SUBSIDIZES — the DApp pays for user operations.
|
|
17
|
+
// Recharge the credit pool via dapp_system::recharge_credit before users can write.
|
|
18
|
+
// Initialise any DappStorage-level defaults here (e.g. resource starting values).`;
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
const code = `module ${config.name}::deploy_hook {
|
|
21
|
+
use dubhe::dapp_service::DappStorage;
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
public(package) fun run(_dapp_storage: &mut DappStorage, _ctx: &mut TxContext) {
|
|
24
|
+
${modeComment}
|
|
25
|
+
}
|
|
21
26
|
}`;
|
|
22
27
|
await formatAndWriteMove(code, path, 'formatAndWriteMove');
|
|
23
28
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { DubheConfig } from '../../types';
|
|
2
|
-
// import { formatAndWriteMove } from // Unused '../formatAndWrite';
|
|
3
2
|
import { existsSync } from 'fs';
|
|
4
3
|
import fs from 'node:fs/promises';
|
|
5
|
-
// import path from // Unused 'node:path';
|
|
6
4
|
|
|
7
5
|
export async function generateSystemsAndTests(config: DubheConfig, srcPrefix: string) {
|
|
8
6
|
if (!existsSync(`${srcPrefix}/src/${config.name}/sources/systems`)) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DubheConfig } from '../../types';
|
|
2
|
+
import { formatAndWriteMove } from '../formatAndWrite';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generates a `user_storage_init.move` module that provides a single entry-point
|
|
6
|
+
* for end-users to create their `UserStorage` object for the DApp.
|
|
7
|
+
*
|
|
8
|
+
* Only generated for non-dubhe packages; the dubhe framework manages its own
|
|
9
|
+
* internal UserStorage creation through dapp_system::create_user_storage.
|
|
10
|
+
*/
|
|
11
|
+
export async function generateUserStorageInit(config: DubheConfig, path: string) {
|
|
12
|
+
if (config.name === 'dubhe') return;
|
|
13
|
+
|
|
14
|
+
const code = `module ${config.name}::user_storage_init {
|
|
15
|
+
use dubhe::dapp_service::{DappHub, DappStorage};
|
|
16
|
+
use dubhe::dapp_system;
|
|
17
|
+
use ${config.name}::dapp_key;
|
|
18
|
+
use ${config.name}::dapp_key::DappKey;
|
|
19
|
+
use ${config.name}::migrate;
|
|
20
|
+
|
|
21
|
+
/// Create a UserStorage for the transaction sender within this DApp.
|
|
22
|
+
/// Must be called once before the user can interact with any user-level resources.
|
|
23
|
+
/// Aborts if the DApp version does not match this package, the DApp is paused,
|
|
24
|
+
/// or the framework version has advanced.
|
|
25
|
+
#[allow(lint(public_entry))]
|
|
26
|
+
public entry fun init_user_storage(
|
|
27
|
+
dapp_hub: &DappHub,
|
|
28
|
+
dapp_storage: &mut DappStorage,
|
|
29
|
+
ctx: &mut TxContext,
|
|
30
|
+
) {
|
|
31
|
+
dapp_system::ensure_latest_version<DappKey>(dapp_storage, migrate::on_chain_version());
|
|
32
|
+
dapp_system::create_user_storage(dapp_key::new(), dapp_hub, dapp_storage, ctx);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
await formatAndWriteMove(code, path, 'formatAndWriteMove');
|
|
37
|
+
}
|