const crypto = require('crypto') const fs = require('fs/promises') const { addressToScriptPubKey, } = require('./bitcoin-address') const storePath = '/data/store.json' async function readStore() { try { const data = await fs.readFile(storePath, 'utf8') return JSON.parse(data) } catch (error) { if (error.code === 'ENOENT') { return {} } throw error } } async function writeStore(store) { const temporaryPath = `${storePath}.${crypto.randomBytes(8).toString('hex')}.tmp` await fs.writeFile( temporaryPath, JSON.stringify(store, null, 2) + '\n', { mode: 0o600, }, ) await fs.rename(temporaryPath, storePath) } function normalizeAddress(address) { if (typeof address !== 'string') { return null } const normalized = address.trim() if (!normalized) { return null } return normalized } function normalizeLabel(label) { if (typeof label !== 'string') { return undefined } const normalized = label.trim() return normalized || undefined } function validateBitcoinAddress(address) { try { addressToScriptPubKey(address) } catch (error) { throw new Error( error instanceof Error ? error.message : 'Invalid Bitcoin address', ) } } async function listAddresses() { const store = await readStore() return Array.isArray(store.addresses) ? store.addresses : [] } async function addAddress(address, label) { const normalizedAddress = normalizeAddress(address) if (!normalizedAddress) { throw new Error('Bitcoin address is required') } validateBitcoinAddress(normalizedAddress) const addresses = await listAddresses() if ( addresses.some( (item) => item.address === normalizedAddress, ) ) { throw new Error( 'Bitcoin address is already being watched', ) } const entry = { address: normalizedAddress, } const normalizedLabel = normalizeLabel(label) if (normalizedLabel) { entry.label = normalizedLabel } const store = await readStore() store.addresses = [...addresses, entry] await writeStore(store) return entry } async function removeAddress(address) { const normalizedAddress = normalizeAddress(address) if (!normalizedAddress) { throw new Error('Bitcoin address is required') } const store = await readStore() const addresses = Array.isArray(store.addresses) ? store.addresses : [] const filtered = addresses.filter( (item) => item.address !== normalizedAddress, ) if (filtered.length === addresses.length) { throw new Error( 'Bitcoin address is not being watched', ) } store.addresses = filtered await writeStore(store) return true } module.exports = { listAddresses, addAddress, removeAddress, }