What Self-Custody Means in Practice
Self-custody means you hold the material that can move the funds. For most wallets that material is a mnemonic phrase: 12 or 24 words that derive every key the wallet will ever use.
The chain from phrase to address has three standards: BIP39 (mnemonic to seed), BIP32 (seed to master key), BIP44 (master key to accounts). Understanding them is what lets you verify a wallet instead of trusting its UI.
Mnemonic to Address, Step by Step
BIP39 turns entropy into words. The 12 or 24 words are a checksummed encoding of a random number. BIP32 takes the seed and walks down a tree of keys. BIP44 fixes the path so every wallet derives the same account from the same phrase.
Ethers.js hides most of this. The full path, for reference:
import { Wallet, HDNodeWallet } from "ethers";
// 1. Generate a phrase. This is what you back up.
const wallet = HDNodeWallet.createRandom();
console.log(wallet.mnemonic.phrase);
// "candy maple cake ..."
// 2. The same phrase always derives the same account.
const restored = HDNodeWallet.fromPhrase(wallet.mnemonic.phrase);
console.log(restored.address === wallet.address); // true
// 3. Derive account #0 on Ethereum mainnet (path m/44'/60'/0'/0/0)
const account = HDNodeWallet.fromPhrase(wallet.mnemonic.phrase, undefined, "m/44'/60'/0'/0/0");
console.log(account.address);
// 4. A passphrase changes everything. Empty passphrase !== "hunter2".
const secured = HDNodeWallet.fromPhrase(wallet.mnemonic.phrase, "hunter2");
console.log(secured.address !== wallet.address); // true
The derivation path m/44'/60'/0'/0/0 breaks down as: BIP44 purpose, coin type 60 (Ethereum), account 0, external chain, address index 0. Change the coin type and the same phrase produces an address on another chain. This is why a phrase can manage Ethereum and Solana keys from one backup.
What to Back Up
Back up exactly three things:
- The words, in order. Wrong order, wrong wallet.
- The passphrase, if you used one. A phrase without its passphrase is a different wallet, one the phrase alone does not open.
- The derivation path, if it is unusual. Standard paths are recoverable by any wallet. Custom paths are not.
Do not back up: screenshots of the phrase, the phrase in cloud notes, the phrase in a chat. The words on paper, split across two physical locations, remain the baseline.
Verifying a Wallet Without a Network
Before moving real funds, prove the wallet holds the key. Sign a message and verify it. This works offline and never touches a chain:
import { Wallet, verifyMessage } from "ethers";
const wallet = new Wallet(account.privateKey);
const message = "I control this wallet";
const signature = await wallet.signMessage(message);
const recovered = verifyMessage(message, signature);
console.log(recovered === wallet.address); // true
If the recovered address matches, the software holds the key. Do the same test after restoring the phrase on a fresh device, before sending anything.
Common Failures
- 12 vs 24 words: 24 words do not mean more security for the same entropy. Either is fine; both must be backed up fully.
- Typing the phrase into a site: no legitimate service asks for the phrase. This rule alone filters most drainers.
- Backing up after importing: the phrase you restored from must be rewritten and checked, not assumed.
Self-custody is a chain of verified steps, not a checkbox. Generate, back up, restore, verify. Then test with a small transfer. The rest is repetition.