@0xobelisk/sui-cli 1.1.13 → 1.2.0-pre.1
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 +68 -93
- package/dist/dubhe.js.map +1 -1
- package/package.json +10 -7
- package/src/commands/faucet.ts +55 -21
- package/src/commands/generateKey.ts +9 -9
- package/src/commands/index.ts +3 -3
- package/src/commands/localnode.ts +9 -3
- package/src/commands/wait.ts +59 -0
- package/src/utils/callHandler.ts +4 -36
- package/src/utils/checkBalance.ts +3 -18
- package/src/utils/generateAccount.ts +71 -67
- package/src/utils/index.ts +0 -1
- package/src/utils/publishHandler.ts +275 -63
- package/src/utils/queryStorage.ts +4 -18
- package/src/utils/startNode.ts +117 -61
- package/src/utils/storeConfig.ts +12 -24
- package/src/utils/upgradeHandler.ts +9 -19
- package/src/utils/utils.ts +74 -3
- package/src/commands/indexer.ts +0 -56
- package/src/utils/indexerHandler.ts +0 -264
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xobelisk/sui-cli",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.0-pre.1",
|
|
4
4
|
"description": "Tookit for interacting with move eps framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sui",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@mysten/sui": "^1.19.0",
|
|
35
35
|
"@types/sqlite3": "^3.1.11",
|
|
36
|
+
"@types/wait-on": "^5.3.4",
|
|
36
37
|
"chalk": "^5.0.1",
|
|
37
38
|
"child_process": "^1.0.2",
|
|
38
39
|
"chokidar": "^3.5.3",
|
|
@@ -40,28 +41,30 @@
|
|
|
40
41
|
"ejs": "^3.1.8",
|
|
41
42
|
"execa": "^7.0.0",
|
|
42
43
|
"glob": "^8.0.3",
|
|
44
|
+
"ora": "^5.4.1",
|
|
43
45
|
"path": "^0.12.7",
|
|
44
46
|
"sqlite": "^5.1.1",
|
|
45
47
|
"sqlite3": "^5.1.7",
|
|
46
48
|
"typescript": "5.1.6",
|
|
49
|
+
"wait-on": "^7.0.1",
|
|
47
50
|
"yargs": "^17.7.1",
|
|
48
51
|
"zod": "^3.22.3",
|
|
49
52
|
"zod-validation-error": "^1.3.0",
|
|
50
|
-
"@0xobelisk/sui-client": "1.1
|
|
51
|
-
"@0xobelisk/sui-common": "1.1
|
|
53
|
+
"@0xobelisk/sui-client": "1.2.0-pre.1",
|
|
54
|
+
"@0xobelisk/sui-common": "1.2.0-pre.1"
|
|
52
55
|
},
|
|
53
56
|
"devDependencies": {
|
|
54
57
|
"@types/ejs": "^3.1.1",
|
|
55
58
|
"@types/glob": "^7.2.0",
|
|
56
59
|
"@types/node": "^18.15.11",
|
|
57
60
|
"@types/yargs": "^17.0.10",
|
|
61
|
+
"eslint": "^8.56.0",
|
|
62
|
+
"eslint-config-prettier": "^9.1.0",
|
|
63
|
+
"prettier": "3.3.3",
|
|
58
64
|
"ts-node": "^10.9.1",
|
|
59
65
|
"tsup": "^6.7.0",
|
|
60
66
|
"tsx": "^3.12.6",
|
|
61
|
-
"vitest": "0.31.4"
|
|
62
|
-
"eslint": "^8.56.0",
|
|
63
|
-
"eslint-config-prettier": "^9.1.0",
|
|
64
|
-
"prettier": "3.3.3"
|
|
67
|
+
"vitest": "0.31.4"
|
|
65
68
|
},
|
|
66
69
|
"scripts": {
|
|
67
70
|
"build": "pnpm run type-check && pnpm run build:js",
|
package/src/commands/faucet.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { Dubhe } from '@0xobelisk/sui-client';
|
|
2
1
|
import type { CommandModule } from 'yargs';
|
|
3
2
|
import { requestSuiFromFaucetV0, getFaucetHost } from '@mysten/sui/faucet';
|
|
4
3
|
import { SuiClient, getFullnodeUrl, GetBalanceParams } from '@mysten/sui/client';
|
|
5
|
-
import {
|
|
4
|
+
import { initializeDubhe } from '../utils';
|
|
6
5
|
|
|
7
6
|
type Options = {
|
|
8
7
|
network: any;
|
|
9
8
|
recipient?: string;
|
|
10
9
|
};
|
|
11
10
|
|
|
11
|
+
const MAX_RETRIES = 60; // 60s timeout
|
|
12
|
+
const RETRY_INTERVAL = 1000; // 1s retry interval
|
|
13
|
+
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
14
|
+
|
|
12
15
|
const commandModule: CommandModule<Options, Options> = {
|
|
13
16
|
command: 'faucet',
|
|
14
17
|
|
|
@@ -32,21 +35,7 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
32
35
|
async handler({ network, recipient }) {
|
|
33
36
|
let faucet_address = '';
|
|
34
37
|
if (recipient === undefined) {
|
|
35
|
-
const
|
|
36
|
-
if (!privateKey)
|
|
37
|
-
throw new DubheCliError(
|
|
38
|
-
`Missing PRIVATE_KEY environment variable.
|
|
39
|
-
Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
|
|
40
|
-
in your contracts directory to use the default sui private key.`
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const privateKeyFormat = validatePrivateKey(privateKey);
|
|
44
|
-
if (privateKeyFormat === false) {
|
|
45
|
-
throw new DubheCliError(`Please check your PRIVATE_KEY.`);
|
|
46
|
-
}
|
|
47
|
-
const dubhe = new Dubhe({
|
|
48
|
-
secretKey: privateKeyFormat
|
|
49
|
-
});
|
|
38
|
+
const dubhe = initializeDubhe(network);
|
|
50
39
|
faucet_address = dubhe.getAddress();
|
|
51
40
|
} else {
|
|
52
41
|
faucet_address = recipient;
|
|
@@ -63,10 +52,55 @@ const commandModule: CommandModule<Options, Options> = {
|
|
|
63
52
|
}
|
|
64
53
|
|
|
65
54
|
console.log(' ├─ Requesting funds from faucet...');
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
|
|
56
|
+
let retryCount = 0;
|
|
57
|
+
let success = false;
|
|
58
|
+
let spinnerIndex = 0;
|
|
59
|
+
const startTime = Date.now();
|
|
60
|
+
let isInterrupted = false;
|
|
61
|
+
|
|
62
|
+
const handleInterrupt = () => {
|
|
63
|
+
isInterrupted = true;
|
|
64
|
+
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
65
|
+
console.log('\n └─ Operation cancelled by user');
|
|
66
|
+
process.exit(0);
|
|
67
|
+
};
|
|
68
|
+
process.on('SIGINT', handleInterrupt);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
while (retryCount < MAX_RETRIES && !success && !isInterrupted) {
|
|
72
|
+
try {
|
|
73
|
+
await requestSuiFromFaucetV0({
|
|
74
|
+
host: getFaucetHost(network),
|
|
75
|
+
recipient: faucet_address
|
|
76
|
+
});
|
|
77
|
+
success = true;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (isInterrupted) break;
|
|
80
|
+
|
|
81
|
+
retryCount++;
|
|
82
|
+
if (retryCount === MAX_RETRIES) {
|
|
83
|
+
console.log(` └─ Failed to request funds after ${MAX_RETRIES} attempts.`);
|
|
84
|
+
console.log(' └─ Please check your network connection and try again later.');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const elapsedTime = Math.floor((Date.now() - startTime) / 1000);
|
|
89
|
+
const spinner = SPINNER[spinnerIndex % SPINNER.length];
|
|
90
|
+
spinnerIndex++;
|
|
91
|
+
|
|
92
|
+
process.stdout.write(`\r ├─ ${spinner} Retrying... (${elapsedTime}s)`);
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} finally {
|
|
97
|
+
process.removeListener('SIGINT', handleInterrupt);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (isInterrupted) {
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
70
104
|
|
|
71
105
|
console.log(' └─ Checking balance...');
|
|
72
106
|
const client = new SuiClient({ url: getFullnodeUrl(network) });
|
|
@@ -3,27 +3,27 @@ import { generateAccountHandler } from '../utils/generateAccount';
|
|
|
3
3
|
|
|
4
4
|
type Options = {
|
|
5
5
|
force?: boolean;
|
|
6
|
-
'
|
|
6
|
+
'use-next-public'?: boolean;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
const commandModule: CommandModule<Options, Options> = {
|
|
10
10
|
command: 'generate-key',
|
|
11
|
-
describe:
|
|
12
|
-
'Generate a new account key pair and save it to a .env file, with an option to output to a TypeScript file.',
|
|
11
|
+
describe: 'Generate a new account keypair and save it to a .env file',
|
|
13
12
|
builder: {
|
|
14
13
|
force: {
|
|
15
14
|
type: 'boolean',
|
|
16
15
|
default: false,
|
|
17
|
-
desc: 'Force generate a new
|
|
16
|
+
desc: 'Force generate a new keypair'
|
|
18
17
|
},
|
|
19
|
-
'
|
|
20
|
-
type: '
|
|
21
|
-
|
|
18
|
+
'use-next-public': {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
default: false,
|
|
21
|
+
desc: 'Use the NEXT_PUBLIC_ prefix for client-side usage'
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
|
-
async handler({ force, '
|
|
24
|
+
async handler({ force, 'use-next-public': useNextPublic }) {
|
|
25
25
|
try {
|
|
26
|
-
await generateAccountHandler(force,
|
|
26
|
+
await generateAccountHandler(force, useNextPublic);
|
|
27
27
|
} catch (error) {
|
|
28
28
|
console.error('Error generating account:', error);
|
|
29
29
|
process.exit(1);
|
package/src/commands/index.ts
CHANGED
|
@@ -13,8 +13,8 @@ import checkBalance from './checkBalance';
|
|
|
13
13
|
import configStore from './configStore';
|
|
14
14
|
import query from './query';
|
|
15
15
|
import call from './call';
|
|
16
|
-
import indexer from './indexer';
|
|
17
16
|
import watch from './watch';
|
|
17
|
+
import wait from './wait';
|
|
18
18
|
|
|
19
19
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
|
|
20
20
|
export const commands: CommandModule<any, any>[] = [
|
|
@@ -31,6 +31,6 @@ export const commands: CommandModule<any, any>[] = [
|
|
|
31
31
|
generateKey,
|
|
32
32
|
checkBalance,
|
|
33
33
|
configStore,
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
watch,
|
|
35
|
+
wait
|
|
36
36
|
];
|
|
@@ -7,12 +7,18 @@ const commandModule: CommandModule = {
|
|
|
7
7
|
describe: 'Manage local Sui node',
|
|
8
8
|
|
|
9
9
|
builder(yargs) {
|
|
10
|
-
return yargs
|
|
10
|
+
return yargs
|
|
11
|
+
.option('force-regenesis', {
|
|
12
|
+
alias: 'f',
|
|
13
|
+
type: 'boolean',
|
|
14
|
+
description: 'Force regenesis the local node',
|
|
15
|
+
default: true
|
|
16
|
+
});
|
|
11
17
|
},
|
|
12
18
|
|
|
13
|
-
async handler() {
|
|
19
|
+
async handler(argv) {
|
|
14
20
|
try {
|
|
15
|
-
await startLocalNode();
|
|
21
|
+
await startLocalNode({ forceRegenesis: argv['force-regenesis'] as boolean });
|
|
16
22
|
} catch (error) {
|
|
17
23
|
console.error('Error executing command:', error);
|
|
18
24
|
process.exit(1);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { CommandModule } from 'yargs';
|
|
2
|
+
import waitOn from 'wait-on';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
|
|
6
|
+
interface WaitOptions {
|
|
7
|
+
url: string;
|
|
8
|
+
timeout: number;
|
|
9
|
+
interval: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const commandModule: CommandModule = {
|
|
13
|
+
command: 'wait',
|
|
14
|
+
describe: 'Wait for service to be ready',
|
|
15
|
+
builder(yargs) {
|
|
16
|
+
return yargs
|
|
17
|
+
.option('url', {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'URL to wait for'
|
|
20
|
+
})
|
|
21
|
+
.option('timeout', {
|
|
22
|
+
type: 'number',
|
|
23
|
+
description: 'Timeout (in milliseconds)',
|
|
24
|
+
default: 180000
|
|
25
|
+
})
|
|
26
|
+
.option('interval', {
|
|
27
|
+
type: 'number',
|
|
28
|
+
description: 'Check interval (in milliseconds)',
|
|
29
|
+
default: 1000
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
async handler(argv) {
|
|
33
|
+
const options = argv as unknown as WaitOptions;
|
|
34
|
+
const spinner = ora({
|
|
35
|
+
text: `Waiting for service to start ${chalk.cyan(options.url)}...`,
|
|
36
|
+
color: 'cyan'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
spinner.start();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await waitOn({
|
|
43
|
+
resources: [options.url],
|
|
44
|
+
timeout: options.timeout,
|
|
45
|
+
interval: options.interval,
|
|
46
|
+
validateStatus: (status: number) => status === 200
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
spinner.succeed(chalk.green('Service is ready!'));
|
|
50
|
+
process.exit(0);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
spinner.fail(chalk.red('Timeout waiting for service'));
|
|
53
|
+
console.error(chalk.yellow('Please make sure the service is running...'));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default commandModule;
|
package/src/utils/callHandler.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadMetadata, Transaction, TransactionResult } from '@0xobelisk/sui-client';
|
|
2
2
|
import { DubheCliError } from './errors';
|
|
3
|
-
import {
|
|
3
|
+
import { getOldPackageId, initializeDubhe } from './utils';
|
|
4
4
|
import { DubheConfig } from '@0xobelisk/sui-common';
|
|
5
5
|
import { loadMetadataFromFile } from './queryStorage';
|
|
6
6
|
|
|
@@ -91,19 +91,6 @@ export async function callHandler({
|
|
|
91
91
|
packageId?: string;
|
|
92
92
|
metadataFilePath?: string;
|
|
93
93
|
}) {
|
|
94
|
-
const privateKey = process.env.PRIVATE_KEY;
|
|
95
|
-
if (!privateKey) {
|
|
96
|
-
throw new DubheCliError(
|
|
97
|
-
`Missing PRIVATE_KEY environment variable.
|
|
98
|
-
Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
|
|
99
|
-
in your contracts directory to use the default sui private key.`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
const privateKeyFormat = validatePrivateKey(privateKey);
|
|
103
|
-
if (privateKeyFormat === false) {
|
|
104
|
-
throw new DubheCliError(`Please check your privateKey.`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
94
|
const path = process.cwd();
|
|
108
95
|
const projectPath = `${path}/contracts/${dubheConfig.name}`;
|
|
109
96
|
|
|
@@ -123,29 +110,10 @@ in your contracts directory to use the default sui private key.`
|
|
|
123
110
|
);
|
|
124
111
|
}
|
|
125
112
|
|
|
126
|
-
// if (!dubheConfig.schemas[schema]) {
|
|
127
|
-
// throw new DubheCliError(
|
|
128
|
-
// `Schema "${schema}" not found in dubhe config. Available schemas: ${Object.keys(
|
|
129
|
-
// dubheConfig.schemas
|
|
130
|
-
// ).join(', ')}`
|
|
131
|
-
// );
|
|
132
|
-
// }
|
|
133
|
-
|
|
134
|
-
// if (!dubheConfig.schemas[schema].structure[struct]) {
|
|
135
|
-
// throw new DubheCliError(
|
|
136
|
-
// `Struct "${struct}" not found in schema "${schema}". Available structs: ${Object.keys(
|
|
137
|
-
// dubheConfig.schemas[schema].structure
|
|
138
|
-
// ).join(', ')}`
|
|
139
|
-
// );
|
|
140
|
-
// }
|
|
141
|
-
|
|
142
|
-
// const storageType = dubheConfig.schemas[schema].structure[struct];
|
|
143
|
-
|
|
144
113
|
const processedParams = params || [];
|
|
145
114
|
validateParams(processedParams);
|
|
146
|
-
const dubhe =
|
|
147
|
-
|
|
148
|
-
networkType: network,
|
|
115
|
+
const dubhe = initializeDubhe({
|
|
116
|
+
network,
|
|
149
117
|
packageId,
|
|
150
118
|
metadata
|
|
151
119
|
});
|
|
@@ -1,28 +1,13 @@
|
|
|
1
|
-
import { Dubhe, NetworkType } from '@0xobelisk/sui-client';
|
|
2
1
|
import chalk from 'chalk';
|
|
3
2
|
import dotenv from 'dotenv';
|
|
4
|
-
import {
|
|
3
|
+
import { initializeDubhe } from './utils';
|
|
5
4
|
import { DubheCliError } from './errors';
|
|
6
5
|
dotenv.config();
|
|
7
6
|
|
|
8
7
|
export async function checkBalanceHandler(network: 'mainnet' | 'testnet' | 'devnet' | 'localnet') {
|
|
9
8
|
try {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
throw new DubheCliError(
|
|
13
|
-
`Missing PRIVATE_KEY environment variable.
|
|
14
|
-
Run 'echo "PRIVATE_KEY=YOUR_PRIVATE_KEY" > .env'
|
|
15
|
-
in your contracts directory to use the default sui private key.`
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
const privateKeyFormat = validatePrivateKey(privateKey);
|
|
19
|
-
if (privateKeyFormat === false) {
|
|
20
|
-
throw new DubheCliError(`Please check your privateKey.`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const dubhe = new Dubhe({
|
|
24
|
-
secretKey: process.env.PRIVATE_KEY,
|
|
25
|
-
networkType: network as NetworkType
|
|
9
|
+
const dubhe = initializeDubhe({
|
|
10
|
+
network
|
|
26
11
|
});
|
|
27
12
|
|
|
28
13
|
const balance = await dubhe.getBalance();
|
|
@@ -2,96 +2,100 @@ import { Dubhe } from '@0xobelisk/sui-client';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
|
|
5
|
-
export async function generateAccountHandler(
|
|
6
|
-
|
|
5
|
+
export async function generateAccountHandler(
|
|
6
|
+
force: boolean = false,
|
|
7
|
+
useNextPublic: boolean = false
|
|
8
|
+
) {
|
|
9
|
+
if (useNextPublic) {
|
|
7
10
|
console.log(
|
|
8
|
-
chalk.
|
|
9
|
-
'Note: The generated account will be stored in the .env file
|
|
11
|
+
chalk.gray(
|
|
12
|
+
'Note: The generated account will be stored in the .env file with NEXT_PUBLIC_ prefix for client-side usage.'
|
|
10
13
|
)
|
|
11
14
|
);
|
|
12
15
|
console.log(
|
|
13
|
-
chalk.yellow('Warning: Do not expose the
|
|
16
|
+
chalk.yellow('Warning: Do not expose the .env file, it is intended for local testing only.\n')
|
|
14
17
|
);
|
|
15
18
|
}
|
|
16
19
|
const path = process.cwd();
|
|
17
|
-
let privateKey: string;
|
|
20
|
+
let privateKey: string | undefined;
|
|
21
|
+
let envContent = '';
|
|
18
22
|
|
|
19
|
-
if
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
privateKey = keypair.getSecretKey();
|
|
23
|
-
|
|
24
|
-
fs.writeFileSync(`${path}/.env`, `PRIVATE_KEY=${privateKey}`);
|
|
25
|
-
console.log(chalk.green(`File created at: ${path}/.env`));
|
|
23
|
+
// Check if .env file exists
|
|
24
|
+
try {
|
|
25
|
+
envContent = fs.readFileSync(`${path}/.env`, 'utf8');
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
fs.writeFileSync(
|
|
33
|
-
outputTsPath,
|
|
34
|
-
`export const PRIVATEKEY = '${privateKey}';
|
|
35
|
-
export const ACCOUNT = '${keypair.toSuiAddress()}';
|
|
36
|
-
`
|
|
37
|
-
);
|
|
38
|
-
console.log(chalk.green(`File created at: ${outputTsPath}\n`));
|
|
27
|
+
// privateKey = process.env.PRIVATE_KEY || process.env.NEXT_PUBLIC_PRIVATE_KEY;
|
|
28
|
+
let privateKey = process.env.PRIVATE_KEY || process.env.NEXT_PUBLIC_PRIVATE_KEY;
|
|
29
|
+
if (useNextPublic) {
|
|
30
|
+
privateKey = process.env.NEXT_PUBLIC_PRIVATE_KEY || process.env.PRIVATE_KEY;
|
|
39
31
|
}
|
|
40
32
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
if (privateKey) {
|
|
34
|
+
// If key exists, decide whether to update keyname based on useNextPublic
|
|
35
|
+
const newKeyName = useNextPublic ? 'NEXT_PUBLIC_PRIVATE_KEY' : 'PRIVATE_KEY';
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const match = envContent.match(/PRIVATE_KEY=(.+)/);
|
|
49
|
-
if (match && match[1]) {
|
|
50
|
-
privateKey = match[1];
|
|
51
|
-
const dubhe = new Dubhe({ secretKey: privateKey });
|
|
52
|
-
const keypair = dubhe.getSigner();
|
|
37
|
+
// Find and update the last matching line based on privateKey value
|
|
38
|
+
const lines = envContent.split('\n');
|
|
39
|
+
let shouldUpdate = false;
|
|
53
40
|
|
|
54
|
-
if
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
41
|
+
// First check if the last matching line already has the correct keyname
|
|
42
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
43
|
+
const line = lines[i];
|
|
44
|
+
if (line.endsWith(privateKey)) {
|
|
45
|
+
// If useNextPublic is true, only update if the line starts with PRIVATE_KEY=
|
|
46
|
+
// If useNextPublic is false, only update if the line starts with NEXT_PUBLIC_PRIVATE_KEY=
|
|
47
|
+
const [currentKeyName] = line.split('=');
|
|
48
|
+
if (useNextPublic) {
|
|
49
|
+
shouldUpdate = currentKeyName === 'PRIVATE_KEY';
|
|
50
|
+
} else {
|
|
51
|
+
shouldUpdate = currentKeyName === 'NEXT_PUBLIC_PRIVATE_KEY';
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
58
54
|
}
|
|
59
|
-
fs.writeFileSync(
|
|
60
|
-
outputTsPath,
|
|
61
|
-
`export const PRIVATEKEY = '${privateKey}';
|
|
62
|
-
export const ACCOUNT = '${keypair.toSuiAddress()}';
|
|
63
|
-
`
|
|
64
|
-
);
|
|
65
|
-
console.log(chalk.green(`File created at: ${outputTsPath}\n`));
|
|
66
55
|
}
|
|
67
56
|
|
|
68
|
-
|
|
57
|
+
// Only update if necessary
|
|
58
|
+
if (shouldUpdate) {
|
|
59
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
60
|
+
const line = lines[i];
|
|
61
|
+
if (line.endsWith(privateKey)) {
|
|
62
|
+
const newLine = `${newKeyName}=${privateKey}`;
|
|
63
|
+
lines[i] = newLine;
|
|
64
|
+
envContent = lines.join('\n');
|
|
65
|
+
fs.writeFileSync(`${path}/.env`, envContent);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const dubhe = new Dubhe({ secretKey: privateKey });
|
|
72
|
+
const keypair = dubhe.getSigner();
|
|
73
|
+
console.log(chalk.blue(`Using existing account: ${keypair.toSuiAddress()}`));
|
|
69
74
|
return;
|
|
70
75
|
}
|
|
71
76
|
} catch (error) {
|
|
72
77
|
// .env file doesn't exist or failed to read, continue to generate new account
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.log(chalk.green(`File created at: ${path}/.env`));
|
|
80
|
+
// Generate a new account if no existing key is found or force generation is requested
|
|
81
|
+
if (force || !privateKey) {
|
|
82
|
+
const dubhe = new Dubhe();
|
|
83
|
+
const keypair = dubhe.getSigner();
|
|
84
|
+
privateKey = keypair.getSecretKey();
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
const newKeyName = useNextPublic ? 'NEXT_PUBLIC_PRIVATE_KEY' : 'PRIVATE_KEY';
|
|
87
|
+
const newContent = `${newKeyName}=${privateKey}`;
|
|
88
|
+
|
|
89
|
+
// If .env file exists, append new content; otherwise create a new file
|
|
90
|
+
if (envContent) {
|
|
91
|
+
envContent = envContent.trim() + '\n' + newContent;
|
|
92
|
+
} else {
|
|
93
|
+
envContent = newContent;
|
|
86
94
|
}
|
|
87
|
-
fs.writeFileSync(
|
|
88
|
-
outputTsPath,
|
|
89
|
-
`export const PRIVATEKEY = '${privateKey}';
|
|
90
|
-
export const ACCOUNT = '${keypair.toSuiAddress()}';
|
|
91
|
-
`
|
|
92
|
-
);
|
|
93
|
-
console.log(chalk.green(`File created at: ${outputTsPath}\n`));
|
|
94
|
-
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
fs.writeFileSync(`${path}/.env`, envContent);
|
|
97
|
+
console.log(chalk.green(`File created/updated at: ${path}/.env`));
|
|
98
|
+
|
|
99
|
+
console.log(chalk.blue(`New account generated: ${keypair.toSuiAddress()}`));
|
|
100
|
+
}
|
|
97
101
|
}
|
package/src/utils/index.ts
CHANGED