#!/usr/bin/env node
/**
* Deep Debugging: Mnemonic vs Storage Address Mismatch
*
* This script performs a systematic analysis of:
* 1. What addresses are stored in the database
* 2. What addresses the current mnemonic derives to
* 3. Where the mismatch occurs
* 4. Device and timestamp information
*/
// CRITICAL: Load bare-node-runtime FIRST
require('bare-node-runtime/global')
const fs = require('bare-fs')
const path = require('bare-path')
const os = require('bare-os')
const Corestore = require('corestore')
const Autobase = require('autobase')
const Hyperbee = require('hyperbee')
const WDK = require('@tetherto/wdk')
const WalletManagerEvm = require('@tetherto/wdk-wallet-evm')
const WalletManagerBtc = require('@tetherto/wdk-wallet-btc')
const { decrypt } = require('./lib/encryption.cjs')
const STORAGE_DIR = path.join(os.homedir(), '.hyper-wallet')
const DB_DIR = path.join(STORAGE_DIR, 'storage')
const WALLET_MNEMONIC_FILE = path.join(STORAGE_DIR, '.wallet-mnemonic')
const IDENTITY_MNEMONIC_FILE = path.join(STORAGE_DIR, '.mnemonic')
// Colors for terminal output
const colors = {
reset: '\x1b[0m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
bold: '\x1b[1m'
}
function log(msg, color = 'reset') {
console.log(`${colors[color]}${msg}${colors.reset}`)
}
function header(msg) {
console.log()
log('='.repeat(80), 'cyan')
log(msg, 'bold')
log('='.repeat(80), 'cyan')
console.log()
}
async function debugMnemonicMismatch(password) {
header('DEEP DEBUGGING: Mnemonic vs Storage Mismatch Analysis')
// ========================================
// STEP 1: Read stored mnemonics
// ========================================
header('STEP 1: Read Stored Mnemonics')
let walletMnemonic = null
let identityMnemonic = null
try {
const walletEncrypted = fs.readFileSync(WALLET_MNEMONIC_FILE, 'utf8').trim()
walletMnemonic = decrypt(walletEncrypted, password)
log(`✓ Wallet mnemonic loaded: ${walletMnemonic.split(' ').length} words`, 'green')
log(` First 3 words: ${walletMnemonic.split(' ').slice(0, 3).join(' ')}...`, 'blue')
} catch (err) {
log(`✗ Failed to load wallet mnemonic: ${err.message}`, 'red')
process.exit(1)
}
try {
const identityEncrypted = fs.readFileSync(IDENTITY_MNEMONIC_FILE, 'utf8').trim()
identityMnemonic = decrypt(identityEncrypted, password)
log(`✓ Identity mnemonic loaded: ${identityMnemonic.split(' ').length} words`, 'green')
log(` First 3 words: ${identityMnemonic.split(' ').slice(0, 3).join(' ')}...`, 'blue')
} catch (err) {
log(`⚠ No identity mnemonic found`, 'yellow')
}
// ========================================
// STEP 2: Derive expected addresses from wallet mnemonic
// ========================================
header('STEP 2: Derive Expected Addresses from Wallet Mnemonic')
const wdk = new WDK.default(walletMnemonic)
.registerWallet('ethereum', WalletManagerEvm.default, {
provider: 'https://ethereum-sepolia-rpc.publicnode.com'
})
.registerWallet('bitcoin', WalletManagerBtc.default, {
network: 'testnet',
host: 'electrum.blockstream.info',
port: 60001
})
const expectedAddresses = {}
// Derive Ethereum addresses (indices 0-5)
log('Deriving Ethereum addresses...', 'cyan')
expectedAddresses.ethereum = []
for (let i = 0; i < 5; i++) {
const account = await wdk.getAccount('ethereum', i)
const address = await account.getAddress()
expectedAddresses.ethereum.push({ index: i, address })
log(` [${i}] ${address}`, i === 0 ? 'green' : 'blue')
}
// Derive Bitcoin addresses (indices 0-5)
log('\nDeriving Bitcoin addresses...', 'cyan')
expectedAddresses.bitcoin = []
for (let i = 0; i < 5; i++) {
const account = await wdk.getAccount('bitcoin', i)
const address = await account.getAddress()
expectedAddresses.bitcoin.push({ index: i, address })
log(` [${i}] ${address}`, i === 0 ? 'green' : 'blue')
}
// ========================================
// STEP 3: Read stored addresses from database
// ========================================
header('STEP 3: Read Stored Addresses from Database')
const store = new Corestore(DB_DIR)
const autobase = new Autobase(store, null, {
valueEncoding: 'json',
open: () => store.get({ name: 'main' })
})
const db = new Hyperbee(autobase.view, {
keyEncoding: 'utf-8',
valueEncoding: 'json'
})
await db.ready()
const storedAddresses = {
ethereum: [],
'ethereum-usdt': [],
bitcoin: []
}
// Read all stored addresses
log('Reading Ethereum addresses from storage...', 'cyan')
for await (const { key, value } of db.createReadStream({
gte: 'wallet:address:ethereum:',
lt: 'wallet:address:ethereum:\xFF'
})) {
storedAddresses.ethereum.push({ key, ...value })
const current = value.isCurrent ? ' [CURRENT]' : ''
const color = value.isCurrent ? 'green' : 'blue'
log(` [${value.index}] ${value.address}${current}`, color)
log(` Device: ${value.device || 'unknown'} | Created: ${new Date(value.createdAt).toISOString()}`, 'blue')
}
log('\nReading Ethereum-USDT addresses from storage...', 'cyan')
for await (const { key, value } of db.createReadStream({
gte: 'wallet:address:ethereum-usdt:',
lt: 'wallet:address:ethereum-usdt:\xFF'
})) {
storedAddresses['ethereum-usdt'].push({ key, ...value })
const current = value.isCurrent ? ' [CURRENT]' : ''
const color = value.isCurrent ? 'green' : 'blue'
log(` [${value.index}] ${value.address}${current}`, color)
log(` Device: ${value.device || 'unknown'} | Created: ${new Date(value.createdAt).toISOString()}`, 'blue')
}
log('\nReading Bitcoin addresses from storage...', 'cyan')
for await (const { key, value } of db.createReadStream({
gte: 'wallet:address:bitcoin:',
lt: 'wallet:address:bitcoin:\xFF'
})) {
storedAddresses.bitcoin.push({ key, ...value })
const current = value.isCurrent ? ' [CURRENT]' : ''
const color = value.isCurrent ? 'green' : 'blue'
log(` [${value.index}] ${value.address}${current}`, color)
log(` Device: ${value.device || 'unknown'} | Created: ${new Date(value.createdAt).toISOString()}`, 'blue')
}
// ========================================
// STEP 4: Compare derived vs stored
// ========================================
header('STEP 4: Validation - Compare Derived vs Stored')
const mismatches = []
// Check Ethereum
log('Validating Ethereum addresses...', 'cyan')
for (const stored of storedAddresses.ethereum) {
const expected = expectedAddresses.ethereum.find(e => e.index === stored.index)
if (!expected) {
log(` [${stored.index}] WARNING: Stored address has no expected derivation`, 'yellow')
mismatches.push({ chain: 'ethereum', index: stored.index, stored: stored.address, expected: null })
continue
}
const match = stored.address.toLowerCase() === expected.address.toLowerCase()
if (match) {
log(` [${stored.index}] ✓ MATCH: ${stored.address}`, 'green')
} else {
log(` [${stored.index}] ✗ MISMATCH:`, 'red')
log(` Stored: ${stored.address}`, 'red')
log(` Expected: ${expected.address}`, 'green')
mismatches.push({
chain: 'ethereum',
index: stored.index,
stored: stored.address,
expected: expected.address,
device: stored.device,
createdAt: new Date(stored.createdAt).toISOString()
})
}
}
// Check Ethereum-USDT (should use same addresses as Ethereum)
log('\nValidating Ethereum-USDT addresses...', 'cyan')
for (const stored of storedAddresses['ethereum-usdt']) {
const expected = expectedAddresses.ethereum.find(e => e.index === stored.index)
if (!expected) {
log(` [${stored.index}] WARNING: Stored address has no expected derivation`, 'yellow')
mismatches.push({ chain: 'ethereum-usdt', index: stored.index, stored: stored.address, expected: null })
continue
}
const match = stored.address.toLowerCase() === expected.address.toLowerCase()
if (match) {
log(` [${stored.index}] ✓ MATCH: ${stored.address}`, 'green')
} else {
log(` [${stored.index}] ✗ MISMATCH:`, 'red')
log(` Stored: ${stored.address}`, 'red')
log(` Expected: ${expected.address}`, 'green')
mismatches.push({
chain: 'ethereum-usdt',
index: stored.index,
stored: stored.address,
expected: expected.address,
device: stored.device,
createdAt: new Date(stored.createdAt).toISOString()
})
}
}
// Check Bitcoin
log('\nValidating Bitcoin addresses...', 'cyan')
for (const stored of storedAddresses.bitcoin) {
const expected = expectedAddresses.bitcoin.find(e => e.index === stored.index)
if (!expected) {
log(` [${stored.index}] WARNING: Stored address has no expected derivation`, 'yellow')
continue
}
const match = stored.address === expected.address
if (match) {
log(` [${stored.index}] ✓ MATCH: ${stored.address}`, 'green')
} else {
log(` [${stored.index}] ✗ MISMATCH:`, 'red')
log(` Stored: ${stored.address}`, 'red')
log(` Expected: ${expected.address}`, 'green')
mismatches.push({
chain: 'bitcoin',
index: stored.index,
stored: stored.address,
expected: expected.address,
device: stored.device,
createdAt: new Date(stored.createdAt).toISOString()
})
}
}
// ========================================
// STEP 5: Check devices
// ========================================
header('STEP 5: Check Devices')
const devices = []
for await (const { key, value } of db.createReadStream({
gte: 'wallet:device:',
lt: 'wallet:device:\xFF'
})) {
devices.push(value)
log(`Device: ${value.name}`, 'cyan')
log(` Writer Key: ${Buffer.from(value.key).toString('hex')}`, 'blue')
log(` Added: ${new Date(value.addedAt).toISOString()}`, 'blue')
}
if (devices.length === 0) {
log('No devices found in storage', 'yellow')
}
// ========================================
// STEP 6: Summary
// ========================================
header('SUMMARY')
log(`Total stored addresses:`, 'cyan')
log(` Ethereum: ${storedAddresses.ethereum.length}`, 'blue')
log(` Ethereum-USDT: ${storedAddresses['ethereum-usdt'].length}`, 'blue')
log(` Bitcoin: ${storedAddresses.bitcoin.length}`, 'blue')
log(`\nTotal mismatches: ${mismatches.length}`, mismatches.length > 0 ? 'red' : 'green')
if (mismatches.length > 0) {
log('\nMismatch Details:', 'red')
for (const m of mismatches) {
log(` ${m.chain} [${m.index}]:`, 'red')
log(` Stored: ${m.stored}`, 'red')
log(` Expected: ${m.expected || 'N/A'}`, 'green')
if (m.device) log(` Device: ${m.device}`, 'yellow')
if (m.createdAt) log(` Created: ${m.createdAt}`, 'yellow')
}
log('\n⚠️ CRITICAL: Storage contains addresses that do NOT match the current wallet mnemonic!', 'red')
log('This means the exported mnemonic will NOT recover these addresses.', 'red')
} else {
log('\n✓ All stored addresses match the wallet mnemonic!', 'green')
}
await db.close()
await store.close()
}
// Main
const password = process.argv[2]
if (!password) {
console.error('Usage: node debug-mnemonic-mismatch.cjs <password>')
console.error('Example: node debug-mnemonic-mismatch.cjs mypassword')
process.exit(1)
}
debugMnemonicMismatch(password).catch(err => {
console.error('\n❌ Error:', err.message)
console.error(err.stack)
process.exit(1)
})