CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ethersproject--hdnode

BIP32 Hierarchical Deterministic Node operations for Ethereum wallets and key derivation.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utility-functions.mddocs/

Utility Functions

Helper functions and constants for common BIP32/BIP44 operations including standard derivation paths and account path generation.

Capabilities

Default Path Constant

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); // true

Account Path Generation

Generates 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"

Path Format Explanation

BIP44 defines a 5-level path structure for hierarchical deterministic wallets:

m / purpose' / coin_type' / account' / change / address_index

Path Components

  • m: Master key (root)
  • purpose': Always 44' for BIP44 (hardened)
  • coin_type': 60' for Ethereum (hardened)
  • account': Account index (hardened) - allows multiple accounts
  • change: 0 for external addresses, 1 for internal (change) addresses
  • address_index: Sequential address index within the account

Standard Ethereum Paths

import { 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);

Custom Path Construction

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}`);
});

Input Validation

Account Index Validation

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);
}

Multi-Account Wallet Implementation

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());

Error Conditions

Utility functions throw errors in the following situations:

  • Invalid account index: Index is negative, exceeds maximum value, or is not an integer
  • Type validation: Non-numeric values passed to getAccountPath

Error 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

docs

hdnode-class.md

index.md

mnemonic-operations.md

utility-functions.md

tile.json