aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: 96a35dd32047e68be1a9a3496518ab154719ea0e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# Bitcoin Wallet

A self-contained, **single-file** Bitcoin wallet that runs entirely in the
browser. Think bitaddress.org, but a modern BIP84 HD wallet built from a seed
phrase, able to scan history, fetch UTXOs, and spend — online or fully offline.

- **BIP84 / native SegWit (p2wpkh)** HD wallet from a 12/24-word BIP39 seed
  (optional passphrase).
- **HD scanning** with the standard gap limit across the receive (`…/0/i`) and
  change (`…/1/i`) chains — real aggregate balance, fresh addresses, and
  transaction history via [mempool.space](https://mempool.space).
- **Spending** with proper coin selection + fee estimation
  (`@scure/btc-signer`'s `selectUTXO`), a fee-rate picker, send-max, and
  **manual coin control**.
- **Fresh addresses** for receiving and for change — no address reuse.
- **Offline mode**: import UTXOs from a JSON snapshot (fetched on an online
  device), sign locally, and export the signed transaction (hex / file / QR) to
  broadcast elsewhere. No network calls are made.
- **Runs offline from `file://`** — keys never leave the page; nothing is sent
  anywhere except, when online, read-only requests + a broadcast to
  mempool.space.

Built with the modern audited [`@scure`](https://github.com/paulmillr/scure-btc-signer)
/ [`@noble`](https://github.com/paulmillr/noble-hashes) libraries. Pure JS: no
`crypto.subtle`, so it works from the filesystem with no server.

## Develop

Requires [Bun](https://bun.sh).

```bash
bun install
bun run dev      # http://localhost:5173 (rebuilds on each refresh)
```

## Build

```bash
bun run build    # → dist/index.html  (one self-contained file)
```

`dist/index.html` inlines all code, the crypto libraries, the QR generator, and
the CSS. **To use it offline: save that one file and open it directly in a
browser** — no server, no internet.

## Using it offline (air-gapped spending)

1. **Online device** (with internet): open the wallet, let it scan, then go to
   **Tools → Export snapshot**. This downloads a JSON file of your UTXOs and fee
   rates. It contains **no keys**.
2. Move the file to your **offline device** (e.g. an air-gapped laptop running
   the saved `index.html`).
3. On the offline device, open the wallet, enter your **seed phrase** with
   *Offline mode* checked, then **Tools → Import snapshot**.
4. Build and **sign** a transaction. Copy/download the signed hex (or scan the
   QR) and broadcast it from any online device (e.g. mempool.space → Broadcast).

## Layout

| File | Purpose |
| --- | --- |
| `src/wallet.js` | BIP84 derivation, scanning, coin selection, signing, snapshots |
| `src/api.js` | Esplora REST wrapper (mempool.space + Blockstream, with throttle/rotation/cooldown to dodge rate limits); the single network choke-point |
| `src/app.js` | UI controller (vanilla DOM) |
| `src/qr.js` | QR → SVG (zero-dep) |
| `src/format.js` | sat/BTC formatting helpers |
| `src/style.css` | Hand-rolled styles |
| `build.js` / `dev.js` | Bun bundler → single inlined `index.html`, and dev server |

## Security notes

- This is self-custody software handling real keys — review the code before
  trusting it with funds, and prefer an offline machine for the seed phrase.
- Mainnet and testnet are both supported (select on the unlock screen).
- The seed phrase and passphrase live only in memory while the page is open;
  locking or closing the tab clears them.