From db7e70fac51e16c7f389e031a80355b2d9d0f57e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 5 Jul 2026 08:02:34 -0700 Subject: Boarding UX: label the funding tx and show an in-flight ark balance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The board's on-chain send showed as a generic 'Sent' and the sats vanished from the balance until the vtxo registered. The funding tx now reads 'Ark board' in History (with a detail section showing the net credit), and an 'Ark (boarding…)' line carries the pending amount from broadcast until the board completes. Co-Authored-By: Claude Fable 5 --- src/ark/manager.js | 8 +++++++- src/features/ark.js | 27 +++++++++++++++++++++++++-- src/i18n.js | 2 ++ 3 files changed, 34 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ark/manager.js b/src/ark/manager.js index 310bab5..e35bb89 100644 --- a/src/ark/manager.js +++ b/src/ark/manager.js @@ -122,7 +122,13 @@ export class ArkManager { balance() { const sum = (st) => this.state.vtxos.filter((v) => v.state === st).reduce((n, v) => n + v.amountSat, 0); - return { spendableSat: sum('spendable'), pendingSat: sum('pending') }; + // Boards whose funding tx is broadcast but whose vtxo isn't registered yet: + // the sats have left the on-chain balance, so surface them here instead of + // letting them vanish until the board completes. + const boardingSat = this.state.actions + .filter((a) => a.type === 'board' && a.fundingTxid && !['done', 'failed'].includes(a.step)) + .reduce((n, a) => n + (a.amountSat - a.feeSat), 0); + return { spendableSat: sum('spendable'), pendingSat: sum('pending'), boardingSat }; } // Receives newer than the last acknowledgement — the UI's "Payment diff --git a/src/features/ark.js b/src/features/ark.js index ca718ee..6584dc7 100644 --- a/src/features/ark.js +++ b/src/features/ark.js @@ -453,8 +453,31 @@ export function arkFeature(ctx) { }, balanceLines() { const b = arkBalance(); - if (!b || (b.spendableSat + b.pendingSat) <= 0) return []; - return [{ label: t('arkBalance'), sat: b.spendableSat + b.pendingSat }]; + if (!b) return []; + const lines = []; + if (b.spendableSat + b.pendingSat > 0) lines.push({ label: t('arkBalance'), sat: b.spendableSat + b.pendingSat }); + // A board in flight: the sats already left the on-chain balance, so show + // where they went instead of having them silently disappear. + if (b.boardingSat > 0) lines.push({ label: t('arkBoarding'), sat: b.boardingSat }); + return lines; + }, + decorateTxRow(tx) { + if (tx.net >= 0 || !ark || !ark.state) return null; + const a = ark.state.actions.find((x) => x.type === 'board' && x.fundingTxid === tx.txid); + if (!a) return null; + return { icon: '⚔', label: h('span', {}, t('arkBoardHistory')) }; + }, + txDetailSection(tx) { + if (!ark || !ark.state) return null; + const a = ark.state.actions.find((x) => x.type === 'board' && x.fundingTxid === tx.txid); + if (!a) return null; + const done = a.step === 'done'; + return h('div', { class: 'summary col', style: 'gap:0' }, + h('div', { style: 'font-weight:600;margin:12px 0 2px' }, '⚔ ' + t('arkBoardHistory')), + h('div', { class: 'line' }, + h('span', { class: 'k' }, t('arkBalance')), + h('span', { class: 'v' }, '+' + fmtAmount(a.amountSat - a.feeSat) + ' ' + unitLabel())), + done ? null : h('div', { class: 'small muted', style: 'margin-top:2px' }, t('arkBoardedNote'))); }, settingsCards() { return [arkCard()]; }, }; diff --git a/src/i18n.js b/src/i18n.js index d710da6..2ba6da6 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -364,6 +364,8 @@ const STR = { arkConnectBtn: 'Connect', arkNotConnected: 'Ark is not connected — pick a server in Settings.', arkBalance: 'Ark balance', + arkBoarding: 'Ark (boarding…)', + arkBoardHistory: 'Ark board', arkVtxos: 'Coins (VTXOs)', arkPendingActions: '{n} operation(s) in progress', arkBoardPlaceholder: 'Board amount (min {n} sats)', -- cgit v1.2.3