@0xobelisk/sui-cli 0.5.23 → 0.5.25

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.
@@ -14,31 +14,49 @@ import {
14
14
  validatePrivateKey,
15
15
  schema,
16
16
  } from './utils';
17
+ import { DubheConfig } from '@0xobelisk/sui-common';
17
18
 
18
19
  async function getDappsObjectId(
19
20
  network: 'mainnet' | 'testnet' | 'devnet' | 'localnet'
20
21
  ) {
21
22
  switch (network) {
22
23
  case 'testnet':
23
- return '0x92c78ef688a5cb7f6a9f18e76d1da927e26281c367564ffbe5f886ec06434f08';
24
+ return '0x181befc40b3dafe2740b41d5a970e49bed2cca20205506ee6be2cfb73ff2d3e9';
24
25
  default:
25
- return '0x92c78ef688a5cb7f6a9f18e76d1da927e26281c367564ffbe5f886ec06434f08';
26
+ return '0x181befc40b3dafe2740b41d5a970e49bed2cca20205506ee6be2cfb73ff2d3e9';
26
27
  }
27
28
  }
28
29
 
30
+ function capitalizeAndRemoveUnderscores(input: string): string {
31
+ return input
32
+ .split('_')
33
+ .map((word, index) => {
34
+ return index === 0
35
+ ? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
36
+ : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
37
+ })
38
+ .join('');
39
+ }
40
+
41
+ function getLastSegment(input: string): string {
42
+ const segments = input.split('::');
43
+ return segments.length > 0 ? segments[segments.length - 1] : '';
44
+ }
45
+
29
46
  export async function publishHandler(
30
- name: string,
47
+ dubheConfig: DubheConfig,
31
48
  network: 'mainnet' | 'testnet' | 'devnet' | 'localnet',
32
49
  dappsObjectId?: string
33
50
  ) {
34
- console.log('\nšŸš€ Starting Contract Publication...');
35
- console.log(` ā”œā”€ Project: ${name}`);
36
- console.log(` ā”œā”€ Network: ${network}`);
51
+
37
52
 
38
53
  const path = process.cwd();
39
- const projectPath = `${path}/contracts/${name}`;
54
+ const projectPath = `${path}/contracts/${dubheConfig.name}`;
40
55
  dappsObjectId = dappsObjectId || (await getDappsObjectId(network));
41
56
 
57
+ console.log('\nšŸš€ Starting Contract Publication...');
58
+ console.log(` ā”œā”€ Project: ${projectPath}`);
59
+ console.log(` ā”œā”€ Network: ${network}`);
42
60
  console.log(' ā”œā”€ Validating Environment...');
43
61
  const privateKey = process.env.PRIVATE_KEY;
44
62
  if (!privateKey) {
@@ -108,6 +126,7 @@ in your contracts directory to use the default sui private key.`
108
126
  let packageId = '';
109
127
  let schemas: schema[] = [];
110
128
  let upgradeCapId = '';
129
+ let schemaHubId = '';
111
130
 
112
131
  result.objectChanges!.map(object => {
113
132
  if (object.type === 'published') {
@@ -121,6 +140,13 @@ in your contracts directory to use the default sui private key.`
121
140
  console.log(` ā”œā”€ Upgrade Cap: ${object.objectId}`);
122
141
  upgradeCapId = object.objectId;
123
142
  }
143
+ if (
144
+ object.type === 'created' &&
145
+ object.objectType.includes("schema_hub")
146
+ ) {
147
+ console.log(` ā”œā”€ Schema Hub: ${object.objectId}`);
148
+ schemaHubId = object.objectId;
149
+ }
124
150
  });
125
151
 
126
152
  console.log(` └─ Transaction: ${result.digest}`);
