@0xobelisk/sui-cli 1.2.0-pre.11 → 1.2.0-pre.110

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.
Files changed (38) hide show
  1. package/README.md +3 -3
  2. package/dist/dubhe.js +126 -49
  3. package/dist/dubhe.js.map +1 -1
  4. package/package.json +31 -19
  5. package/src/commands/build.ts +47 -16
  6. package/src/commands/call.ts +83 -83
  7. package/src/commands/checkBalance.ts +12 -5
  8. package/src/commands/configStore.ts +12 -4
  9. package/src/commands/convertJson.ts +70 -0
  10. package/src/commands/doctor.ts +1515 -0
  11. package/src/commands/faucet.ts +11 -7
  12. package/src/commands/generateKey.ts +3 -2
  13. package/src/commands/index.ts +16 -7
  14. package/src/commands/info.ts +55 -0
  15. package/src/commands/loadMetadata.ts +57 -0
  16. package/src/commands/localnode.ts +22 -6
  17. package/src/commands/publish.ts +21 -7
  18. package/src/commands/query.ts +101 -101
  19. package/src/commands/schemagen.ts +15 -4
  20. package/src/commands/shell.ts +198 -0
  21. package/src/commands/switchEnv.ts +26 -0
  22. package/src/commands/test.ts +54 -11
  23. package/src/commands/upgrade.ts +11 -4
  24. package/src/commands/wait.ts +333 -22
  25. package/src/commands/watch.ts +2 -1
  26. package/src/dubhe.ts +12 -4
  27. package/src/utils/axios-downloader.ts +116 -0
  28. package/src/utils/callHandler.ts +118 -118
  29. package/src/utils/constants.ts +5 -0
  30. package/src/utils/generateAccount.ts +1 -1
  31. package/src/utils/index.ts +4 -3
  32. package/src/utils/metadataHandler.ts +16 -0
  33. package/src/utils/publishHandler.ts +330 -293
  34. package/src/utils/queryStorage.ts +141 -141
  35. package/src/utils/startNode.ts +115 -16
  36. package/src/utils/storeConfig.ts +6 -12
  37. package/src/utils/upgradeHandler.ts +147 -86
  38. package/src/utils/utils.ts +771 -55
@@ -7,48 +7,29 @@ import {
7
7
  getVersion,
8
8
  getUpgradeCap,
9
9
  saveContractData,
10
- getOnchainSchemas,
11
10
  switchEnv,
12
- getSchemaId,
13
- initializeDubhe
11
+ initializeDubhe,
12
+ getOnchainResources,
13
+ getOnchainComponents,
14
+ getStartCheckpoint,
15
+ updateGenesisUpgradeFunction,
16
+ getDubheDappHub,
17
+ updatePublishedToml,
18
+ clearPublishedTomlEntry,
19
+ restorePublishedTomlEntry,
20
+ readPublishedToml,
21
+ updateEphemeralPubFile,
22
+ getEphemeralPubFilePath
14
23
  } from './utils';
15
24
  import * as fs from 'fs';
16
25
  import * as path from 'path';
17
26
  import { DubheConfig } from '@0xobelisk/sui-common';
18
27
 
19
28
  type Migration = {
20
- schemaName: string;
21
- fields: string;
29
+ name: string;
30
+ fields: any;
22
31
  };
23
32
 
24
- function updateMigrateMethod(projectPath: string, migrations: Migration[]): void {
25
- let filePath = `${projectPath}/sources/codegen/core/schema.move`;
26
- const fileContent = fs.readFileSync(filePath, 'utf-8');
27
- const migrateMethodRegex = new RegExp(
28
- `public fun migrate\\(_schema: &mut Schema, _ctx: &mut TxContext\\) {[^}]*}`
29
- );
30
- const newMigrateMethod = `
31
- public fun migrate(_schema: &mut Schema, _ctx: &mut TxContext) {
32
- ${migrations
33
- .map((migration) => {
34
- let storage_type = '';
35
- if (migration.fields.includes('StorageValue')) {
36
- storage_type = `storage_value::new(b"${migration.schemaName}", _ctx)`;
37
- } else if (migration.fields.includes('StorageMap')) {
38
- storage_type = `storage_map::new(b"${migration.schemaName}", _ctx)`;
39
- } else if (migration.fields.includes('StorageDoubleMap')) {
40
- storage_type = `storage_double_map::new(b"${migration.schemaName}", _ctx)`;
41
- }
42
- return `storage::add_field<${migration.fields}>(&mut _schema.id, b"${migration.schemaName}", ${storage_type});`;
43
- })
44
- .join('')}
45
- }
46
- `;
47
-
48
- const updatedContent = fileContent.replace(migrateMethodRegex, newMigrateMethod);
49
- fs.writeFileSync(filePath, updatedContent, 'utf-8');
50
- }
51
-
52
33
  function replaceEnvField(
53
34
  filePath: string,
54
35
  networkType: 'mainnet' | 'testnet' | 'devnet' | 'localnet',
@@ -88,6 +69,7 @@ function replaceEnvField(
88
69
 
89
70
  return previousValue;
90
71
  }
72
+
91
73
  export async function upgradeHandler(
92
74
  config: DubheConfig,
93
75
  name: string,
@@ -96,16 +78,38 @@ export async function upgradeHandler(
96
78
  await switchEnv(network);
97
79
 
98
80
  const path = process.cwd();
99
- const projectPath = `${path}/contracts/${name}`;
81
+ const projectPath = `${path}/src/${name}`;
100
82
 
101
- const dubhe = initializeDubhe({
102
- network
103
- });
83
+ const dubhe = initializeDubhe({ network });
104
84
 
105
85
  let oldVersion = Number(await getVersion(projectPath, network));
106
86
  let oldPackageId = await getOldPackageId(projectPath, network);
107
87
  let upgradeCap = await getUpgradeCap(projectPath, network);
108
- let schemaId = await getSchemaId(projectPath, network);
88
+ let startCheckpoint = await getStartCheckpoint(projectPath, network);
89
+ let dappHub = await getDubheDappHub(network);
90
+ let onchainResources = await getOnchainResources(projectPath, network);
91
+ let onchainComponents = await getOnchainComponents(projectPath, network);
92
+
93
+ let pendingMigration: Migration[] = [];
94
+ Object.entries(config.resources).forEach(([key, value]) => {
95
+ if (!onchainResources.hasOwnProperty(key)) {
96
+ pendingMigration.push({ name: key, fields: value });
97
+ }
98
+ });
99
+ Object.entries(config.components).forEach(([key, value]) => {
100
+ if (!onchainComponents.hasOwnProperty(key)) {
101
+ pendingMigration.push({ name: key, fields: value });
102
+ }
103
+ });
104
+
105
+ const tables = pendingMigration.map((migration) => migration.name);
106
+ // Only update genesis.move when there are new tables to register.
107
+ // When tables is empty, there are no schema changes so no migration needed.
108
+ // Note: updating genesis.move also requires separator comments inserted by
109
+ // `dubhe schemagen`; if they are missing, the update will throw.
110
+ if (tables.length > 0) {
111
+ updateGenesisUpgradeFunction(projectPath, tables);
112
+ }
109
113
 
110
114
  const original_published_id = replaceEnvField(
111
115
  `${projectPath}/Move.lock`,
@@ -114,33 +118,62 @@ export async function upgradeHandler(
114
118
  '0x0000000000000000000000000000000000000000000000000000000000000000'
115
119
  );
116
120
 
117
- let pendingMigration: Migration[] = [];
118
- let schemas = await getOnchainSchemas(projectPath, network);
119
- Object.entries(config.schemas).forEach(([key, value]) => {
120
- if (!schemas.hasOwnProperty(key)) {
121
- pendingMigration.push({ schemaName: key, fields: value });
121
+ // For persistent networks (testnet/mainnet): zero out Published.toml so the
122
+ // package compiles with address 0x0 for upgrade.
123
+ // For localnet: we use --build-env testnet + Pub.localnet.toml, so Published.toml
124
+ // is not consulted during the build and does not need to be cleared.
125
+ const savedPublishedEntry =
126
+ network !== 'localnet' ? clearPublishedTomlEntry(projectPath, network) : undefined;
127
+
128
+ // For localnet upgrades: refresh Pub.localnet.toml with dubhe's current address
129
+ // so that the build can resolve the dubhe dependency.
130
+ const cwd = process.cwd();
131
+ if (network === 'localnet') {
132
+ const dubheProjectPath = `${cwd}/src/dubhe`;
133
+ const dubheEntries = readPublishedToml(dubheProjectPath);
134
+ const dubheEntry = dubheEntries['localnet'];
135
+ if (dubheEntry) {
136
+ const pubfilePath = getEphemeralPubFilePath(cwd, network);
137
+ const dubheUpgradeCap = await getUpgradeCap(dubheProjectPath, network).catch(() => '');
138
+ updateEphemeralPubFile(pubfilePath, dubheEntry.chainId, 'testnet', {
139
+ source: dubheProjectPath,
140
+ publishedAt: dubheEntry.publishedAt,
141
+ originalId: dubheEntry.originalId,
142
+ upgradeCap: dubheUpgradeCap
143
+ });
122
144
  }
123
- });
124
- updateMigrateMethod(projectPath, pendingMigration);
145
+ }
125
146
 
126
147
  try {
127
148
  let modules: any, dependencies: any, digest: any;
128
149
  try {
150
+ // For localnet: use --build-env testnet --pubfile-path Pub.localnet.toml
151
+ // so the package compiles with address 0x0 (not in pubfile) and links
152
+ // against the already-published dubhe dependency (from pubfile).
153
+ // For testnet/mainnet: use -e <network> as usual.
154
+ let buildCmd: string;
155
+ if (network === 'localnet') {
156
+ const pubfilePath = getEphemeralPubFilePath(cwd, network);
157
+ buildCmd = `sui move build --dump-bytecode-as-base64 --no-tree-shaking --build-env testnet --pubfile-path ${pubfilePath} --path ${path}/src/${name}`;
158
+ } else {
159
+ buildCmd = `sui move build --dump-bytecode-as-base64 --no-tree-shaking -e ${network} --path ${path}/src/${name}`;
160
+ }
161
+
129
162
  const {
130
163
  modules: extractedModules,
131
164
  dependencies: extractedDependencies,
132
165
  digest: extractedDigest
133
- } = JSON.parse(
134
- execSync(`sui move build --dump-bytecode-as-base64 --path ${path}/contracts/${name}`, {
135
- encoding: 'utf-8'
136
- })
137
- );
166
+ } = JSON.parse(execSync(buildCmd, { encoding: 'utf-8', stdio: 'pipe' }));
138
167
 
139
168
  modules = extractedModules;
140
169
  dependencies = extractedDependencies;
141
170
  digest = extractedDigest;
142
171
  } catch (error: any) {
143
- throw new UpgradeError(error.stdout);
172
+ // Restore Published.toml before throwing (only for persistent networks)
173
+ if (savedPublishedEntry) {
174
+ restorePublishedTomlEntry(projectPath, network, savedPublishedEntry);
175
+ }
176
+ throw new UpgradeError(error.stdout || error.stderr || error.message);
144
177
  }
145
178
 
146
179
  console.log('\nšŸš€ Starting Upgrade Process...');
@@ -199,51 +232,79 @@ export async function upgradeHandler(
199
232
  replaceEnvField(`${projectPath}/Move.lock`, network, 'latest-published-id', newPackageId);
200
233
  replaceEnvField(`${projectPath}/Move.lock`, network, 'published-version', oldVersion + 1 + '');
201
234
 
235
+ // Update Published.toml with the new package ID after upgrade.
236
+ // For localnet: savedPublishedEntry is undefined (we skip clearPublishedTomlEntry),
237
+ // so fall back to reading the current Published.toml entry for chainId/originalId.
238
+ const existingEntry = readPublishedToml(projectPath)[network];
239
+ const chainId = savedPublishedEntry?.chainId ?? existingEntry?.chainId ?? '';
240
+ updatePublishedToml(
241
+ projectPath,
242
+ network,
243
+ chainId,
244
+ newPackageId,
245
+ savedPublishedEntry?.originalId ?? existingEntry?.originalId ?? original_published_id,
246
+ oldVersion + 1
247
+ );
248
+
202
249
  saveContractData(
203
250
  name,
204
251
  network,
252
+ startCheckpoint,
205
253
  newPackageId,
206
- schemaId,
254
+ dappHub,
207
255
  upgradeCap,
208
256
  oldVersion + 1,
209
- config.schemas
257
+ config.components,
258
+ config.resources,
259
+ config.enums
210
260
  );
211
261
 
212
- console.log(`\nšŸš€ Starting Migration Process...`);
213
- pendingMigration.forEach((migration) => {
214
- console.log('šŸ“‹ Added Fields:', JSON.stringify(migration, null, 2));
215
- });
216
- await new Promise((resolve) => setTimeout(resolve, 5000));
217
-
218
- const migrateTx = new Transaction();
219
- const newVersion = oldVersion + 1;
220
- let args = [];
221
- if (name !== 'dubhe') {
222
- let dubheSchemaId = await getSchemaId(`${process.cwd()}/contracts/dubhe-framework`, network);
223
- args.push(migrateTx.object(dubheSchemaId));
224
- }
225
- args.push(migrateTx.object(schemaId));
226
- args.push(migrateTx.pure.address(newPackageId));
227
- args.push(migrateTx.pure.u32(newVersion));
228
- migrateTx.moveCall({
229
- target: `${newPackageId}::${name}_migrate::migrate_to_v${newVersion}`,
230
- arguments: args
231
- });
262
+ // Only run the migration transaction if there are pending schema changes.
263
+ // A "bug-fix" upgrade with no new fields does not need a migration call.
264
+ // The migrate_to_vX function is only generated by `dubhe schemagen` when
265
+ // new components / resources are added.
266
+ if (pendingMigration.length > 0) {
267
+ console.log(`\nšŸš€ Starting Migration Process...`);
268
+ pendingMigration.forEach((migration) => {
269
+ console.log('šŸ“‹ Added Fields:', JSON.stringify(migration, null, 2));
270
+ });
271
+ await new Promise((resolve) => setTimeout(resolve, 5000));
232
272
 
233
- await dubhe.signAndSendTxn({
234
- tx: migrateTx,
235
- onSuccess: (result) => {
236
- console.log(chalk.green(`Migration Transaction Digest: ${result.digest}`));
237
- },
238
- onError: (error) => {
239
- console.log(
240
- chalk.red('Migration Transaction failed!, Please execute the migration manually.')
241
- );
242
- console.error(error);
243
- }
244
- });
273
+ const migrateTx = new Transaction();
274
+ const newVersion = oldVersion + 1;
275
+ migrateTx.moveCall({
276
+ target: `${newPackageId}::migrate::migrate_to_v${newVersion}`,
277
+ arguments: [
278
+ migrateTx.object(dappHub),
279
+ migrateTx.pure.address(newPackageId),
280
+ migrateTx.pure.u32(newVersion)
281
+ ]
282
+ });
283
+
284
+ await dubhe.signAndSendTxn({
285
+ tx: migrateTx,
286
+ onSuccess: (result) => {
287
+ console.log(chalk.green(`Migration Transaction Digest: ${result.digest}`));
288
+ },
289
+ onError: (error) => {
290
+ console.log(
291
+ chalk.red('Migration Transaction failed!, Please execute the migration manually.')
292
+ );
293
+ console.error(error);
294
+ }
295
+ });
296
+ } else {
297
+ console.log(`\nāœ… No schema changes — migration step skipped.`);
298
+ // Brief delay to allow localnet to index the upgraded package before
299
+ // subsequent on-chain queries.
300
+ await new Promise((resolve) => setTimeout(resolve, 2000));
301
+ }
245
302
  } catch (error: any) {
303
+ // Restore Published.toml to original state on failure (persistent networks only)
304
+ if (savedPublishedEntry) {
305
+ restorePublishedTomlEntry(projectPath, network, savedPublishedEntry);
306
+ }
246
307
  console.log(chalk.red('upgrade handler execution failed!'));
247
- console.error(error.message);
308
+ throw error;
248
309
  }
249
310
  }