From 08d1753e8433fcae6e9068e87cff93813f0ed76d Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 24 Jun 2026 20:28:12 -0700 Subject: Gift links: stop pre-reserving fee, show it at claim time Previously createGift reserved a claim-fee headroom on top of the entered amount based on the fee rate at creation. Because the fee was only actually charged at claim time, fee-rate drift between the two moments silently ate into (or padded) the recipient's amount. Now the entered amount is exactly the recipient's full received total (sum of inputs less our change); no fee is reserved. The claim screen shows that full total as the headline and surfaces the live network-fee estimate on the Claim button, where it's deducted from the recipient's balance at claim time. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/app.js') diff --git a/src/app.js b/src/app.js index c8ff8b1..4aca644 100644 --- a/src/app.js +++ b/src/app.js @@ -1288,8 +1288,12 @@ function claimScreen() { ); } const pv = previewGift(ui.claimCode); - const estFee = Math.ceil((11 + 68 + 31 * 2) * ((wallet.feeRates && wallet.feeRates.halfHourFee) || 5)); - const approx = pv ? Math.max(0, pv.room - estFee) : 0; + // The headline is the full amount received (inputs minus the sender's change). + // The network fee is determined now, at claim time, and comes out of that + // amount โ€” we surface the estimate on the Claim button so it isn't a surprise. + const rate = Math.max(1, Math.round((wallet.feeRates && wallet.feeRates.halfHourFee) || 5)); + const estFee = pv ? Math.ceil((11 + 68 * pv.inputs + 31 * 2) * rate) : 0; + const total = pv ? pv.room : 0; return h( 'div', { class: 'col', style: 'gap:16px' }, @@ -1298,14 +1302,15 @@ function claimScreen() { h('div', { class: 'check-badge', style: 'background:var(--accent)' }, '๐ŸŽ'), h('h2', { style: 'margin:0' }, t('giftWelcome')), h('div', { class: 'amt', style: 'font-size:30px' }, - h('span', { class: 'amount-pos' }, '~' + fmtAmount(approx)), ' ', unitTag('unit') + h('span', { class: 'amount-pos' }, fmtAmount(total)), ' ', unitTag('unit') ), h('p', { class: 'muted', style: 'margin:0' }, t('claimBody')) ), ui.claimError && h('div', { class: 'notice err' }, ui.claimError), ui.busy ? h('button', { class: 'btn-primary btn-block', disabled: true }, h('span', { class: 'spinner' })) - : h('button', { class: 'btn-primary btn-block', onClick: doClaim }, t('claimBtn')) + : h('button', { class: 'btn-primary btn-block', onClick: doClaim }, + t('claimBtn') + ' ยท ' + t('claimFeeNote', { n: fmtAmount(estFee) + ' ' + unitLabel() })) ); } -- cgit v1.2.3