The Journey of a Crypto Wallet

From One Seed Phrase to Infinite Addresses

When you open a crypto wallet—whether it’s MetaMask, Phantom, or even your own Custom CLI (like I built this one)—the experience feels almost effortless: one seed phrase, one wallet, and suddenly an endless list of accounts and addresses spanning multiple blockchains. But behind that simplicity is a beautifully engineered foundation of standards—especially BIP-32, BIP-39, and BIP-44—that work together to deterministically generate keys and keep the entire wallet ecosystem interoperable, recoverable, and consistent.

This post walks through that journey in a clear, step-by-step narrative, explaining how BIP-32, BIP-39, and BIP-44 form the backbone of nearly every modern wallet—whether you’re dealing with Bitcoin, Ethereum, Solana, or any chain built on hierarchical deterministic (HD) wallets.

If you’re building your first wallet or simply want to understand what really happens under the hood each time you click “Create Wallet,” this guide will walk you through the entire process.

Before the BIPs: The Age of Random Keys

In the early days of Bitcoin, wallets generated random private keys for every address.

Problems were immediate:

  • Every new keypair had to be stored manually

  • Losing the wallet file meant losing funds

  • No standard way to back up or restore keys

  • No connection between keys—each was an isolated identity

There was no structure, no hierarchy, and no recoverability. Clearly unsustainable.

This is where the BIPs stepped in.

BIP-32 — The Foundation: Hierarchical Deterministic Wallets

BIP-32 introduced the HD (Hierarchical Deterministic) wallet.

Core idea:

From one master seed, generate a tree of keys deterministically.

Benefits:

  • Single backup → infinite keys

  • Parent → child key derivation

  • Organized accounts and subaccounts

  • No need to store every private key

The tree looks like:

m
├─ 44′ (purpose)
   ├─ 0′ (Bitcoin)
   │   ├─ 0′ (Account 0)
   │   │   ├─ 0 (Addr 0)
   │   │   ├─ 1 (Addr 1)
   │   ├─ 1′ (Account 1)
   │       ├─ 0 (Addr 0)
   │       ├─ 1 (Addr 1)
   ├─ 60′ (Ethereum)
   │   ├─ 0′ (Account 0)
   │   │   ├─ 0 (Addr 0)
   │   │   ├─ 1 (Addr 1)
   │   ├─ 1′ (Account 1)
   │       ├─ 0 (Addr 0)
   │       ├─ 1 (Addr 1)
   ├─ 501′ (Solana)
       ├─ 0′ (Account 0)
       │   ├─ 0 (Addr 0)
       │   ├─ 1 (Addr 1)
       ├─ 1′ (Account 1)
           ├─ 0 (Addr 0)
           ├─ 1 (Addr 1)

Every wallet today—whether it's Bitcoin, Ethereum, or Solana—builds on this principle.

BIP-39 — Human-Readable Mnemonics

A 512-bit seed is not user-friendly. Humans needed a safe way to back up their HD wallets.

BIP-39 solved this by introducing:

  • 12/18/24-word mnemonic phrases

  • Deterministic entropy → mnemonic mapping

  • Multi-language wordlists

  • Mnemonic → seed via PBKDF2

Example:

abandon amount liar ... zoo

This mnemonic is the only thing a user needs to restore all their accounts and addresses.

BIP-44 — Organizing Multichain Wallets

With HD wallets and mnemonics established, the next challenge was consistency across:

  • Multiple accounts

  • Multiple chains

  • External vs internal addresses

BIP-44 provided a universal path structure:

m / purpose' / coin_type' / account' / change / address_index

Example derivation paths:

Chain	 BIP-44 Path
Bitcoin	 m/44'/0'/0'/0/0 (Legacy)
Bitcoin  m/84'/0'/0'/0/0 (Native SegWit)
Ethereum m/44'/60'/0'/0/0
Solana	 m/44'/501'/0'/0'

This standardization enables a single mnemonic to power wallets across multiple chains.

BIP-44 brought order to the ecosystem.

The Full Journey: From Seed Phrase to Address

Here's the entire flow in one place:

User writes down mnemonic (BIP-39)
        ↓
Mnemonic → Seed (PBKDF2)
        ↓
