aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-11-14 21:38:58 -0700
committerAdam Soltys <[email protected]>2026-11-14 21:38:58 -0700
commit065d1b96afa32781f1a0805e0b4a02d32bf883ee (patch)
tree6c31c0d79d64269df726bde03a8611cdfc2e384c /src/features
parent968c086b5adbfdc9638c190163f391791e16ae65 (diff)
downloadcoinosv3-065d1b96afa32781f1a0805e0b4a02d32bf883ee.tar.gz
coinosv3-065d1b96afa32781f1a0805e0b4a02d32bf883ee.zip
A withdraw link says when a claim couldn't be delivered, and while one is still being paid. "As you can see, I made a transaction for 1,000,000 sats using the Withdraw link method, but they never arrived" (a user via Adam, 2026-11-14). The registrar couldn't route the claim to the wallet that asked, so nothing was sent and the 1M went back on the link, but the link's page said only "1,000,000 sats left", the same as an unclaimed one. Now the latest claim shows on the link's page: "on its way" / "couldn't find a Lightning route yet, still trying for a few minutes" (the registrar now retries for up to ten minutes, coinosv3-server a29af6f), looked at again every 10 s, or "couldn't be delivered … nothing was sent and the sats are still in this link", with the QR and Take back still there; the list row reads "claim failed · N left". lnurl-withdraw-links-test claims a second link with no route: retried, given back, both messages shown, and the same link pays once a route turns up
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6UKGJyuGyZFxddYRxS
Diffstat (limited to 'src/features')
-rw-r--r--src/features/withdraw-links.js25
1 files changed, 24 insertions, 1 deletions
diff --git a/src/features/withdraw-links.js b/src/features/withdraw-links.js
index a63d180..38b2d8c 100644
--- a/src/features/withdraw-links.js
+++ b/src/features/withdraw-links.js
@@ -114,6 +114,18 @@ export function withdrawLinks(ctx) {
} finally { s.taking = null; render(); load(); }
}
+ // What became of the latest claim someone made (reclaims aside): on its
+ // way, or turned back with the sats still here. "I made a transaction for
+ // 1,000,000 sats using the Withdraw link method, but they never arrived"
+ // (a user, 2026-11-14): the claim had failed and the link said only
+ // "1,000,000 sats left".
+ function lastClaim(l) {
+ const c = (l.claims || []).filter((x) => !x.reclaim).at(-1);
+ if (!c || c.status === 'paid') return null;
+ if (c.status === 'paying') return { kind: 'paying', c };
+ return l.status === 'open' && l.remainingSat >= c.sat ? { kind: 'failed', c } : null;
+ }
+
function linkCard(l) {
const s = st();
const lnurl = lnurlOf(l);
@@ -130,6 +142,15 @@ export function withdrawLinks(ctx) {
live ? h('div', { class: 'addr-box break mono', style: 'width:100%;font-size:11px' }, lnurl) : h('div', { class: 'notice small' }, l.status === 'closed' ? t('wlClosed') : t('wlUsedUp')),
live ? h('div', { class: 'row gap6 wrap', style: 'width:100%' }, copyBtn(lnurl, t('wlCopy'))) : null,
live ? h('div', { class: 'small faint', style: 'text-align:center' }, t('wlBearer')) : null,
+ (() => {
+ const lc = lastClaim(l);
+ if (!lc) return null;
+ // while it's being paid, look again every 10 s so the answer shows up here
+ if (lc.kind === 'paying' && !s.poll) s.poll = setTimeout(() => { st().poll = null; if (ui.giftMode === 'lnurl') load(); }, 10_000);
+ return lc.kind === 'paying'
+ ? h('div', { class: 'notice info small wl-claim-paying', style: 'width:100%' }, t(lc.c.tries > 1 ? 'wlClaimRetrying' : 'wlClaimPaying', { amount: amt(lc.c.sat) }))
+ : h('div', { class: 'notice err small wl-claim-failed', style: 'width:100%' }, t('wlClaimFailed', { amount: amt(lc.c.sat) }));
+ })(),
s.error && h('div', { class: 'notice err', style: 'width:100%' }, s.error),
live || (l.status === 'open' && l.remainingSat > 0)
? (s.taking === l.id
@@ -171,7 +192,9 @@ export function withdrawLinks(ctx) {
...s.list.map((l) => h('button', { class: 'row between wl-row', style: 'text-align:left', onClick: () => { s.open = l.id; s.made = null; s.error = ''; render(); } },
h('span', { class: 'small' }, amt(l.sat), l.uses > 1 ? ` × ${l.uses}` : '', l.note ? h('span', { class: 'faint' }, ' · ' + l.note) : null),
h('span', { class: 'small faint' },
- l.status === 'closed' ? t('wlClosedTag') : l.remainingSat < 1 || l.used >= l.uses ? t('wlUsedUpTag') : t('wlLeft', { amount: amt(l.remainingSat) })))));
+ l.status === 'closed' ? t('wlClosedTag') : l.remainingSat < 1 || l.used >= l.uses ? t('wlUsedUpTag')
+ : lastClaim(l)?.kind === 'failed' ? t('wlClaimFailedTag', { amount: amt(l.remainingSat) })
+ : t('wlLeft', { amount: amt(l.remainingSat) })))));
}
function view() {