diff options
| -rw-r--r-- | names/server.js | 28 | ||||
| -rw-r--r-- | src/features/names.js | 9 |
2 files changed, 30 insertions, 7 deletions
diff --git a/names/server.js b/names/server.js index 0005782..bd62f81 100644 --- a/names/server.js +++ b/names/server.js @@ -189,14 +189,32 @@ const arkParamOf = (uri) => { return m ? decodeURIComponent(m[1]) : null; }; -// Forward one settled offer payment; queue it on failure (empty float, etc). +// Deliver a settled payment to the name's owner. Two ways, and we try the +// one that works while they're asleep first: +// 1. an arkoor send from the float — instant, free, needs no cooperation +// 2. ask their wallet for an invoice and pay it over Lightning — needs no +// float at all, but only works while something of theirs is listening +// Failing both, it queues and retries; nothing is ever dropped silently. async function forward(name, sat) { const rec = state.names[name]; const dest = rec && arkParamOf(rec.uri); - if (!dest) { log(`forward: no ark destination for ${name}, dropping ${sat} sat`); return; } - if (!fwd) throw new Error('no forwarder wallet'); - await fwd.send(dest, sat); - log(`forwarded ${sat} sat to ${name}`); + if (!dest && !rec?.offerPk) { log(`forward: nowhere to send ${sat} sat for ${name}`); return; } + + if (dest && fwd && fwd.balance().spendableSat >= sat) { + await fwd.send(dest, sat); + log(`forwarded ${sat} sat to ${name}`); + return; + } + + if (rec?.offerPk && ln) { + const pr = await requestInvoiceFromWallet(rec.offerPk, { amountSat: sat, description: `${name} payment` }); + if (pr) { + await ln.pay(pr, { maxfeeSat: Math.max(2, Math.ceil(sat * 0.005)) }); + log(`delivered ${sat} sat to ${name} over lightning (no float needed)`); + return; + } + } + throw new Error(fwd && dest ? 'insufficient float and the wallet is not listening' : 'no delivery route'); } // NIP-57: a zap we invoiced is only "a zap" once we publish the receipt, diff --git a/src/features/names.js b/src/features/names.js index 4c0ffaf..54f15f7 100644 --- a/src/features/names.js +++ b/src/features/names.js @@ -74,7 +74,7 @@ export function namesFeature(ctx) { ...(manager ? { manager } : {}), }, signer); const prev = load().name; - save({ name, domain: DOMAIN, uri, updated: Date.now() }); + save({ name, domain: DOMAIN, uri, offerPk: hook('nwcOfferPubkey') || null, updated: Date.now() }); if (prev && prev !== name) { post('/register', 'DELETE', { name: prev, domain: DOMAIN }).catch(() => {}); } @@ -147,7 +147,12 @@ export function namesFeature(ctx) { render(); if (!st.name) return; const uri = await currentUri(); - if (uri && uri !== st.uri) await claim(st.name); + // Re-publish when the address changed OR when the registrar doesn't yet + // know this wallet's offer key — that key is what lets an incoming + // Lightning payment be delivered straight to us instead of waiting on + // the operator's float. + const offerPk = hook('nwcOfferPubkey') || null; + if (uri && (uri !== st.uri || (offerPk && st.offerPk !== offerPk))) await claim(st.name); } catch (e) { console.warn('names: refresh failed —', e.message); lastError = e.message; |
