OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-wallet-lib / address-manager.cjs

92 lines · javascript ref:
// lib/address-manager.cjs - Address Generation & Management (Phase 6.2)
// CRITICAL: Load bare-node-runtime FIRST before any other requires
require('bare-node-runtime/global')

const {
  initializeWallets,
  storeAddress,
  getAddresses,
  getNextAddressIndex,
  getCurrentAddress: getLatestAddress
} = require('./wallet-storage.cjs')

/**
 * Generate new receiving address and store in Autobase
 * @param {string} chain - 'bitcoin' or 'ethereum'
 * @param {Object} config - { testnet: boolean }
 * @returns {Object} - { address, path, index, chain }
 */
async function generateNewAddress(chain, config = { testnet: true }) {
  // Normalize chain name
  const chainNormalized = chain.toLowerCase()
  if (chainNormalized !== 'bitcoin' && chainNormalized !== 'ethereum') {
    throw new Error(`Unsupported chain: ${chain}. Use 'bitcoin' or 'ethereum'`)
  }

  // Initialize WDK
  const { wdk } = await initializeWallets(config)

  // Get next address index
  const index = await getNextAddressIndex(chainNormalized)

  // Determine derivation path fragment for WDK getAccountByPath
  // Bitcoin (BIP-84): m/84'/coinType'/0'/0/{index}
  // Ethereum (BIP-44): m/44'/60'/0'/0/{index}
  // WDK expects path fragment like "0'/0/{index}"
  const pathFragment = `0'/0/${index}`

  // Get account using custom derivation path
  const account = await wdk.getAccountByPath(chainNormalized, pathFragment)
  const address = await account.getAddress()

  // Build full path for display
  const coinType = chainNormalized === 'bitcoin'
    ? (config.testnet ? "1'" : "0'")
    : "60'"

  const path = chainNormalized === 'bitcoin'
    ? `m/84'/${coinType}/${pathFragment}`
    : `m/44'/${coinType}/${pathFragment}`

  // Store address in Autobase (syncs to all devices)
  await storeAddress({
    chain: chainNormalized,
    network: config.testnet ? 'testnet' : 'mainnet',
    address,
    path,
    index
  })

  return { address, path, index, chain: chainNormalized }
}

/**
 * List all addresses for a chain
 * @param {string} chain - 'bitcoin', 'ethereum', or 'all'
 * @returns {Array} - Array of address objects sorted by index
 */
async function listAddresses(chain = 'all') {
  const chainNormalized = chain.toLowerCase()
  return await getAddresses(chainNormalized)
}

/**
 * Get current (latest) address for a chain
 * @param {string} chain - 'bitcoin' or 'ethereum'
 * @returns {Object|null} - Latest address or null if none exist
 */
async function getCurrentAddress(chain) {
  const chainNormalized = chain.toLowerCase()
  if (chainNormalized !== 'bitcoin' && chainNormalized !== 'ethereum') {
    throw new Error(`Unsupported chain: ${chain}. Use 'bitcoin' or 'ethereum'`)
  }

  return await getLatestAddress(chainNormalized)
}

module.exports = {
  generateNewAddress,
  listAddresses,
  getCurrentAddress
}