## 1 Overview & Purpose

CryptoCalc is a non-custodial, standalone desktop application for generating cryptocurrency wallets. It is designed to run entirely offline ("cold wallet" philosophy) so that sensitive cryptographic material — Private Keys, WIF, and Secret phrases — never leaves the user's machine and is never exposed to a remote server.

Wallets can be Non-Deterministic (Simple Wallet) or Hierarchical Deterministic (HD Wallet, `BIP32`). CryptoCalc supports 23 cryptocurrencies and 18 Secret phrase languages.

Since its first release, CryptoCalc has been downloaded more than 16 552 times on npm.

The application is built with JavaScript / ElectronJS and is available as a standalone installer (Windows) as well as via source clone (Windows & Linux). Wallet output is saved as `.wits` JSON files under a timestamped `_output/` subfolder.

## 2 Entropy Generation & Sources

All wallet generation starts with a high-quality Entropy value. CryptoCalc provides four distinct entropy sources:

### 2.1 D6 Dice Rolls (default)

The user rolls virtual six-sided dice. The number of rolls is determined by the chosen Entropy Size (e.g. 100 rolls for 256-bit entropy).

### 2.2 Mouse Movement

Entropy bytes are captured from the user's mouse pointer movements, providing a non-deterministic physical source.

### 2.3 Image Drop

The user can drag-and-drop any `PNG`, `JPG`, or `SVG` image onto the application. Pressing [Generate] draws a random cryptocurrency logo from `www/img/CryptoCurrency`. Sample images are provided in `www/img/`.

### 2.4 Fortune Cookies

A corpus of 12 803 quotes is used as a source. A random quote is drawn each time [Generate] is pressed.

### 2.5 Salted Entropy

Regardless of the source, CryptoCalc combines the raw entropy value with a Salt (a dynamically generated `UUID`, 128 bits of additional entropy) using `SHA-256`:

`Salted Entropy = SHA256(Salt + Entropy_source_value)`

This guarantees uniqueness at every [Generate] press, even when the same image or fortune cookie is reused.

### 2.6 Entropy Size

The user can choose an entropy size between 128 and 256 bits (32 to 64 hex digits), which corresponds to a Secret phrase of 12 to 24 words. Both representations remain synchronized in real time.

## 3 Wallet Modes

Three wallet generation modes are available, selectable from the Wallet tab page.

#### Simple Wallet

Default mode. Each wallet is independent; no BIP32 hierarchy or Derivation Path is involved. Ideal for beginners. Less resistant to dictionary attacks if low-entropy inputs are used.

#### HD Wallet (BIP32)

Full Hierarchical Deterministic wallet tree. All wallets share the same Secret phrase. Navigation via Account and Address Index fields (0–999 999). Supports BIP44, BIP49, BIP84 purposes.

#### SWORD Wallet

Simple Wallet Over Randomized Deterministic — a hybrid. Generates all HD-wallet-compatible cryptocurrencies without exposing the BIP32 derivation path complexity to the user.

#### Special Cases

For Cardano HD wallets, Account and Address Index are hard-coded to 0 to match the behavior of Guarda and Yoroi wallet managers.

Generated HD wallets can be cross-checked with the Ian Coleman BIP39 tool (linked in Help / Resources menu). Remember to enable "Use hardened addresses".

## 4 BIP39 — Secret Phrase & Word Indexes

### 4.1 Secret Phrase Generation

Entropy is converted to a BIP39 Secret phrase (also called Mnemonics or Secret Recovery Passphrase) of 12 to 24 words. The conversion appends a checksum (first N bits of `SHA256(entropy)`) to pad to a multiple of 11 bits, then each 11-bit segment selects a word from the 2048-word BIP39 dictionary.

### 4.2 Shortened Secret Phrase

Because only the first 4 characters of each BIP39 mnemonic are significant, CryptoCalc derives a Shortened Secret phrase where each word is abbreviated to its first 4 characters (first letter capitalized):