Seed → Master Private Key + Chain Code (BIP-32)
        ↓
Use the derivation path to derive the child key (BIP-44)
        ↓
Chain-specific private key → Public key
        ↓
Public key → Address

No private key or address is ever random. Everything is deterministic, organized, and reproducible from the mnemonic.

Generating Bitcoin Address

import bip39 from "bip39";
import BIP32Factory from "bip32";
import * as ecc from "tiny-secp256k1";
import { payments, networks } from "bitcoinjs-lib";

// Generate 128 bits of entropy → 12 words
const mnemonic = bip39.generateMnemonic(128);
console.log("Mnemonic:", mnemonic);

// Convert mnemonic → seed (64 bytes)
const seed = await bip39.mnemonicToSeed(mnemonic);

// Get root from Seed Buffer
const bip32 = BIP32Factory(ecc);
const root = bip32.fromSeed(seed);

const btcPath = `m/84'/0'/0'/0/0`; // Native SegWit
const btcChild = root.derivePath(btcPath);

// BTC Address (SegWit)
const btcAddress = payments.p2wpkh({
  pubkey: btcChild.publicKey,
  network: networks.bitcoin
  }).address;

Generating Ethereum Address

import bip39 from "bip39";
import BIP32Factory from "bip32";
import * as ecc from "tiny-secp256k1";
import { ethers } from "ethers";

// Generate 128 bits of entropy → 12 words
const mnemonic = bip39.generateMnemonic(128);
console.log("Mnemonic:", mnemonic);

// Convert mnemonic → seed (64 bytes)
const seed = await bip39.mnemonicToSeed(mnemonic);

// Get root from Seed Buffer
const bip32 = BIP32Factory(ecc);
const root = bip32.fromSeed(seed);

const ethPath = `m/44'/60'/0'/0/0`;
const ethChild = root.derivePath(ethPath);

const ethPriv = ethers.hexlify(ethChild.privateKey);
const ethWallet = new ethers.Wallet(ethPriv);

// ETH Address
const ethAddress = ethWallet.address;

Generating Solana Address

import bip39 from "bip39";
import BIP32Factory from "bip32";
import * as ecc from "tiny-secp256k1";
import nacl from "tweetnacl";
import bs58 from "bs58";
import { derivePath as deriveEd25519 } from "ed25519-hd-key";
import { PublicKey } from "@solana/web3.js";

// Generate 128 bits of entropy → 12 words
const mnemonic = bip39.generateMnemonic(128);
console.log("Mnemonic:", mnemonic);

// Convert mnemonic → seed (64 bytes)
const seed = await bip39.mnemonicToSeed(mnemonic);

// Get root from Seed Buffer
const bip32 = BIP32Factory(ecc);
const root = bip32.fromSeed(seed);

const solPath = `m/44'/501'/0'/0'`;
const solDerived = deriveEd25519(solPath, seed.toString("hex"));

const solKeypair = nacl.sign.keyPair.fromSeed(solDerived.key);
const solPrivateKey = bs58.encode(solKeypair.secretKey);
const solPubKey = new PublicKey(solKeypair.publicKey).toBase58()

// SOL Address
const solAddress = solPubKey;

Chain Differences: Same Roots, Different Branches

While BIPs come from Bitcoin, other ecosystems adopted them with small variations:

Ethereum

  • Still uses BIP-39 and BIP-44

  • Uses secp256k1 keys

  • Address = last 20 bytes of keccak(publicKey)

Solana

  • BIP-39 and BIP-44 for mnemonic + path

  • Uses ed25519 keys

  • Different signing scheme

The seed → key → address pipeline remains the same. Only the last step changes per chain.

Every time a wallet displays a new address, switches networks, or allows you to create Account #2, it's the result of years of standards working together perfectly.

The magic formula:

  • BIP-32 → Deterministic key trees

  • BIP-39 → Human-readable mnemonics

  • BIP-44 → Organized multichain structure

Understanding these standards is the first step for any developer building wallet software, exploring Web3 security, or simply becoming a more informed user.

If you're starting your wallet journey, the best way to learn is to implement these pieces yourself—generate a mnemonic, derive the seed, apply a derivation path, and produce an address. Everything else becomes much clearer from there.

I tried with npx new-wallet.