diff options
| -rw-r--r-- | src/app.js | 17 | ||||
| -rw-r--r-- | src/i18n.js | 1 | ||||
| -rw-r--r-- | src/wallet.js | 13 |
3 files changed, 26 insertions, 5 deletions
@@ -1450,18 +1450,25 @@ function offlineBanner() { function balanceCard() { // Only dim on the very first load; background updates happen silently. const firstLoad = wallet.scanning && !wallet.loaded; + const locked = wallet.lockedValue; return h( 'div', { class: 'card balance' }, h('div', { class: 'small faint', style: 'text-transform:uppercase;letter-spacing:.05em' }, t('balance')), - // Headline is the projected balance (confirmed + mempool), so a pending - // spend is debited immediately rather than waiting for confirmation. - h('div', { class: 'amt', style: firstLoad ? 'opacity:.3' : '' }, fmtAmount(wallet.total), ' ', unitTag('unit')), - wallet.pending > 0 + // Headline is the spendable, projected balance (confirmed + mempool, minus + // coins locked in unclaimed gifts), so both a pending spend and a reserved + // gift are debited immediately rather than waiting to confirm/claim. + h('div', { class: 'amt', style: firstLoad ? 'opacity:.3' : '' }, fmtAmount(wallet.spendable), ' ', unitTag('unit')), + wallet.pending > 0 || locked > 0 ? h( 'div', { class: 'split' }, - h('div', {}, h('div', { class: 'k' }, t('pending')), h('div', { class: 'v pending' }, fmtAmount(wallet.pending), ' ', unitTag())) + wallet.pending > 0 + ? h('div', {}, h('div', { class: 'k' }, t('pending')), h('div', { class: 'v pending' }, fmtAmount(wallet.pending), ' ', unitTag())) + : null, + locked > 0 + ? h('div', {}, h('div', { class: 'k' }, t('lockedInGifts')), h('div', { class: 'v' }, fmtAmount(locked), ' ', unitTag())) + : null ) : null ); diff --git a/src/i18n.js b/src/i18n.js index 42fd34b..8e7cbf4 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -195,6 +195,7 @@ const STR = { giftAmountInvalid: 'Enter at least {n}.', giftMinNote: 'Minimum {n} at current fees, so it clears dust when claimed.', giftAnother: 'Create another', + lockedInGifts: 'Locked in gifts', giftReserved: 'Unclaimed gift links ({n})', giftReclaim: 'Reclaim', giftReclaimPrompt: 'Reclaim frees this coin for your next payment, but the link stays claimable until you spend it. Pay a network fee to revoke it right now instead?', diff --git a/src/wallet.js b/src/wallet.js index 72d33be..2871c5e 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -583,6 +583,19 @@ export class Wallet { return this.confirmed + this.pending; } + // Confirmed coins locked behind unclaimed gift links. The whole source coin is + // committed until the gift is claimed (our change only comes back in the + // claimer's tx), so it's already excluded from spending — and from the + // spendable balance below. + get lockedValue() { + const res = this.reservedSet(); + return this.utxos.reduce((s, u) => s + (res.has(utxoId(u)) ? u.value : 0), 0); + } + // What the user can actually spend right now: everything minus gift locks. + get spendable() { + return this.total - this.lockedValue; + } + _recomputeBalanceFromChains() { let c = 0; let p = 0; |