Example (12 words):
Full: `rent expand super sea summer pull catalog mobile proud solve oven goose`
Short: `RentExpaSupeSeaSummPullCataMobiProuSolvOvenGoos`

The Shortened Secret phrase is not for importing into a Wallet Manager. Its purpose is compact storage (e.g. on a `NTAG213 NFC` SmartRing with 144 bytes capacity — 24 words × 4 chars = 96 bytes max).

### 4.3 Word Indexes Display

Word indexes (0–2047) are displayed alongside the Secret phrase in Decimal or Binary format. In Binary mode, the checksum bits appended to the last word are clearly visible. Word indexes are language-independent — the same entropy yields the same indexes regardless of the chosen wordlist language.

### 4.4 Dynamic Entropy ↔ Secret Phrase Conversion

Pasting a raw hex entropy value automatically recomputes the Secret phrase, and vice versa.

### 4.5 BIP39 Passphrase (HD Wallet only)

An optional BIP39 Passphrase (acting as an additional password) shifts the entire BIP32 hierarchy to a completely different tree. To avoid accidental application, the field is `readonly` by default:

- Click [Edit] (pen icon) to enter edit mode.
- Click [Apply] to recompute the BIP32 hierarchy.
- Click [Cancel] to discard changes.

## 5 BIP32 — HD Wallet & Derivation Path

### 5.1 Derivation Path

CryptoCalc uses the standard BIP44 derivation path structure: `m / purpose' / coin_type' / account' / change / address_index`

Example for Ethereum: `m/44'/60'/0'/0/0`

Segment | Meaning
--- | ---
`m` | Master key (root of the tree)
`44'` | BIP44 purpose (hardened)
`60'` | Coin type (e.g. 60 = Ethereum)
`0'` | Account (hardened by default)
`0` | External chain (public addresses)
`0` | Address index

### 5.2 Supported Purposes

- `BIP44` — legacy (all supported coins)
- `BIP49` — SegWit P2SH-P2WPKH
- `BIP84` — native SegWit (Bitcoin and Litecoin only)

### 5.3 Account & Address Index

Both fields accept decimal values from 0 to 999 999 (6 digits max), giving 1 000 000 possible values each. Editing either field displays a [Refresh] button (also triggered by `Enter`) to recompute the wallet address.

### 5.4 Hardened Derivation

Hardened derivation is mandatory and on by default (since v0.3.18) for security: a compromised child key cannot be used to derive sibling or parent keys.

## 6 BIP38 — Private Key Encryption

CryptoCalc supports BIP38 NON-EC encryption: the Private Key is symmetrically encrypted with a user-supplied passphrase, producing a BIP38 Encrypted Private Key.

### 6.1 How to Use

1. Enter a value in the BIP38 Passphrase field.
2. Press [Save] or use File / Save.
3. The BIP38 Encrypted PK is computed and saved alongside the wallet.

### 6.2 BIP38 Encrypt / Decrypt Tool

A dedicated dialog (Tools / BIP38 Encrypt/Decrypt) is provided to:

- Encrypt a raw Private Key → BIP38 Encrypted PK
- Decrypt a BIP38 Encrypted PK → raw Private Key

A progress bar gives visual feedback during the time-consuming scrypt computation.

### 6.3 Key Use Case

The BIP38 Encrypted PK allows outsourcing paper wallet printing (with premium features: watermark, hologram, embossing…) without disclosing the raw Private Key to the printer. The Passphrase is communicated via a separate channel.

Security: The raw Private Key is still saved in `wallet_info.txt`. The BIP38 Encrypted PK may be shared in certain use cases; the raw Private Key must never be disclosed, nor should the BIP38 Passphrase.

### 6.4 QR Code Output

A new QR code for the BIP38 Encrypted PK is generated as both a `PNG` file and an `SVG` file (in the `xtras/` subfolder).

## 7 Passphrase Strength Evaluator

