Skip to content

HD Wallet API

The HD Wallet API provides hierarchical deterministic wallet functionality, allowing you to derive multiple keys and addresses from a single master key. This is an alternative to the Account API that supports enhanced privacy through key derivation and follows BIP32/CIP1852 standards.

  • Hierarchical Key Derivation: Generate multiple keys from a single master key
  • Separate Addresses: Use a new address for each payment. Addresses in one account share a stake key, so they can be linked on-chain
  • BIP32/CIP1852 Compliance: Follow industry standards for key derivation
  • Multi-Account Support: Manage multiple accounts within a single wallet
  • Deterministic Generation: Same mnemonic always generates same addresses

The main interface for HD wallet operations, providing methods for address generation, account management, and transaction signing.

The default implementation of the Wallet interface, supporting standard HD wallet functionality.

Create one with the static methods on Wallet: Wallet.create(network) for a new mnemonic, or Wallet.createFromMnemonic(network, mnemonic) to restore one.

Key Methods:

  • getBaseAddress() - Get base address at specific index
  • getEntAddress() - Get enterprise address at specific index
  • sign() - Sign transactions with wallet keys

Create wallets with different mnemonic lengths and configurations:

// Create wallet with 24-word mnemonic (default)
Wallet wallet = Wallet.create(Networks.testnet());
String mnemonic = wallet.getMnemonic();
System.out.println("Generated 24-word mnemonic");
// Create wallet with 15-word mnemonic
Wallet wallet15 = Wallet.create(Networks.testnet(), Words.FIFTEEN);
String mnemonic15 = wallet15.getMnemonic();
System.out.println("Generated 15-word mnemonic");
// Create wallet with 12-word mnemonic
Wallet wallet12 = Wallet.create(Networks.testnet(), Words.TWELVE);
String mnemonic12 = wallet12.getMnemonic();
System.out.println("Generated 12-word mnemonic");

Restore wallets from existing mnemonic phrases:

// Restore wallet from mnemonic
String mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
Wallet restoredWallet = Wallet.createFromMnemonic(Networks.mainnet(), mnemonic);
// Restore wallet for specific account
Wallet accountWallet = Wallet.createFromMnemonic(Networks.mainnet(), mnemonic, 1);

Generate multiple addresses from a single wallet:

// Generate base addresses at different indexes
Address address0 = wallet.getBaseAddress(0);
Address address1 = wallet.getBaseAddress(1);
Address address2 = wallet.getBaseAddress(2);
System.out.println("Address 0: " + address0.getAddress());
System.out.println("Address 1: " + address1.getAddress());
System.out.println("Address 2: " + address2.getAddress());
// Generate enterprise addresses (no staking)
Address entAddress0 = wallet.getEntAddress(0);
Address entAddress1 = wallet.getEntAddress(1);
System.out.println("Enterprise Address 0: " + entAddress0.getAddress());
System.out.println("Enterprise Address 1: " + entAddress1.getAddress());

Manage multiple accounts within a single wallet:

// Get addresses for different accounts
Address account0Address = wallet.getBaseAddress(0, 0); // Account 0, Index 0
Address account1Address = wallet.getBaseAddress(1, 0); // Account 1, Index 0
Address account2Address = wallet.getBaseAddress(2, 0); // Account 2, Index 0
// Switch between accounts
wallet.setAccountNo(0); // Switch to account 0
Address currentAccountAddress = wallet.getBaseAddress(0);
wallet.setAccountNo(1); // Switch to account 1
Address newAccountAddress = wallet.getBaseAddress(0);

Get Account objects for transaction operations:

// Get account at specific index for current account number
Account account0 = wallet.getAccountAtIndex(0);
Account account1 = wallet.getAccountAtIndex(1);
// Get account for specific account number and index
Account specificAccount = wallet.getAccount(1, 5); // Account 1, Index 5
// Use accounts for transaction signing
String accountAddress = account0.baseAddress();
Transaction signedTx = account0.sign(transaction);

To give each payment its own address, increment the address index. This separates payment credentials, but base addresses in one account share a stake key, so anyone can link them on-chain:

// Generate a fresh address for each transaction
Address address0 = wallet.getBaseAddress(0); // First transaction
Address address1 = wallet.getBaseAddress(1); // Second transaction
Address address2 = wallet.getBaseAddress(2); // Third transaction

Implement wallet recovery with address scanning:

// Configure wallet scanning
DefaultWallet wallet = new DefaultWallet(Networks.testnet());
// Set gap limit for address scanning
wallet.setGapLimit(50); // Scan 50 consecutive empty addresses
// Set specific indexes to scan (bypass gap limit)
wallet.setIndexesToScan(new int[]{0, 1, 2, 5, 10, 20});
// Scan for used addresses
public List<Address> scanForUsedAddresses(Wallet wallet, UtxoSupplier utxoSupplier) {
List<Address> usedAddresses = new ArrayList<>();
int gapCount = 0;
int index = 0;
while (gapCount < wallet.getGapLimit()) {
Address address = wallet.getBaseAddress(index);
List<Utxo> utxos = utxoSupplier.getAll(address.getAddress());
if (!utxos.isEmpty()) {
usedAddresses.add(address);
gapCount = 0; // Reset gap counter
} else {
gapCount++;
}
index++;
}
return usedAddresses;
}

Access and manage wallet keys securely:

// Get root key pair (if available)
Optional<HdKeyPair> rootKeyPair = wallet.getRootKeyPair();
if (rootKeyPair.isPresent()) {
HdKeyPair keyPair = rootKeyPair.get();
System.out.println("Root key available");
}
// Get root private key bytes
Optional<byte[]> rootPrivateKey = wallet.getRootPvtKey();
if (rootPrivateKey.isPresent()) {
byte[] keyBytes = rootPrivateKey.get();
System.out.println("Root private key: " + keyBytes.length + " bytes");
}
// Get stake address for delegation
String stakeAddress = wallet.getStakeAddress();
System.out.println("Stake Address: " + stakeAddress);

With QuickTx, use the wallet as the sender and the signer. It selects the wallet’s UTXOs and signs with the right keys:

Tx tx = new Tx()
.payToAddress(receiverAddress, Amount.ada(10))
.from(wallet);
TxResult result = new QuickTxBuilder(backendService)
.compose(tx)
.withSigner(SignerProviders.signerFrom(wallet))
.completeAndWait();

To sign a transaction you built yourself, pass the WalletUtxos it spends. Each one needs its derivation path, which the wallet’s UTXO selection sets; without paths, signing fails with “No signers found!”:

Set<WalletUtxo> walletUtxos = ...; // the wallet UTXOs this transaction spends
Transaction signedTx = wallet.sign(transaction, walletUtxos);
// Sign with stake key
Transaction stakeSignedTx = wallet.signWithStakeKey(transaction);
// Combined signing
Transaction fullySignedTx = wallet.sign(
wallet.signWithStakeKey(transaction),
walletUtxos
);
// Generate wallet securely
Wallet secureWallet = Wallet.create(Networks.mainnet());
String mnemonic = secureWallet.getMnemonic();
// Store mnemonic securely (encrypted storage recommended)
// Never store mnemonic in plain text
storeSecurely(mnemonic);
// Recreate wallet when needed
Wallet restoredWallet = Wallet.createFromMnemonic(Networks.mainnet(), mnemonic);

Use different account numbers to organize addresses by purpose. Each account has its own stake key:

// Personal addresses (account 0)
Address personalAddr = wallet.getBaseAddress(0, 0);
// Savings addresses (account 1)
Address savingsAddr = wallet.getBaseAddress(1, 0);
// Business addresses (account 2)
Address businessAddr = wallet.getBaseAddress(2, 0);
FeatureHD Wallet APIAccount API
Key ManagementHierarchical key derivationSingle key pair
Address GenerationMultiple derived addressesFixed addresses
Addresses per paymentA new one each time, linkable through the stake keyOne per account instance
Use CaseApplications managing many addressesSimple applications
ComplexityMedium to HighLow
Multi-AccountNative supportManual management

Use Account API if your application is using only one address or account.