Wallet Management

Deriving Wallets

Once a mnemonic is created or restored, derive a wallet using the derive() method on the Mnemonic instance. This method generates the corresponding private key, public key, and address from the mnemonic phrase. To derive multiple wallets from the same mnemonic, use the deriveMultiple() method. The derivation process is deterministic, meaning the same mnemonic always produces the same wallets.

For advanced use cases, the Mnemonic class provides additional derivation methods. Use deriveCustomPath() to derive a wallet using a custom BIP32 derivation path. The deriveOPWallet() method derives a wallet compatible with the Unisat wallet format, while deriveMultipleUnisat() generates multiple Unisat-compatible wallets from the same mnemonic.

Single Wallet Derivation

The following example demonstrate how to derive a single wallet:
typescript
import { Mnemonic, MnemonicStrength, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

const mnemonic = Mnemonic.generate();

// Derive wallet at index 0
const wallet0 = mnemonic.derive(0);

// Derive wallet at index 1
const wallet1 = mnemonic.derive(1);

// Each wallet has both classical and quantum keys
console.log('Classical Public Key:', wallet0.publicKey);
console.log('Quantum Public Key:', wallet0.quantumPublicKeyHex);

Multiple Wallet Derivation

The following example demonstrate how to derive multiple wallets:
typescript
import { Mnemonic, MnemonicStrength, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

const mnemonic = Mnemonic.generate();

// Derive first 5 wallets
const wallets = mnemonic.deriveMultiple(5);

wallets.forEach((wallet, index) => {
    console.log(`Wallet ${index}:`);
    console.log('  P2TR:', wallet.p2tr);
    console.log('  ML-DSA Hash:', wallet.address.toHex());
});

Custom Derivation Path

The following example demonstrate how to use a custom path to derive a single wallet:
typescript
import { Mnemonic, MnemonicStrength, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

const mnemonic = Mnemonic.generate();

// Custom BIP44/BIP84 path
const customWallet = mnemonic.deriveCustomPath(
    "m/84'/0'/0'/0/5",  // BIP84 path for account 0, index 5
    "m/360'/0'/0'/0/5"  // BIP360 quantum path (parallel)
);

console.log('Custom wallet address:', customWallet.p2wpkh);

Unisat Wallet Compatibility

For compatibility with Unisat and other HD wallets, use deriveOPWallet() which follows standard BIP derivation paths.

The following example demonstrate how to derive Unisat wallets:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

// Derive P2TR (Taproot) - BIP86
const taprootWallet = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0);
console.log('Taproot:', taprootWallet.p2tr); // bc1p...

// Derive P2WPKH (Native SegWit) - BIP84
const segwitWallet = mnemonic.deriveOPWallet(AddressTypes.P2WPKH, 0);
console.log('Native SegWit:', segwitWallet.p2wpkh); // bc1q...

// Derive P2PKH (Legacy) - BIP44
const legacyWallet = mnemonic.deriveOPWallet(AddressTypes.P2PKH, 0);
console.log('Legacy:', legacyWallet.legacy); // 1...

// Derive P2SH (Nested SegWit) - BIP49
const nestedSegwitWallet = mnemonic.deriveOPWallet(AddressTypes.P2SH_OR_P2SH_P2WPKH, 0);
console.log('Nested SegWit:', nestedSegwitWallet.segwitLegacy); // 3...

BIP Standard Mapping

Address Type BIP Standard Path Format Address Prefix
P2TR BIP86 m/86'/0'/account'/change/index bc1p... (mainnet)
P2WPKH BIP84 m/84'/0'/account'/change/index bc1q... (mainnet)
P2PKH BIP44 m/44'/0'/account'/change/index 1... (mainnet)
P2SH BIP49 m/49'/0'/account'/change/index 3... (mainnet)
Info

Unisat-compatible paths always use coin type 0 for the purpose field, regardless of network.

Accounts and Change Addresses

The following example demonstrate how to derive Unisat wallets for change:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

// Main account (account 0), receiving addresses
const receiving0 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0, 0, false);
const receiving1 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 1, 0, false);

// Main account (account 0), change addresses
const change0 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0, 0, true);
const change1 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 1, 0, true);

// Second account (account 1), receiving addresses
const account1_0 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0, 1, false);

console.log('Receiving 0:', receiving0.p2tr);
console.log('Receiving 1:', receiving1.p2tr);
console.log('Change 0:', change0.p2tr);
console.log('Account 1:', account1_0.p2tr);

Bulk Derivation

The following example demonstrate how to derive multiple Unisat-compatible wallets at once:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

// Derive first 5 Taproot addresses
const taprootWallets = mnemonic.deriveMultipleUnisat(
    AddressTypes.P2TR,  // Address type
    5,                  // Count
    0,                  // Start index
    0,                  // Account
    false               // Not change addresses
);

taprootWallets.forEach((wallet, i) => {
    console.log(`Address ${i}: ${wallet.p2tr}`);
});

