dipcoin-cli 1.2.1 → 1.2.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.
- package/README.md +4 -3
- package/dist/cli.cjs +57 -167
- package/dist/cli.cjs.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ dipcoin-cli setup import # mainnet (default)
|
|
|
29
29
|
dipcoin-cli setup import --network testnet
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Paste either your `suiprivkey1...` private key **or** a 12-word (or 15/18/21/24) BIP39 mnemonic at the hidden prompt. The input is auto-detected; mnemonics are validated against the BIP39 wordlist and checksum.
|
|
33
33
|
|
|
34
34
|
**Or generate a new wallet:**
|
|
35
35
|
|
|
@@ -46,10 +46,11 @@ The generated `~/.config/dipcoin/env` contains:
|
|
|
46
46
|
|
|
47
47
|
| Variable | Required | Description |
|
|
48
48
|
|----------|----------|-------------|
|
|
49
|
-
| `DIPCOIN_PRIVATE_KEY` |
|
|
49
|
+
| `DIPCOIN_PRIVATE_KEY` | One of these | Sui private key (`suiprivkey1...`), supports ED25519/Secp256k1/Secp256r1 |
|
|
50
|
+
| `DIPCOIN_MNEMONIC` | is required | 12/15/18/21/24-word BIP39 mnemonic |
|
|
50
51
|
| `DIPCOIN_NETWORK` | No | `mainnet` or `testnet` (default: `mainnet`) |
|
|
51
52
|
|
|
52
|
-
Manual editing is supported but discouraged — prefer the `setup` commands so format and permissions stay correct.
|
|
53
|
+
If both are set, `DIPCOIN_PRIVATE_KEY` takes precedence. Manual editing is supported but discouraged — prefer the `setup` commands so format and permissions stay correct.
|
|
53
54
|
|
|
54
55
|
### Quick Start
|
|
55
56
|
|
package/dist/cli.cjs
CHANGED
|
@@ -7,6 +7,8 @@ var path = require('path');
|
|
|
7
7
|
var os = require('os');
|
|
8
8
|
var fs = require('fs');
|
|
9
9
|
var ed25519 = require('@mysten/sui/keypairs/ed25519');
|
|
10
|
+
var bip39 = require('@scure/bip39');
|
|
11
|
+
var cryptography = require('@mysten/sui/cryptography');
|
|
10
12
|
var utils = require('@mysten/sui/utils');
|
|
11
13
|
var BigNumber = require('bignumber.js');
|
|
12
14
|
var buffer = require('buffer');
|
|
@@ -15,6 +17,7 @@ var transactions = require('@mysten/sui/transactions');
|
|
|
15
17
|
var pythSuiJs = require('@pythnetwork/pyth-sui-js');
|
|
16
18
|
var child_process = require('child_process');
|
|
17
19
|
var Table = require('cli-table3');
|
|
20
|
+
var english_js = require('@scure/bip39/wordlists/english.js');
|
|
18
21
|
var readline = require('readline');
|
|
19
22
|
|
|
20
23
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -195,16 +198,6 @@ function toBytes(data) {
|
|
|
195
198
|
abytes$1(data);
|
|
196
199
|
return data;
|
|
197
200
|
}
|
|
198
|
-
/**
|
|
199
|
-
* Helper for KDFs: consumes uint8array or string.
|
|
200
|
-
* When string is passed, does utf8 decoding, using TextDecoder.
|
|
201
|
-
*/
|
|
202
|
-
function kdfInputToBytes(data) {
|
|
203
|
-
if (typeof data === 'string')
|
|
204
|
-
data = utf8ToBytes(data);
|
|
205
|
-
abytes$1(data);
|
|
206
|
-
return data;
|
|
207
|
-
}
|
|
208
201
|
/** Copies several Uint8Arrays into one. */
|
|
209
202
|
function concatBytes(...arrays) {
|
|
210
203
|
let sum = 0;
|
|
@@ -221,12 +214,6 @@ function concatBytes(...arrays) {
|
|
|
221
214
|
}
|
|
222
215
|
return res;
|
|
223
216
|
}
|
|
224
|
-
function checkOpts(defaults, opts) {
|
|
225
|
-
if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')
|
|
226
|
-
throw new Error('options should be object or undefined');
|
|
227
|
-
const merged = Object.assign(defaults, opts);
|
|
228
|
-
return merged;
|
|
229
|
-
}
|
|
230
217
|
/** For runtime check if class implements interface */
|
|
231
218
|
class Hash {
|
|
232
219
|
}
|
|
@@ -3785,7 +3772,7 @@ function padding(bits, chr = '=') {
|
|
|
3785
3772
|
/**
|
|
3786
3773
|
* @__NO_SIDE_EFFECTS__
|
|
3787
3774
|
*/
|
|
3788
|
-
function normalize
|
|
3775
|
+
function normalize(fn) {
|
|
3789
3776
|
afn(fn);
|
|
3790
3777
|
return { encode: (from) => from, decode: (to) => fn(to) };
|
|
3791
3778
|
}
|
|
@@ -4040,7 +4027,7 @@ chain(radix2(5), alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'), join$1(''));
|
|
|
4040
4027
|
* // => Uint8Array.from([0x12, 0xab])
|
|
4041
4028
|
* ```
|
|
4042
4029
|
*/
|
|
4043
|
-
chain(radix2(5), alphabet('0123456789ABCDEFGHJKMNPQRSTVWXYZ'), join$1(''), normalize
|
|
4030
|
+
chain(radix2(5), alphabet('0123456789ABCDEFGHJKMNPQRSTVWXYZ'), join$1(''), normalize((s) => s.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1')));
|
|
4044
4031
|
// Built-in base64 conversion https://caniuse.com/mdn-javascript_builtins_uint8array_frombase64
|
|
4045
4032
|
// prettier-ignore
|
|
4046
4033
|
const hasBase64Builtin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === 'function' &&
|
|
@@ -4265,7 +4252,7 @@ const hexBuiltin = {
|
|
|
4265
4252
|
*/
|
|
4266
4253
|
hasHexBuiltin
|
|
4267
4254
|
? hexBuiltin
|
|
4268
|
-
: chain(radix2(4), alphabet('0123456789abcdef'), join$1(''), normalize
|
|
4255
|
+
: chain(radix2(4), alphabet('0123456789abcdef'), join$1(''), normalize((s) => {
|
|
4269
4256
|
if (typeof s !== 'string' || s.length % 2 !== 0)
|
|
4270
4257
|
throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
|
|
4271
4258
|
return s.toLowerCase();
|
|
@@ -12413,7 +12400,6 @@ function parseSerializedSignature(serializedSignature) {
|
|
|
12413
12400
|
}
|
|
12414
12401
|
|
|
12415
12402
|
const PRIVATE_KEY_SIZE = 32;
|
|
12416
|
-
const LEGACY_PRIVATE_KEY_SIZE = 64;
|
|
12417
12403
|
const SUI_PRIVATE_KEY_PREFIX = "suiprivkey";
|
|
12418
12404
|
class Signer {
|
|
12419
12405
|
/**
|
|
@@ -12495,131 +12481,6 @@ function encodeSuiPrivateKey(bytes, scheme) {
|
|
|
12495
12481
|
return bech32.encode(SUI_PRIVATE_KEY_PREFIX, bech32.toWords(privKeyBytes));
|
|
12496
12482
|
}
|
|
12497
12483
|
|
|
12498
|
-
/**
|
|
12499
|
-
* PBKDF (RFC 2898). Can be used to create a key from password and salt.
|
|
12500
|
-
* @module
|
|
12501
|
-
*/
|
|
12502
|
-
// Common prologue and epilogue for sync/async functions
|
|
12503
|
-
function pbkdf2Init(hash, _password, _salt, _opts) {
|
|
12504
|
-
ahash(hash);
|
|
12505
|
-
const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
|
|
12506
|
-
const { c, dkLen, asyncTick } = opts;
|
|
12507
|
-
anumber$1(c);
|
|
12508
|
-
anumber$1(dkLen);
|
|
12509
|
-
anumber$1(asyncTick);
|
|
12510
|
-
if (c < 1)
|
|
12511
|
-
throw new Error('iterations (c) should be >= 1');
|
|
12512
|
-
const password = kdfInputToBytes(_password);
|
|
12513
|
-
const salt = kdfInputToBytes(_salt);
|
|
12514
|
-
// DK = PBKDF2(PRF, Password, Salt, c, dkLen);
|
|
12515
|
-
const DK = new Uint8Array(dkLen);
|
|
12516
|
-
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
|
12517
|
-
const PRF = hmac.create(hash, password);
|
|
12518
|
-
const PRFSalt = PRF._cloneInto().update(salt);
|
|
12519
|
-
return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
|
|
12520
|
-
}
|
|
12521
|
-
function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) {
|
|
12522
|
-
PRF.destroy();
|
|
12523
|
-
PRFSalt.destroy();
|
|
12524
|
-
if (prfW)
|
|
12525
|
-
prfW.destroy();
|
|
12526
|
-
clean(u);
|
|
12527
|
-
return DK;
|
|
12528
|
-
}
|
|
12529
|
-
/**
|
|
12530
|
-
* PBKDF2-HMAC: RFC 2898 key derivation function
|
|
12531
|
-
* @param hash - hash function that would be used e.g. sha256
|
|
12532
|
-
* @param password - password from which a derived key is generated
|
|
12533
|
-
* @param salt - cryptographic salt
|
|
12534
|
-
* @param opts - {c, dkLen} where c is work factor and dkLen is output message size
|
|
12535
|
-
* @example
|
|
12536
|
-
* const key = pbkdf2(sha256, 'password', 'salt', { dkLen: 32, c: Math.pow(2, 18) });
|
|
12537
|
-
*/
|
|
12538
|
-
function pbkdf2(hash, password, salt, opts) {
|
|
12539
|
-
const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
|
|
12540
|
-
let prfW; // Working copy
|
|
12541
|
-
const arr = new Uint8Array(4);
|
|
12542
|
-
const view = createView(arr);
|
|
12543
|
-
const u = new Uint8Array(PRF.outputLen);
|
|
12544
|
-
// DK = T1 + T2 + ⋯ + Tdklen/hlen
|
|
12545
|
-
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
|
12546
|
-
// Ti = F(Password, Salt, c, i)
|
|
12547
|
-
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
|
12548
|
-
view.setInt32(0, ti, false);
|
|
12549
|
-
// F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
|
|
12550
|
-
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
|
12551
|
-
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
|
12552
|
-
Ti.set(u.subarray(0, Ti.length));
|
|
12553
|
-
for (let ui = 1; ui < c; ui++) {
|
|
12554
|
-
// Uc = PRF(Password, Uc−1)
|
|
12555
|
-
PRF._cloneInto(prfW).update(u).digestInto(u);
|
|
12556
|
-
for (let i = 0; i < Ti.length; i++)
|
|
12557
|
-
Ti[i] ^= u[i];
|
|
12558
|
-
}
|
|
12559
|
-
}
|
|
12560
|
-
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
|
12561
|
-
}
|
|
12562
|
-
|
|
12563
|
-
/**
|
|
12564
|
-
* Audited & minimal JS implementation of
|
|
12565
|
-
* [BIP39 mnemonic phrases](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki).
|
|
12566
|
-
* @module
|
|
12567
|
-
* @example
|
|
12568
|
-
```js
|
|
12569
|
-
import * as bip39 from '@scure/bip39';
|
|
12570
|
-
import { wordlist } from '@scure/bip39/wordlists/english';
|
|
12571
|
-
const mn = bip39.generateMnemonic(wordlist);
|
|
12572
|
-
console.log(mn);
|
|
12573
|
-
const ent = bip39.mnemonicToEntropy(mn, wordlist)
|
|
12574
|
-
bip39.entropyToMnemonic(ent, wordlist);
|
|
12575
|
-
bip39.validateMnemonic(mn, wordlist);
|
|
12576
|
-
await bip39.mnemonicToSeed(mn, 'password');
|
|
12577
|
-
bip39.mnemonicToSeedSync(mn, 'password');
|
|
12578
|
-
|
|
12579
|
-
// Wordlists
|
|
12580
|
-
import { wordlist as czech } from '@scure/bip39/wordlists/czech';
|
|
12581
|
-
import { wordlist as english } from '@scure/bip39/wordlists/english';
|
|
12582
|
-
import { wordlist as french } from '@scure/bip39/wordlists/french';
|
|
12583
|
-
import { wordlist as italian } from '@scure/bip39/wordlists/italian';
|
|
12584
|
-
import { wordlist as japanese } from '@scure/bip39/wordlists/japanese';
|
|
12585
|
-
import { wordlist as korean } from '@scure/bip39/wordlists/korean';
|
|
12586
|
-
import { wordlist as portuguese } from '@scure/bip39/wordlists/portuguese';
|
|
12587
|
-
import { wordlist as simplifiedChinese } from '@scure/bip39/wordlists/simplified-chinese';
|
|
12588
|
-
import { wordlist as spanish } from '@scure/bip39/wordlists/spanish';
|
|
12589
|
-
import { wordlist as traditionalChinese } from '@scure/bip39/wordlists/traditional-chinese';
|
|
12590
|
-
```
|
|
12591
|
-
*/
|
|
12592
|
-
// Normalization replaces equivalent sequences of characters
|
|
12593
|
-
// so that any two texts that are equivalent will be reduced
|
|
12594
|
-
// to the same sequence of code points, called the normal form of the original text.
|
|
12595
|
-
// https://tonsky.me/blog/unicode/#why-is-a----
|
|
12596
|
-
function nfkd(str) {
|
|
12597
|
-
if (typeof str !== 'string')
|
|
12598
|
-
throw new TypeError('invalid mnemonic type: ' + typeof str);
|
|
12599
|
-
return str.normalize('NFKD');
|
|
12600
|
-
}
|
|
12601
|
-
function normalize(str) {
|
|
12602
|
-
const norm = nfkd(str);
|
|
12603
|
-
const words = norm.split(' ');
|
|
12604
|
-
if (![12, 15, 18, 21, 24].includes(words.length))
|
|
12605
|
-
throw new Error('Invalid mnemonic');
|
|
12606
|
-
return { nfkd: norm, words };
|
|
12607
|
-
}
|
|
12608
|
-
const psalt = (passphrase) => nfkd('mnemonic' + passphrase);
|
|
12609
|
-
/**
|
|
12610
|
-
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
|
|
12611
|
-
* @param mnemonic 12-24 words
|
|
12612
|
-
* @param passphrase string that will additionally protect the key
|
|
12613
|
-
* @returns 64 bytes of key data
|
|
12614
|
-
* @example
|
|
12615
|
-
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
|
12616
|
-
* mnemonicToSeedSync(mnem, 'password');
|
|
12617
|
-
* // new Uint8Array([...64 bytes])
|
|
12618
|
-
*/
|
|
12619
|
-
function mnemonicToSeedSync(mnemonic, passphrase = '') {
|
|
12620
|
-
return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
|
12621
|
-
}
|
|
12622
|
-
|
|
12623
12484
|
function isValidBIP32Path(path) {
|
|
12624
12485
|
if (!new RegExp("^m\\/(54|74)'\\/784'\\/[0-9]+'\\/[0-9]+\\/[0-9]+$").test(path)) {
|
|
12625
12486
|
return false;
|
|
@@ -12627,7 +12488,7 @@ function isValidBIP32Path(path) {
|
|
|
12627
12488
|
return true;
|
|
12628
12489
|
}
|
|
12629
12490
|
function mnemonicToSeed(mnemonics) {
|
|
12630
|
-
return mnemonicToSeedSync(mnemonics, "");
|
|
12491
|
+
return bip39.mnemonicToSeedSync(mnemonics, "");
|
|
12631
12492
|
}
|
|
12632
12493
|
|
|
12633
12494
|
const SECP256K1_PUBLIC_KEY_SIZE = 33;
|
|
@@ -13018,16 +12879,16 @@ function fromExportedKeypair(secret, legacySupport = false) {
|
|
|
13018
12879
|
schema = secret.schema;
|
|
13019
12880
|
}
|
|
13020
12881
|
else {
|
|
13021
|
-
const decoded = decodeSuiPrivateKey(secret);
|
|
12882
|
+
const decoded = cryptography.decodeSuiPrivateKey(secret);
|
|
13022
12883
|
schema = decoded.schema;
|
|
13023
12884
|
secretKey = decoded.secretKey;
|
|
13024
12885
|
}
|
|
13025
12886
|
switch (schema) {
|
|
13026
12887
|
case "ED25519": {
|
|
13027
12888
|
let pureSecretKey = secretKey;
|
|
13028
|
-
if (secretKey.length === LEGACY_PRIVATE_KEY_SIZE) {
|
|
12889
|
+
if (secretKey.length === cryptography.LEGACY_PRIVATE_KEY_SIZE) {
|
|
13029
12890
|
// Legacy secret key, strip public key bytes
|
|
13030
|
-
pureSecretKey = secretKey.slice(0, PRIVATE_KEY_SIZE);
|
|
12891
|
+
pureSecretKey = secretKey.slice(0, cryptography.PRIVATE_KEY_SIZE);
|
|
13031
12892
|
}
|
|
13032
12893
|
return ed25519.Ed25519Keypair.fromSecretKey(pureSecretKey);
|
|
13033
12894
|
}
|
|
@@ -13059,7 +12920,7 @@ async function signMessage(keypair, messageBytes) {
|
|
|
13059
12920
|
* @returns Formatted signature string
|
|
13060
12921
|
*/
|
|
13061
12922
|
function buildSignature(signature, isKeyPair = false) {
|
|
13062
|
-
const signatureData = parseSerializedSignature(signature);
|
|
12923
|
+
const signatureData = cryptography.parseSerializedSignature(signature);
|
|
13063
12924
|
let signatureHex = buffer.Buffer.from(signatureData.signature).toString("hex");
|
|
13064
12925
|
let publicKey = buffer.Buffer.from(signatureData.publicKey).toString("base64");
|
|
13065
12926
|
let flag = SignerTypes.KP_SECP256;
|
|
@@ -21061,9 +20922,12 @@ function readHiddenInput(prompt) {
|
|
|
21061
20922
|
stdin.on("data", onData);
|
|
21062
20923
|
});
|
|
21063
20924
|
}
|
|
21064
|
-
function writeEnvFile(
|
|
20925
|
+
function writeEnvFile(cred, network) {
|
|
21065
20926
|
fs__default["default"].mkdirSync(CONFIG_DIR, { recursive: true });
|
|
21066
|
-
const
|
|
20927
|
+
const line = cred.kind === "privateKey"
|
|
20928
|
+
? `DIPCOIN_PRIVATE_KEY=${cred.value}`
|
|
20929
|
+
: `DIPCOIN_MNEMONIC=${cred.value}`;
|
|
20930
|
+
const content = `${line}\nDIPCOIN_NETWORK=${network}\n`;
|
|
21067
20931
|
fs__default["default"].writeFileSync(ENV_PATH, content, { mode: 0o600 });
|
|
21068
20932
|
try {
|
|
21069
20933
|
fs__default["default"].chmodSync(ENV_PATH, 0o600);
|
|
@@ -21072,6 +20936,11 @@ function writeEnvFile(privateKey, network) {
|
|
|
21072
20936
|
// best-effort on platforms without POSIX perms
|
|
21073
20937
|
}
|
|
21074
20938
|
}
|
|
20939
|
+
const VALID_MNEMONIC_WORD_COUNTS = new Set([12, 15, 18, 21, 24]);
|
|
20940
|
+
function looksLikeMnemonic(input) {
|
|
20941
|
+
const words = input.split(/\s+/).filter(Boolean);
|
|
20942
|
+
return VALID_MNEMONIC_WORD_COUNTS.has(words.length);
|
|
20943
|
+
}
|
|
21075
20944
|
function resolveNetwork(input) {
|
|
21076
20945
|
return input === "testnet" ? "testnet" : "mainnet";
|
|
21077
20946
|
}
|
|
@@ -21081,7 +20950,7 @@ function registerSetupCommands(program) {
|
|
|
21081
20950
|
.description("Configure credentials (~/.config/dipcoin/env)");
|
|
21082
20951
|
setup
|
|
21083
20952
|
.command("import")
|
|
21084
|
-
.description("Import an existing Sui private key (interactive, hidden input)")
|
|
20953
|
+
.description("Import an existing Sui private key or mnemonic (interactive, hidden input)")
|
|
21085
20954
|
.option("--network <network>", "mainnet | testnet", "mainnet")
|
|
21086
20955
|
.action(async (opts) => {
|
|
21087
20956
|
try {
|
|
@@ -21090,27 +20959,48 @@ function registerSetupCommands(program) {
|
|
|
21090
20959
|
console.error("Aborted.");
|
|
21091
20960
|
process.exit(1);
|
|
21092
20961
|
}
|
|
21093
|
-
const
|
|
21094
|
-
if (!
|
|
20962
|
+
const raw = (await readHiddenInput("Paste your Sui private key (suiprivkey1...) or 12-word mnemonic: ")).trim();
|
|
20963
|
+
if (!raw) {
|
|
21095
20964
|
console.error("No input provided.");
|
|
21096
20965
|
process.exit(1);
|
|
21097
20966
|
}
|
|
21098
|
-
|
|
21099
|
-
console.error("Invalid format. Sui private keys must start with 'suiprivkey1'.");
|
|
21100
|
-
process.exit(1);
|
|
21101
|
-
}
|
|
20967
|
+
let cred;
|
|
21102
20968
|
let address;
|
|
21103
|
-
|
|
21104
|
-
|
|
21105
|
-
|
|
20969
|
+
if (raw.startsWith("suiprivkey1")) {
|
|
20970
|
+
try {
|
|
20971
|
+
cryptography.decodeSuiPrivateKey(raw);
|
|
20972
|
+
address = fromExportedKeypair(raw).toSuiAddress();
|
|
20973
|
+
}
|
|
20974
|
+
catch (e) {
|
|
20975
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
20976
|
+
console.error(`Failed to decode private key: ${msg}`);
|
|
20977
|
+
process.exit(1);
|
|
20978
|
+
}
|
|
20979
|
+
cred = { kind: "privateKey", value: raw };
|
|
21106
20980
|
}
|
|
21107
|
-
|
|
21108
|
-
const
|
|
21109
|
-
|
|
20981
|
+
else if (looksLikeMnemonic(raw)) {
|
|
20982
|
+
const normalized = raw.split(/\s+/).filter(Boolean).join(" ").toLowerCase();
|
|
20983
|
+
if (!bip39.validateMnemonic(normalized, english_js.wordlist)) {
|
|
20984
|
+
console.error("Invalid mnemonic: words must be from the BIP39 English wordlist and the checksum must match.");
|
|
20985
|
+
process.exit(1);
|
|
20986
|
+
}
|
|
20987
|
+
try {
|
|
20988
|
+
address = ed25519.Ed25519Keypair.deriveKeypair(normalized, `m/44'/784'/0'/0'/0'`).toSuiAddress();
|
|
20989
|
+
}
|
|
20990
|
+
catch (e) {
|
|
20991
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
20992
|
+
console.error(`Failed to derive keypair from mnemonic: ${msg}`);
|
|
20993
|
+
process.exit(1);
|
|
20994
|
+
}
|
|
20995
|
+
cred = { kind: "mnemonic", value: normalized };
|
|
20996
|
+
}
|
|
20997
|
+
else {
|
|
20998
|
+
console.error("Unrecognized format. Expected a Sui private key (starts with 'suiprivkey1') or a 12/15/18/21/24-word mnemonic.");
|
|
21110
20999
|
process.exit(1);
|
|
21111
21000
|
}
|
|
21112
|
-
writeEnvFile(
|
|
21001
|
+
writeEnvFile(cred, network);
|
|
21113
21002
|
console.log(`Saved to ${ENV_PATH} (chmod 600).`);
|
|
21003
|
+
console.log(`Type: ${cred.kind === "privateKey" ? "private key" : "mnemonic"}`);
|
|
21114
21004
|
console.log(`Network: ${network}`);
|
|
21115
21005
|
console.log(`Address: ${address}`);
|
|
21116
21006
|
}
|
|
@@ -21134,7 +21024,7 @@ function registerSetupCommands(program) {
|
|
|
21134
21024
|
const kp = new ed25519.Ed25519Keypair();
|
|
21135
21025
|
const privateKey = kp.getSecretKey();
|
|
21136
21026
|
const address = kp.toSuiAddress();
|
|
21137
|
-
writeEnvFile(privateKey, network);
|
|
21027
|
+
writeEnvFile({ kind: "privateKey", value: privateKey }, network);
|
|
21138
21028
|
console.log(`Generated new keypair and saved to ${ENV_PATH} (chmod 600).`);
|
|
21139
21029
|
console.log(`Network: ${network}`);
|
|
21140
21030
|
console.log(`Address: ${address}`);
|