aboutsummaryrefslogtreecommitdiffstats
path: root/src/app.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-24 20:28:12 -0700
committerAdam Soltys <[email protected]>2026-06-24 20:28:12 -0700
commit08d1753e8433fcae6e9068e87cff93813f0ed76d (patch)
tree82e36ab3181c80d48217bb79a03940813e84b47d /src/app.js
parentaeb6a68e15b04ff35c8154a8f219dcca0a07de0e (diff)
downloadcoinosv3-08d1753e8433fcae6e9068e87cff93813f0ed76d.tar.gz
coinosv3-08d1753e8433fcae6e9068e87cff93813f0ed76d.zip
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) <[email protected]>
Diffstat (limited to 'src/app.js')
-rw-r--r--src/app.js13
1 files changed, 9 insertions, 4 deletions
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() }))
);
}