nkamoto 1.2.0
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/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/balance.d.ts +16 -0
- package/dist/balance.js +71 -0
- package/dist/balance.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +145 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/qr.d.ts +5 -0
- package/dist/qr.js +9 -0
- package/dist/qr.js.map +1 -0
- package/dist/wallet/derive.d.ts +4 -0
- package/dist/wallet/derive.js +28 -0
- package/dist/wallet/derive.js.map +1 -0
- package/dist/wallet/generate.d.ts +9 -0
- package/dist/wallet/generate.js +26 -0
- package/dist/wallet/generate.js.map +1 -0
- package/dist/wallet/passphrase.d.ts +4 -0
- package/dist/wallet/passphrase.js +22 -0
- package/dist/wallet/passphrase.js.map +1 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nkamoto contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# nkamoto
|
|
2
|
+
|
|
3
|
+
A terminal Bitcoin wallet CLI built around BIP-39 and BIP-84.
|
|
4
|
+
|
|
5
|
+
> **Security status:** development release. Do not use this implementation to store real BTC until it has been independently reviewed and audited.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 20.19+.
|
|
10
|
+
- npm.
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
Running `nkamoto` without a command displays help.
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
nkamoto
|
|
18
|
+
nkamoto generate
|
|
19
|
+
nkamoto validate
|
|
20
|
+
nkamoto balance <bc1...>
|
|
21
|
+
nkamoto --help
|
|
22
|
+
nkamoto --version
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### `nkamoto generate`
|
|
26
|
+
|
|
27
|
+
Generates:
|
|
28
|
+
|
|
29
|
+
- 256 bits of cryptographically secure entropy.
|
|
30
|
+
- A 24-word BIP-39 English mnemonic.
|
|
31
|
+
- A separately generated 12-word BIP-39 passphrase.
|
|
32
|
+
- A Bitcoin mainnet BIP-84 native SegWit address.
|
|
33
|
+
- Terminal QR codes for the mnemonic and passphrase.
|
|
34
|
+
|
|
35
|
+
Derivation path:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
m/84'/0'/0'/0/0
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `nkamoto validate`
|
|
42
|
+
|
|
43
|
+
Reads the mnemonic interactively rather than accepting it as a command-line argument, reducing the chance of shell-history leakage.
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
nkamoto validate
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
It validates the BIP-39 checksum, accepts the optional BIP-39 passphrase interactively, and derives the first BIP-84 address.
|
|
50
|
+
|
|
51
|
+
### `nkamoto balance`
|
|
52
|
+
|
|
53
|
+
Checks a public Bitcoin address using the Blockstream Esplora API.
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
nkamoto balance bc1q...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Only the public address is sent to the balance service. The command does not accept or require a mnemonic or private key.
|
|
60
|
+
|
|
61
|
+
The provider is isolated behind `BitcoinBalanceProvider` so a self-hosted or alternative backend can be added later.
|
|
62
|
+
|
|
63
|
+
## Development
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install
|
|
67
|
+
npm run lint
|
|
68
|
+
npm test
|
|
69
|
+
npm run build
|
|
70
|
+
npm start
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For direct development:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm run dev
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Security
|
|
80
|
+
|
|
81
|
+
The mnemonic and BIP-39 passphrase are recovery secrets.
|
|
82
|
+
|
|
83
|
+
Do not:
|
|
84
|
+
|
|
85
|
+
- put them in shell arguments;
|
|
86
|
+
- paste them into websites or chat;
|
|
87
|
+
- commit them to source control;
|
|
88
|
+
- redirect wallet-generation output to files;
|
|
89
|
+
- use generated wallets with real funds before independent security review.
|
|
90
|
+
|
|
91
|
+
The public API intentionally does not return the derived BIP-39 seed.
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface BitcoinBalance {
|
|
2
|
+
readonly address: string;
|
|
3
|
+
readonly confirmedSatoshis: bigint;
|
|
4
|
+
readonly unconfirmedSatoshis: bigint;
|
|
5
|
+
readonly totalSatoshis: bigint;
|
|
6
|
+
}
|
|
7
|
+
export interface BitcoinBalanceProvider {
|
|
8
|
+
getBalance(address: string): Promise<BitcoinBalance>;
|
|
9
|
+
}
|
|
10
|
+
export declare class EsploraBalanceProvider implements BitcoinBalanceProvider {
|
|
11
|
+
private readonly baseUrl;
|
|
12
|
+
constructor(baseUrl?: string);
|
|
13
|
+
getBalance(address: string): Promise<BitcoinBalance>;
|
|
14
|
+
}
|
|
15
|
+
export declare function isBitcoinAddress(address: string): boolean;
|
|
16
|
+
export declare function satoshisToBtc(satoshis: bigint): string;
|
package/dist/balance.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export class EsploraBalanceProvider {
|
|
2
|
+
baseUrl;
|
|
3
|
+
constructor(baseUrl = "https://blockstream.info/api") {
|
|
4
|
+
this.baseUrl = baseUrl;
|
|
5
|
+
}
|
|
6
|
+
async getBalance(address) {
|
|
7
|
+
if (!isBitcoinAddress(address)) {
|
|
8
|
+
throw new Error("Invalid Bitcoin address");
|
|
9
|
+
}
|
|
10
|
+
const response = await fetch(`${this.baseUrl.replace(/\/$/, "")}/address/${encodeURIComponent(address)}`, {
|
|
11
|
+
headers: {
|
|
12
|
+
accept: "application/json",
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`Bitcoin balance request failed with HTTP ${response.status}`);
|
|
17
|
+
}
|
|
18
|
+
const data = await response.json();
|
|
19
|
+
const stats = parseAddressStats(data);
|
|
20
|
+
const confirmedSatoshis = stats.chainStats.funded - stats.chainStats.spent;
|
|
21
|
+
const unconfirmedSatoshis = stats.mempoolStats.funded - stats.mempoolStats.spent;
|
|
22
|
+
return {
|
|
23
|
+
address,
|
|
24
|
+
confirmedSatoshis,
|
|
25
|
+
unconfirmedSatoshis,
|
|
26
|
+
totalSatoshis: confirmedSatoshis + unconfirmedSatoshis,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function parseAddressStats(value) {
|
|
31
|
+
if (!isRecord(value)) {
|
|
32
|
+
throw new Error("Invalid Bitcoin API response");
|
|
33
|
+
}
|
|
34
|
+
const chainStats = parseStats(value.chain_stats);
|
|
35
|
+
const mempoolStats = parseStats(value.mempool_stats);
|
|
36
|
+
return { chainStats, mempoolStats };
|
|
37
|
+
}
|
|
38
|
+
function parseStats(value) {
|
|
39
|
+
if (!isRecord(value)) {
|
|
40
|
+
throw new Error("Invalid Bitcoin API response");
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
funded: parseNonNegativeInteger(value.funded_txo_sum),
|
|
44
|
+
spent: parseNonNegativeInteger(value.spent_txo_sum),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function parseNonNegativeInteger(value) {
|
|
48
|
+
if (typeof value !== "number" && typeof value !== "string") {
|
|
49
|
+
throw new Error("Invalid Bitcoin API response");
|
|
50
|
+
}
|
|
51
|
+
const text = String(value);
|
|
52
|
+
if (!/^\d+$/.test(text)) {
|
|
53
|
+
throw new Error("Invalid Bitcoin API response");
|
|
54
|
+
}
|
|
55
|
+
return BigInt(text);
|
|
56
|
+
}
|
|
57
|
+
function isRecord(value) {
|
|
58
|
+
return typeof value === "object" && value !== null;
|
|
59
|
+
}
|
|
60
|
+
export function isBitcoinAddress(address) {
|
|
61
|
+
return /^bc1[ac-hj-np-z02-9]{11,87}$/.test(address);
|
|
62
|
+
}
|
|
63
|
+
export function satoshisToBtc(satoshis) {
|
|
64
|
+
const whole = satoshis / 100000000n;
|
|
65
|
+
const fraction = (satoshis % 100000000n)
|
|
66
|
+
.toString()
|
|
67
|
+
.padStart(8, "0")
|
|
68
|
+
.replace(/0+$/, "");
|
|
69
|
+
return fraction ? `${whole}.${fraction}` : `${whole}.00000000`;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=balance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance.js","sourceRoot":"","sources":["../src/balance.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "node:readline/promises";
|
|
3
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
4
|
+
import { EsploraBalanceProvider, isBitcoinAddress, satoshisToBtc, } from "./balance.js";
|
|
5
|
+
import { renderQr } from "./qr.js";
|
|
6
|
+
import { BIP84_PATH, deriveBitcoinAddress, generateWallet, validateMnemonic, } from "./index.js";
|
|
7
|
+
const VERSION = "0.2.0";
|
|
8
|
+
const HELP = `NKAMOTO — Bitcoin wallet CLI
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
nkamoto <command>
|
|
12
|
+
|
|
13
|
+
Commands:
|
|
14
|
+
generate Generate a new Bitcoin wallet
|
|
15
|
+
qr Generate a new wallet with qr code
|
|
16
|
+
validate Validate a BIP-39 mnemonic
|
|
17
|
+
balance Check a Bitcoin address balance
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
-h, --help Show help
|
|
21
|
+
-v, --version Show version
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
nkamoto generate
|
|
25
|
+
nkamoto validate
|
|
26
|
+
nkamoto balance bc1q...
|
|
27
|
+
|
|
28
|
+
Security:
|
|
29
|
+
Never share your BIP-39 mnemonic or passphrase.
|
|
30
|
+
Never put recovery secrets in shell arguments.
|
|
31
|
+
`;
|
|
32
|
+
function printHelp() {
|
|
33
|
+
console.log(HELP);
|
|
34
|
+
}
|
|
35
|
+
function printVersion() {
|
|
36
|
+
console.log(`nkamoto ${VERSION}`);
|
|
37
|
+
}
|
|
38
|
+
async function runGenerate(qr_included) {
|
|
39
|
+
const wallet = generateWallet();
|
|
40
|
+
console.log("");
|
|
41
|
+
console.log("========================================");
|
|
42
|
+
console.log(" NKAMOTO BTC WALLET");
|
|
43
|
+
console.log("========================================");
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log("Network: Bitcoin Mainnet");
|
|
46
|
+
console.log("Standard: BIP-39");
|
|
47
|
+
console.log("Address type: BIP-84 / P2WPKH");
|
|
48
|
+
console.log(`Derivation path: ${BIP84_PATH}`);
|
|
49
|
+
console.log("");
|
|
50
|
+
if (qr_included) {
|
|
51
|
+
await printQr("BIP-39 MNEMONIC QR", wallet.mnemonic);
|
|
52
|
+
await printQr("BIP-39 PASSPHRASE QR", wallet.passphrase);
|
|
53
|
+
}
|
|
54
|
+
console.log("Bitcoin address:");
|
|
55
|
+
console.log(wallet.address);
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("WARNING");
|
|
58
|
+
console.log("-------");
|
|
59
|
+
console.log("Your mnemonic and passphrase control this wallet.");
|
|
60
|
+
console.log("Never share them with anyone.");
|
|
61
|
+
console.log("Store recovery information offline.");
|
|
62
|
+
console.log("");
|
|
63
|
+
}
|
|
64
|
+
async function runValidate() {
|
|
65
|
+
const rl = createInterface({ input, output });
|
|
66
|
+
try {
|
|
67
|
+
const mnemonic = await rl.question("Enter BIP-39 mnemonic: ");
|
|
68
|
+
if (!validateMnemonic(mnemonic.trim())) {
|
|
69
|
+
console.error("Invalid BIP-39 mnemonic.");
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const passphrase = await rl.question("Enter BIP-39 passphrase (leave empty if none): ");
|
|
74
|
+
const address = deriveBitcoinAddress(mnemonic.trim(), passphrase);
|
|
75
|
+
console.log("");
|
|
76
|
+
console.log("Valid BIP-39 mnemonic.");
|
|
77
|
+
console.log(`BIP-84 address: ${address}`);
|
|
78
|
+
console.log("");
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
rl.close();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function runBalance(address) {
|
|
85
|
+
if (!address || !isBitcoinAddress(address)) {
|
|
86
|
+
throw new Error("Usage: nkamoto balance <bc1... Bitcoin address>");
|
|
87
|
+
}
|
|
88
|
+
const provider = new EsploraBalanceProvider();
|
|
89
|
+
const balance = await provider.getBalance(address);
|
|
90
|
+
console.log("");
|
|
91
|
+
console.log(`Address: ${balance.address}`);
|
|
92
|
+
console.log(`Confirmed: ${satoshisToBtc(balance.confirmedSatoshis)} BTC`);
|
|
93
|
+
console.log(`Unconfirmed: ${satoshisToBtc(balance.unconfirmedSatoshis)} BTC`);
|
|
94
|
+
console.log(`Total: ${satoshisToBtc(balance.totalSatoshis)} BTC`);
|
|
95
|
+
console.log("");
|
|
96
|
+
}
|
|
97
|
+
async function printQr(label, value) {
|
|
98
|
+
console.log("");
|
|
99
|
+
console.log(label);
|
|
100
|
+
console.log("");
|
|
101
|
+
console.log(await renderQr(value));
|
|
102
|
+
}
|
|
103
|
+
async function main(argv) {
|
|
104
|
+
const [command, ...args] = argv;
|
|
105
|
+
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
106
|
+
printHelp();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
110
|
+
printVersion();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
switch (command) {
|
|
114
|
+
case "qr":
|
|
115
|
+
if (args.length > 0) {
|
|
116
|
+
throw new Error("qr does not accept arguments");
|
|
117
|
+
}
|
|
118
|
+
await runGenerate(true);
|
|
119
|
+
return;
|
|
120
|
+
case "generate":
|
|
121
|
+
if (args.length > 0) {
|
|
122
|
+
throw new Error("generate does not accept arguments");
|
|
123
|
+
}
|
|
124
|
+
await runGenerate(false);
|
|
125
|
+
return;
|
|
126
|
+
case "validate":
|
|
127
|
+
if (args.length > 0) {
|
|
128
|
+
throw new Error("validate reads the mnemonic interactively; do not pass secrets as arguments");
|
|
129
|
+
}
|
|
130
|
+
await runValidate();
|
|
131
|
+
return;
|
|
132
|
+
case "balance":
|
|
133
|
+
await runBalance(args[0]);
|
|
134
|
+
return;
|
|
135
|
+
default:
|
|
136
|
+
printHelp();
|
|
137
|
+
throw new Error(`Unknown command: ${command}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
main(process.argv.slice(2)).catch((error) => {
|
|
141
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
142
|
+
console.error(`nkamoto: ${message}`);
|
|
143
|
+
process.exitCode = 1;
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { BIP84_PATH, deriveBitcoinAddress, mnemonicToSeed, validateMnemonic, } from "./wallet/derive.js";
|
|
2
|
+
export { generateMnemonic, generateWallet, } from "./wallet/generate.js";
|
|
3
|
+
export type { BitcoinWallet, } from "./wallet/generate.js";
|
|
4
|
+
export { generatePassphrase, } from "./wallet/passphrase.js";
|
|
5
|
+
export type { RandomWordSource, } from "./wallet/passphrase.js";
|
|
6
|
+
export { renderQr, } from "./qr.js";
|
|
7
|
+
export type { QrOptions, } from "./qr.js";
|
|
8
|
+
export { EsploraBalanceProvider, isBitcoinAddress, satoshisToBtc, } from "./balance.js";
|
|
9
|
+
export type { BitcoinBalance, BitcoinBalanceProvider, } from "./balance.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BIP84_PATH, deriveBitcoinAddress, mnemonicToSeed, validateMnemonic, } from "./wallet/derive.js";
|
|
2
|
+
export { generateMnemonic, generateWallet, } from "./wallet/generate.js";
|
|
3
|
+
export { generatePassphrase, } from "./wallet/passphrase.js";
|
|
4
|
+
export { renderQr, } from "./qr.js";
|
|
5
|
+
export { EsploraBalanceProvider, isBitcoinAddress, satoshisToBtc, } from "./balance.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,QAAQ,GACT,MAAM,SAAS,CAAC;AAMjB,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,GACd,MAAM,cAAc,CAAC"}
|
package/dist/qr.d.ts
ADDED
package/dist/qr.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import QRCode from "qrcode";
|
|
2
|
+
export async function renderQr(value, options = {}) {
|
|
3
|
+
return QRCode.toString(value, {
|
|
4
|
+
type: "terminal",
|
|
5
|
+
errorCorrectionLevel: options.errorCorrectionLevel ?? "M",
|
|
6
|
+
margin: options.margin ?? 2,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=qr.js.map
|
package/dist/qr.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr.js","sourceRoot":"","sources":["../src/qr.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAO5B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAAa,EACb,UAAqB,EAAE;IAEvB,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;QAC5B,IAAI,EAAE,UAAU;QAChB,oBAAoB,EAAE,OAAO,CAAC,oBAAoB,IAAI,GAAG;QACzD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC;KAC5B,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const BIP84_PATH = "m/84'/0'/0'/0/0";
|
|
2
|
+
export declare function validateMnemonic(mnemonic: string): boolean;
|
|
3
|
+
export declare function mnemonicToSeed(mnemonic: string, passphrase: string): Uint8Array;
|
|
4
|
+
export declare function deriveBitcoinAddress(mnemonic: string, passphrase: string): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as bip32 from "@scure/bip32";
|
|
2
|
+
import * as bip39 from "@scure/bip39";
|
|
3
|
+
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
4
|
+
import * as btc from "@scure/btc-signer";
|
|
5
|
+
export const BIP84_PATH = "m/84'/0'/0'/0/0";
|
|
6
|
+
export function validateMnemonic(mnemonic) {
|
|
7
|
+
return bip39.validateMnemonic(mnemonic, wordlist);
|
|
8
|
+
}
|
|
9
|
+
export function mnemonicToSeed(mnemonic, passphrase) {
|
|
10
|
+
if (!validateMnemonic(mnemonic)) {
|
|
11
|
+
throw new Error("Invalid BIP-39 mnemonic");
|
|
12
|
+
}
|
|
13
|
+
return bip39.mnemonicToSeedSync(mnemonic, passphrase);
|
|
14
|
+
}
|
|
15
|
+
export function deriveBitcoinAddress(mnemonic, passphrase) {
|
|
16
|
+
const seed = mnemonicToSeed(mnemonic, passphrase);
|
|
17
|
+
const root = bip32.HDKey.fromMasterSeed(seed);
|
|
18
|
+
const child = root.derive(BIP84_PATH);
|
|
19
|
+
if (!child.publicKey) {
|
|
20
|
+
throw new Error("Failed to derive BIP-84 public key");
|
|
21
|
+
}
|
|
22
|
+
const payment = btc.p2wpkh(child.publicKey);
|
|
23
|
+
if (!payment.address) {
|
|
24
|
+
throw new Error("Failed to derive Bitcoin address");
|
|
25
|
+
}
|
|
26
|
+
return payment.address;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/wallet/derive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,KAAK,GAAG,MAAM,mBAAmB,CAAC;AAEzC,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAE5C,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,QAAgB,EAChB,UAAkB;IAElB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,KAAK,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,UAAkB;IAElB,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAEtC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BIP84_PATH } from "./derive.js";
|
|
2
|
+
export interface BitcoinWallet {
|
|
3
|
+
readonly mnemonic: string;
|
|
4
|
+
readonly passphrase: string;
|
|
5
|
+
readonly derivationPath: typeof BIP84_PATH;
|
|
6
|
+
readonly address: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function generateMnemonic(entropy?: Uint8Array): string;
|
|
9
|
+
export declare function generateWallet(): BitcoinWallet;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import * as bip39 from "@scure/bip39";
|
|
3
|
+
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
4
|
+
import { BIP84_PATH, deriveBitcoinAddress } from "./derive.js";
|
|
5
|
+
import { generatePassphrase } from "./passphrase.js";
|
|
6
|
+
const ENTROPY_BYTES = 32;
|
|
7
|
+
function generateEntropy() {
|
|
8
|
+
return new Uint8Array(randomBytes(ENTROPY_BYTES));
|
|
9
|
+
}
|
|
10
|
+
export function generateMnemonic(entropy = generateEntropy()) {
|
|
11
|
+
if (entropy.length !== ENTROPY_BYTES) {
|
|
12
|
+
throw new RangeError("Entropy must contain exactly 32 bytes");
|
|
13
|
+
}
|
|
14
|
+
return bip39.entropyToMnemonic(entropy, wordlist);
|
|
15
|
+
}
|
|
16
|
+
export function generateWallet() {
|
|
17
|
+
const mnemonic = generateMnemonic();
|
|
18
|
+
const passphrase = generatePassphrase();
|
|
19
|
+
return {
|
|
20
|
+
mnemonic,
|
|
21
|
+
passphrase,
|
|
22
|
+
derivationPath: BIP84_PATH,
|
|
23
|
+
address: deriveBitcoinAddress(mnemonic, passphrase),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/wallet/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAE7D,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,aAAa,GAAG,EAAE,CAAC;AASzB,SAAS,eAAe;IACtB,OAAO,IAAI,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,UAAsB,eAAe,EAAE;IAEvC,IAAI,OAAO,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QACrC,MAAM,IAAI,UAAU,CAAC,uCAAuC,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,KAAK,CAAC,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IACpC,MAAM,UAAU,GAAG,kBAAkB,EAAE,CAAC;IAExC,OAAO;QACL,QAAQ;QACR,UAAU;QACV,cAAc,EAAE,UAAU;QAC1B,OAAO,EAAE,oBAAoB,CAAC,QAAQ,EAAE,UAAU,CAAC;KACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { randomInt } from "node:crypto";
|
|
2
|
+
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
3
|
+
const DEFAULT_WORD_COUNT = 12;
|
|
4
|
+
const cryptoWordSource = {
|
|
5
|
+
next(maxExclusive) {
|
|
6
|
+
return randomInt(0, maxExclusive);
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
export function generatePassphrase(wordCount = DEFAULT_WORD_COUNT, random = cryptoWordSource) {
|
|
10
|
+
if (!Number.isInteger(wordCount) || wordCount < 1) {
|
|
11
|
+
throw new RangeError("wordCount must be a positive integer");
|
|
12
|
+
}
|
|
13
|
+
const words = Array.from({ length: wordCount }, () => {
|
|
14
|
+
const index = random.next(wordlist.length);
|
|
15
|
+
if (!Number.isInteger(index) || index < 0 || index >= wordlist.length) {
|
|
16
|
+
throw new Error("Random source returned an invalid word index");
|
|
17
|
+
}
|
|
18
|
+
return wordlist[index];
|
|
19
|
+
});
|
|
20
|
+
return words.join(" ");
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=passphrase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passphrase.js","sourceRoot":"","sources":["../../src/wallet/passphrase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAE7D,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAM9B,MAAM,gBAAgB,GAAqB;IACzC,IAAI,CAAC,YAAoB;QACvB,OAAO,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IACpC,CAAC;CACF,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAChC,SAAS,GAAG,kBAAkB,EAC9B,SAA2B,gBAAgB;IAE3C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,UAAU,CAAC,sCAAsC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE3C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nkamoto",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "NKAMOTO is a security-focused Bitcoin wallet CLI for generating BIP-39 wallets, managing Bitcoin keys, addresses, and QR codes from the terminal.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
|
|
7
|
+
"bin": {
|
|
8
|
+
"nkamoto": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20.19.0"
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Coperbyte/nkamoto.app.git"
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
"homepage": "https://nkamoto.app",
|
|
27
|
+
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/Coperbyte/nkamoto.app/issues"
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
}
|
|
37
|
+
}
|