or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

hdnode-class.mdindex.mdmnemonic-operations.mdutility-functions.md
tile.json

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