// Generated, do not edit. sha256:1aab7b8b0f1a8c9ae297214b001ed051798627cb16552a7cd6582bdf219ea871 import * as db from '../db.js'; import { ENUMS } from '../../shared/config.js'; import { assertEnum, nowIso } from './_shared.js'; import { fail } from '../../shared/app-error.js'; import { trackDelete, trackUpdate } from './change-log.js'; import { hasFeature } from '../license.mjs'; import { services } from '../registers.mjs'; const nwc = () => services.get('nwc'); export async function purgeWalletSourceSecret(id) { await nwc()?.deleteNwcUri(id); } export function assertSourceMatchesAccount(tabel, accountId, sourceId) { if (sourceId == null) return; const bron = db.one(`SELECT accountId FROM WalletSource WHERE id = ?`, [sourceId]); if (!bron) throw new Error(`${tabel}: source ${sourceId} does not exist.`); if (Number(bron.accountId) !== Number(accountId)) { throw new Error(`${tabel}: source ${sourceId} belongs to account ${bron.accountId}, not to ${accountId}.`); } } export function listWalletSources(accountId) { return db.all(`SELECT s.*, c.name AS connection_name, c.url AS connection_url FROM WalletSource s LEFT JOIN Connection c ON c.id = s.connectionId WHERE s.accountId = ? ORDER BY s.id`, [accountId]); } export function listAllWalletSources() { return db.all(`SELECT s.*, a.name AS account_name FROM WalletSource s JOIN Account a ON a.id = s.accountId ORDER BY a.name, s.id`); } function assertLndConnection(connectionId) { const c = db.one(`SELECT id, kind FROM Connection WHERE id = ?`, [connectionId]); if (!c) fail('accounts.lndNoConnection', null, 'Pick an LND connection.'); if (c.kind !== 'lnd') fail('accounts.sourceNotLnd', null, 'The chosen connection is not an LND connection.'); } function connectionFor(kind, connectionId) { if (kind === 'lnd') { assertLndConnection(Number(connectionId)); return Number(connectionId); } if (ENUMS.ONCHAIN_SOURCE_KIND.includes(kind) && connectionId != null && connectionId !== '') { assertLndConnection(Number(connectionId)); return Number(connectionId); } return null; } const LIGHTNING_SOURCE = new Set(['nwc', 'lnd']); function assertLightningAllowed(kind) { if (LIGHTNING_SOURCE.has(kind) && (!hasFeature('lightning') || (kind === 'nwc' && !nwc()))) { fail('connections.lightningPaid', null, 'Lightning connections belong to the paid version.'); } } export async function createWalletSource({ accountId, kind, value, name, scriptType, connectionId = null, secret = null }) { assertEnum('kind', ENUMS.WALLET_SOURCE_KIND, kind); assertLightningAllowed(kind); if (kind === 'xpub') assertEnum('scriptType', ENUMS.SCRIPT_TYPE, scriptType); if (kind === 'nwc' && !secret) fail('accounts.sourceUriMissing', null, 'The NWC URI is missing.'); const verbinding = connectionFor(kind, connectionId); db.run(`INSERT INTO WalletSource (accountId, kind, value, name, scriptType, connectionId, createdAt) VALUES (?,?,?,?,?,?,?)`, [accountId, kind, kind === 'lnd' ? '' : value, name ?? null, kind === 'xpub' ? scriptType : null, verbinding, nowIso()]); const id = db.lastId(); if (kind === 'nwc') await nwc().setNwcUri(id, secret); await db.persist(); return id; } export async function updateWalletSource(id, { kind, value, name, scriptType, connectionId = null, secret = null }) { assertEnum('kind', ENUMS.WALLET_SOURCE_KIND, kind); if (kind === 'xpub') assertEnum('scriptType', ENUMS.SCRIPT_TYPE, scriptType); const oud = db.one(`SELECT kind FROM WalletSource WHERE id = ?`, [id]); if (oud?.kind !== kind) assertLightningAllowed(kind); const nieuwValue = kind === 'lnd' ? '' : value; const nieuwConnectie = connectionFor(kind, connectionId); trackUpdate('WalletSource', id, () => db.run(`UPDATE WalletSource SET kind=?, value=?, name=?, scriptType=?, connectionId=?, balanceSats = CASE WHEN kind = ? AND value = ? AND connectionId IS ? THEN balanceSats END, lastScannedAt = CASE WHEN kind = ? AND value = ? AND connectionId IS ? THEN lastScannedAt END WHERE id=?`, [kind, nieuwValue, name ?? null, kind === 'xpub' ? scriptType : null, nieuwConnectie, kind, nieuwValue, nieuwConnectie, kind, nieuwValue, nieuwConnectie, id])); if (kind === 'nwc' && secret) await nwc().setNwcUri(id, secret); if (kind !== 'nwc') await nwc()?.deleteNwcUri(id); await db.persist(); } export async function recordSourceBalance(id, sats) { const bron = db.one(`SELECT kind FROM WalletSource WHERE id = ?`, [Number(id)]); if (!bron) throw new Error(`Wallet source ${id} does not exist.`); if (bron.kind !== 'lnd' && bron.kind !== 'nwc') throw new Error(`Wallet source ${id} is on-chain; its balance comes from its addresses.`); if (!Number.isInteger(sats) || sats < 0) throw new Error(`A balance is a whole number of sats from zero: '${sats}'.`); db.run(`UPDATE WalletSource SET balanceSats = ?, lastScannedAt = ? WHERE id = ?`, [sats, nowIso(), Number(id)]); await db.persist(); } export function lightningBalances() { return db.all(`SELECT WalletSource.accountId, Account.name AS account_name, SUM(WalletSource.balanceSats) AS sats, MAX(WalletSource.lastScannedAt) AS scannedAt FROM WalletSource JOIN Account ON Account.id = WalletSource.accountId WHERE WalletSource.lastScannedAt IS NOT NULL AND (WalletSource.kind = 'lnd' OR (WalletSource.kind = 'nwc' AND NOT EXISTS ( SELECT 1 FROM WalletSource node WHERE node.accountId = WalletSource.accountId AND node.kind = 'lnd'))) GROUP BY WalletSource.accountId, Account.name ORDER BY Account.name`); } export async function deleteWalletSource(id) { await purgeWalletSourceSecret(id); trackDelete('WalletSource', id, () => db.run(`DELETE FROM WalletSource WHERE id=?`, [id])); await db.persist(); }