@0xobelisk/sui-cli 1.0.0 → 1.0.2

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,115 @@
1
+ import type { CommandModule } from 'yargs';
2
+ import { logError } from '../utils/errors';
3
+ import { queryStorage } from '../utils';
4
+ import { loadConfig, DubheConfig } from '@0xobelisk/sui-common';
5
+
6
+ type Options = {
7
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
8
+ 'config-path': string;
9
+ schema: string;
10
+ struct: string;
11
+ 'object-id'?: string;
12
+ 'package-id'?: string;
13
+ 'metadata-path'?: string;
14
+ params?: any[];
15
+ };
16
+
17
+ /**
18
+ * CLI command module for querying schema struct state
19
+ *
20
+ * Examples:
21
+ *
22
+ * 1. Query StorageValue (no params required):
23
+ * ```bash
24
+ * dubhe query --config-path dubhe.config.ts --network devnet --schema counter --struct value
25
+ * ```
26
+ *
27
+ * 2. Query StorageMap (one param required):
28
+ * ```bash
29
+ * dubhe query --config-path dubhe.config.ts --network devnet --schema token --struct balances \
30
+ * --params "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
31
+ * ```
32
+ *
33
+ * 3. Query StorageDoubleMap (two params required):
34
+ * ```bash
35
+ * dubhe query --config-path dubhe.config.ts --network devnet --schema game --struct player_relations \
36
+ * --params "0x123...456" "0x789...abc"
37
+ * ```
38
+ */
39
+ const commandModule: CommandModule<Options, Options> = {
40
+ command: 'query',
41
+
42
+ describe: 'Query dubhe schema struct state',
43
+
44
+ builder: {
45
+ network: {
46
+ type: 'string',
47
+ choices: ['mainnet', 'testnet', 'devnet', 'localnet'],
48
+ desc: 'Node network (mainnet/testnet/devnet/localnet)',
49
+ demandOption: true,
50
+ },
51
+ 'config-path': {
52
+ type: 'string',
53
+ default: 'dubhe.config.ts',
54
+ desc: 'Configuration file path',
55
+ },
56
+ schema: {
57
+ type: 'string',
58
+ desc: 'Schema name',
59
+ demandOption: true,
60
+ },
61
+ struct: {
62
+ type: 'string',
63
+ desc: 'Struct name',
64
+ demandOption: true,
65
+ },
66
+ 'object-id': {
67
+ type: 'string',
68
+ desc: 'Object ID (optional)',
69
+ },
70
+ 'package-id': {
71
+ type: 'string',
72
+ desc: 'Package ID (optional)',
73
+ },
74
+ 'metadata-path': {
75
+ type: 'string',
76
+ desc: 'Path to metadata JSON file (optional)',
77
+ },
78
+ params: {
79
+ type: 'array',
80
+ desc: 'Params for storage type: StorageValue(no params), StorageMap(1 param), StorageDoubleMap(2 params)',
81
+ },
82
+ },
83
+
84
+ async handler({
85
+ network,
86
+ 'config-path': configPath,
87
+ schema,
88
+ struct,
89
+ 'object-id': objectId,
90
+ 'package-id': packageId,
91
+ 'metadata-path': metadataPath,
92
+ params,
93
+ }) {
94
+ try {
95
+ const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
96
+
97
+ await queryStorage({
98
+ dubheConfig,
99
+ schema,
100
+ struct,
101
+ objectId,
102
+ network,
103
+ packageId,
104
+ metadataFilePath: metadataPath,
105
+ params,
106
+ });
107
+ } catch (error: any) {
108
+ logError(error);
109
+ process.exit(1);
110
+ }
111
+ process.exit(0);
112
+ },
113
+ };
114
+
115
+ export default commandModule;
@@ -5,7 +5,6 @@ import chalk from 'chalk';
5
5
  type Options = {
6
6
  'config-path'?: string;
7
7
  network?: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
8
- 'framework-id'?: string;
9
8
  };
10
9
 
11
10
  const commandModule: CommandModule<Options, Options> = {
@@ -24,20 +23,12 @@ const commandModule: CommandModule<Options, Options> = {
24
23
  choices: ['mainnet', 'testnet', 'devnet', 'localnet'] as const,
25
24
  desc: 'Node network (mainnet/testnet/devnet/localnet)',
26
25
  },
27
- 'framework-id': {
28
- type: 'string',
29
- desc: 'Framework Package ID',
30
- },
31
26
  },
32
27
 