A real-time visual indicator evaluates the strength of the BIP39 and BIP38 passphrases using the `zxcvbn` library (developed by Dropbox). It accounts for dictionary words, common patterns, keyboard walks, and Leetspeak substitutions.

Score | Label | Color
--- | --- | ---
0 | Very Weak | Red
1 | Weak | Orange
2 | Fair | Yellow
3 | Good | Green
4 | Strong | Violet

The score is displayed as a colored bar (length proportional to score) and a text label. Hovering over the label shows the entropy in bits.

It is strongly recommended to use the [Random] button (circular arrow icon) to generate a passphrase, rather than typing one manually, to avoid predictable patterns.

## 8 QR Code Generation

QR codes are automatically generated and saved when a wallet is saved. They cover the following data fields:

- Wallet Address
- Private Key
- WIF (Wallet Import Format, when applicable)
- Secret phrase (Mnemonics)
- Entropy
- BIP38 Encrypted Private Key (when a BIP38 passphrase is set)

### 8.1 Output Formats

- PNG — standard raster QR codes (saved in the wallet folder)
- SVG — vector QR codes (in the `xtras/` subfolder)
- rMQR — Rectangular Micro QR Code (`R15x59` or `R15x77` depending on entropy size) of the Entropy value
- Ultracode — experimental colored-module QR code of the Entropy value

### 8.2 Recovering a Wallet from a Rectangular Micro QR Code

1. Scan the rMQR with an Android app compatible with rMQR (e.g. QRQR by Arara).
2. Copy the scanned entropy hex string into CryptoCalc's Entropy field.
3. Ensure Entropy Size and Derivation Path match those recorded in `wallet_info.txt` / `wallet_info.wits`.

## 9 Save & Open Wallet Informations

### 9.1 Saving a Wallet

Use File / Save or the Save toolbar icon. A timestamped subfolder is created under `_output/` (e.g. `2024_10_07_21h-4m-4s-3_BTC_EN`), containing:

- `wallet_info.txt` — human-readable wallet fields
- `wallet.wits` — machine-readable JSON (all entropy + wallet data)
- QR code PNG images for all fields
- `xtras/` — SVG, rMQR and Ultracode QR variants

A popup dialog confirms saving and offers to open the output folder.

### 9.2 Opening a Previously Saved Wallet

Use File / Open… or the Open toolbar icon to load a `.wits` file. On Windows, double-clicking a `.wits` file launches `Cryptocalc.exe` and opens it directly (file-extension association).

- An opened wallet is read-only to prevent accidental overwrite.
- Use File / Save As… to save a modified copy with a new timestamp.
- For an HD Wallet, you may change Account / Address Index, press [Refresh], then save as a new wallet that belongs to the same BIP32 tree.

## 10 Wallets Database (SQLite)

Via Tools / Database Management, previously saved `.wits` files can be imported into a local SQLite database. The database can then be explored and queried with an external tool such as DBeaver (which also provides a visual DB schema).

- Source files: `.wits` JSON files in timestamped subfolders under `_output/`
- Database fields include: Address, Private Key, WIF, Derivation Path, BIP38 Encrypted PK, etc.
- Useful for managing large sets of generated wallets.

## 11 Dedicated Tools

### 11.1 Secret Phrase Translator (`Tools / Secret Phrase Translator`)

Translates a Secret phrase from one BIP39 language to another. Primary use case: a Secret phrase written in a non-English language (e.g. Russian) must be translated to English before it can be imported into a Wallet Manager.

- Paste the Secret phrase, select the Output language, press [Translate].
- A special `Word Indexes` pseudo-language outputs the numeric word indexes (language-independent).
- Changing the output language re-translates automatically.

### 11.2 BIP38 Encrypt / Decrypt (`Tools / BIP38 Encrypt/Decrypt`)

Standalone dialog to encrypt a raw Private Key to a BIP38 Encrypted PK, or conversely decrypt a BIP38 Encrypted PK back to the raw Private Key. A progress bar shows the computation progress.

### 11.3 Options (`Tools / Options`)

Set persistent defaults for:

- Default Blockchain
- Wallet Mode (Simple / HD / SWORD)
- Entropy Size

Options are stored in `www/config/options.json` and can be reset to factory defaults (from `www/config/defaults/options.json`).

## 12 Dynamic Links

CryptoCalc provides contextual links that open the relevant page in the user's browser:

- Blockchain Explorer — opens the generated wallet address directly in the appropriate explorer for the selected blockchain (e.g. blockchain.com for Bitcoin).
- CoinMarketCap — opens the cryptocurrency information page for the selected coin.
- CryptoShape / 3D Secret Phrase — opens an experimental 3D visual representation of the Secret phrase at aladas-org.github.io. The underlying whitepaper is hosted on Zenodo.

## 13 Internet Connection Status

An icon on the right side of the main toolbar permanently displays the network status:

- Red "Wi-Fi ON" icon — Internet connected (warning: not recommended for wallet generation)
- Green "Wi-Fi OFF" icon — Offline (recommended operating mode)

A text label Online / Offline accompanies the icon. This reinforces the cold-wallet, non-custodial philosophy of the application.

## 14 Customizable Options

Options (Tools / Options) persist across sessions in `www/config/options.json`:

Option | Values | Default
--- | --- | ---
Default Blockchain | Any of the 23 supported coins | BTC
Wallet Mode | Simple / HD / SWORD | Simple
Entropy Size | 128 / 160 / 192 / 224 / 256 bits | 256 bits

A Reset to Defaults action restores the values from `www/config/defaults/options.json`.

## 15 Localization (L10n)

GUI labels are translated to the user's system language via JSON localization files located in `www/js/L10n/`. The locale is determined from the host OS environment (2-letter ISO code, e.g. `en`, `fr`).

- Currently provided: English (`gui-msg-en.json`) and French (`gui-msg-fr.json`).
- Adding a new language requires only a new `gui-msg-XX.json` file.

## 16 Supported Cryptocurrencies (23)

CryptoCalc supports wallet generation for the following 23 cryptocurrencies:

BTC — Bitcoin ETH — Ethereum XRP — Ripple BNB — Binance Smart Chain SOL — Solana DOGE — Dogecoin TRX — TRON ADA — Cardano XLM — Stellar SUI — Sui BCH — Bitcoin Cash AVAX — Avalanche TON — Toncoin LTC — Litecoin ETC — Ethereum Classic POL — Polygon VET — VeChain BSV — Bitcoin SV DASH — Dash RVN — Ravencoin ZEN — Horizen LUNA — Terra 2.0 FIRO — Firo

Notes: BNB is on Binance Smart Chain (BEP-20 token). LUNA is LUNA 2.0 (Terra blockchain), not LUNA Classic. SUI support was validated with the Suiet Chrome extension. BIP84 (native SegWit) is available only for BTC and LTC. A list of the top-50 market-cap coins with CryptoCalc support indicators is provided in `_doc/top_50_marketcap_coins.txt`.

## 17 Supported Secret Phrase Languages (18)

### 17.1 Official BIP39 Languages (10)

English French Spanish Italian Czech Portuguese Simplified Chinese Traditional Chinese Japanese Korean

Only English is accepted by hardware wallets (Ledger, Trezor) and most software wallet managers.

### 17.2 Non-Official Languages (8)

Deutsch Russian Esperanto Latin Greek Hindi Gujarati Bengali

Using a non-English language is an obfuscation layer: the Secret phrase must be translated back to English (via the Secret Phrase Translator tool) before it can be imported into a Wallet Manager. The reference data is always the Word Indexes, which are language-independent.

## 18 Security Considerations

Critical: Never disclose the Private Key. In the BIP38 Encryption use case, never share both the BIP38 Encrypted PK and the BIP38 Passphrase through the same channel.

### 18.1 Cold Wallet Philosophy

CryptoCalc is designed to be used offline. The Internet Connection Status indicator warns the user when the machine is online. Generating wallets while connected to the Internet is actively discouraged.

