Helper functions and constants for common BIP32/BIP44 operations including standard derivation paths and account path generation.
Standard BIP44 derivation path for Ethereum accounts.
/**
* Default BIP44 derivation path for Ethereum
* Value: "m/44'/60'/0'/0/0"
*/
const defaultPath: string;Usage Examples:
import { HDNode, defaultPath } from "@ethersproject/hdnode";
// Use default path for standard Ethereum account
const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
const rootNode = HDNode.fromMnemonic(mnemonic);
const defaultAccount = rootNode.derivePath(defaultPath);
console.log("Default path:", defaultPath); // "m/44'/60'/0'/0/0"
console.log("Default account address:", defaultAccount.address);
// Equivalent manual derivation
const manualAccount = rootNode.derivePath("m/44'/60'/0'/0/0");
console.log("Addresses match:", defaultAccount.address === manualAccount.address); // trueGenerates BIP44 account derivation paths for sequential account management.
/**
* Generate BIP44 account path for given index
* @param index - Account index (0-2147483647)
* @returns BIP44 path string in format "m/44'/60'/{index}'/0/0"
*/
function getAccountPath(index: number): string;Usage Examples:
import { HDNode, getAccountPath } from "@ethersproject/hdnode";
const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
const rootNode = HDNode.fromMnemonic(mnemonic);
// Generate multiple accounts
for (let i = 0; i < 5; i++) {
const accountPath = getAccountPath(i);
const accountNode = rootNode.derivePath(accountPath);
console.log(`Account ${i}:`);
console.log(` Path: ${accountPath}`); // "m/44'/60'/0'/0/0", "m/44'/60'/1'/0/0", etc.
console.log(` Address: ${accountNode.address}`);
}
// Account paths follow BIP44 structure
console.log("Account 0:", getAccountPath(0)); // "m/44'/60'/0'/0/0"
console.log("Account 1:", getAccountPath(1)); // "m/44'/60'/1'/0/0"
console.log("Account 10:", getAccountPath(10)); // "m/44'/60'/10'/0/0"BIP44 defines a 5-level path structure for hierarchical deterministic wallets:
m / purpose' / coin_type' / account' / change / address_indeximport { getAccountPath } from "@ethersproject/hdnode";
// Standard account paths (change = 0, address_index = 0)
const account0 = getAccountPath(0); // "m/44'/60'/0'/0/0"
const account1 = getAccountPath(1); // "m/44'/60'/1'/0/0"
const account2 = getAccountPath(2); // "m/44'/60'/2'/0/0"
// For multiple addresses within an account, modify the last component
const rootNode = HDNode.fromMnemonic(mnemonic);
const account0Node = rootNode.derivePath("m/44'/60'/0'/0"); // Account 0 base
// Generate multiple addresses for account 0
const address0 = account0Node.derivePath("0"); // First address
const address1 = account0Node.derivePath("1"); // Second address
const address2 = account0Node.derivePath("2"); // Third address
console.log("Account 0, Address 0:", address0.address);
console.log("Account 0, Address 1:", address1.address);
console.log("Account 0, Address 2:", address2.address);import { HDNode } from "@ethersproject/hdnode";
const rootNode = HDNode.fromMnemonic(mnemonic);
// Custom derivation paths
const customPaths = [
"m/44'/60'/0'/0/0", // Standard first account
"m/44'/60'/0'/1/0", // Change address for first account
"m/44'/60'/5'/0/10", // 10th address of 5th account
"m/0'/0'/0'", // Custom hardened path
];
customPaths.forEach((path, index) => {
const node = rootNode.derivePath(path);
console.log(`Path ${index}: ${path}`);
console.log(` Address: ${node.address}`);
console.log(` Depth: ${node.depth}`);
});The getAccountPath function validates account indices to ensure they're within valid BIP32 range:
import { getAccountPath } from "@ethersproject/hdnode";
// Valid indices (0 to 2^31 - 1)
console.log(getAccountPath(0)); // Valid
console.log(getAccountPath(1000)); // Valid
console.log(getAccountPath(2147483647)); // Valid (max value)
// Invalid indices throw errors
try {
getAccountPath(-1); // Negative number
} catch (error) {
console.log("Negative index error:", error.message);
}
try {
getAccountPath(2147483648); // Exceeds hardened bit
} catch (error) {
console.log("Index too large error:", error.message);
}
try {
getAccountPath(1.5); // Non-integer
} catch (error) {
console.log("Non-integer error:", error.message);
}import { HDNode, getAccountPath } from "@ethersproject/hdnode";
class MultiAccountWallet {
private rootNode: HDNode;
private accounts: Map<number, HDNode> = new Map();
constructor(mnemonic: string, password?: string) {
this.rootNode = HDNode.fromMnemonic(mnemonic, password);
}
getAccount(index: number): HDNode {
if (!this.accounts.has(index)) {
const accountPath = getAccountPath(index);
const accountNode = this.rootNode.derivePath(accountPath);
this.accounts.set(index, accountNode);
}
return this.accounts.get(index)!;
}
getAccountAddress(index: number): string {
return this.getAccount(index).address;
}
getAllAccounts(): { index: number; address: string; path: string }[] {
return Array.from(this.accounts.entries()).map(([index, node]) => ({
index,
address: node.address,
path: node.path
}));
}
}
// Usage
const wallet = new MultiAccountWallet(mnemonic);
// Access accounts
const account0Address = wallet.getAccountAddress(0);
const account1Address = wallet.getAccountAddress(1);
console.log("Account 0:", account0Address);
console.log("Account 1:", account1Address);
console.log("All accounts:", wallet.getAllAccounts());Utility functions throw errors in the following situations:
getAccountPathError Handling Examples:
import { getAccountPath } from "@ethersproject/hdnode";
function safeGetAccountPath(index: any): string | null {
try {
if (typeof index !== 'number' || !Number.isInteger(index)) {
throw new Error('Index must be an integer');
}
return getAccountPath(index);
} catch (error) {
console.log(`Invalid account index ${index}:`, error.message);
return null;
}
}
// Safe usage
const validPath = safeGetAccountPath(5); // Returns path
const invalidPath = safeGetAccountPath(-1); // Returns null
const invalidPath2 = safeGetAccountPath(1.5); // Returns null