You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Multi-chain HD Wallet CLI — Generate xprv/xpub, private keys and addresses for EVM, Bitcoin, and Solana from a single BIP39 mnemonic, with EIP-55 compliant checksums and SLIP-0010 compatible Ed25519 derivation.
EVM: Uses EIP-55 checksums — computes Keccak256 of the address hex string (not the public key) to produce mixed-case checksums compatible with all wallets and exchanges.
Bitcoin: Uses Native SegWit P2WPKH (Bech32) addresses starting with bc1q with WIF private key format. Standard compressed public key derivation (BIP32 compliance).
Solana: Uses SLIP-0010 compliant Ed25519 derivation with all-hardened path segments (no modulo order reduction) — compatible with Phantom and Solflare wallets when using the same mnemonic.
Exchange Workflow
Architecture
┌──────────────────────────────────────────────────────────────────┐
│ CRYPTO EXCHANGE SETUP │
├──────────────────────────┬───────────────────────────────────────┤
│ COLD WALLET (offline) │ HOT SERVER (online) │
│ │ │
│ mnemonic phrase │ xpub (BIP32 extended public key) │
│ │ │ │ │
│ ▼ │ ▼ │
│ master_xprv │ derive_pub(0) → User A deposit addr │
│ │ │ derive_pub(1) → User B deposit addr │
│ ▼ │ derive_pub(2) → User C deposit addr │
│ account xpub ──────────►│ ... │
│ (hardened path) │ │
│ │ No private keys on hot server │
│ sign withdraw tx ◄──────┤ Cold wallet signs on request │
│ with private_key[i] │ │
└──────────────────────────┴───────────────────────────────────────┘
Full Cycle (verified on Anvil + bitcoind regtest + Solana validator)
Solana uses Ed25519 with hardened derivation — all child indices require the private key. xgen provides 4 security modes:
Mode
Private key exposed?
Can sweep?
Use case
full
✅ Visible
✅ Yes
Testing, small amounts on hot server
hsm-sim
✅ Visible (simulated HSM)
✅ Yes
When using HSM/secure enclave
cold-export
❌ HIDDEN_FOR_SECURITY
✅ Yes (with xgen priv key)
🔒 Recommended for exchanges
pda
❌ PDA_CONTROLLED_BY_PROGRAM
❌ No (needs on-chain program)
Receive-only monitoring
PDA Mode
Program Derived Addresses are controlled by a Solana program, not by a private key:
# PDA with default program (Token Program)
xgen gen --chain solana --solana-mode pda --index 0
# → 3zJqUDFX2mJvcXUBpCkhM18E3TdvWhR6HJ4uMbXHXR8N# PDA with custom program ID
xgen gen --chain solana --solana-mode pda --index 42 --program-id "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
PDA addresses can receive SOL but cannot sweep without a deployed program with invoke_signed. Use PDA mode for monitoring-only deposit addresses.
Solana: How to Sweep
Generate address with full or cold-export mode
Extract private key from JSON output
Create a [priv(32) + pub(32)] keypair file
Use solana transfer --keypair keypair.json to sweep
# Generate keypair from xgen output
PRIV=$(xgen gen --chain solana --mnemonic "..." --index 0 --json | jq -r '.keys[0].private_key')
PUB=$(xgen gen --chain solana --mnemonic "..." --index 0 --json | jq -r '.keys[0].public_key')
python3 -c "import json; priv=bytes.fromhex('$PRIV'); pub=bytes.fromhex('$PUB'); json.dump(list(priv)+list(pub),open('key.json','w'))"# Sweep to hot wallet
solana transfer --keypair key.json --allow-unfunded-recipient "$HOT_WALLET" ALL
Encryption
# Encrypt wallet output (password from command line)
xgen gen --chain solana --password "mypassword" --output wallet.enc
# Encrypt with interactive prompt (secure — no password in shell history)
xgen gen --chain solana --encrypt --output wallet.enc
# → Enter encryption password: # → Confirm encryption password:# Decrypt
xgen decrypt wallet.enc
xgen decrypt wallet.enc --output wallet.json
xgen decrypt wallet.enc --password "mypassword"# non-interactive
Uses AES-256-GCM with scrypt key derivation (N=2^16, r=8, p=1). Salt and nonce are generated via OS-level CSPRNG (OsRng). Wallet version field is enforced during decryption.
Batch Derivation
# Generate specific indices (comma-separated)
xgen gen --chain evm --indexes "0,5,10,42"
xgen gen --chain solana --solana-mode cold-export --indexes "100,200,300"
xgen gen --chain btc --xpub "xpub6..." --indexes "1000,2000,3000"# Sequential range (consecutive)
xgen gen --chain evm --num 100
Library Usage
xgen exposes a public library interface. Add it to your Cargo.toml:
[dependencies]
xgen = "1.1"bip39 = "2.2"
Programmatic Address Generation
use xgen::{generate_for_chain,KeyInfo,WalletOutput};use bip39::Mnemonic;fnmain() -> Result<(),Box<dyn std::error::Error>>{let phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";let mnemonic = Mnemonic::parse(phrase)?;let seed = mnemonic.to_seed("");// Generate an EVM address at index 0let wallet:WalletOutput = generate_for_chain(&seed,"m/44'/60'/0'/0/0",Some(0),// index1,// num&mnemonic,"",// passphrase"evm","full",// solana_mode (ignored for evm)"",// program_id (ignored for evm)&None,// explicit indexes)?;for key in&wallet.keys{println!("Path: {}, Address: {}", key.path, key.address);}Ok(())}
xpub Watch-Only Mode
use xgen::generate_from_xpub;let wallet = generate_from_xpub("xpub6DCoCpSuQZB2...","m/44'/60'/0'/0",None,// index (None = use num)10,// num"evm",)?;
xpriv Derivation Mode
use xgen::generate_from_xpriv;// secp256k1 (EVM/BTC): standard BIP32 xpriv base58let wallet = generate_from_xpriv("xprv9wTYmMFdV23N2TdNG573QoEsfRr...","m/44'/60'/0'/0",None,// index (None = use num)5,// num"evm","full",// solana_mode (ignored for evm)"",// program_id (ignored for evm)&None,// explicit indexes)?;// Ed25519 (Solana): 64-byte hex xpriv (private_key || chain_code)let wallet = generate_from_xpriv("a1b2c3...64_byte_hex...","m/44'/501'/0'/0'",Some(0),// specific index1,// num"solana","cold-export",// solana_mode"",// program_id&None,// explicit indexes)?;
Encryption / Decryption
use xgen::{encrypt_data, decrypt_data,EncryptedWallet};// Encrypt a wallet JSON stringlet encrypted = encrypt_data(wallet_json,"password")?;// Decryptlet enc:EncryptedWallet = serde_json::from_str(&encrypted)?;let decrypted = decrypt_data(&enc,"password")?;
Public API
Function / Type
Description
generate_for_chain(...)
Generate HD wallet addresses for a chain
generate_from_xpub(...)
Watch-only address generation from xpub
generate_from_xpriv(...)
Key derivation from extended private key (BIP32 or SLIP-0010)
derive_slip10_ed25519_child(...)
SLIP-0010 child derivation from parent 64-byte state
Generate xprv/xpub, private keys and addresses for EVM, Bitcoin, and Solana from a single BIP39 mnemonic, with EIP-55 compliant checksums and SLIP-0010 compatible Ed25519 derivation.