### 18.2 Hardened BIP32 Derivation

HD wallets use hardened derivation by default, preventing a compromised child key from being used to derive sibling or parent keys.

### 18.3 BIP38 Additional Layer

The Private Key can be encrypted with a BIP38 Passphrase, adding a second layer of protection if the wallet file is ever exposed (see §6).

### 18.4 Language Obfuscation

Storing the Secret phrase in a non-English language makes it unusable without knowledge of the language used. Combined with the BIP39 Passphrase, this provides a multi-layer security approach.

### 18.5 NFC SmartRing Storage

The Shortened Secret phrase (max 96 bytes for 24 words) can be stored on an entry-level `NTAG213 NFC` SmartRing (144 bytes usable capacity), providing a wearable physical backup.

## 19 Setup & Installation

### 19.1 Standalone Installer (recommended for end users)

Download the installer from SourceForge. Generated with electron packager and Inno Setup.

- Default install path: `C:\Users\<USER>\AppData\Local\Programs\Cryptocalc`
- Wallet output: `…\resources\app\_output\` (not removed on uninstall)
- The installer is not code-signed; Windows Defender SmartScreen will require manual confirmation. Users may also rebuild the installer themselves using the `_inno_setup/` howto.

### 19.2 Source Clone — Windows

Prerequisites: NodeJS, Git

    git clone https://github.com/ALADAS-org/cryptocalc.git
    cd cryptocalc
    npm install
    _runW.bat        # or: npm start

### 19.3 Source Clone — Linux (tested on Linux Mint 22.2)

Prerequisites: NodeJS, Git, npm, xdg-utils

    sudo apt-get install nodejs git npm xdg-utils
    git clone https://github.com/ALADAS-org/Cryptocalc.git
    cd Cryptocalc
    npm install
    chmod 777 ./_runX.sh
    ./_runX.sh        # or: npm start

## 20 Unit Tests (Jest)

Unit tests use the Jest framework (ongoing effort since v0.5.4). They run in a Node.js environment (no browser / Electron renderer required) and cover cryptographic utilities, wallet generators, and general-purpose helpers.

### 20.1 Running the Tests

    npm test                          # run all Jest unit tests
    npx jest <path/to/file.test.js>   # run a single file
    npm run test:jest:watch           # watch mode
    npm run test:jest:coverage        # with HTML coverage report

The HTML coverage report is generated at `tests/coverage/jest/test-report.html`.
Coverage thresholds: ≥ 70% for all four metrics (branches, functions, lines, statements).

### 20.2 Configuration (`jest.config.js`)

Setting | Value
--- | ---
Test environment | Node.js
Timeout | 10 000 ms
Test root | `tests/jest/`
Workers | 50% of available CPUs
Coverage reporters | text, text-summary, lcov, html, json, cobertura
HTML test report | `tests/coverage/jest/test-report.html` (via jest-html-reporter)

### 20.3 Module Aliases

Alias | Resolved path
--- | ---
`@/` | `www/`
`@crypto/` | `www/js/crypto/`
`@api/` | `www/js/api/`
`@util/` | `www/js/util/`
`@tests/` | `tests/jest/`
`@fixtures/` | `tests/jest/fixtures/`

### 20.4 Global Test Setup (`tests/jest/setup.js`)

Provides shared helpers and custom matchers available to all test files:

#### Helper functions

- `loadFixture(filename)` — load JSON from `fixtures/inputs/`
- `loadExpected(filename)` — load JSON from `fixtures/expected/`
- `saveFixture(filename, data, type)` — persist fixture files

#### Custom Jest matchers

- `toBeValidHash(length)` — validates a hex string of exact length
- `toBeValidBitcoinAddress()` — legacy, P2SH & SegWit formats
- `toBeValidWIF()` — WIF private key format
- `toBeValidEthereumAddress()` — checksummed ETH address
- `toBeValidMnemonic()` — 12/15/18/21/24-word BIP39 phrase

### 20.5 Test File Inventory

File | Scope | Key tested functions | # tests
--- | --- | --- | ---
`crypto/bip39_utils.test.js` | BIP39 core | EntropyToMnemonics, MnemonicsToEntropyInfo, GetWordIndexes, GuessMnemonicsLang, CheckMnemonics, MnemonicsAs4letter, GetBIP39Dictionary… | 77
`crypto/bip39_extras.test.js` | BIP39 extras | PrivateKeyToMnemonics, MnemonicsAs4letter, MnemonicsAsTwoParts, LabelWithSize | 32
`crypto/bip32_utils.test.js` | BIP32 / HD Wallet | MnemonicsToHDWalletInfo (BTC/ETH/+), GetDerivationPath, account & address index derivation, BIP39 passphrase, BIP44/49/84 purposes, reference vectors | 112
`crypto/bip38_utils.test.js` | BIP38 encryption | encrypt(), decrypt(), scrypt params, round-trip, wrong passphrase, progress callback (bip38 mocked) | 79
`crypto/crypto_services.test.js` | CryptoServices singleton | getUUID() (UUID v4 format), pk2WIF(), singleton pattern | ~15
`crypto/entropy_size.test.js` | Entropy ↔ size helpers | GetBitCount, GetWordCount, GetExpectedWordCount, GetChecksumBitCount, GetSHA256Substring | 29
`crypto/password_strength_evaluator.test.js` | Passphrase strength | is_binary_string, is_hexa_string, is_base58/64/octal, getPasswordStrengthAsBits, getPasswordStrengthScore (zxcvbn), getPasswordStrengthInfo | 79
`crypto/base58_utils.test.js` | Base58 encoding | isBase58String, hexToB58, b58ToHex, round-trip, alphabet validation | 18
`utils/hex_utils.test.js` | Hex utilities | hexWithPrefix/WithoutPrefix, isHexString, hexToBinary, hexToUint8Array, hexToB64, getRandomHexValue, round-trips | 43
`utils/number_utils.test.js` | Number helpers | stringToInt, stringToFloat, valueIsNumber, stringIsNumber | 28
`utils/string_utils.test.js` | String helpers | isString, stringify (circular ref), insertAfterEveryN, stringToHex, getShortenedString, asTwoParts | 35
`wallet/address_validation.test.js` | Address formats | Bitcoin (legacy/P2SH/SegWit), Ethereum checksummed, WIF (compressed/uncompressed), BIP39 mnemonic (12/24 words) | 8
`wallet/simple_wallet.test.js` | Simple Wallet generation | Wallet structure for BTC, ETH, DOGE, LTC, SOL, AVAX, POL, TON, LUNA, ZEN — validates address, private key, public key, mnemonics, wallet mode | 10+
`smoke.test.js` | Jest config sanity | TEST_MODE global, CRYPTO_CONFIG (SUPPORTED_COINS, ENTROPY_SIZES), TEST_PATHS | 4

### 20.6 Known Reference Vectors (BIP32)

The BIP32 tests include deterministic reference checks with known expected values (account=2, address_index=5, passphrase=`"my secret passphrase"`):

Coin | Address | Private Key (prefix)
--- | --- | ---
Bitcoin | `1BQQ4VjXtPGd3YEV45vuMkNKjo42pjLLUB` | `ca2dc38…` / WIF `L3ziiGb…`
Ethereum | `0x67C0ae27e79Ba1B6f58af5DCF3d893f7394ac0e5` | `cfe5210…`

## 21 E2E Tests (Playwright)

End-to-end tests launch the full Electron application and interact with it programmatically via Playwright. They validate complete user workflows — from entropy generation to wallet save/reload.

### 21.1 Running the Tests

    npm run test:playwright          # headless
    npm run test:playwright:ui       # interactive Playwright UI
    npm run test:playwright:debug    # step-by-step debugger

### 21.2 Configuration (`tests/playwright/playwright.config.js`)

Setting | Value
--- | ---
Test directory | `tests/playwright/e2e/`
Workers | 1 (Electron limitation — no parallel tests)
Retries on failure | 2
Test timeout | 30 s
Action timeout | 10 s
Navigation timeout | 30 s
Screenshots/Videos/Traces | Only on failure
Report | HTML — `tests/playwright/playwright-report/`
Raw results | `tests/playwright/test-results/`

### 21.3 Custom Fixtures & Helpers (`tests/playwright/setup.js`)

#### Fixtures

- `electronApp` — launches `www/js/_main/electron_main.js`
- `page` — waits for DOM content loaded
- `appScreenshot` — timestamped screenshots

#### Helper functions

- `waitForAppReady(page)` — DOM ready + 3 s Electron init delay
- `loadFixture(filename)` — loads JSON from `fixtures/`

### 21.4 E2E Test Scenarios

#### Scenario 1 — Bitcoin HD Wallet (`hd_wallet_usecase.test.js`)

Tests BIP32 HD wallet derivation for Bitcoin with fixed, reproducible input data (fixed salt + entropy, account=2, address_index=5).

Test case | What is verified
--- | ---
Bitcoin address validity | Derived address matches legacy/P2SH/Bech32 regex
BIP39 passphrase effect | Same account/index with different passphrase → different address

Page interaction helpers used: `switchToHDWallet`, `deriveFromFixedEntropy`, `setBip39Passphrase`, `clickRefresh`, `getDisplayedAddress`, `setFieldValue`.

#### Scenario 2 — Dogecoin HD Wallet Save/Load/Update (`dogecoin_hd_wallet_usecase.test.js`)

Tests the complete wallet lifecycle for Dogecoin HD wallets.

Step | Action | Assertion
--- | --- | ---
1 | Select Dogecoin, HD mode, account=1, index=3 | Address generated and displayed
2 | Save wallet (`/tmp/cryptocalc_test_doge_1.json`, dialogs mocked) | File written successfully
3 | Open saved `.wits` file | Address and fields reload correctly
4 | Change account → 4, address index → 7, press [Refresh] | New address is different from original
5 | Save As (`/tmp/cryptocalc_test_doge_2.json`) | Second file contains updated address

Page interaction helpers used: `switchToHDWallet`, `selectBlockchain`, `setFieldValue`.

Playwright test protocols are documented in `tests/playwright/_doc/hd_wallet_usecase_test_protocols.html`.

## 22 Technology Stack

#### Runtime

- ElectronJS ≤ 31 (pinned — later versions block dropped file paths)
- Node.js — main process & test runner
- JavaScript — both renderer and main process

#### Crypto Libraries

- `bs58` v5.0.0 (pinned — ESM incompatibility in v6+)
- `ed25519-hd-key`, `@mysten/sui`, `@ton/crypto`
- `zxcvbn` — passphrase strength
- `cashaddrjs` — Bitcoin Cash address encoding

#### Testing

- Jest — unit tests (344 tests in v0.5.9)
- Playwright — E2E tests
- Coverage report at `tests/coverage/jest/test-report.html`
- Coverage threshold: ≥ 70% for all four metrics

#### Build & Distribution

- electron packager — produces the distributable app
- Inno Setup — Windows installer
- Published on SourceForge and npm
- SQLite via better-sqlite3 for wallet database

### Architecture Overview

Layer | Entry Point / Key File | Role
--- | --- | ---
Main Process | `www/js/_main/electron_main.js` | BrowserWindow, IPC, file I/O, menus
Preload | `www/js/_main/preload.js` | Safe IPC bridge to renderer
Renderer | `www/index.html` | UI entry point
Crypto | `www/js/crypto/` | BIP32/39/38, wallet generators
View | `www/js/view/main_gui.js` | MainGUI singleton, dialogs
Model | `www/js/model/` | QR codes, wallet persistence, SQLite
Utils | `www/js/util/` | Logging, HTML helpers, value utils
L10n | `www/js/L10n/` | GUI label translations (JSON)