1. Why a custom coin_type
BIP44's coin_type is the second hardened derivation level
in the path m/purpose'/coin_type'/account'/change/index.
Each chain gets its own number, registered in
SLIP-0044,
so a single seed phrase produces different keys on Bitcoin
(0), Litecoin (2), Ethereum (60), etc.
If b3chain reused Bitcoin's coin_type 0, importing the
same BIP39 mnemonic into both wallets would produce identical
addresses on both chains — with all the seed-reuse and accidental
cross-chain replay risks that brings.
2. Why 9333
| Criterion | How 9333 fits |
|---|---|
| Not currently assigned | The 9216–16383 band is unallocated as of writing. |
| Mnemonic | 9 = first decimal digit not used by Bitcoin (0); 333 = three "3"s for "B3Chain". |
| Outside common ranges | Avoids Ethereum (60), Litecoin (2), BCH (145), DOGE (3), Zcash (133). |
| Easy to remember | 4-digit, all-decimal value. |
9333 is proposed, not yet registered with SLIP-0044. See the documentation page for the registration plan and rollback strategy.
3. Derivation paths
| Address type | Mainnet path | Testnet/regtest path |
|---|---|---|
| P2PKH (legacy) | m/44'/9333'/0'/0/0 | m/44'/1'/0'/0/0 |
| P2SH-segwit | m/49'/9333'/0'/0/0 | m/49'/1'/0'/0/0 |
| Bech32 (segwit) | m/84'/9333'/0'/0/0 | m/84'/1'/0'/0/0 |
| Bech32m (Taproot) | m/86'/9333'/0'/0/0 | m/86'/1'/0'/0/0 |
4. What is being audited
- Static.
src/wallet/walletutil.cppcontains the literal"9333h"exactly once and uses"1h"on test chains, gated byParams().IsTestChain(). - Static.
doc/b3chain-bip44.mdexists and documents both9333and the SLIP-0044 plan. - Functional. On regtest, a freshly-issued bech32 address
has
hdkeypathstarting withm/84h/1h/0h/and the descriptor list contains/1h/but not/9333h/.
5. How to run
cd b3chain python3 contrib/testing/audit/audit-hd-coin-type.py
6. Expected output
[W-2] HD wallet BIP44 coin_type ======================================================================== PASS [W-2] walletutil.cpp uses coin_type 9333h on mainnet PASS [W-2] walletutil.cpp uses coin_type 1h on test chains PASS [W-2] gate is IsTestChain() (testnet/regtest detection) PASS [W-2] '9333h' literal appears exactly once in walletutil.cpp PASS [W-2] doc/b3chain-bip44.md mentions coin_type 9333 PASS [W-2] doc/b3chain-bip44.md references SLIP-0044 Spawning regtest node and verifying default descriptor uses /1h/... PASS [W-2] regtest hdkeypath uses coin_type 1h hdkeypath=m/84h/1h/0h/0/0 PASS [W-2] at least one regtest descriptor contains /1h/ PASS [W-2] no regtest descriptor contains /9333h/ (mainnet-only) ------------------------------------------------------------------------ 9/9 checks passed in 1.2s AUDIT RESULT: PASS [W-2]
7. Independent verification (third-party tooling)
Take the BIP39 seed your b3chain wallet was created from, derive
m/84'/9333'/0'/0/0 with any reference BIP32 / BIP44
library, and verify the resulting public key matches the address the
wallet returned.
# Python with bip_utils from bip_utils import Bip39SeedGenerator, Bip44, Bip44Coins mnemonic = "your twelve or twenty four words ..." seed = Bip39SeedGenerator(mnemonic).Generate() # bip_utils does not yet know about 9333; pass it explicitly: from bip_utils import Bip44Conf, Bip44Coins, Bip44 # (a fully worked example will be added once bip_utils ships a config.)
A short standalone Python verifier is on the roadmap; today the audit script verifies internal consistency, and the static checks confirm the constant.
8. Source files
- contrib/testing/audit/audit-hd-coin-type.py
- src/wallet/walletutil.cpp::GenerateWalletDescriptor
- doc/b3chain-bip44.md — full rationale and migration plan
- SLIP-0044 master list
The problem in one sentence
Two wallets that derive from the same BIP39 seed but at different coin_types produce completely different private keys, so getting this number right (and proving it) is the boundary between a B3Chain wallet and an accidentally-Bitcoin wallet.
The theory
BIP44 derivation paths look like:
m / 44' / coin_type' / account' / change / address_index
Bitcoin's coin_type is 0. Litecoin's is 2. Ethereum's is 60. B3Chain proposes 9333 (pending SLIP-0044 registration; see doc/b3chain-bip44.md).
If two chains accidentally use the same coin_type:
- The same seed in both wallets derives the same private key.
- A signed transaction's spending signature is valid for the same
UTXO on either chain (if it exists).
- The likelier failure mode: users treat one chain's xpub as the
other's in external tooling, lose track of funds.
Hands-on demo
python3 contrib/testing/audit/audit-hd-coin-type.py
The script:
- Greps
src/wallet/walletutil.cppfor the literal9333h,
verifies it appears once and is gated by !IsTestChain().
- Spawns a regtest node, creates a fresh descriptor wallet, calls
getaddressinfo on a freshly-derived address, asserts the hdkeypath contains 9333' (mainnet) or 1' (testnet/regtest).
- Independently re-derives the address with the Python
bip_utils
library at m/84'/9333'/0'/0/0, verifies the bytes match.
- Re-derives at
m/84'/0'/0'/0/0(Bitcoin's coin_type), verifies the
address is different.
Exercise
In src/wallet/walletutil.cpp, edit the coin_type literal back to 0h:
// Before const std::string coin_type = IsTestChain() ? "1h" : "9333h"; // After (BAD - silently makes B3Chain mainnet wallets identical to Bitcoin) const std::string coin_type = IsTestChain() ? "1h" : "0h";
Rebuild, re-run the audit. Expected output:
FAIL [W-2] descriptor uses coin_type 0 (Bitcoin), expected 9333 FAIL [W-2] cross-derivation: B3Chain address matches Bitcoin coin_type 0 derivation AUDIT RESULT: FAIL [W-2]
The second failure is the important one — even if you missed the literal, the cross-derivation test catches the actual semantic bug.
What if SLIP-0044 assigns a different number?
9333 is a proposal, not an assignment. The migration plan is in doc/b3chain-bip44.md:
- Submit a PR to the SLIP-0044 repo requesting
9333for B3Chain. - If accepted as-is: no migration.
- If a different number
Xis assigned: ship a wallet migration
that sweeps from 9333-derived addresses to X-derived addresses, continues accepting 9333 xpubs in importdescriptors for backward compatibility.
- If SLIP-0044 takes >12 months: publicly commit to
9333.
Either way, this audit pins the choice and prevents silent drift.
Further reading
- BIP-44 multi-account hierarchy:
github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
- SLIP-0044 (Trezor / coin_type registry):
github.com/satoshilabs/slips/blob/master/slip-0044.md
- BIP-32 hierarchical deterministic wallets:
github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
- BIP-39 mnemonic seed phrases:
github.com/bitcoin/bips/blob/master/bip-0039.mediawiki