@0xobelisk/sui-cli 1.0.3 → 1.0.5
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/dist/dubhe.js +57 -55
- package/dist/dubhe.js.map +1 -1
- package/package.json +3 -3
- package/src/commands/call.ts +90 -0
- package/src/commands/index.ts +2 -0
- package/src/commands/query.ts +10 -9
- package/src/commands/test.ts +8 -4
- package/src/utils/callHandler.ts +166 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/queryStorage.ts +7 -7
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
import { logError } from '../utils/errors';
|
|
3
|
+
import { callHandler } from '../utils';
|
|
4
|
+
import { loadConfig, DubheConfig } from '@0xobelisk/sui-common';
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
|
|
8
|
+
module: string;
|
|
9
|
+
function: string;
|
|
10
|
+
'config-path'?: string;
|
|
11
|
+
'package-id'?: string;
|
|
12
|
+
'metadata-path'?: string;
|
|
13
|
+
params?: any[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* CLI command for calling a function in a module
|
|
18
|
+
*/
|
|
19
|
+
const commandModule: CommandModule<Options, Options> = {
|
|
20
|
+
command: 'call',
|
|
21
|
+
|
|
22
|
+
describe: 'Call a function in a module',
|
|
23
|
+
|
|
24
|
+
builder: {
|
|
25
|
+
network: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
choices: ['mainnet', 'testnet', 'devnet', 'localnet'],
|
|
28
|
+
desc: 'Node network (mainnet/testnet/devnet/localnet)',
|
|
29
|
+
demandOption: true,
|
|
30
|
+
},
|
|
31
|
+
module: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
desc: 'Module name',
|
|
34
|
+
demandOption: true,
|
|
35
|
+
},
|
|
36
|
+
function: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
desc: 'Function name',
|
|
39
|
+
demandOption: true,
|
|
40
|
+
},
|
|
41
|
+
'config-path': {
|
|
42
|
+
type: 'string',
|
|
43
|
+
default: 'dubhe.config.ts',
|
|
44
|
+
desc: 'Configuration file path',
|
|
45
|
+
},
|
|
46
|
+
'package-id': {
|
|
47
|
+
type: 'string',
|
|
48
|
+
desc: 'Package ID (optional)',
|
|
49
|
+
},
|
|
50
|
+
'metadata-path': {
|
|
51
|
+
type: 'string',
|
|
52
|
+
desc: 'Path to metadata JSON file (optional)',
|
|
53
|
+
},
|
|
54
|
+
params: {
|
|
55
|
+
type: 'array',
|
|
56
|
+
desc: 'Params for the function',
|
|
57
|
+
string: true,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
async handler({
|
|
62
|
+
network,
|
|
63
|
+
'config-path': configPath,
|
|
64
|
+
module: moduleName,
|
|
65
|
+
function: funcName,
|
|
66
|
+
'package-id': packageId,
|
|
67
|
+
'metadata-path': metadataPath,
|
|
68
|
+
params,
|
|
69
|
+
}) {
|
|
70
|
+
try {
|
|
71
|
+
const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
|
|
72
|
+
|
|
73
|
+
await callHandler({
|
|
74
|
+
dubheConfig,
|
|
75
|
+
moduleName,
|
|
76
|
+
funcName,
|
|
77
|
+
network,
|
|
78
|
+
packageId,
|
|
79
|
+
metadataFilePath: metadataPath,
|
|
80
|
+
params,
|
|
81
|
+
});
|
|
82
|
+
} catch (error: any) {
|
|
83
|
+
logError(error);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
process.exit(0);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default commandModule;
|
package/src/commands/index.ts
CHANGED
|
@@ -12,11 +12,13 @@ import generateKey from './generateKey';
|
|
|
12
12
|
import checkBalance from './checkBalance';
|
|
13
13
|
import configStore from './configStore';
|
|
14
14
|
import query from './query';
|
|
15
|
+
import call from './call';
|
|
15
16
|
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
|
|
17
18
|
export const commands: CommandModule<any, any>[] = [
|
|
18
19
|
localnode,
|
|
19
20
|
publish,
|
|
21
|
+
call,
|
|
20
22
|
query,
|
|
21
23
|
faucet,
|
|
22
24
|
schemagen,
|
package/src/commands/query.ts
CHANGED
|
@@ -5,9 +5,9 @@ import { loadConfig, DubheConfig } from '@0xobelisk/sui-common';
|
|
|
5
5
|
|
|
6
6
|
type Options = {
|
|
7
7
|
network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
|
|
8
|
-
'config-path'
|
|
8
|
+
'config-path'?: string;
|
|
9
9
|
schema: string;
|
|
10
|
-
|
|
10
|
+
field: string;
|
|
11
11
|
'object-id'?: string;
|
|
12
12
|
'package-id'?: string;
|
|
13
13
|
'metadata-path'?: string;
|
|
@@ -21,18 +21,18 @@ type Options = {
|
|
|
21
21
|
*
|
|
22
22
|
* 1. Query StorageValue (no params required):
|
|
23
23
|
* ```bash
|
|
24
|
-
* dubhe query --config-path dubhe.config.ts --network devnet --schema counter --
|
|
24
|
+
* dubhe query --config-path dubhe.config.ts --network devnet --schema counter --field value
|
|
25
25
|
* ```
|
|
26
26
|
*
|
|
27
27
|
* 2. Query StorageMap (one param required):
|
|
28
28
|
* ```bash
|
|
29
|
-
* dubhe query --config-path dubhe.config.ts --network devnet --schema token --
|
|
29
|
+
* dubhe query --config-path dubhe.config.ts --network devnet --schema token --field balances \
|
|
30
30
|
* --params "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
|
|
31
31
|
* ```
|
|
32
32
|
*
|
|
33
33
|
* 3. Query StorageDoubleMap (two params required):
|
|
34
34
|
* ```bash
|
|
35
|
-
* dubhe query --config-path dubhe.config.ts --network devnet --schema game --
|
|
35
|
+
* dubhe query --config-path dubhe.config.ts --network devnet --schema game --field player_relations \
|
|
36
36
|
* --params "0x123...456" "0x789...abc"
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
@@ -58,9 +58,9 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
58
58
|
desc: 'Schema name',
|
|
59
59
|
demandOption: true,
|
|
60
60
|
},
|
|
61
|
-
|
|
61
|
+
field: {
|
|
62
62
|
type: 'string',
|
|
63
|
-
desc: '
|
|
63
|
+
desc: 'Field name',
|
|
64
64
|
demandOption: true,
|
|
65
65
|
},
|
|
66
66
|
'object-id': {
|
|
@@ -78,6 +78,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
78
78
|
params: {
|
|
79
79
|
type: 'array',
|
|
80
80
|
desc: 'Params for storage type: StorageValue(no params), StorageMap(1 param), StorageDoubleMap(2 params)',
|
|
81
|
+
string: true,
|
|
81
82
|
},
|
|
82
83
|
},
|
|
83
84
|
|
|
@@ -85,7 +86,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
85
86
|
network,
|
|
86
87
|
'config-path': configPath,
|
|
87
88
|
schema,
|
|
88
|
-
|
|
89
|
+
field,
|
|
89
90
|
'object-id': objectId,
|
|
90
91
|
'package-id': packageId,
|
|
91
92
|
'metadata-path': metadataPath,
|
|
@@ -97,7 +98,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
97
98
|
await queryStorage({
|
|
98
99
|
dubheConfig,
|
|
99
100
|
schema,
|
|
100
|
-
|
|
101
|
+
field,
|
|
101
102
|
objectId,
|
|
102
103
|
network,
|
|
103
104
|
packageId,
|
package/src/commands/test.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { DubheConfig, loadConfig } from '@0xobelisk/sui-common';
|
|
|
6
6
|
type Options = {
|
|
7
7
|
'config-path': string;
|
|
8
8
|
'test'?: string;
|
|
9
|
+
'gas-limit'?: string;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
const commandModule: CommandModule<Options, Options> = {
|
|
@@ -24,19 +25,22 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
24
25
|
type: 'string',
|
|
25
26
|
desc: 'Run a specific test',
|
|
26
27
|
},
|
|
28
|
+
'gas-limit': {
|
|
29
|
+
type: 'string',
|
|
30
|
+
desc: 'Set the gas limit for the test',
|
|
31
|
+
},
|
|
27
32
|
});
|
|
28
33
|
},
|
|
29
34
|
|
|
30
|
-
async handler({ 'config-path': configPath, test }) {
|
|
35
|
+
async handler({ 'config-path': configPath, test, 'gas-limit': gasLimit }) {
|
|
31
36
|
// Start an internal anvil process if no world address is provided
|
|
32
37
|
try {
|
|
33
38
|
console.log('🚀 Running move test');
|
|
34
39
|
const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
|
|
35
40
|
const path = process.cwd();
|
|
36
41
|
const projectPath = `${path}/contracts/${dubheConfig.name}`;
|
|
37
|
-
const command = `sui move test --path ${projectPath} ${test ? ` --test ${test}` : ''}`;
|
|
38
|
-
|
|
39
|
-
console.log(output);
|
|
42
|
+
const command = `sui move test --path ${projectPath} ${test ? ` --test ${test}` : ''} ${gasLimit ? ` --gas-limit ${gasLimit}` : ''}`;
|
|
43
|
+
execSync(command, { stdio: 'inherit', encoding: "utf-8" });
|
|
40
44
|
} catch (error: any) {
|
|
41
45
|
console.error(chalk.red("Error executing sui move test:"));
|
|
42
46
|
console.log(error.stdout);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dubhe,
|
|
3
|
+
loadMetadata,
|
|
4
|
+
Transaction,
|
|
5
|
+
TransactionResult,
|
|
6
|
+
} from '@0xobelisk/sui-client';
|
|
7
|
+
import { DubheCliError } from './errors';
|
|
8
|
+
import { validatePrivateKey, getOldPackageId, getObjectId } from './utils';
|
|
9
|
+
import { DubheConfig } from '@0xobelisk/sui-common';
|
|
10
|
+
import { loadMetadataFromFile } from './queryStorage';
|
|
11
|
+
|
|
12
|
+
const BaseTxType = [
|
|
13
|
+
'u8',
|
|
14
|
+
'u16',
|
|
15
|
+
'u32',
|
|
16
|
+
'u64',
|
|
17
|
+
'u128',
|
|
18
|
+
'u256',
|
|
19
|
+
'bool',
|
|
20
|
+
'id',
|
|
21
|
+
'string',
|
|
22
|
+
'address',
|
|
23
|
+
'object',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function validateParams(params: any[]) {
|
|
27
|
+
try {
|
|
28
|
+
params.forEach(param => {
|
|
29
|
+
const [type, value] = param.split(':');
|
|
30
|
+
if (!BaseTxType.includes(type)) {
|
|
31
|
+
throw new Error(`Invalid param type: ${type}`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
throw new Error(`Invalid params: ${error}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// param:
|
|
40
|
+
// u8:1
|
|
41
|
+
// u16:1
|
|
42
|
+
// u32:1
|
|
43
|
+
// u64:1
|
|
44
|
+
// u128:1
|
|
45
|
+
// u256:1
|
|
46
|
+
// object:0x1
|
|
47
|
+
// address:0x1
|
|
48
|
+
// bool:true
|
|
49
|
+
// string:"hello"
|
|
50
|
+
function formatBCS(tx: Transaction, param: string) {
|
|
51
|
+
const [type, value] = param.split(':');
|
|
52
|
+
switch (type) {
|
|
53
|
+
case 'u8':
|
|
54
|
+
return tx.pure.u8(parseInt(value));
|
|
55
|
+
case 'u16':
|
|
56
|
+
return tx.pure.u16(parseInt(value));
|
|
57
|
+
case 'u32':
|
|
58
|
+
return tx.pure.u32(parseInt(value));
|
|
59
|
+
case 'u64':
|
|
60
|
+
return tx.pure.u64(parseInt(value));
|
|
61
|
+
case 'u128':
|
|
62
|
+
return tx.pure.u128(parseInt(value));
|
|
63
|
+
case 'u256':
|
|
64
|
+
return tx.pure.u256(parseInt(value));
|
|
65
|
+
case 'object':
|
|
66
|
+
return tx.object(value);
|
|
67
|
+
case 'address':
|
|
68
|
+
return tx.pure.address(value);
|
|
69
|
+
case 'bool':
|
|
70
|
+
return tx.pure.bool(value === 'true');
|
|
71
|
+
case 'string':
|
|
72
|
+
return tx.pure.string(value);
|
|
73
|
+
default:
|
|
74
|
+
throw new Error(`Invalid param type: ${type}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function formatBCSParams(tx: Transaction, params: any[]) {
|
|
79
|
+
return params.map(param => formatBCS(tx, param));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function callHandler({
|
|
83
|
+
dubheConfig,
|
|
84
|
+
moduleName,
|
|
85
|
+
funcName,
|
|
86
|
+
params,
|
|
87
|
+
network,
|
|
88
|
+
packageId,
|
|
89
|
+
metadataFilePath,
|
|
90
|
+
}: {
|
|
91
|
+
dubheConfig: DubheConfig;
|
|
92
|
+
moduleName: string;
|
|
93
|
+
funcName: string;
|
|
94
|
+
params?: any[];
|
|
95
|
+
network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
|
|
96
|
+
packageId?: string;
|
|
97
|
+
metadataFilePath?: string;
|
|
98
|
+
}) {
|
|
99
|
+
const privateKey = process.env.PRIVATE_KEY;
|
|
100
|
+
if (!privateKey) {
|
|
101
|
+
throw new DubheCliError(
|
|
102
|
+
`Missing PRIVATE_KEY environment variable.
|
|
103
|
+
Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
|
|
104
|
+
in your contracts directory to use the default sui private key.`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const privateKeyFormat = validatePrivateKey(privateKey);
|
|
108
|
+
if (privateKeyFormat === false) {
|
|
109
|
+
throw new DubheCliError(`Please check your privateKey.`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const path = process.cwd();
|
|
113
|
+
const projectPath = `${path}/contracts/${dubheConfig.name}`;
|
|
114
|
+
|
|
115
|
+
packageId = packageId || (await getOldPackageId(projectPath, network));
|
|
116
|
+
|
|
117
|
+
// objectId = objectId || (await getObjectId(projectPath, network, schema));
|
|
118
|
+
|
|
119
|
+
let metadata;
|
|
120
|
+
if (metadataFilePath) {
|
|
121
|
+
metadata = await loadMetadataFromFile(metadataFilePath);
|
|
122
|
+
} else {
|
|
123
|
+
metadata = await loadMetadata(network, packageId);
|
|
124
|
+
}
|
|
125
|
+
if (!metadata) {
|
|
126
|
+
throw new DubheCliError(
|
|
127
|
+
`Metadata file not found. Please provide a metadata file path or set the packageId.`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// if (!dubheConfig.schemas[schema]) {
|
|
132
|
+
// throw new DubheCliError(
|
|
133
|
+
// `Schema "${schema}" not found in dubhe config. Available schemas: ${Object.keys(
|
|
134
|
+
// dubheConfig.schemas
|
|
135
|
+
// ).join(', ')}`
|
|
136
|
+
// );
|
|
137
|
+
// }
|
|
138
|
+
|
|
139
|
+
// if (!dubheConfig.schemas[schema].structure[struct]) {
|
|
140
|
+
// throw new DubheCliError(
|
|
141
|
+
// `Struct "${struct}" not found in schema "${schema}". Available structs: ${Object.keys(
|
|
142
|
+
// dubheConfig.schemas[schema].structure
|
|
143
|
+
// ).join(', ')}`
|
|
144
|
+
// );
|
|
145
|
+
// }
|
|
146
|
+
|
|
147
|
+
// const storageType = dubheConfig.schemas[schema].structure[struct];
|
|
148
|
+
|
|
149
|
+
const processedParams = params || [];
|
|
150
|
+
validateParams(processedParams);
|
|
151
|
+
const dubhe = new Dubhe({
|
|
152
|
+
secretKey: privateKeyFormat,
|
|
153
|
+
networkType: network,
|
|
154
|
+
packageId,
|
|
155
|
+
metadata,
|
|
156
|
+
});
|
|
157
|
+
const tx = new Transaction();
|
|
158
|
+
const formattedParams = formatBCSParams(tx, processedParams);
|
|
159
|
+
|
|
160
|
+
const result = (await dubhe.tx[moduleName][funcName]({
|
|
161
|
+
tx,
|
|
162
|
+
params: formattedParams,
|
|
163
|
+
})) as TransactionResult;
|
|
164
|
+
|
|
165
|
+
console.log(result);
|
|
166
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -36,7 +36,7 @@ function getExpectedParamsCount(storageType: string): number {
|
|
|
36
36
|
export async function queryStorage({
|
|
37
37
|
dubheConfig,
|
|
38
38
|
schema,
|
|
39
|
-
|
|
39
|
+
field,
|
|
40
40
|
params,
|
|
41
41
|
network,
|
|
42
42
|
objectId,
|
|
@@ -45,7 +45,7 @@ export async function queryStorage({
|
|
|
45
45
|
}: {
|
|
46
46
|
dubheConfig: DubheConfig;
|
|
47
47
|
schema: string;
|
|
48
|
-
|
|
48
|
+
field: string;
|
|
49
49
|
params?: any[];
|
|
50
50
|
network: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
|
|
51
51
|
objectId?: string;
|
|
@@ -92,15 +92,15 @@ in your contracts directory to use the default sui private key.`
|
|
|
92
92
|
);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
if (!dubheConfig.schemas[schema]
|
|
95
|
+
if (!dubheConfig.schemas[schema][field]) {
|
|
96
96
|
throw new DubheCliError(
|
|
97
|
-
`
|
|
98
|
-
dubheConfig.schemas[schema]
|
|
97
|
+
`Field "${field}" not found in schema "${schema}". Available fields: ${Object.keys(
|
|
98
|
+
dubheConfig.schemas[schema]
|
|
99
99
|
).join(', ')}`
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
const storageType = dubheConfig.schemas[schema]
|
|
103
|
+
const storageType = dubheConfig.schemas[schema][field];
|
|
104
104
|
|
|
105
105
|
const processedParams = params || [];
|
|
106
106
|
if (!validateParams(storageType, processedParams)) {
|
|
@@ -119,7 +119,7 @@ in your contracts directory to use the default sui private key.`
|
|
|
119
119
|
});
|
|
120
120
|
const result = await dubhe.state({
|
|
121
121
|
schema,
|
|
122
|
-
|
|
122
|
+
field,
|
|
123
123
|
objectId,
|
|
124
124
|
storageType,
|
|
125
125
|
params: processedParams,
|