@@ -132,7 +158,9 @@ in your contracts directory to use the default sui private key.`
132
158
  deployHookTx.moveCall({
133
159
  target: `${packageId}::deploy_hook::run`,
134
160
  arguments: [
161
+ deployHookTx.object(schemaHubId),
135
162
  deployHookTx.object(dappsObjectId),
163
+ deployHookTx.object(upgradeCapId),
136
164
  deployHookTx.object('0x6'),
137
165
  ],
138
166
  });
@@ -158,24 +186,34 @@ in your contracts directory to use the default sui private key.`
158
186
  deployHookResult.objectChanges?.map(object => {
159
187
  if (
160
188
  object.type === 'created' &&
161
- object.objectType.includes('schema')
189
+ object.objectType.includes('_schema') && !object.objectType.includes("dynamic_field")
162
190
  ) {
163
191
  console.log(` ā”œā”€ ${object.objectType}`);
164
192
  console.log(` └─ ID: ${object.objectId}`);
193
+
194
+ let structure: Record<string, string> = {};
195
+ for (let schemaKey in dubheConfig.schemas) {
196
+ if (capitalizeAndRemoveUnderscores(schemaKey) === getLastSegment(object.objectType)) {
197
+ structure = dubheConfig.schemas[schemaKey].structure;
198
+ }
199
+ }
200
+
165
201
  schemas.push({
166
202
  name: object.objectType,
167
203
  objectId: object.objectId,
204
+ structure,
168
205
  });
169
206
  }
170
207
  });
171
208
 
172
209
  saveContractData(
173
- name,
210
+ dubheConfig.name,
174
211
  network,
175
212
  packageId,
176
- schemas,
177
213
  upgradeCapId,
178
- version
214
+ schemaHubId,
215
+ version,
216
+ schemas,
179
217
  );
180
218
  console.log('\nāœ… Contract Publication Complete\n');