33
- async handler({
34
- 'config-path': configPath,
35
- network,
36
- 'framework-id': frameworkId,
37
- }) {
28
+ async handler({ 'config-path': configPath, network }) {
38
29
  try {
39
30
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
40
- await schemaGen(dubheConfig, undefined, network, frameworkId);
31
+ await schemaGen(dubheConfig, undefined, network);
41
32
  process.exit(0);
42
33
  } catch (error: any) {
43
34
  console.log(chalk.red('Schemagen failed!'));
@@ -3,3 +3,4 @@ export * from './publishHandler';
3
3
  export * from './errors';
4
4
  export * from './printDubhe';
5
5
  export * from './utils';
6
+ export * from './queryStorage';
@@ -0,0 +1,166 @@
1
+ import { Dubhe, loadMetadata } from '@0xobelisk/sui-client';
2
+ import { DubheCliError } from './errors';
3
+ import { validatePrivateKey, getOldPackageId, getObjectId } from './utils';
4
+ import { DubheConfig } from '@0xobelisk/sui-common';
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+
8
+ function validateParams(storageType: string, params: any[]): boolean {
9
+ const formatStorageType = storageType.split('<')[0].trim();
10
+ switch (formatStorageType) {
11
+ case 'StorageValue':
12
+ return params.length === 0;
13
+ case 'StorageMap':
14
+ return params.length === 1;
15
+ case 'StorageDoubleMap':
16
+ return params.length === 2;
17
+ default:
18
+ return false;
19
+ }
20
+ }
21
+
22
+ function getExpectedParamsCount(storageType: string): number {
23
+ const formatStorageType = storageType.split('<')[0].trim();
24
+ switch (formatStorageType) {
25
+ case 'StorageValue':
26
+ return 0;
27
+ case 'StorageMap':
28
+ return 1;
29
+ case 'StorageDoubleMap':
30
+ return 2;
31
+ default:
32
+ return 0;
33
+ }
34
+ }
35
+
36
+ export async function queryStorage({
37
+ dubheConfig,
38
+ schema,
39
+ struct,
40
+ params,
41
+ network,
42
+ objectId,
43
+ packageId,
44
+ metadataFilePath,
45
+ }: {
46
+ dubheConfig: DubheConfig;
47
+ schema: string;
48
+ struct: string;
49
+ params?: any[];
50
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
51
+ objectId?: string;
52
+ packageId?: string;
53
+ metadataFilePath?: string;
54
+ }) {
55
+ const privateKey = process.env.PRIVATE_KEY;
56
+ if (!privateKey) {
57
+ throw new DubheCliError(
58
+ `Missing PRIVATE_KEY environment variable.
59
+ Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
60
+ in your contracts directory to use the default sui private key.`
61
+ );
62
+ }
63
+ const privateKeyFormat = validatePrivateKey(privateKey);
64
+ if (privateKeyFormat === false) {
65
+ throw new DubheCliError(`Please check your privateKey.`);
66
+ }
67
+
68
+ const path = process.cwd();
69
+ const projectPath = `${path}/contracts/${dubheConfig.name}`;
70
+
71
+ packageId = packageId || (await getOldPackageId(projectPath, network));
72
+
73
+ objectId = objectId || (await getObjectId(projectPath, network, schema));
74
+
75
+ let metadata;
76
+ if (metadataFilePath) {
77
+ metadata = await loadMetadataFromFile(metadataFilePath);
78
+ } else {
79
+ metadata = await loadMetadata(network, packageId);
80
+ }
81
+ if (!metadata) {
82
+ throw new DubheCliError(
83
+ `Metadata file not found. Please provide a metadata file path or set the packageId.`
84
+ );
85
+ }
86
+
87
+ if (!dubheConfig.schemas[schema]) {
88
+ throw new DubheCliError(
89
+ `Schema "${schema}" not found in dubhe config. Available schemas: ${Object.keys(
90
+ dubheConfig.schemas
91
+ ).join(', ')}`
92
+ );
93
+ }
94
+
95
+ if (!dubheConfig.schemas[schema].structure[struct]) {
96
+ throw new DubheCliError(
97
+ `Struct "${struct}" not found in schema "${schema}". Available structs: ${Object.keys(
98
+ dubheConfig.schemas[schema].structure
99
+ ).join(', ')}`
100
+ );
101
+ }
102
+
103
+ const storageType = dubheConfig.schemas[schema].structure[struct];
104
+
105
+ const processedParams = params || [];
106
+ if (!validateParams(storageType, processedParams)) {
107
+ throw new Error(
108
+ `Invalid params count for ${storageType}. ` +
109
+ `Expected: ${getExpectedParamsCount(storageType)}, ` +
110
+ `Got: ${processedParams.length}`
111
+ );
112
+ }
113
+
114
+ const dubhe = new Dubhe({
115
+ secretKey: privateKeyFormat,
116
+ networkType: network,
117
+ packageId,
118
+ metadata,
119
+ });
120
+ const result = await dubhe.state({
121
+ schema,
122
+ struct,
123
+ objectId,
124
+ storageType,
125
+ params: processedParams,
126
+ });
127
+
128
+ console.log(result);
129
+ }
130
+
131
+ /**
132
+ * Load metadata from a JSON file and construct the metadata structure
133
+ * @param metadataFilePath Path to the metadata JSON file
134
+ * @param network Network type
135
+ * @param packageId Package ID
136
+ * @returns Constructed metadata object
137
+ */
138
+ export async function loadMetadataFromFile(metadataFilePath: string) {
139
+ // Verify file extension is .json
140
+ if (path.extname(metadataFilePath) !== '.json') {
141
+ throw new Error('Metadata file must be in JSON format');
142
+ }
143
+
144
+ try {
145
+ // Read JSON file content
146
+ const rawData = fs.readFileSync(metadataFilePath, 'utf8');
147
+ const jsonData = JSON.parse(rawData);
148
+
149
+ // Validate JSON structure
150
+ if (!jsonData || typeof jsonData !== 'object') {
151
+ throw new Error('Invalid JSON format');
152
+ }
153
+
154
+ // Construct metadata structure
155
+ const metadata = {
156
+ ...jsonData,
157
+ };
158
+
159
+ return metadata;
160
+ } catch (error) {
161
+ if (error instanceof Error) {
162
+ throw new Error(`Failed to read metadata file: ${error.message}`);
163
+ }
164
+ throw error;
165
+ }
166
+ }
@@ -10,7 +10,7 @@ import { spawn } from 'child_process';
10
10
  export type schema = {
11
11
  name: string;
12
12
  objectId: string;
13
- structure: Record<string, string>
13
+ structure: Record<string, string>;
14
14
  };
15
15
 
16
16
  export type DeploymentJsonType = {
@@ -110,6 +110,27 @@ export async function getOldPackageId(
110
110
  return deployment.packageId;
111
111
  }
112
112
 
113
+ export async function getObjectId(
114
+ projectPath: string,
115
+ network: string,
116
+ schemaName: string
117
+ ): Promise<string> {
118
+ const deployment = await getDeploymentJson(projectPath, network);
119
+ const schema = deployment.schemas.find(schema =>
120
+ schema.name
121
+ .toLowerCase()
122
+ .endsWith(`::${schemaName.toLowerCase()}_schema::${schemaName}`)
123
+ );
124
+
125
+ if (!schema?.objectId) {
126
+ throw new Error(
127
+ `Schema '${schemaName}' not found in deployment history`
128
+ );
129
+ }
130
+
131
+ return schema.objectId;
132
+ }
133
+
113
134
  export async function getUpgradeCap(
114
135
  projectPath: string,
115
136
  network: string
@@ -134,7 +155,7 @@ export function saveContractData(
134
155
  packageId: string,
135
156
  upgradeCap: string,
136
157
  version: number,
137
- schemas: schema[],
158
+ schemas: schema[]
138
159
  ) {
139
160
  const DeploymentData: DeploymentJsonType = {
140
161
  projectName,
@@ -167,7 +188,9 @@ export async function writeOutput(
167
188
  }
168
189
  }
169
190
 
170
- function getDubheDependency(network: 'mainnet' | 'testnet' | 'devnet' | 'localnet'): string {
191
+ function getDubheDependency(
192
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet'
193
+ ): string {
171
194
  switch (network) {
172
195
  case 'localnet':
173
196
  return 'Dubhe = { local = "../dubhe-framework" }';
@@ -180,14 +203,19 @@ function getDubheDependency(network: 'mainnet' | 'testnet' | 'devnet' | 'localn
180
203
  }
181
204
  }
182
205
 
183
- export function updateDubheDependency(filePath: string, network: 'mainnet' | 'testnet' | 'devnet' | 'localnet') {
206
+ export function updateDubheDependency(
207
+ filePath: string,
208
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet'
209
+ ) {
184
210
  const fileContent = fs.readFileSync(filePath, 'utf-8');
185
211
  const newDependency = getDubheDependency(network);
186
212
  const updatedContent = fileContent.replace(/Dubhe = \{.*\}/, newDependency);
187
213
  fs.writeFileSync(filePath, updatedContent, 'utf-8');
188
214
  console.log(`Updated Dubhe dependency in ${filePath} for ${network}.`);
189
215
  }
190
- export async function switchEnv(network: 'mainnet' | 'testnet' | 'devnet' | 'localnet') {
216
+ export async function switchEnv(
217
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet'
218
+ ) {
191
219
  try {
192
220
  return new Promise<void>((resolve, reject) => {
193
221
  const suiProcess = spawn(
@@ -195,7 +223,7 @@ export async function switchEnv(network: 'mainnet' | 'testnet' | 'devnet' | 'loc
195
223
  ['client', 'switch', '--env', network],
196
224
  {
197
225
  env: { ...process.env },
198
- stdio: 'pipe'
226
+ stdio: 'pipe',
199
227
  }
200
228
  );
201
229
 
@@ -209,9 +237,11 @@ export async function switchEnv(network: 'mainnet' | 'testnet' | 'devnet' | 'loc
209
237
  reject(error); // Reject promise on error
210
238
  });
211
239
 
212
- suiProcess.on('exit', (code) => {
240
+ suiProcess.on('exit', code => {
213
241
  if (code !== 0) {
214
- console.error(chalk.red(`\n❌ Process exited with code: ${code}`));
242
+ console.error(
243
+ chalk.red(`\n❌ Process exited with code: ${code}`)
244
+ );
215
245
  reject(new Error(`Process exited with code: ${code}`));
216
246
  } else {
217
247
  resolve(); // Resolve promise on successful exit