// Derive 10 Native SegWit change addresses starting from index 5
const changeWallets = mnemonic.deriveMultipleUnisat(
    AddressTypes.P2WPKH,  // Native SegWit
    10,                   // Count
    5,                    // Start at index 5
    0,                    // Account 0
    true                  // Change addresses
);

Quantum Keys with Unisat Derivation

The following example demonstrate how to retreive both classical and quantum keys:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

const wallet = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0);

// Classical Taproot address (BIP86)
console.log('Classical P2TR:', wallet.p2tr);

// Quantum ML-DSA keys (BIP360: m/360'/0'/0'/0/0)
console.log('Quantum Public Key:', wallet.quantumPublicKeyHex);
console.log('Security Level:', wallet.securityLevel);

// Both keys are deterministically derived
console.log('Has quantum keypair:', wallet.mldsaKeypair !== undefined); // true

Wallet Properties

Once a wallet is derived from the mnemonic, its properties are accessible through the returned wallet object. This includes classical keys (private key and public key), quantum-resistant keys (ML-DSA key pair), and derived addresses for both classical and quantum formats.

Classical Keys

The following example demonstrate how to get wallet classic keys:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

const wallet = mnemonic.derive(0);

// Public keys
console.log('Compressed:', wallet.publicKey);             // 33 bytes
console.log('Hex:', wallet.toPublicKeyHex());             // 0x...
console.log('Uncompressed:', wallet.toUncompressedPublicKey()); // 65 bytes

// Private key (handle with care!)
console.log('Private key:', wallet.privateKey);            // 32 bytes hex

// Key pair
console.log('EC Keypair:', wallet.keypair);                // ECPairInterface

Quantum Keys

The following example demonstrate how to get wallet quantum keys:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

const wallet = mnemonic.derive(0);

// ML-DSA keypair
console.log('ML-DSA Keypair:', wallet.mldsaKeypair);
console.log('Security Level:', wallet.securityLevel);      // LEVEL2, LEVEL3, or LEVEL5

// Quantum public keys
console.log('Public Key (hex):', wallet.quantumPublicKeyHex);
console.log('Public Key (buffer):', wallet.quantumPublicKey);
console.log('Public Key Size:', wallet.quantumPublicKey.length); // 1312, 1952, or 2592 bytes

Addresses

The following example demonstrate how to get wallet addresses:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const mnemonic = Mnemonic.generate();

const wallet = mnemonic.derive(0);

// Classical addresses
console.log('P2TR:', wallet.p2tr);                        // bc1p...
console.log('P2WPKH:', wallet.p2wpkh);                    // bc1q...
console.log('Legacy (P2PKH):', wallet.legacy);            // 1...

// Quantum address
console.log('Public Key:', wallet.address.toHex());

// Address object
const address = wallet.address;
console.log('ML-DSA Hash:', address.toHex());             // SHA-256 of quantum key
console.log('Classical Key:', address.tweakedToHex());    // Classical public key

Security Best Practices

Mnemonic Security

Warning

Access sensitive information only when needed and in a limited scope!

The following example demonstrate access to sensitive information:
typescript
const phrase = mnemonic.phrase;        // Warning: Highly sensitive
const seed = mnemonic.seed;            // Warning: Highly sensitive

Good Practices:

  • Use hardware wallets.
  • Use encrypted storage.
  • Use paper backup in secure location.

Bad Practices:

  • Use console.log() to log sensitive information.
  • Save to a file unencrypted.
  • Transmit over network.
  • Store in version control.

Passphrase Protection

Tip

Add extra security layer with passphrase.

The following example demonstrate how to add specify a passphrase:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';

const passphrase = 'my-very-strong-passphrase-12345';

const mnemonic = Mnemonic.generate(
    MnemonicStrength.MAXIMUM,            // 24 words
    passphrase,                          // Required to recover wallet
    networks.bitcoin,                    // Mainnet
    MLDSASecurityLevel.LEVEL3            // Security level
);

// IMPORTANT: You need BOTH mnemonic AND passphrase to recover!
// Losing either means permanent loss of funds

Network Awareness

Warning

Different network will generate DIFFERENT addresses even with same mnemonic. Always ensure the address format matches the intended network.

The following example demonstrate how to use different network to generate keys:
typescript
import {Mnemonic, MnemonicStrength, MLDSASecurityLevel, AddressTypes } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

// Different networks generate different keys!
const mainnetMnemonic = new Mnemonic(phrase, '', networks.bitcoin);
const testnetMnemonic = new Mnemonic(phrase, '', networks.testnet);

const mainnetWallet = mainnetMnemonic.derive(0);
const testnetWallet = testnetMnemonic.derive(0);

// These will be DIFFERENT addresses even with same mnemonic
console.log('Mainnet:', mainnetWallet.p2tr);  // bc1p...
console.log('Testnet:', testnetWallet.p2tr);  // tb1p...