181
219
  } else {
@@ -1,246 +1,239 @@
1
- // import { Dubhe } from '@0xobelisk/sui-client';
2
- // import { Transaction, UpgradePolicy } from '@mysten/sui/transactions';
3
- // import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
4
- // import { execSync } from 'child_process';
5
- // import chalk from 'chalk';
6
- // import { DubheCliError, UpgradeError } from './errors';
7
- // import {
8
- // updateVersionInFile,
9
- // getOldPackageId,
10
- // getVersion,
11
- // getUpgradeCap,
12
- // saveContractData,
13
- // validatePrivateKey,
14
- // } from './utils';
15
-
16
- // type ObjectContent = {
17
- // type: string;
18
- // fields: Record<string, any>;
19
- // hasPublicTransfer: boolean;
20
- // dataType: string;
21
- // };
22
-
23
- // export async function upgradeHandler(
24
- // name: string,
25
- // network: 'mainnet' | 'testnet' | 'devnet' | 'localnet',
26
- // schemaNames: string[]
27
- // ) {
28
- // const path = process.cwd();
29
- // const projectPath = `${path}/contracts/${name}`;
30
- // const privateKey = process.env.PRIVATE_KEY;
31
- // if (!privateKey)
32
- // throw new DubheCliError(
33
- // `Missing PRIVATE_KEY environment variable.
34
- // Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
35
- // in your contracts directory to use the default sui private key.`
36
- // );
37
-
38
- // const privateKeyFormat = validatePrivateKey(privateKey);
39
- // if (privateKeyFormat === false) {
40
- // throw new DubheCliError(`Please check your privateKey.`);
41
- // }
42
- // const dubhe = new Dubhe({
43
- // secretKey: privateKeyFormat,
44
- // });
45
- // const keypair = dubhe.getKeypair();
46
-
47
- // const client = new SuiClient({
48
- // url: getFullnodeUrl(network),
49
- // });
50
-
51
- // let oldVersion = Number(await getVersion(projectPath, network));
52
- // let oldPackageId = await getOldPackageId(projectPath, network);
53
- // let worldId = await getWorldId(projectPath, network);
54
- // let upgradeCap = await getUpgradeCap(projectPath, network);
55
- // let adminCap = await getAdminCap(projectPath, network);
56
-
57
- // const newVersion = oldVersion + 1;
58
- // await updateVersionInFile(projectPath, newVersion.toString());
59
-
60
- // try {
61
- // let modules: any, dependencies: any, digest: any;
62
- // try {
63
- // const {
64
- // modules: extractedModules,
65
- // dependencies: extractedDependencies,
66
- // digest: extractedDigest,
67
- // } = JSON.parse(
68
- // execSync(
69
- // `sui move build --dump-bytecode-as-base64 --path ${path}/contracts/${name}`,
70
- // {
71
- // encoding: 'utf-8',
72
- // }
73
- // )
74
- // );
75
-
76
- // modules = extractedModules;
77
- // dependencies = extractedDependencies;
78
- // digest = extractedDigest;
79
- // } catch (error: any) {
80
- // throw new UpgradeError(error.stdout);
81
- // }
82
-
83
- // const tx = new Transaction();
84
- // const ticket = tx.moveCall({
85
- // target: '0x2::package::authorize_upgrade',
86
- // arguments: [
87
- // tx.object(upgradeCap),
88
- // tx.pure.u8(UpgradePolicy.COMPATIBLE),
89
- // tx.pure.vector('u8', digest),
90
- // ],
91
- // });
92
-
93
- // const receipt = tx.upgrade({
94
- // modules,
95
- // dependencies,
96
- // package: oldPackageId,
97
- // ticket,
98
- // });
99
-
100
- // tx.moveCall({
101
- // target: '0x2::package::commit_upgrade',
102
- // arguments: [tx.object(upgradeCap), receipt],
103
- // });
104
-
105
- // tx.transferObjects(
106
- // [tx.object(upgradeCap)],
107
- // keypair.toSuiAddress()
108
- // );
109
-
110
- // const result = await client.signAndExecuteTransaction({
111
- // signer: keypair,
112
- // transaction: tx,
113
- // options: {
114
- // showObjectChanges: true,
115
- // },
116
- // });
117
-
118
- // console.log('');
119
- // console.log(`${name} WorldId: ${worldId}`);
120
-
121
- // let newPackageId = '';
122
- // let newUpgradeCap = '';
123
- // result.objectChanges!.map(object => {
124
- // if (object.type === 'published') {
125
- // console.log(
126
- // chalk.blue(`${name} PackageId: ${object.packageId}`)
127
- // );
128
- // newPackageId = object.packageId;
129
- // }
130
- // if (
131
- // object.type === 'mutated' &&
132
- // object.objectType === '0x2::package::UpgradeCap'
133
- // ) {
134
- // console.log(
135
- // chalk.blue(`${name} UpgradeCap: ${object.objectId}`)
136
- // );
137
- // newUpgradeCap = object.objectId;
138
- // }
139
- // });
140
-
141
- // console.log(
142
- // chalk.green(`Upgrade Transaction Digest: ${result.digest}`)
143
- // );
144
-
145
- // saveContractData(
146
- // name,
147
- // network,
148
- // newPackageId,
149
- // worldId,
150
- // newUpgradeCap,
151
- // adminCap,
152
- // newVersion
153
- // );
154
-
155
- // oldPackageId = newPackageId;
156
- // upgradeCap = newUpgradeCap;
157
- // oldVersion = newVersion;
158
-
159
- // console.log('\nExecuting the migrate: ');
160
- // const delay = (ms: number) =>
161
- // new Promise(resolve => setTimeout(resolve, ms));
162
- // await delay(5000);
163
-
164
- // const migrateTx = new Transaction();
165
- // migrateTx.moveCall({
166
- // target: `${newPackageId}::migrate::run`,
167
- // arguments: [migrateTx.object(worldId), migrateTx.object(adminCap)],
168
- // });
169
-
170
- // let newWorldObject = await client.getObject({
171
- // id: worldId,
172
- // options: {
173
- // showContent: true,
174
- // showDisplay: true,
175
- // showType: true,
176
- // showOwner: true,
177
- // },
178
- // });
179
- // let newObjectContent = newWorldObject.data!.content as ObjectContent;
180
-
181
- // const uniqueSchema: string[] = schemaNames.filter(
182
- // item => !newObjectContent.fields['schema_names'].includes(item)
183
- // );
184
-
185
- // console.log('new schema:', uniqueSchema);
186
- // let needRegisterSchema = [];
187
- // for (const newSchema of uniqueSchema) {
188
- // migrateTx.moveCall({
189
- // target: `${newPackageId}::${newSchema}_schema::register`,
190
- // arguments: [
191
- // migrateTx.object(worldId),
192
- // migrateTx.object(adminCap),
193
- // ],
194
- // });
195
- // needRegisterSchema.push(`${newSchema}_schema`);
196
- // }
197
- // const migrateResult = await client.signAndExecuteTransaction({
198
- // signer: keypair,
199
- // transaction: migrateTx,
200
- // options: {
201
- // showEffects: true,
202
- // },
203
- // });
204
-
205
- // if (migrateResult.effects?.status.status === 'success') {
206
- // console.log(
207
- // chalk.green(
208
- // `${name} migrate world success, new world version is: ${newObjectContent.fields['version']}, package version is ${newVersion}`
209
- // )
210
- // );
211
- // if (needRegisterSchema.length !== 0) {
212
- // console.log(
213
- // chalk.green(
214
- // `new schema: ${needRegisterSchema.toString()} register success.`
215
- // )
216
- // );
217
- // }
218
-
219
- // console.log(
220
- // chalk.blue(
221
- // `\n${name} world schemas is ${newObjectContent.fields['schema_names']}`
222
- // )
223
- // );
224
- // } else {
225
- // console.log(
226
- // chalk.red(
227
- // `${name} migrate world failed, world version is: ${newObjectContent.fields['version']}, package version is ${newVersion}`
228
- // )
229
- // );
230
- // }
231
- // } catch (error: any) {
232
- // console.log(chalk.red('Upgrade failed!'));
233
- // console.error(error.message);
234
-
235
- // saveContractData(
236
- // name,
237
- // network,
238
- // oldPackageId,
239
- // worldId,
240
- // upgradeCap,
241
- // adminCap,
242
- // oldVersion
243
- // );
244
- // await updateVersionInFile(projectPath, oldVersion.toString());
245
- // }
246
- // }
1
+ import { Dubhe } from '@0xobelisk/sui-client';
2
+ import { Transaction, UpgradePolicy } from '@mysten/sui/transactions';
3
+ import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
4
+ import { execSync } from 'child_process';
5
+ import chalk from 'chalk';
6
+ import { DubheCliError, UpgradeError } from './errors';
7
+ import {
8
+ updateVersionInFile,
9
+ getOldPackageId,
10
+ getVersion,
11
+ getUpgradeCap,
12
+ saveContractData,
13
+ validatePrivateKey, getOnchainSchemas, getSchemaHub,
14
+ } from './utils';
15
+ import * as fs from 'fs';
16
+ import * as path from 'path';
17
+ import { DubheConfig } from '@0xobelisk/sui-common';
18
+
19
+ type ObjectContent = {
20
+ type: string;
21
+ fields: Record<string, any>;
22
+ hasPublicTransfer: boolean;
23
+ dataType: string;
24
+ };
25
+
26
+ type Field = {
27
+ name: string;
28
+ type: string;
29
+ }
30
+
31
+ type Migration = {
32
+ schemaName: string;
33
+ fields: Field[];
34
+ };
35
+
36
+ function updateMigrateMethod(projectPath: string, migrations: Migration[]): void {
37
+ migrations.forEach((migration) => {
38
+ let filePath = `${projectPath}/sources/codegen/schemas/${migration.schemaName}.move`;
39
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
40
+ const migrateMethodRegex = new RegExp(`public fun migrate\\(_${migration.schemaName}: &mut ${capitalizeAndRemoveUnderscores(migration.schemaName)}, _cap: &UpgradeCap\\) {[^}]*}`);
41
+ const newMigrateMethod = `
42
+ public fun migrate(${migration.schemaName}: &mut ${capitalizeAndRemoveUnderscores(migration.schemaName)}, _cap: &UpgradeCap) {
43
+ ${migration.fields.map((field) => {
44
+ let storage_type = '';
45
+ if (field.type.includes('StorageValue')) {
46
+ storage_type = `storage_value::new()`;
47
+ } else if (field.type.includes('StorageMap')) {
48
+ storage_type = `storage_map::new()`;
49
+ } else if (
50
+ field.type.includes('StorageDoubleMap')
51
+ ) {
52
+ storage_type = `storage_double_map::new()`;
53
+ }
54
+ return `storage_migrate::add_field<${field.type}>(&mut ${migration.schemaName}.id, b"${field.name}", ${storage_type});`;
55
+ }).join('')}
56
+ }
57
+ `;
58
+
59
+ const updatedContent = fileContent.replace(migrateMethodRegex, newMigrateMethod);
60
+ fs.writeFileSync(filePath, updatedContent, 'utf-8');
61
+ });
62
+
63
+
64
+ }
65
+
66
+ function capitalizeAndRemoveUnderscores(input: string): string {
67
+ return input
68
+ .split('_')
69
+ .map((word, index) => {
70
+ return index === 0
71
+ ? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
72
+ : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
73
+ })
74
+ .join('');
75
+ }
76
+
77
+ function getLastSegment(input: string): string {
78
+ const segments = input.split('::');
79
+ return segments.length > 0 ? segments[segments.length - 1] : '';
80
+ }
81
+
82
+ export async function upgradeHandler(
83
+ config: DubheConfig,
84
+ name: string,
85
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet',
86
+ ) {
87
+ const path = process.cwd();
88
+ const projectPath = `${path}/contracts/${name}`;
89
+ const privateKey = process.env.PRIVATE_KEY;
90
+ if (!privateKey)
91
+ throw new DubheCliError(
92
+ `Missing PRIVATE_KEY environment variable.
93
+ Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
94
+ in your contracts directory to use the default sui private key.`,
95
+ );
96
+
97
+ const privateKeyFormat = validatePrivateKey(privateKey);
98
+ if (privateKeyFormat === false) {
99
+ throw new DubheCliError(`Please check your privateKey.`);
100
+ }
101
+ const dubhe = new Dubhe({
102
+ secretKey: privateKeyFormat,
103
+ });
104
+ const keypair = dubhe.getKeypair();
105
+
106
+ const client = new SuiClient({
107
+ url: getFullnodeUrl(network),
108
+ });
109
+
110
+ let oldVersion = Number(await getVersion(projectPath, network));
111
+ let oldPackageId = await getOldPackageId(projectPath, network);
112
+ let schemaHub = await getSchemaHub(projectPath, network);
113
+ let upgradeCap = await getUpgradeCap(projectPath, network);
114
+ // let adminCap = await getAdminCap(projectPath, network);
115
+
116
+ let pendingMigration: Migration[] = [];
117
+ let schemas = await getOnchainSchemas(projectPath, network);
118
+ for (let schemaKey in config.schemas) {
119
+ schemas.forEach((schema) => {
120
+ if (capitalizeAndRemoveUnderscores(schemaKey) == getLastSegment(schema.name)) {
121
+ let migrate: Migration = { schemaName: '', fields: [] };
122
+ let fields: Field[] = [];
123
+ let isMigration = false;
124
+ for (const key in config.schemas[schemaKey].structure) {
125
+ if (!(key in schema.structure)) {
126
+ isMigration = true;
127
+ fields.push({
128
+ name: key,
129
+ type: config.schemas[schemaKey].structure[key],
130
+ });
131
+ schema.structure[key] = config.schemas[schemaKey].structure[key];
132
+ }
133
+ }
134
+ if (isMigration) {
135
+ migrate.schemaName = schemaKey;
136
+ migrate.fields = fields;
137
+ pendingMigration.push(migrate);
138
+ }
139
+ }
140
+ });
141
+ }
142
+
143
+
144
+ pendingMigration.forEach((migration) => {
145
+ console.log(`\nšŸš€ Starting Migration for ${migration.schemaName}...`);
146
+ console.log('šŸ“‹ Migration Fields:', migration.fields);
147
+ });
148
+ updateMigrateMethod(projectPath, pendingMigration);
149
+
150
+ try {
151
+ let modules: any, dependencies: any, digest: any;
152
+ try {
153
+ const {
154
+ modules: extractedModules,
155
+ dependencies: extractedDependencies,
156
+ digest: extractedDigest,
157
+ } = JSON.parse(
158
+ execSync(
159
+ `sui move build --dump-bytecode-as-base64 --path ${path}/contracts/${name}`,
160
+ {
161
+ encoding: 'utf-8',
162
+ },
163
+ ),
164
+ );
165
+
166
+ modules = extractedModules;
167
+ dependencies = extractedDependencies;
168
+ digest = extractedDigest;
169
+ } catch (error: any) {
170
+ throw new UpgradeError(error.stdout);
171
+ }
172
+
173
+ console.log('\nšŸš€ Starting Upgrade Process...');
174
+ console.log('šŸ“‹ OldPackageId:', oldPackageId);
175
+ console.log('šŸ“‹ UpgradeCap Object Id:', upgradeCap);
176
+ console.log('šŸ“‹ OldVersion:', oldVersion);
177
+
178
+ const tx = new Transaction();
179
+ const ticket = tx.moveCall({
180
+ target: '0x2::package::authorize_upgrade',
181
+ arguments: [
182
+ tx.object(upgradeCap),
183
+ tx.pure.u8(UpgradePolicy.COMPATIBLE),
184
+ tx.pure.vector('u8', digest),
185
+ ],
186
+ });
187
+
188
+ const receipt = tx.upgrade({
189
+ modules,
190
+ dependencies,
191
+ package: oldPackageId,
192
+ ticket,
193
+ });
194
+
195
+ tx.moveCall({
196
+ target: '0x2::package::commit_upgrade',
197
+ arguments: [tx.object(upgradeCap), receipt],
198
+ });
199
+
200
+ const result = await client.signAndExecuteTransaction({
201
+ signer: keypair,
202
+ transaction: tx,
203
+ options: {
204
+ showObjectChanges: true,
205
+ },
206
+ });
207
+
208
+ let newPackageId = '';
209
+ result.objectChanges!.map(object => {
210
+ if (object.type === 'published') {
211
+ console.log(
212
+ chalk.blue(`${name} PackageId: ${object.packageId}`),
213
+ );
214
+ console.log(
215
+ chalk.blue(`${name} Version: ${oldVersion + 1}`),
216
+ );
217
+ newPackageId = object.packageId;
218
+ }
219
+ });
220
+
221
+ console.log(
222
+ chalk.green(`Upgrade Transaction Digest: ${result.digest}`),
223
+ );
224
+
225
+ saveContractData(
226
+ name,
227
+ network,
228
+ newPackageId,
229
+ upgradeCap,
230
+ schemaHub,
231
+ oldVersion + 1,
232
+ schemas,
233
+ );
234
+
235
+ } catch (error: any) {
236
+ console.log(chalk.red('Upgrade failed!'));
237
+ console.error(error.message);
238
+ }
239
+ }