| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
| |
The pencil opens a dedicated screen — no balances, no tabs — wired into
the history stack like the other sub-pages.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
| |
The avatar img was recreated on every render — boot's render bursts made
it flash; there is exactly one header avatar, so the node is reused until
the profile actually changes.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
| |
Anyone still on the npub-shaped default sees their address here, not in
the collapsed corner of Settings where the claim form lived.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
The registrar now lets a migrated coinos user's nostr identity (re)take
its own name — migration could land the claim in whatever wallet ran it,
stranding the name there. The claim form signs with the (re)attached
login identity when there is one; the wallet key alone could never prove
the takeover.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
Signing in mid-wizard with a key whose wallet was restored left you on
the sign-in step: the back-button hold matched the restored account and
blocked the auto-advance. A login now clears the hold explicitly — and a
restored wallet skips the rest of onboarding entirely; it was already
onboarded wherever it came from.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Signing in with a key whose wallet backup exists on relays could still
land in 'create a new wallet' when the lookup failed (relays unreachable,
signer decrypt denied) — and confirming would have replaced the real
backup on any relay the new one reached. Absence is now only believed
when a relay actually answered; decrypt failures surface as errors; and
the create path takes one last look and adopts a backup that surfaces
rather than clobbering it.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
Back from username (and sign-in) holds the auto-advance for the wallet
you backed away from, so welcome doesn't bounce you straight forward;
Get started then continues with the already-minted wallet instead of
minting another.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The recipient candidate list was hiding under the on-screen keyboard:
scroll the field to the top on focus and when fresh candidates land,
give the list scroll room to get there, and let the keyboard resize the
viewport (interactive-widget) so the scroll has somewhere to go.
The wizard now shows whenever the device has no wallet — the one-time
onboarded flag is gone; deleting every wallet brings the wizard back.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
The wizard mints the wallet on its first step, so 'an account exists'
stopped meaning 'wizard done' — reloading dropped you into the half-set-up
wallet. Persist the current step until the wizard finishes.
Also trims the balance coach-mark copy.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
A background repaint rebuilt the strip at scrollLeft 0 mid-swipe; render()
now carries scroll positions across the swap the same way it carries focus.
The onboarding column also sized itself to the strip's intrinsic width
(auto margins defeat flex stretch), overflowing phones below ~450px.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Paste, on the import and load-seed screens, was a bordered box floating
beside a small label — heavier than the label, detached from the field it
fills. It now sits inside the textarea, and only while that textarea is
empty: the only time it's wanted, and the only time it can't cover what
you typed. It's toggled on the node rather than through render(), since
re-rendering a textarea per keystroke rebuilds it under the caret. Beside
a one-line input (Send) the old placement was right and is untouched.
The footer measured 100dvh, which on a phone can resolve to the tall
viewport at first paint and leave the language picker just below the
fold. svh is the one that fits with the address bar showing. Short
screens also tighten their padding, which buys back the ~50px the
create/import screen was overflowing at 375x553.
And the wizard no longer asks every new user whether they have an old
coinos.io account before letting them have a name. Claiming the name is
the step; the people who do have an old account know it, and say so with
a link. That screen is a statement now, not a question they just
answered. The npub-shaped default address is no longer offered as a
button — a plain skip goes past without showing anyone that.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
| |
Same construction as the sign-in button on the unlock screen — .btn-block
forces display:block, so the flex centering lives on an inner wrapper
rather than the button.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The sign-in screen stacked 'Connect a signer app' directly above a
bunker/nsec field, which reads as two steps rather than two ways in.
A divider says which it is.
The wizard's second step asked whether you have a nostr account, then
sent you to a screen that asks the same thing. Step one now offers both
paths directly — Get started, or sign in with Nostr — and the middle
step is gone, along with its strings. The welcome blurb goes too: the
screen is one decision, and prose above it is something to read before
you can make it.
The footer sinks to the bottom of the window rather than trailing the
content up the page. #app is a full-height column now; the chat card
sizes itself against the viewport, so the layout test covers it at
three sizes.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Locking with no password locks nothing — the wallets sit on the device
under an empty one and reopen with a tap. So the first deliberate lock
now asks whether to set one, explaining plainly what happens if you
don't. 'Not now' is a real answer, recorded, and never asked again: a
wallet that nags is a wallet people stop reading.
The offer rides the deliberate lock only. lock() is also where the idle
timer, the last-wallet-removed path and boot-after-expiry land, and a
password form appearing because you went to lunch is a different app
than the one you left.
Two subtleties worth naming: the offer is set after lock()'s ui reset
block, which clears ui.pw and had been swallowing it; and taking the
offer re-enters lock(), which now finds a password and lands on the
unlock screen instead of the wallet list.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
'Logout' promises a return to a fresh app with nothing of yours left on
it. This closes the open wallet and keeps everything saved, which is why
it read as interchangeable with 'Clear all' — the one that really does
send you back to the beginning.
Renamed via a new key rather than rewording the old one: nineteen locale
tables carry their own word for 'Logout' and t() prefers the locale's
value, so reusing the key would have kept the wrong meaning in every
language but English. The dead key is dropped from those files; they
fall back to English until translated.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wallets save themselves to this device as soon as you open one, encrypted
under an empty password unless you choose one. Logging out still sent
you to 'Unlock saved wallets — enter your password', which asks for
something that doesn't exist and makes logout look like it did something
drastic. It didn't: logout only drops the keys from memory, and 'Clear
all' is the one that deletes.
With no password, logout now returns to the wallet list — honest, since
nothing is protecting those wallets and a blank prompt protects nothing.
With a password set it prompts exactly as before.
Fixed underneath: mergeVaultList derived the comparison xpub with
accountXpubFor's mainnet default, so on any other network it never
matched the stored one and every unlock re-added the same wallet as a
fresh entry — visible as the same wallet listed twice, once watch-only.
The seed-mismatch checks in 'load recovery phrase' had the same default
and would have rejected the correct seed on testnet.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It looked like the dot was flickering on and off after a refresh. It
wasn't: measured over the first twelve seconds it appeared once and never
went away, while its entrance animation started seven separate times.
render() rebuilds the whole DOM, so the pop replayed on every repaint.
A dot that means 'someone is waiting' has nothing to animate about, so
the animation is gone rather than gated. tools/unread-dot-test.js counts
animation starts against real appear/disappear transitions, so a future
entrance effect here fails instead of shipping as a flicker.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The message log had a fixed 62vh height, so the card was head + panels +
log + composer tall and the input fell off the bottom of the screen. The
card is now sized to the viewport and the log is the only part that
flexes: opening the invite or member panel shrinks the scroll area
instead of pushing the composer out of reach.
Three header changes, all the same idea — don't show a control for a
choice nobody is making:
'+' becomes 'Add person', because a plus sign doesn't say what it adds.
A lone channel isn't named at all. '#general' next to a composer that
says 'Message #general' points at a choice of one; several channels
become a select, which is what a choice looks like.
The new-channel field hides behind a 'New channel' button. Sitting open
right after you create a community, it reads as something you're
supposed to fill in.
tools/chat-layout-test.js holds the line at three viewport sizes with
both panels open, and covers the header behaviour through actually
adding a second channel.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
| |
A dark pill floating at the bottom of the screen reads as a stray button
under the footer, and it was saying something the page already showed:
the badge flips to connected and the reconnect controls disappear.
Failures still surface — those go in the card, where the problem is.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The app is inlined in the page, so when a new service worker took
control the page reloaded — otherwise it would keep running the old
build. But navigations are network-first: the refresh that triggered
the update had already fetched the new page, so the reload landed a
second or two later as an unasked-for second refresh.
The page and the worker now carry the same build token and the page
asks which build took over, reloading only on a real mismatch. The
token is hashed before substitution, since a page cannot contain a
hash of itself.
tools/sw-reload-test.js pins all three cases against a swappable
server: a first visit doesn't reload itself, a refresh after a deploy
is the only refresh, and a page left sitting open across a deploy is
still reloaded — exactly once. The previous build takes two loads for
one manual refresh; this one takes one.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The app could tell you your signer wasn't connected and then send you
somewhere with nothing to click: once an account was linked, the nostr
card showed only an npub. It now shows connected/not connected, says
what's missing, and offers the same signer options as signing in —
refusing a different account rather than quietly swapping identities,
since this is a reconnect and not a login.
Pasted keys go back to not being persisted at all. Storing one would
have survived a reload, but the UI promises a pasted key is used once
and never kept, and that promise is worth more than saving a paste;
those logins reconnect from this card like any other.
The chat banner now tracks the live signer alone. The flag that
suppressed it after a reconnect would also have hidden a later genuine
disconnect.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
| |
A NIP-46 connection can die quietly, leaving the app with a signer
object that will never reply — and since it's still the cached live
signer, every send after that fails the same way until the page is
reloaded. Wrap a remote signer so the first failed call drops it,
letting the next attempt resume a fresh connection instead.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
A remote signer dropped by a reload now says so above the composer, with
a button that reconnects in place — rather than letting someone write a
message and only then be told it can't be sent as them. Failing that it
opens the nostr settings, where logging in again is the fallback.
Every remote-signer login made before sessions were persisted lands in
exactly this state once.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Logging in with a remote signer and reloading left the app showing your
avatar and profile while signing everything with the wallet's own key —
so chat messages arrived under a different npub with a stranger's punk
on them. identity() had a fallback: when the login signer wasn't
available it quietly used the wallet key instead. That fallback is gone.
If you logged in as a nostr account, the app speaks as that account or
it refuses and says so.
Refusing is only reasonable if the signer usually comes back, so a login
now persists what it takes to be that identity again. A remote signer
stores its NIP-46 client key and pointer — the signer authorised that
client key, not one page load, so rebuilding from it resumes the session
without prompting. A pasted key stores the key, which is already the
seed of everything here since the wallet's mnemonic derives from it.
Resume is single-flight with a pause after failure, because identity()
is asked on every send and a signer that isn't answering must not mean a
relay connection per keystroke.
Existing remote-signer logins predate the stored session, so they need
one more sign-in to become resumable.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A NIP-17 wrap is signed by a throwaway key with the sender sealed under
two layers of nip44, so no server can filter DMs by who sent them. The
notifier now ships the wrap inside the push payload and the service
worker opens it locally: a message from someone you follow arrives with
their name on it, a stranger's is dropped, and your own sent-copy — every
DM is wrapped to the sender too — no longer notifies you about what you
just typed.
That needs the nostr identity key in the worker's IndexedDB, which
dm-inbox.js states plainly: for a seed-derived identity it is a second
copy of a key localStorage's seed already yields, and it exists only to
keep strangers out. A remote signer never hands its key over, so those
wallets store no secret and keep getting unfiltered notifications rather
than silence.
Silence is always the riskier failure here, so the rule leans the other
way whenever it isn't sure: a wrap we can't open notifies, an account
with no contact list published notifies (otherwise a new user's welcome
message would vanish), and anyone you already have a thread with counts
as known whether or not you follow them. The server-side DM cooldown
drops to a second — with the device discarding pushes, a throttle there
would let a discarded one swallow the message behind it.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The header carries a message button again, left of the wallet selector,
with a red dot when a conversation is waiting. Unread is a per-thread
watermark on the newest message from someone else, kept in the rumor's
own created_at so it means the same thing on every device it syncs to.
Rooms subscribe at startup now, or the dot could not speak for a
community nobody was listening to.
Communities no longer buzz a phone by default: push registration only
carries the stream keys of communities you have opted in, per community,
from a bell in the room header. DMs and payments are unchanged.
Presence and typing ride the channel stream as 21059 wraps, so who is
around stays inside the community's encryption rather than becoming a
public status. Measured against relay.coinos.io and nos.lol, neither
actually drops NIP-01 ephemeral kinds, so beats carry a NIP-40
expiration and relay.coinos.io sweeps kind 21059 hourly — and presence
is dated by the beat, never by arrival, or a replayed beat would light
up the whole member list.
The member list follows Telegram: online, then last seen in minutes and
hours, then a vague 'recently' rather than advertising how long someone
has been gone.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
giftRecords() caches the parsed blob on the wallet object, but the app
runs a single Wallet for its lifetime and load() never dropped that
cache. Switching wallets carried the old wallet's gift links into the
new one, where they all rendered as claimed — none of their outpoints
are live in a wallet that never issued them — and the first save wrote
them back under the new wallet's key.
Clear the cache on load alongside the other two gift caches, and forget
records whose funding tx isn't in this wallet's own history, to clean up
what earlier builds already misfiled.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
| |
Editing it here reads like renaming your coinos account, and for someone
using an address from elsewhere it invites breaking their own zaps. The
field is gone; an existing address is preserved untouched, and one is
filled in from the coinos payment address only when the profile has
none, so other clients can still zap them.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Importing a seed on a second device replayed "Payment received!" for a
payment that had arrived on the first one. The two-hour recency guard
couldn't catch it: a movement is stamped with the moment THIS device
discovered it, so on a fresh device the entire history looks like it
just landed — a week-old payment would have celebrated too.
A wallet whose ark state didn't exist on this device now treats its
first catch-up as history and acknowledges it, so only what turns up
afterwards is news. Reopening an existing wallet is unaffected, and a
payment that lands while you're watching still celebrates.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The service worker can't watch a relay, so it doesn't try: the app
resolves the destination to something concrete (ark address, LNURL
endpoint, or on-chain script) and mirrors it beside the keys the
background NWC payer already uses. On a push wake-up — which is exactly
when money has just landed — the worker re-checks the same gate and
sends, writing the outcome back into the mirror for the app to absorb on
next open. A partial on-chain forward still waits for the app, since
carving an exact vtxo needs more round trips than a worker is promised.
writeBgMirror now carries forward the NWC connections and offer when
another caller refreshes the mirror, instead of blanking them.
And onboarding's legacy step loses its Back: the wallet exists by then,
so returning to the nostr question just bounced straight forward again
and the link looked broken. Its copy no longer promises a rename either.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
| |
The placeholder repeated a minimum the line below already states, and it
was clipped anyway — the amount field had 14px of usable width at 360px
because "Move to Spending" crushed it. The row wraps to two full-width
lines when it's tight and stays on one line when there's room.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Settings → Payments takes a destination, a threshold, and an optional
amount to keep behind. When Spending crosses the threshold the wallet
sends the rest on by itself, resolving the destination the same way the
send form does — an ark address goes native and free, a payment name
prefers its ark instruction before falling back to lightning, an npub
tries its ark advert then its lightning address, and an on-chain
address becomes a cooperative offboard (carving out an exact-amount
vtxo first when it isn't sending everything, since offboards move whole
vtxos).
Money moving without a human watching deserves guardrails: one transfer
at a time, never while another ark action is in flight, a fifteen-minute
backoff after a failure with the reason kept for the card, destinations
validated before it can be switched on, and dust amounts skipped.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A seed that only lives in this tab is one refresh from gone, and that
surprise costs people money — so a wallet now saves itself to the device
when it's opened or committed, no button required. No password is set
(Settings still offers one), and a locked existing vault is left to the
manual Save button since writing it needs their password.
The recovery card gains a middle step: the first click opens the grid
with the words masked — the warning and the shape of what's coming are
on screen before anything readable is — and a second click shows them.
Copy only appears once they're visible.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
| |
"Instant · free to send" and "On-chain · mining fees apply" were one
line that swapped with the account; the card is just the balance now.
Strings, styles and stale translations removed with it, and the face's
reserved height comes down to match.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
| |
Opening it hides the payment address and its QR — two payment codes on
one screen is a good way to have someone scan the wrong one. "Hide"
becomes "Back", which is what it now does.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
| |
The dots were an indicator pressed into service as a control — fine
under a thumb that can just swipe, too small for a mouse. They're
replaced by a pill in the header row naming the account it takes you to
(⇄ Savings / ⇄ Spending), which is both a proper click target and a
clearer answer to "what's the other one?". Swiping the card still works.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
| |
takenByCoinosUser now reads the account it finds: a live one still
blocks the name, but one flagged migrated has handed receiving over, so
v3 may claim it.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
| |
The step needed this wallet's payment address for the migrate link, and
the background claim often hasn't landed yet when the step appears — so
it flashed a spinner first. The page renders complete now; if someone
taps before the address exists, the wait happens on the button instead.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Between "do you have a nostr account" and claiming a username, new users
are asked whether they already have an account on the original coinos.
Yes hands off to coinos.io/migrate with their fresh v3 payment address
and a return URL — they're already signed in there, so no password or
key ever travels. That page sweeps the balance over Lightning and
renames the old account, releasing the username.
Coming back, coinos.io returns ?migrated=<username>; v3 claims that name
on the registrar (retrying for a minute, since the registrar's
"is this a legacy user?" guard caches), and their lightning address now
resolves to the v3 wallet.
The legacy page ships in coinos-ui and is NOT deployed yet.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The inline-progress attempt still read as a flash — the send form was
visible behind it with the raw npub, its verification block and the
gift button, then all of that was replaced. Now both resolution phases
(ark advert, then lightning) render the SHAPE of the destination card:
same title, same recipient chip, a spinner where the amount form will
be, and a working Back. The card fills in instead of the screen
changing twice, and the two flows share one title so it never
re-titles at the handoff.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
|