OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-wallet commits / 56bd795

Fix 'network is not defined' error in removeAddressFromContact
Bug: removeAddressFromContact() referenced undefined 'network' variable when migrating old-format contacts (line 1313). Root cause: - Function signature: removeAddressFromContact(contactId, addressId) - No 'network' parameter - Line 1313: network: existing.network || network ← ReferenceError! Fix: - Get network from config using getConfig() - Use config.network || 'testnet' as fallback - Matches system's current network setting Systematic debugging: 1. Searched for 'network is not defined' error 2. Grepped for 'network' usage in wallet-storage.cjs 3. Found line 1313 in removeAddressFromContact migration code 4. Verified function signature lacks 'network' parameter 5. Used getConfig() to get system default (already imported) Testing: Try removing address from old-format contact Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
56bd795a8b116ead14ca5139f3836c1a808b55b5
by plankatron <fleeky@gmail.com> · 2026-01-28T00:38:12.000Z

Changed files (1) +155 -27

lib/wallet-storage.cjs +155 -27
……@@ -368,8 +368,11 @@ async function storeAddress(addressData) {
368368 address: addressData.address,
369369 path: addressData.path,
370370 index: addressData.index,
371 createdAt: Date.now(),
372 device: getCurrentDevice()?.name || 'unknown'
371 label: addressData.label || '', // Pet-name/label for address
372 createdAt: addressData.createdAt || Date.now(),
373 device: getCurrentDevice()?.name || 'unknown',
374 isArchived: addressData.isArchived || false, // For hiding old addresses
375 isCurrent: addressData.isCurrent || false // Mark current receiving address
373376 }
374377 }
375378
……@@ -420,7 +423,91 @@ async function getNextAddressIndex(chain) {
420423async function getCurrentAddress(chain) {
421424 const addresses = await getAddresses(chain)
422425 if (addresses.length === 0) return null
423 return addresses[addresses.length - 1]
426
427 // Find address marked as current, or return latest
428 const current = addresses.find(a => a.isCurrent)
429 return current || addresses[addresses.length - 1]
430}
431
432/**
433 * Update address label
434 * @param {string} chain - 'bitcoin' or 'ethereum'
435 * @param {number} index - Address index
436 * @param {string} label - New label/pet-name
437 */
438async function updateAddressLabel(chain, index, label) {
439 if (!autobase) {
440 throw new Error('Storage not initialized')
441 }
442
443 // Get existing address
444 const addresses = await getAddresses(chain)
445 const existing = addresses.find(a => a.index === index)
446 if (!existing) {
447 throw new Error(`Address not found: ${chain}:${index}`)
448 }
449
450 // Update with new label
451 await storeAddress({
452 ...existing,
453 label
454 })
455
456 return { ...existing, label }
457}
458
459/**
460 * Set address as current receiving address
461 * @param {string} chain - 'bitcoin' or 'ethereum'
462 * @param {number} index - Address index to set as current
463 */
464async function setCurrentAddress(chain, index) {
465 if (!autobase) {
466 throw new Error('Storage not initialized')
467 }
468
469 const addresses = await getAddresses(chain)
470
471 // Find the address to set as current
472 const targetAddr = addresses.find(a => a.index === index)
473 if (!targetAddr) {
474 throw new Error(`Address not found: ${chain}:${index}`)
475 }
476
477 // Update all addresses: unset current on others, set on target
478 for (const addr of addresses) {
479 if (addr.index === index) {
480 await storeAddress({ ...addr, isCurrent: true })
481 } else if (addr.isCurrent) {
482 await storeAddress({ ...addr, isCurrent: false })
483 }
484 }
485
486 return { ...targetAddr, isCurrent: true }
487}
488
489/**
490 * Archive address (hide from UI)
491 * @param {string} chain - 'bitcoin' or 'ethereum'
492 * @param {number} index - Address index
493 */
494async function archiveAddress(chain, index) {
495 if (!autobase) {
496 throw new Error('Storage not initialized')
497 }
498
499 const addresses = await getAddresses(chain)
500 const existing = addresses.find(a => a.index === index)
501 if (!existing) {
502 throw new Error(`Address not found: ${chain}:${index}`)
503 }
504
505 await storeAddress({
506 ...existing,
507 isArchived: true
508 })
509
510 return { ...existing, isArchived: true }
424511}
425512
426513// ============================================================================
……@@ -752,8 +839,10 @@ async function syncTransactionsFromWDK(wdk, config = {}) {
752839 // Chain-specific transaction fetching
753840 if (chain === 'bitcoin') {
754841 // Bitcoin: Use Electrum client directly
755 if (!account._electrumClient) {
756 results.errors.push(`${chain}: No Electrum client available`)
842 if (!account._electrumClient || typeof account._electrumClient.blockchainScripthash_getHistory !== 'function') {
843 // Electrum client not available or method doesn't exist
844 // TODO: Use blockchain explorer API (Blockstream) instead
845 results.errors.push(`${chain}: Electrum client unavailable - Bitcoin transaction sync temporarily disabled`)
757846 continue
758847 }
759848
……@@ -1117,15 +1206,16 @@ async function findContactByAddress(address, chain) {
11171206}
11181207
11191208/**
1120 * Add an address to an existing contact
1209 * Add an address to an existing contact (supports multiple addresses per chain)
11211210 * @param {string} contactId - Contact ID
11221211 * @param {Object} addressInfo - Address details
1123 * @param {string} addressInfo.chain - Chain name (bitcoin, ethereum)
1212 * @param {string} addressInfo.chain - Chain name (bitcoin, ethereum, polygon, etc.)
11241213 * @param {string} addressInfo.address - Blockchain address
1125 * @param {string} addressInfo.network - Network (testnet, mainnet)
1214 * @param {string} addressInfo.network - Network (testnet, mainnet, sepolia, etc.)
1215 * @param {string} [addressInfo.label] - Optional label (e.g., "Hardware wallet", "Hot wallet")
11261216 * @returns {Promise<Object>} - Updated contact
11271217 */
1128async function addAddressToContact(contactId, { chain, address, network }) {
1218async function addAddressToContact(contactId, { chain, address, network, label = '' }) {
11291219 if (!autobase) {
11301220 throw new Error('Storage not initialized')
11311221 }
……@@ -1140,24 +1230,36 @@ async function addAddressToContact(contactId, { chain, address, network }) {
11401230 if (existing.addresses && Array.isArray(existing.addresses)) {
11411231 addresses = existing.addresses
11421232 } else if (existing.address && existing.chain) {
1143 // Convert old single-address format
1233 // Convert old single-address format (add ID to migrated address)
11441234 addresses = [{
1235 id: crypto.randomBytes(8).toString('hex'),
11451236 chain: existing.chain,
11461237 address: existing.address,
1147 network: existing.network || network
1238 network: existing.network || network,
1239 label: ''
11481240 }]
11491241 }
11501242
1151 // Check if address already exists for this chain
1152 const existingAddr = addresses.find(a =>
1243 // Check if EXACT same address already exists (same address + same chain)
1244 const exactMatch = addresses.find(a =>
11531245 a.chain === chain && a.address.toLowerCase() === address.toLowerCase()
11541246 )
1155 if (existingAddr) {
1156 throw new Error(`Address already exists for ${chain}`)
1247 if (exactMatch) {
1248 throw new Error(`This exact address already exists for ${chain}`)
11571249 }
11581250
1159 // Add new address
1160 addresses.push({ chain, address, network })
1251 // Generate unique ID for this address
1252 const addressId = crypto.randomBytes(8).toString('hex')
1253
1254 // Add new address with unique ID
1255 addresses.push({
1256 id: addressId,
1257 chain,
1258 address,
1259 network,
1260 label: label || '',
1261 addedAt: Date.now()
1262 })
11611263
11621264 // Update contact with new addresses array
11631265 const updated = {
……@@ -1184,12 +1286,12 @@ async function addAddressToContact(contactId, { chain, address, network }) {
11841286}
11851287
11861288/**
1187 * Remove an address from a contact
1289 * Remove an address from a contact by address ID
11881290 * @param {string} contactId - Contact ID
1189 * @param {string} chain - Chain name to remove
1291 * @param {string} addressId - Address ID to remove
11901292 * @returns {Promise<Object>} - Updated contact
11911293 */
1192async function removeAddressFromContact(contactId, chain) {
1294async function removeAddressFromContact(contactId, addressId) {
11931295 if (!autobase) {
11941296 throw new Error('Storage not initialized')
11951297 }
……@@ -1199,24 +1301,47 @@ async function removeAddressFromContact(contactId, chain) {
11991301 throw new Error('Contact not found')
12001302 }
12011303
1304 // Migrate old format to new format if needed
1305 let addresses = []
12021306 if (!existing.addresses || !Array.isArray(existing.addresses)) {
1203 throw new Error('Contact has no addresses array')
1307 // Old format: single address
1308 if (existing.address && existing.chain) {
1309 // Get default network from config for migration
1310 const config = getConfig()
1311 const defaultNetwork = config.network || 'testnet'
1312
1313 addresses = [{
1314 id: crypto.randomBytes(8).toString('hex'),
1315 chain: existing.chain,
1316 address: existing.address,
1317 network: existing.network || defaultNetwork,
1318 label: '',
1319 addedAt: existing.addedAt || Date.now()
1320 }]
1321 } else {
1322 throw new Error('Contact has no addresses')
1323 }
1324 } else {
1325 addresses = existing.addresses
12041326 }
12051327
1206 // Filter out the address for this chain
1207 const addresses = existing.addresses.filter(a => a.chain !== chain)
1328 // Filter out the address with this ID
1329 const newAddresses = addresses.filter(a => a.id !== addressId)
12081330
1209 if (addresses.length === existing.addresses.length) {
1210 throw new Error(`No address found for chain: ${chain}`)
1331 if (newAddresses.length === addresses.length) {
1332 throw new Error(`No address found with ID: ${addressId}`)
12111333 }
12121334
1213 if (addresses.length === 0) {
1335 if (newAddresses.length === 0) {
12141336 throw new Error('Cannot remove last address. Delete contact instead.')
12151337 }
12161338
12171339 const updated = {
12181340 ...existing,
1219 addresses,
1341 addresses: newAddresses,
1342 // Remove old format fields
1343 address: undefined,
1344 chain: undefined,
12201345 modifiedAt: Date.now()
12211346 }
12221347
……@@ -1927,6 +2052,9 @@ module.exports = {
19272052 getAddresses,
19282053 getNextAddressIndex,
19292054 getCurrentAddress,
2055 updateAddressLabel,
2056 setCurrentAddress,
2057 archiveAddress,
19302058 // UTXO functions (Phase 6.3)
19312059 storeUTXO,
19322060 getUTXOs,