aboutsummaryrefslogtreecommitdiffstats
path: root/names/server.js
Commit message (Collapse)AuthorAgeFilesLines
* names: custom offers carry their owner's key; ones that can't reach a wallet ↵Adam Soltys4 days1-9/+32
| | | | | | | | | | | | | | | | are retired Releasing a name disabled its own offer but left its custom offers live (27 orphans on 2026-10-22, rick@ had 4): a payment to one found no name and no key, and would have sat in the forward queue for good. Custom offers now record the owner's pubkey (backfilled at start from the name, or for an orphaned npub1xxxxxxx@ name from the one current key with that npub prefix — 4 recovered), and the settle loop forwards by it, so a released name's offer pays the same key's name now, as the name's own offer already did. Orphans with no owner to follow are disabled on the node and dropped (23), as are a released staging name's. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: mint nothing payable for a wallet on another network, and retire what ↵Adam Soltys4 days1-2/+66
| | | | | | | | | | | | | | | | | | was minted A staging name is a mutinynet wallet, but every claim got a mainnet BOLT12 offer on our node published in its record, and custom offers and POS sales were minted there too: real sats paid that way had no route onward (2,092 sat parked on 2026-10-22). otherNetwork() — the record's ark address decides, a staging name without one is mutinynet — now gates the claim's stand-in offer, custom offers and POS invoices (LNURL already refused staging). At start, retireOtherNetworkOffers() disables the offers already out there (83 staging names, 13 custom offers), takes their lno= out of the published DNS record and drops them from state; idempotent, so a failure retries next start. [email protected] keeps its offers: its wallet is mainnet. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: a queued payment the float can cover goes now, backoff or notAdam Soltys4 days1-1/+5
| | | | | | | | | Float top-ups that missed their 60 s settle window landed later (+300k on 2026-10-22 once the ASP's vtxo pool refilled), but only a top-up seen to settle resets the queue's backoff, so jarryd's 248k sat in a 1-hour wait with 477k in the float. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: a wallet on another ark server gets its own Lightning invoice, one on ↵Adam Soltys4 days1-16/+49
| | | | | | | | | | | | | | | | | | | another network is parked The float step threw 'address belongs to a different ark server' before the Lightning step ever ran, so manna and rogerv3 (wallets on Second) were retried 100 times since 10-18 without once asking their wallets for an invoice. The destination's ark id now decides: the float only on our own server, otherwise straight to the wallet's CLINK invoice — those wait for the wallet without paging (waitingOnWallet in /health). A staging name's tark address paid real sats through its mainnet offer has no route at all: such a forward is parked (state.parked, with its reason) instead of retried forever, and /health counts it for the desk monitor. Ten such payments (2,092 sat, Sep–Oct test payments to @staging.coinos.io names) had been retried ~900 times each. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: deliver to coinos wallets over a circular route, shrink failing float ↵Adam Soltys4 days1-21/+96
| | | | | | | | | | | | | | | | | | | | | | | | | top-ups, report stuck money in /health The ASP's vtxo pool sat empty for 35 hours (2026-10-20/22: 614k in the rounds wallet against 1.12M needed to refill), and two forwards of ~124k for jarryd sat in the queue the whole time: - viaClink paid the wallet's own invoice with a plain pay, but a coinos wallet's invoice is minted by our ASP on this very node: a self-payment the hold plugin never sees ('Destination said it doesn't know invoice'). It now goes out and back in over a channel pair (payCircular, shared with the float top-up) and waits for the wallet to claim, so a payment is delivered whenever the wallet is open, float or no float. - a float top-up that doesn't settle halves the next ask (down to 20k), back to full size after one lands: 79 tries of 200k failed where the pool's 100k coins could have funded half of it. - the retry tick can't overlap itself any more (a circular delivery waits up to 4 min; an overlapping tick would forward the same payment twice). - /health reports pendingSat, oldestPendingAt, the top-up failure streak and last error, and payments for wallets on another ark server apart (undeliverable): the desk float monitor pages on these. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* live: a name streams a day after it's claimed (the registrar now records ↵Adam Soltys7 days1-1/+4
| | | | | | | when; older records count from their last update), never if banned; GET /live/allowed says which and until when. Viewers can report a stream (POST /live/<id>/report, NIP-98): kept in .reports.jsonl and DM'd to the admins from the welcome key. An admin takes a stream down (POST /live/<id>/remove {ban}): it ends, its playlists and segments answer 410, its files move to .removed/ (kept for reporting, never trimmed), and a ban stops its sender streaming. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* names: keep state in SQLiteAdam Soltys9 days1-20/+13
| | | | | | | | | | | | | | | | | | persist() rewrote the whole state file, close to 10 MB, on every settled payment and every queue tick, so one crash during a write could take every name with it. State now lives in SQLite (bun:sqlite, WAL, synchronous=FULL): one row per name, offer, invoice and so on, with the forwarder wallet's state kept as a single row. Each persist() is one transaction that writes only the rows that changed, so a crash leaves the previous state or the new one, never a torn file. The in-memory state object and every persist() call stay as they were. On the first start the JSON state file is imported, and a corrupt one stops startup. The file is left in place, so a rollback to the JSON build still finds its data. store.snapshot() makes a consistent copy while the service runs, for backups. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Make this the coinosv3-server repo: the services, with coinosv3 pinnedAdam Soltys9 days1-5/+5
| | | | | | | | | | | | | | | | Carved out of coinosv3 (names, feed, nwcpush, blossom, vmedia, bridge and their tests, with history). The shared wallet code they import (src/ark, noffer, bolt12, popular-feed) now comes from a coinosv3 submodule pinned at 082fc2e, the commit the services have actually run on, so moving here changes no behaviour; bumping it is its own commit. The two text helpers translation uses arrived on the server later than that commit and are vendored under names/vendor at the versions deployed, until the pin moves past them. Root package.json pins the npm versions installed on the server. compose.yml runs names, nwcpush and blossom from this checkout (read-only) with configs and state under $STATE, outside the repo, and pins the Bun image. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: refuse a corrupt state file; flush before replacing itAdam Soltys9 days1-2/+9
| | | | | | | | | | | The loader treated any read or parse error as a fresh registrar and started with no names, then persisted that empty state over the real one. A crash can leave the state file truncated, because persist() renamed the new file into place without flushing it. Now a missing file is a fresh start, an unreadable one stops startup, and persist() fsyncs the file and its directory around the rename. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: bring in the registrar as it ran on csAdam Soltys9 days1-8/+79
| | | | | | | | | | | | | | | | The deployed registrar carried changes made directly on the server between Oct 10 and Oct 14 that never reached the repo: - forward() delivers to the same key's current name when the paid name was released in the meantime (a v2 migration swaps its throwaway npub name for the real one seconds after a payment can settle) - "nowhere to send" throws, so the payout stays queued instead of dropping - the forwarder float merges small coins (consolidateFloat) before a send hits the input cap - floatUpkeep skips coins already past expiry, which the server's sweeper has taken and whose refresh never settles Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Translation: into the phone's language, and DeepL with your own key. ↵Adam Soltys2026-10-101-3/+5
| | | | | | | isolabellart saw the Translate button but nothing became Italian: the target was the app's language, coinos has no Italian UI (so it ran in English), and the language guess didn't know Italian. Posts now translate into the reader's choice (Settings → Nostr → Translation, any of 31 languages), else the phone's language when the app has no UI for it, else the app's; the guess knows Italian, Dutch and Polish. And, as Jumble offers: a DeepL API key of your own, kept on the device and sent per request as x-deepl-key — the registrar passes it to DeepL (api-free for ":fx" keys; DeepL refuses browsers) and never stores or logs it; a refused key or used-up quota says so once. names: translateDeepl (prose only, links/tags kept, detected source back, 401/402/422 statuses), CORS allows the header. Deployed to cs names. tools/translate-italian-test.js, tools/deepl-translate.test.js. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Names: letters and numbers only, 2–24 — coinos v2's rule. The registrar ↵Adam Soltys2026-10-091-2/+11
| | | | | | | took a-z, 0-9 and . _ - (1–30), so bitcoin-education and a dozen others got through. A NEW claim must now match /^[a-z0-9]{2,24}$/ (v2's /^[\p{L}\p{N}]{2,24}$/u, held to ASCII since a name is a DNS label); a name already held (19 with . _ -, plus "f" and "g") is grandfathered — its owner can still update it — as are v2 migrations carrying their own name and npub-shaped defaults. /name/<n> answers invalid: true for a free name that breaks the rule; the claim form says "Letters and numbers only" as it's typed, and the suggested name from a nostr profile is stripped to letters and digits. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Translation: posts in another language are shown in yours — "Translated ↵Adam Soltys2026-10-091-0/+17
| | | | | | | from Spanish · Show original" under the words, automatic by default for posts the language guess calls foreign (Settings → Nostr → Translation switches it off and leaves a Translate link instead), and ⋯ → Translate for any post. The browser's on-device Translator does it when the language pair is already installed (desktop Chrome); otherwise the registrar's new POST /translate (names/translate.js): a cached, 4-at-a-time front for a LibreTranslate container on cs (names/compose-libretranslate.yml, v1.9.6, 32 languages; none for sw/mr/ta/te, so those readers get no offer). Links, nostr: mentions, :emoji:, #tags and long codes are never sent to the model — only the prose between them, batched in one call (src/translate-split.js, shared). Translations are remembered (coinos-translations, 300). tools/translate-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* POS terminals ring up in the owner's currency: the app sends its currency ↵Adam Soltys2026-10-081-1/+6
| | | | | | when minting a terminal token (it sent none, so every terminal priced sales in USD and a $0.03 sale paid out as $0.04 CAD), and a new token retunes the terminals already paired to that name Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Registrar: rateExempt IPs in names-config.json skip the per-minute limits ↵Adam Soltys2026-10-081-0/+4
| | | | | | (the operator's own IP while testing sign-ups) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: a welcome DM counts as sent only when a relay acknowledges it — ↵Adam Soltys2026-10-071-2/+24
| | | | | | dead sockets are dropped and it retries on fresh ones (four welcomes on 2026-10-07 vanished after the uplink dropped while the log said sent) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* names: /name says whether the holder is where a migration grant sent the nameAdam Soltys2026-10-041-1/+9
| | | | | | | | | | coinos.io's v3 bridge forwards a migrated legacy account's incoming payments to the v3 wallet only on proof: the holder is the legacy account's own key, or the wallet its session named via /migrate-grant (granted: true). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Links in posts show as the cards their pages describe.Adam Soltys2026-09-271-0/+23
| | | | | | | | | | | | A plain link becomes an Open Graph card: picture, title, a line, the site. The registrar fetches the page on the reader's behalf (names/preview.js, GET /preview?url=): only public hosts, at most half a megabyte of HTML, cached a day. The client warms the card with the rest of the post so the row arrives whole, keeps a few hundred cards across sessions, and leaves a page with nothing to say as a bare link. Pictures and YouTube keep their boxes. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Registrar: an invoice the wallet hands back must have a minute left; ask ↵Adam Soltys2026-09-221-6/+24
| | | | | | | once more before minting our own. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
* Accounts from the header, snapshot-first Spending restore, name ownership ↵Adam Soltys2026-09-181-4/+2
| | | | | | | | | | | | | | | | grants. Header buttons always leave the current feature screen; an account with no remembered nostr identity opens Accounts instead of nothing. Logout confirms in place. A scan finishing after logout or an account switch no longer drops the new session into offline mode (stateGeneration guards in sync + ark). Spending restores from the snapshot first. A migration grant names the identity that owns an address; its manager may register it without becoming that identity (names/ownership.js). Browser tests for account access, profile retry, spending restore, thread reply focus, custom-emoji reactions and registry ownership. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* A gift made for one head can be put straight on it.Adam Soltys2026-09-141-2/+4
| | | | | Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
* A knight's helm, for one small knight.Adam Soltys2026-09-141-1/+2
| | | | | | | | | | A gifted hat that covers the whole face — its own square drawing over the avatar rather than perched on it: steel great helm, cross slit, breathing holes, a red plume. Never sold; the registrar's gift endpoint knows it beside the beta hard hat. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
* names: a migration grant unlocks a reserved legacy name.Adam Soltys2026-09-101-7/+10
| | | | | | | | | | | | | Migrating the coinos.io house account `coinos` swept its balance fine, then every claim bounced with "name is reserved": the reserved-word check ran before the migration grant was consulted. A reserved word that is also a real coinos.io account can only reach the registrar through a migration, whose grant is the old account's authenticated say-so — so the grant now clears the reserved check too. Reserved names without a grant stay reserved. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Nw1Dijik1tLVKRM1WkU7xE
* Payment push notifications are scoped to their network, so a mainnet payment ↵Adam Soltys2026-09-051-1/+3
| | | | | | | stops opening the staging PWA. The same seed derives the same nostr pubkey on mainnet and staging, so both PWAs registered push under one pubkey and the notifier — matching only by pubkey — fanned every mainnet payment out to the staging subscription too; tapping it opened staging.coinos.io. Now the client stamps its network on the push registration (pushWatch net: getNetwork()), the registrar declares its own network on the /notify call (CFG.forwarder.network), and nwcpush delivers a payment only to registrations whose net matches — with a rollout-safe fallback: a device that hasn't re-registered yet (net=null) still gets the push, and a caller that omits net still reaches everyone, so nobody goes dark mid-deploy. Deployed names + nwcpush on cs Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
* Point of sale: a coinos-pos terminal works against a nameAdam Soltys2026-09-051-2/+209
| | | | | | | | | | | | | | | | | | Registrar: the owner mints a bearer POS token from Settings (NIP-98 POST /pos/token, DELETE revokes; /admin/pos/token for operators). With it the terminal gets /pos/me, rings up sales at /pos/invoice (fiat via coinos.io rates, or sats), reads /pos/payments, and holds a websocket at /pos/ws that gets a payment message when the sale settles. Sales are always minted on our node so the settle loop sees them and the ordinary forward path delivers the sats to the name's ark address. The name's lnurlp pins the newest unpaid sale under five minutes old — coinos.io's /p/<name> rule — so an NFC tap or a scan pays exactly that invoice. Wallet: a "Point of sale" section on the names card creates, copies and revokes tokens. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMi2Y1oKPZ3TeeFmLej47y
* Lightning receives to a [email protected] address now wear the ⚡ instead of ↵Adam Soltys2026-09-041-4/+39
| | | | | | | the Ark mark: a faucet paying the LN address settles on the registrar's CLN and arrives as an anonymous arkoor from the float (the mailbox protocol carries no memo), so the wallet genuinely couldn't tell the rail. The registrar now records a receipt {sat, hash, ts} per LN settlement it forwards via the float (7-day ring per name) and serves them at GET /lnreceipts (NIP-98, owner/manager only — it's a feed of incoming amounts); the wallet fetches them through the names feature (which holds the signer) and fuzzy-matches receive movements by exact amount + delivery within ±3 min, stamping viaLn + the payment hash so a receipt can never claim a second row. History row and detail view show ⚡ for viaLn receives; the tag rides the sync snapshot to other devices via merge enrichment. viaClink deliveries need none of this — the wallet's own LN-receive flow already tags itself. Best-effort by design: an amount+time collision only mislabels an icon Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
* The registrar grows a webhook API — the coinos.io-style merchant notify, ↵Adam Soltys2026-09-031-0/+166
| | | | | | | self-custodial edition: a name's owner registers an https URL (NIP-98, owner or manager key) and every Lightning settlement for that name POSTs {type, address, amount, hash, preimage, memo, secret} there, firing on settlement independent of the ark delivery. URLs are vetted hard (https only, no credentials, every resolved address must be public unicast — RFC1918/CGNAT/loopback/link-local refused, re-checked before every delivery), retries back off 30s/5m/30m from a persisted queue, and GET /webhook shows the config plus the last delivery's outcome. Proven live: a throwaway name, a 21-sat Lightning payment, one webhook delivered Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
* The tester with 233 sats gets to spend them: invoice coverage judges the SUM ↵Adam Soltys2026-09-021-0/+33
| | | | | | | of spendable coins (the single-coin gate silently declined anything over the largest coin, though multi-input pays gather 24), an uncoverable invoice now owns its paste — board the shortfall from Savings, or say what's short — instead of dropping the bolt11 into the address field like a dead click, and chain calls gain a last-resort relay through the registrar (/esplora passthrough, tip cached) for the network that blackholes every public esplora Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
* A hard hat for the crew that builds this with us: an operator-giftable ↵Adam Soltys2026-08-311-3/+28
| | | | | | | construction hat joins the catalog (never listed for sale — like the crown it appears only in a rack that holds it), the registrar grows POST /hats/grant behind the admin token (hex or npub, crown excluded), and a gifted hat settles into the rack instead of knocking a paid hat off a bare-headed recipient wears it at once Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
* Google accounts can speak: the DM seal signs with the present for remote ↵Adam Soltys2026-08-301-4/+10
| | | | | | | signers (the pomegranate FROST operators refuse backdated events, and NIP-59's tweak on the seal protects nothing — only the recipient ever sees that layer; the public-facing wrap keeps its tweak under our own ephemeral key), and the registrar welcomes each PERSON once instead of once per key — the Google flow's two claims (wallet key, then real npub with the wallet as manager) were earning the same inbox two identical greetings Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
* The registrar learns who a migrated name belongs to: coinos.io's migrate ↵Adam Soltys2026-08-301-1/+38
| | | | | | | action — running with the old account's authenticated session, which IS the ownership proof — posts a migrate-grant (Bearer migrateToken) naming the v3 destination, and the claim guard honors that grant where the identity-only check (old account's npub must sign the claim) could never pass for a v3 wallet key; without it every migrated claim 409'd forever and the wizard spun on 'Claiming…' Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
* Staging gets the mainnet fee model end to end: /lnquote?network=mutinynet ↵Adam Soltys2026-08-291-12/+16
| | | | | | | quotes from the staging ASP's own CLN (helpers take their backend), the client asks it by default on mutinynet, and the quote URL concat survives a query string Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019WboeoetMF3MTmgT7Ew8yi
* The wallet learns to read BOLT 12 for itself: offers and invoices decode ↵Adam Soltys2026-08-291-8/+49
| | | | | | | client-side, and every invoice the ASP fetches over onion messages is verified here — payment hash read from the raw TLVs, offer terms mirrored byte-for-byte, the issuer's schnorr signature checked against LDK's exact merkle construction (proven against a live CLN-signed fixture) — so no server can hand back an invoice whose preimage it already holds. Paste an lno1 or resolve a name whose record carries one and the existing HTLC pay flow carries it (captaind's Invoice enum takes lni strings natively); a name's owner may now publish their OWN node's offer in their DNS record, retiring the registrar's stand-in — senders fetch invoices straight from their node and no coinos service ever touches the money. The /lnquote fallback prices blinded paths by entry node + advertised payinfo Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019WboeoetMF3MTmgT7Ew8yi
* An address can point home: a name's owner may register their own CLINK offer ↵Adam Soltys2026-08-291-25/+79
| | | | | | | code and the registrar asks THEIR node for invoices — delivered there first, float as fallback, and no invoice is relayed or paid unless it demands exactly the sats owed on the right network. hal learns to pay pasted noffer1 codes through the zap flow (fixed, variable and payer-chosen pricing, amount verified before the HTLC locks). The depth advisory slims to one line — an uncooperative exit's price and a Manage link — and the new coins screen shows each vtxo's amount, expiry and arkoor depth beside what renewal costs and buys Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019WboeoetMF3MTmgT7Ew8yi
* A name the registrar no longer grants is a costume: the wallet verifies its ↵Adam Soltys2026-08-281-1/+1
| | | | | | | cached name against the record's owner and manager keys each refresh, shedding stale ones (an evicted squat once lingered in the squatter's UI) — the /name endpoint now names the manager too Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
* A name's proof is its key, not a flag: takenByCoinosUser stops trusting ↵Adam Soltys2026-08-281-5/+8
| | | | | | | `migrated` (which let poppy get squatted) — an existing coinos.io name yields only to a claim signed by that account's own nostr key; the squatted record, its DNS entry and its offer are evicted Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
* The chosen name outranks the placeholder everywhere: a claim can no longer ↵Adam Soltys2026-08-271-1/+7
| | | | | | | release a custom name to make room for an npub default (the race that deleted passkeyguy), sign-in asks the registrar about the login identity before reaching for a placeholder, and the registrar answers /pubkey with the name the user picked rather than whichever record is younger Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
* Dead coins stop travelling: an expired vtxo leaves the balance and the coin ↵Adam Soltys2026-08-241-0/+26
| | | | | | | picker (sub-dust IOUs excepted), a shortfall names the dead weight it can't spend, and the names float renews any coin a day ahead of the reaper — a 100k forward left home on an expired coin and the recipient rightly refused it at the door Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
* The float sips instead of gulping: top-ups arrive in pool-sized chunks that ↵Adam Soltys2026-08-181-2/+5
| | | | | | | accumulate to the target, sparing the ask that dies whole on a thin vtxo pool Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_012u4oe1KPx9faCsDBLfZYqi
* The float keeps itself fed: below low water it loops sats off the CLN ↵Adam Soltys2026-08-181-4/+106
| | | | | | | through a neighbourly circular route all by itself, the sync heartbeat drives whatever's mid-flight every minute, and an operator can board on-chain reserves in through two admin calls Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_012u4oe1KPx9faCsDBLfZYqi
* The party hat leaves the party: gone from catalog and price list alike — ↵Adam Soltys2026-08-181-1/+1
| | | | | | | heads that bought one on staging simply go bare Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
* A wallet keeps one name per domain, not one name total: staging and mainnet ↵Adam Soltys2026-08-181-1/+4
| | | | | | | claims stop clobbering each other, the registrar answers who-am-I per domain, and a custom name claimed on one device replaces the npub placeholder on every other Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
* Staging LNURL declines what it cannot deliver: only the recipient wallet ↵Adam Soltys2026-08-171-0/+5
| | | | | | | mints for @staging names — our mainnet node will not take real sats it can only strand Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
* Staging gets a hat economy of its own: mutinynet mints on its own CLN into ↵Adam Soltys2026-08-171-25/+39
| | | | | | | its own registry, play sats never buy mainnet flex — plus the toque earns its Canadian name, the wizard takes the throne at 2.1M, the crown leaves the menu, and every hat sits a little higher and straighter Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
* Hats: put your money where your head is — supporter hats perch above the ↵Adam Soltys2026-08-161-0/+136
| | | | | | | avatar everywhere it appears, from 21-sat beanie to 2.1M-sat top hat; the crown stays on the founder Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
* Every name learns to vouch for its keeper: the registrar answers nostr.json, ↵Adam Soltys2026-08-151-0/+11
| | | | | | | so [email protected] is a NIP-05 too Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
* Welcome DMs stop echoing: sent-copies thread under their recipient whichever ↵Adam Soltys2026-08-151-3/+4
| | | | | | | identity authored them, the registrar keeps no sender copy at all, and the old self-thread residue sweeps itself Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
* A claim with an ark address that doesn't decode is refused at the door — a ↵Adam Soltys2026-08-151-0/+9
| | | | | | | corrupt one recorded is a payment black hole Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
* A failed forward retry says why — the goyslop 190k spent a day failing in ↵Adam Soltys2026-08-151-1/+2
| | | | | | | a bare catch Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
* An invoice's name mapping lives as long as the invoice can settle, and a ↵Adam Soltys2026-08-151-2/+13
| | | | | | | nameless settle leaves a trace — one paid 1000 sats vanished into a silent continue behind a 1-hour sweep Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv