soluser 1.0.9 → 1.0.11
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/README.md +5 -0
- package/bin/index.js +24 -1
- package/package.json +6 -1
- package/src/commands/from_mnemonic.js +79 -0
- package/src/commands/keyfile.js +15 -0
- package/src/utils/example.js +13 -10
- package/src/utils/execExpectInput.js +1 -1
package/README.md
CHANGED
package/bin/index.js
CHANGED
|
@@ -8,7 +8,9 @@ const removeAccount = require('../src/commands/remove');
|
|
|
8
8
|
const { showExamples } = require('../src/utils/example');
|
|
9
9
|
const pruneAccount = require('../src/commands/prune');
|
|
10
10
|
const clear = require('../src/commands/clear');
|
|
11
|
-
|
|
11
|
+
// 导入 keyfile 命令
|
|
12
|
+
const showKeyfilePath = require('../src/commands/keyfile');
|
|
13
|
+
const importMnemonic = require( '../src/commands/from_mnemonic');
|
|
12
14
|
|
|
13
15
|
// 导入地址查询命令
|
|
14
16
|
const showAddress = require('../src/commands/address');
|
|
@@ -44,6 +46,16 @@ program
|
|
|
44
46
|
requestAirdrop(amount, alias);
|
|
45
47
|
});
|
|
46
48
|
|
|
49
|
+
program
|
|
50
|
+
.command('import')
|
|
51
|
+
.description('Import a Solana account from mnemonic')
|
|
52
|
+
.argument('<mnemonic>', 'mnemoic oconsole.logf the account to import')
|
|
53
|
+
.option('--alias <alias>', 'alias of account')
|
|
54
|
+
.action((mnemonic,{alias}) => {
|
|
55
|
+
console.log("alias:" ,alias)
|
|
56
|
+
importMnemonic(mnemonic, alias);
|
|
57
|
+
});
|
|
58
|
+
|
|
47
59
|
// ... existing code ...
|
|
48
60
|
// 定义余额查询命令
|
|
49
61
|
program
|
|
@@ -77,6 +89,17 @@ program
|
|
|
77
89
|
);
|
|
78
90
|
});
|
|
79
91
|
|
|
92
|
+
// ...
|
|
93
|
+
|
|
94
|
+
// 定义 keyfile 命令
|
|
95
|
+
program
|
|
96
|
+
.command('keyfile')
|
|
97
|
+
.alias('k')
|
|
98
|
+
.description('Output the keyfile path of the current Solana account')
|
|
99
|
+
.action(() => {
|
|
100
|
+
showKeyfilePath();
|
|
101
|
+
});
|
|
102
|
+
|
|
80
103
|
|
|
81
104
|
// 定义切换账号命令(修改后)
|
|
82
105
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "soluser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "A CLI tool to manage Solana accounts (new, switch, list)",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,9 +20,13 @@
|
|
|
20
20
|
"author": "guahuzi",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@solana/web3.js": "^1.98.4",
|
|
24
|
+
"bip39": "^3.1.0",
|
|
23
25
|
"chalk": "4.1.2",
|
|
24
26
|
"cli-table3": "^0.6.5",
|
|
25
27
|
"commander": "^14.0.2",
|
|
28
|
+
"dotenv": "^17.2.3",
|
|
29
|
+
"ed25519-hd-key": "^1.3.0",
|
|
26
30
|
"readline": "^1.3.0"
|
|
27
31
|
},
|
|
28
32
|
"devDependencies": {
|
|
@@ -37,6 +41,7 @@
|
|
|
37
41
|
"package-lock.json",
|
|
38
42
|
"README.md"
|
|
39
43
|
],
|
|
44
|
+
"type": "commonjs",
|
|
40
45
|
"repository": {
|
|
41
46
|
"type": "git",
|
|
42
47
|
"url": "https://github.com/nextuser/soluser.git"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const { Keypair } = require( '@solana/web3.js');
|
|
2
|
+
const bip39 = require( 'bip39');
|
|
3
|
+
const { Buffer } = require( 'buffer');
|
|
4
|
+
const dotenv = require( 'dotenv');
|
|
5
|
+
const bs58 = require( 'bs58');
|
|
6
|
+
const fs = require( 'fs');
|
|
7
|
+
const path = require( 'path');
|
|
8
|
+
const {debug} = require('../utils/debug');
|
|
9
|
+
//根据助记词推算密钥(secretkey)和地址(publickey)
|
|
10
|
+
///const ed25519 = = require('ed25519-hd-keyed25519-hd-key')
|
|
11
|
+
const ed25519 = require( 'ed25519-hd-key');
|
|
12
|
+
const { fileURLToPath } = require('url');
|
|
13
|
+
dotenv.config()
|
|
14
|
+
// BIP44路径
|
|
15
|
+
const BIP44_SOLANA_PATH = "m/44'/501'/0'/0'";
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function generate_keypair_path(mnemonic,bip44path) {
|
|
19
|
+
// 生成种子
|
|
20
|
+
const seed = bip39.mnemonicToSeedSync(mnemonic);
|
|
21
|
+
//console.log('seed ', seed)
|
|
22
|
+
const hex_bytes= seed.toString('hex');
|
|
23
|
+
//console.log("hex seed byte",Buffer.from(hex_bytes));
|
|
24
|
+
debug("****BIP44_PATH:",bip44path);
|
|
25
|
+
// 派生密钥
|
|
26
|
+
const derivedSeed = ed25519.derivePath(bip44path,hex_bytes).key
|
|
27
|
+
// 创建 ED25519 密钥对
|
|
28
|
+
const keypair = Keypair.fromSeed(derivedSeed.slice(0, 32)); // 只取前32字节
|
|
29
|
+
return keypair;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function importMnemonic(mnemonic,alias) {
|
|
33
|
+
// 验证助记词
|
|
34
|
+
if (!bip39.validateMnemonic(mnemonic)) {
|
|
35
|
+
debug("mnemonic is ",mnemonic);
|
|
36
|
+
throw new Error('无效的助记词');
|
|
37
|
+
}
|
|
38
|
+
let keypair = generate_keypair_path(mnemonic,BIP44_SOLANA_PATH);
|
|
39
|
+
|
|
40
|
+
// 对公钥进行哈希处理
|
|
41
|
+
// 输出公钥和私钥
|
|
42
|
+
console.log('Address:', keypair.publicKey.toBase58());
|
|
43
|
+
//console.log('SOLANA Private Key:', bs58.encode(keypair.secretKey)); // Base64 编码私钥
|
|
44
|
+
|
|
45
|
+
write_secretekey(keypair,alias);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function test() {
|
|
49
|
+
// 输入助记词
|
|
50
|
+
const mnemonic = process.env.MNEMONIC; // 替换为你的助记词
|
|
51
|
+
if (!mnemonic) {
|
|
52
|
+
console.log('Your need export MNEMONIC= ')
|
|
53
|
+
process.exit(-1)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
importMnemonic(mnemonic,'abc');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
function write_secretekey(keypair ,alias){
|
|
62
|
+
let arr = [];
|
|
63
|
+
keypair.secretKey.forEach((item)=>{
|
|
64
|
+
arr.push(item)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
let account= keypair.publicKey.toBase58()
|
|
68
|
+
let msg = JSON.stringify(arr);
|
|
69
|
+
alias = alias || account;
|
|
70
|
+
//console.log('msg ', msg)
|
|
71
|
+
let file = path.resolve(process.env.HOME,".config/solana/keys/" , alias + ".json");
|
|
72
|
+
fs.writeFileSync(file,msg)
|
|
73
|
+
console.log("write file :",file);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (process.env.TEST == "true"){
|
|
77
|
+
test()
|
|
78
|
+
}
|
|
79
|
+
module.exports = importMnemonic;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
const { execCommand } = require('../utils/solana');
|
|
3
|
+
function getKeyFilePath() {
|
|
4
|
+
const keyfile = execCommand('solana config get keypair');
|
|
5
|
+
if(keyfile && keyfile.includes('Key Path') && keyfile.includes(":")){
|
|
6
|
+
return keyfile.split(":")[1].trim();
|
|
7
|
+
}
|
|
8
|
+
throw new Error('Error: Keypair path not found in config , failed to parse' + keyfile) ;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function showKeyfilePath() {
|
|
12
|
+
console.log(getKeyFilePath());
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = showKeyfilePath;
|
package/src/utils/example.js
CHANGED
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
const examples = `
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Check version
|
|
4
4
|
|
|
5
5
|
$ soluser --version
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## create account
|
|
9
9
|
|
|
10
10
|
$ soluser new alice
|
|
11
11
|
$ soluser new bob --word-length 12
|
|
12
12
|
$ soluser new charlie --word-length 24 --without-passphrase
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Switch account
|
|
16
16
|
|
|
17
17
|
$ soluser switch bob
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
## 列出账号
|
|
19
|
+
## List all accounts
|
|
21
20
|
|
|
22
21
|
$ soluser list
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
## 删除账号
|
|
23
|
+
## Delete account
|
|
26
24
|
|
|
27
25
|
$ soluser remove alice
|
|
28
26
|
|
|
29
|
-
##
|
|
27
|
+
## View address of alias
|
|
30
28
|
|
|
31
29
|
$ soluser address alice
|
|
32
30
|
|
|
33
|
-
##
|
|
31
|
+
## View balance of alias
|
|
34
32
|
|
|
35
33
|
$ soluser balance alice
|
|
36
34
|
|
|
37
|
-
## airdrop
|
|
35
|
+
## airdrop to alias
|
|
38
36
|
|
|
39
37
|
$ soluser airdrop 5 alice
|
|
38
|
+
|
|
39
|
+
## import Mnemonic
|
|
40
|
+
|
|
41
|
+
$ soluser import "mnemonic ... (12words or 24words)" --alias someone
|
|
42
|
+
|
|
40
43
|
`;
|
|
41
44
|
|
|
42
45
|
const chalk = require('chalk');
|
|
@@ -67,7 +67,7 @@ function execExpectOutput(inputArgs, expectOut,finish_callback){
|
|
|
67
67
|
|
|
68
68
|
child.on('close', (code) => {
|
|
69
69
|
try{
|
|
70
|
-
|
|
70
|
+
debug("output :",output);
|
|
71
71
|
//debug("code",code);
|
|
72
72
|
if(expectOut) expect(output).to.include(expectOut);
|
|
73
73
|
if(finish_callback) finish_callback(output);
|