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

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