| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The server prices a renewal on all the coins together: ppm accumulates
sub-satoshi across every input and rounds up once. The per-coin chip
rounded each coin's share up on its own, so nine 1-sat coins each showed
"renewal cost 1 sat" under a total of 4 sats — as if the page were
skipping them. The chip now shows the coin's real share: "under 1 sat"
for a sub-satoshi one, rounded otherwise, and its tooltip says how the
fee is priced.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JuwQqNWtDJcxPWtEm9134z
|
| |
|
|
|
|
|
|
|
| |
Every feature balance line landed on the Spending face, but a gift's
locked reservation is on-chain money still sitting in Savings. Lines now
say which side they belong to and draw on that card: gifts on Savings
beside pending incoming, ark's Moving… on Spending as before.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Under the Spending balance, warnings stacked up as separate boxes — two
red cards and a grey line, with three Manage links between them, all
pointing at the same page. They are one card now: red if anything in it
is a warning, plain otherwise, each notice on its own line, and a single
Manage at the bottom right. A lone quiet advisory (the exit-cost line most
wallets show) keeps its centred grey line.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The wallet used to add two to four seconds of its own around a Lightning
send: a random pause plus a relay look-back before paying, and a
two-second poll for the result after. The notifier's claim now decides
who pays in one round trip, with the relay look-back kept only for
replays and for when the notifier gives no verdict; a phone answering
from behind another app waits a second so a desktop tab wins the claim
instead of paying at a throttled crawl. After the send, one held
CheckLightningPayment call brings the preimage the moment CLN has it —
for wallet-connect pays, the background worker, and the app's own Send.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Every open tab of the same wallet sees every wallet-connect request. Two
hidden tabs on one laptop both tried to pay the same zap: the ASP refused
the second with "payment already in progress", and that error reached
Amethyst half a second before the first tab's preimage. A Web Lock per
request now lets one tab (or the worker) answer while the rest stay
quiet, and a device that does meet "already in progress" waits for the
sibling payment's outcome — relaying its preimage only if the payer never
speaks — instead of shouting a failure over sats that went through. The
losing side also stops writing a failed row into history for it.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Every coin expires, and until now the only thing standing between a
balance and its expiry was maybeAutoRefresh: it renews when the wallet is
opened inside the last 96 blocks, roughly sixteen hours. Bark's own
developers say the same premise fails on mobile — people don't reliably
open a wallet at the right hour, which is why every mobile Ark client
they know of has moved to delegated refreshes and why they are building
server-driven renewal.
captaind already has it, and ark.coinos.io has been carrying the column
unused: SubmitRoundParticipation takes a scheduled_height, and the server
holds that participation out of every round until the height arrives,
then runs it with nobody online — the round tree branch is signed by the
server, which is the whole point of a delegated refresh. The fee is
priced at the height it will run at, so a standing order lands in the
free bracket rather than today's.
So each spendable coin now gets one registered 36 blocks before its
expiry, six hourly rounds of slack. It is deliberately not an action:
the coin stays spendable, the wallet never reads as busy, and spending it
simply kills the order — the server drops a participation whose input is
gone, and _driveScheduled drops ours. The claim comes later, whenever the
wallet next opens: the mailbox breadcrumb we already post wakes it, and
the leaf cosign and forfeit are the ordinary refresh path from there.
Nothing about the input's expiry blocks that claim, which is what makes
this worth having. A wallet that goes quiet for a month comes back to a
coin already renewed and anchored in a fresh tree, instead of one the ASP
has swept and would have to honor out of goodwill.
One cycle per visit is all it can buy — the replacement's id doesn't
exist yet, so its own backstop waits for the next time the app is opened.
tools/ark/scheduled-refresh-test.js covers the five behaviours on
regtest: the server holds the order until its height, runs it while the
wallet is closed, the wallet claims on return, a spend voids the order,
and a claim still works after the input has EXPIRED (the last one mines a
coin's whole lifetime, so it also re-refreshes the funding wallet first —
an expired vtxo can be renewed but not sent).
Riding along: the expired-coin notice that was already sitting in the
working tree, and manager-test's tampered-vtxo check, which had been
reading base64 vtxo bytes as hex since they moved to IndexedDB.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019fMdLypdg5JaU7bdeUFF8v
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The balance read "US$74.67 USD" — the symbol and the unit tag saying the same
thing twice. Amounts now format bare, like sats and BTC do: whatever labels
the number says which money it is. The currency symbol stays where a number
stands alone in prose, which is the "Worth then" line and nowhere else.
The '~' marking a payment older than any price we sampled is gone too. It was
bookkeeping the beta doesn't need: a payment we have a price for is shown at
that price, one we don't is shown at today's, and nobody has to learn a
squiggle.
The currency picker has moved to sit beside the language picker at the foot
of the page — display preferences together, where they're findable. It spent
one day under Settings → Network, where it wasn't.
And a bug this feature exposed rather than caused: nine notices end in the
word "sats" in every language we ship, and were being handed the display
unit. "Uncooperative exit costs about US$2.03 sats" — and long before fiat,
"about 0.00435397 sats" for anyone in BTC. They're given sats now, which is
what they claim to be showing.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A payment is worth what it was worth WHEN IT HAPPENED, and that number is
gone by the time you look at it unless someone wrote it down. So every price
the app fetches is kept as a sample — one an hour, a few months back — and a
payment's fiat value is read off the sample nearest its own timestamp. The
history rows and both detail pages (on-chain and Spending) pass the time the
money moved; balances and forms use the live price, as they should.
A payment older than any sample we hold is priced at today's number and says
so with a '~', because that is a different claim and shouldn't look like the
same one. The detail page spells it out: "Worth then $X · $Y now".
Fiat is a third position on the unit toggle rather than a second number
beside the first: sats → BTC → your money → sats. One figure, and which
figure is your choice. The ring skips fiat entirely until a price has been
fetched — a third position showing blanks is worse than two that work. Typing
an amount with the unit on USD means dollars, priced now.
The rates are coinos' own endpoint, a map of every currency it knows, so
there's no third party watching what the wallet asks about; the currency
picker under Settings → Network lists all of them. Changing it starts the
recorded history again rather than relabelling samples taken in another
currency.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Spending balance and its history are read from the ark store, which is
IndexedDB: synchronous to read, asynchronous to OPEN. Boot didn't wait for
it, so every refresh painted a Spending wallet with nothing in it — no
balance, no history — and filled it in a beat later. On a phone that second
paint arrived as a change rather than an arrival: the balance counted itself
up from 0 in green, wearing the animation a received payment gets.
Boot now waits for the store (capped at 800ms — a store that won't open must
not hold the app hostage), and the shell stays up a moment longer instead of
a wrong balance going up. If the store does land past the cap, initArk
retries on it — so a Spending wallet whose state arrived late also connects,
which it previously didn't until something else happened to kick it — and
that catch-up paint forgets the last amounts first, so it reads as state
arriving rather than money.
Also: the zap tally chip loses its underline. In chat the chip is a reaction
chip too, and .chat-react.on still rings it; on a post row the underline just
read as an artifact.
tools/boot-balance-test.js pins the ordering, with IndexedDB slowed so it
can't pass by luck.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A zap took a few seconds to pay and its public receipt trailed that by
seconds more, so the tally chip appeared long after the tap — the tap looked
ignored, and the only way to tell it had worked was the toast.
Now the chip appears on the tap carrying your amount, breathing while the
payment is in flight; it goes solid the moment the payment lands, and steps
aside when the real receipt arrives (which is also how it avoids counting
your zap twice). The ark and Lightning one-tap flows report their outcome
back — a failure, or a fallback into the form, takes the chip straight off
again rather than leaving it pulsing. An unreported zap gives up after 45s.
A zap sent from the form reports too, so the tally shows it right away
instead of waiting on a relay. Reduced-motion gets a dimmed chip, no pulse.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Two accounts could show the same name and avatar: the identity list read a
key stamped onto the account record, and the stamp was taken during the gap
in a wallet switch where the new account is already loaded and saved but the
features haven't re-inited — so the PREVIOUS account's signer was still
answering "who are you". The live signer now re-checks on every read that it
still belongs to the open wallet, not just at init(); and the switcher reads
each account's own persisted login (or its seed's nostr key) instead of the
stamped mirror, so a record stamped wrong before this still lists right.
The Spending renewal warning belonged to the wallet that computed it and
stayed on screen after switching — the old wallet's amount and deadline over
the new wallet's balance, with a 30-minute throttle keeping it there. It now
resets with the ark manager, and the next connect re-decides.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
localStorage held a deep wallet's ark state as ~700KB of JSON (UTF-16 on
disk), parsed on every boot and stringified on every save, and the wallet
cache blob carried a second ~600KB copy. src/ark/store.js keeps the state
in IndexedDB (db coinos-ark) with each coin's signed bytes as a Uint8Array,
fronted by an in-memory map so loadArkState/saveArkState stay synchronous:
reads return clones, writes coalesce (200ms) and flush immediately when the
page hides. Existing localStorage copies migrate on first open (newest _rev
wins) and are removed only after the IndexedDB write completed; no
IndexedDB means localStorage exactly as before. Records keep their
btc-wallet-cache:<id>:ark… keys, and a wallet wipe clears both stores via
the new per-feature wipeCache hook.
The ark cache extension is now syncOnly: it still rides the sync snapshot
(and the Blossom blob) but the local wallet cache no longer embeds it —
measured on a live wallet the cache blob went from 655KB to 10KB.
Verified in the live tab: all wallets migrated, bytes raw on disk, balance
and coin set unchanged, localStorage ark keys gone. tools/ark-store-test.js
covers migration by _rev, clone-on-read, write-behind, wipe and fallback.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Nw1Dijik1tLVKRM1WkU7xE
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
read, hex still on the wire.
The live coins' signed bytes are most of a deep wallet's state — 560KB of
hex, which localStorage then holds as UTF-16. vtxoBytesToStr/FromStr in
proto.js persist base64 and read either form, _addVtxo writes base64, and
pruneArkState converts hex to base64 on every save, so an existing state
migrates itself the first time it saves. Measured on a live deep wallet:
904KB → 665KB (-26%), all 41 coins decoding identically.
The sync wire (slimArkForSync) keeps sending hex for now: a device still
on an older build would otherwise fail to decode every coin merged from a
newer one. Flip it once pre-2026-09-10 builds are gone.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Nw1Dijik1tLVKRM1WkU7xE
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
on load.
The exit-depth advisory rebuilt every spendable coin's exit chain to learn
its fee, and each hop's input taproot key ran a musig key aggregation
(several secp256k1 multiplies on uncached points). With 27 coins of depth
up to 86 (1685 hops) that was ~5.3s of solid main-thread work on every
boot, laptop and phone alike — requestIdleCallback only delayed it, and
the Android wrapper hits a full boot whenever the OS evicts the app, so
"reopening the app" froze for seconds.
A fee only needs vsizes, and a taproot output script is 34 bytes whatever
key it holds: vtxoTransactions/transitionInputTxout gain a sizeOnly mode
with stand-in keys, exit.js exposes exitTxVsizes (same chain checks, no
EC, nothing broadcastable), and the advisory + coins page use it. Verified
against the real signed chain on the live coin set: identical vsizes on
all 27 coins, 9s → 26ms.
Also: the sync-slot replay at boot merged the ark snapshot and rewrote
~1MB of state (plus re-adopting it into the manager) twice per boot even
when the union brought nothing. Compare the serialized union to what's
stored and skip the write/adopt when unchanged.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Nw1Dijik1tLVKRM1WkU7xE
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
balance (authored by codex).
Root cause of the "signed in and my balance is 0 with a huge Sent I never made": a device's snapshot carrying its change/new coins never reached the relay. The publish was a setTimeout debounce that got canceled on page-hide / logout / feature stop, so coins created by another session were never synced; a fresh device then loaded only the old (now-spent) coins, and reconcile dressed the spent inputs as a definitive "Sent" row and zeroed the balance. No funds ever moved — verified on the ASP that no such payment existed and the change coin was still spendable.
Fix (codex):
- src/sync-outbox.js (new): a durable outbox. Snapshots are signed synchronously at save time under the current identity (no cross-account mixing) and persisted already-encrypted to localStorage (no keys/plaintext in storage). Delivery retries with backoff and wakes on online/pageshow/visibilitychange/storage, surviving suspension, logout and relay outages. The last copy doubles as a local recovery source if an account cache is cleared.
- sync.js: replace the cancel-on-stop debounced publish with the outbox; fetchAllStates also merges the outbox's own (possibly-unpublished) events so a rejected publish is still recoverable locally; forgetAll clears it.
- nostr.js: factor out stateEvent() (synchronous signing) and decodeStateEvents(), shared by fetch and the outbox.
- ark.js: adoptArkSnapshot() applies a synced snapshot to a LIVE connected manager without restarting payment ceremonies (a snapshot arriving while connected previously stayed invisible until reload); the pre-handshake hold-key merges instead of overwrites; and the reconcile row is reworded from a red "Sent -N" to a neutral "History incomplete / Payment details not synced" (↻) with an explainer, since a spent input proves neither an amount nor a date.
- app.js: clearAll also clears the outbox (forgetAll).
Tests (codex): sync-outbox-test, sync-browser-test (real Chrome: relay rejects a snapshot, browser closes, reopens and retries; a second browser recovers the balance + history without reload), sync-split-test, plus build and morph smoke — all green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
|
| |
|
|
|
|
|
|
|
| |
into Paid.
The armed auto-pay flow flashed a "Paying" title/spinner card that then swapped title, badge and footer for the "Paid" card — too much text change and layout shift for something that completes in a moment. Now the in-flight and success states are ONE structurally identical card (autopayCard): recipient name and amount sit in their final positions the whole time, and the step to Paid is just a class flip. The badge starts as a spinner ring (the ⚡ hidden) and, on success, settles into the green success check with a pop while the ⚡ fades in; the "tap to proceed" footer occupies reserved height so nothing jumps. No "Paying" wording at all — the badge carries the state. Respects prefers-reduced-motion. Manual (non-auto) pays keep their normal Paid screen.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
|
| |
|
|
|
|
|
|
|
| |
(1) The auto-pay opt-in on a fixed-amount merchant pay was a single checkbox that stored "up to the amount you just paid". Replaced with preset budget buttons — 1000 / 5000 / 10000 / 100000 sats — so you set the ceiling deliberately; the chosen amount is what's stored on a successful pay.
(2) An NFC tap into an already-armed auto-pay briefly flashed the review/confirm card (the "Getting a quote…" spinner) before advancing to pay. startArkLnPay now decides up front — from the invoice amount and the stored budget — whether it will auto-pay, and the view renders a centered paying screen straight away (matching the paid screen's layout so it morphs cleanly into it), never showing the review. You just see paying → paid.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
|
| |
|
|
|
|
|
| |
steps. (1) Terminology: a payment is a "zap" only when it targets a nostr person or note (npub / note-zap with an eventId, captured as z.social at begin); paying a lightning address, LNURL or merchant now says "Pay over Lightning" / "Pay" everywhere — amount screen, review title, success screen — even when the endpoint supports zap receipts. (2) A fixed-amount payment (min==max — a POS tag, paywall, bolt card) has nothing to type, so the amount screen is skipped and the flow goes straight to the quote/review; the two perceived confirmations collapse to one. (3) Per-recipient auto-pay budget: the review offers "Auto-pay <merchant> up to N next time" (ctx.lnBudget/setLnBudget in prefs, synced), and a fixed charge within a set budget pays as soon as the quote lands — no tap. Guarded: only fixed amounts, only within the budget, only when funds cover it; over budget / no funds / quote error all fall back to the normal review, and social zaps are untouched. Verified with a driven-feature harness (fake ctx + local LNURL server): fixed skips to startLnPay with social=false/fixedSat set, a covering budget sets autopay, variable still shows the amount screen titled/buttoned "Pay"
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
|
| |
|
|
|
|
|
| |
sats" (unit included) instead of "exit 3,688", the renewal price moved off the row's right edge into a chip like its siblings — "renewal cost 117 sats" (or "renewal cost free") — and the expiry chip carries a word beside its hourglass ("⏳ expiry 21d"). The depth chip is gone: hop count is implementation detail nobody needed to weigh, and the exit cost already prices its consequence. depthOf and the depth strings retired with it
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
|
| |
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
| |
rebuilding it costs ~60ms (sort + dedupe + gift resolve + secp256k1), and its 1.5s TTL meant an unhurried flick always hit a cold rebuild, stuttering the slide's tail — 'warms up if I keep going fast, cold if I pause, refresh reproduces' is the classic TTL-expiry signature. Now keyed on a state revision (_save bumps state._rev) so it's reused until the data actually changes and never re-cools between flicks. Diagnostics still on to confirm
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
unfolded on the balance card with no way to dismiss it short of completing or switching tabs. A centered Cancel link closes it back to the plain card
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
every spendable coin and built the exit txs (heavy secp256k1) synchronously on each render, and the cold first compute after a refresh landed right on the carousel drag. Now the render only reads the cached answer; the recompute runs in requestIdleCallback (keyed by coin set + feerate, so it fires only when something changed) and re-renders when done — the EC never competes with input
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
Every _save() — fired dozens of times during a boot reconcile — did a JSON.parse of stored state, a merge over every vtxo and movement, a JSON.stringify, a synchronous localStorage write, and saveCache(). A CPU profile of the first 9s pinned it: ~230ms in saveFeatureState/loadFeatureState/setItem bursts blocking the main thread, which delayed the mouse drag's scrollLeft writes (mouse drag is main-thread; touch scrolls on the compositor). The in-memory state is always current and every live read uses it, so the disk write is now coalesced — immediate when idle, one write ~200ms after a burst settles (800ms cap), flushed on page-hide and wallet switch so nothing is lost
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
back. On open, when Savings is empty and Ark has a balance, the wallet flips you to Spending — a convenience. But it fires on every Ark update and only latches once the balance SYNCS, which after a refresh arrives a second late — right after you've dragged to Savings, so it overrides your choice and slides back. Now any deliberate pick (carousel scroll/tap/flick, swipe, accounts screen) sets accountUserChosen, and the auto-select consumes its one-shot without flipping when you've already chosen
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
a small button in the grouped row with copy tx id / view explorer / copy address — one consistent size for every secondary copy action
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
secondary copy/view action (copy gift link, copy tx id, view on explorer, copy address) now rides one wrapping row at its natural width, rather than each stretching full-width and getting split apart by the block buttons between them. Revoke (now danger-styled) and Back keep the full width they deserve as primary actions
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
and exit each settle as a real bitcoin tx — txid, bc1q address, block explorer — so they wear the Bitcoin mark in the history row and detail header instead of the Ark logo; pure off-chain hops (receive/send/renew) keep the Ark mark, Lightning keeps its bolt
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
coin id — the folded row rides ui state (and nav history) since it isn't a stored movement. Ordinary send details also stop hiding their inputs: 'Coins spent' lists what a payment gathered (up to 24), beside the destination vtxo it minted
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
— an ordinary send row, because it was the user's own spend and nobody needs an alarm about which device made it. (The ASP's status API returns only a spent bit, so the shown time is when this wallet caught up)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
row is now a plain Sent wearing a quiet 'synced' tag, and tapping it unfolds the reassurance — the coins left your wallet in a session this device didn't see (another device, a restore that dropped history, or a server-side renewal), and the balance is correct; the row just keeps the history adding up
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
ASP's service charge (base + lifetime ppm) record separately and the history detail shows them on their own lines — settling the mystery of a ~350-sat chain fee inside a ~650-sat total. The community row's member count anchors to last session's settled figure instead of ticking upward through the guestbook replay, and a profile's Pay button reached from search actually reaches Send — the lingering search screen was winning the router
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
button or finger is still down (release is the choice, shared settle logic for mouse, touch and glide) — and the coins table's dotted meta line becomes little labeled pills: an hourglass countdown, depth, and exit cost each in their own chip, the expired one wearing the warning color
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
one puts it away), every landing — login, account creation, an account snapped into the carousel — is the account's own timeline, and that timeline is now SCOPED: Savings shows the on-chain ledger and gift reservations, Spending shows the ark side. The carousel meanwhile learns mouse and mind-reading: desktop gets a real grab-and-pull drag (snap lifted mid-drag, restored on the glide), the peeking neighbor switches on a single click, and the strip wears grab cursors. And a thread's avatars and author names finally go somewhere: profiles stack on top of the conversation and back returns to it
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
button matching the Back beneath it, and the receive page's lightning address drops its edit pencil — renaming lives in the profile editor's username field, and two doors was one too many
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
full uncooperative exit — every hop of every coin, an EC tweak per hop — on each wallet render; the estimate now memoizes on coin set + feerate, and decoded vtxos cache by id (bytes are immutable). Profiled on a real phone: point add/double/wNAF was 1.3s of a 4.3s six-tab-switch trace
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
memoized (make() runs eight mask trials over a version-20 grid — 30ms+ per call on a phone, paid on EVERY render of the receive pane), the header's unread count reuses its answer behind a revision counter bumped only when messages or read-marks actually change, and ark's history list rebuilds at most every 1.5s instead of per repaint
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
route and re-attempts with a bumped fee budget now says so ('Route failed — retrying with a bigger fee budget (2/3)') instead of three-plus minutes of silent 'Paying invoice…' — a tester paying an unreachable node watched that spinner stonewall through every auto-retry
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
lightning-address zaps all fill spendable-minus-estimated-fees (sum over the 24-input cap, schedule fee plus the routing reserve, real quote confirms at pay time) — emptying Spending over Lightning stops being arithmetic homework
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
| |
still dialing) no longer clobbers a remembered avatar with a punk — stale fields hold while the refresh does its rounds — and the ark merge marks coins spent the moment a synced movement or done action names them as consumed inputs, instead of double-counting a sleeping device's view (output merged in, inputs still 'spendable') until the reconcile caught up and the balance visibly ticked
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
between the configured host, blockstream.info, and mempool.space (remembering whichever answered last, rotating on network failures, 429s and 5xx) — one tester's network simply cannot reach mempool.space and every chain-touching feature was dying for it, stranded mailbox receives included. And a failed quote no longer wedges the Lightning pay form at an eternal spinner: it prices at the outage fallback and lets Pay proceed, where the payment path quotes again for real
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
Savings now fills what Savings can actually fund (the board-shaped sweep), not the Spending balance — pressing Max there handed the board panel a number the funding transaction could never cover, which read as fees calculated wrong
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
they consumed, spend actions sync as slivers (id + net amount + inputIds), and the reconcile exclusion generalizes from renewals to ANY accounted-for coin — a laptop send used to paint the phone's history twice, once as the real Sent and once as a red 'Spent on another device' at full input magnitude. The red row survives only for spends nothing anywhere explains
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
the last tab: the ark move/exit and gift detail views join NAV_FIELDS (an on-chain txDetail always had an entry; the ark rows — most Spending payments — minted none, so Back skipped the history list entirely), and their in-app Back buttons pop that entry rather than pushing another
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
build failing now marks the action failed on the spot, and connect sweeps any unfunded board stub older than an hour — a lingering 'created' stub silently blocked auto-renewal on that wallet for good (cooney had one from the Max shortfall, another wallet a 50k one)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
confirmations' comes from the ASP's requiredBoardConfirmations instead of a hardcoded 1 that contradicted the 0/3 counter under the balance
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|
| |
|
|
|
|
|
| |
compressed point's parity byte made an invalid witness program and Max fell to zero
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
|