<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinosv3.git/src/ark/manager.js, branch master</title>
<subtitle>coinos v3 — bitcoin, Ark, Lightning and nostr wallet (web + Android)</subtitle>
<id>https://git.coinos.io/coinosv3.git/atom?h=master</id>
<link rel='self' href='https://git.coinos.io/coinosv3.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/'/>
<updated>2026-10-09T23:45:22Z</updated>
<entry>
<title>Spending: one coin, one "Received" row — across devices. The Daniel still saw four "Received 1,000" rows and "Payment received! 4,000" for what the ASP shows is a single 1,000 sat coin (and two rows for his 1,005). A receive movement is recorded by every device or tab that sees the coin arrive, each under its own id, and the cross-device merge unions movements by id — so each kept its own row, and the registrar-receipt tagging marked some ⚡. lnFoldedIds now also folds receives of the same coin: the ⚡-tagged one stays (its icon is right), else the earliest. Same read-time derivation as the claim twins (history, celebration, arkMovements, LN tagging), so nothing is deleted and no synced copy brings a twin back.</title>
<updated>2026-10-09T23:45:22Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-09T23:45:22Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=095caadcba5a63f5969e50777d7e482c1d32174e'/>
<id>urn:sha1:095caadcba5a63f5969e50777d7e482c1d32174e</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
</content>
</entry>
<entry>
<title>Spending: a Lightning receive is one row. The ASP settles it as an arkoor the wallet claims — recorded as ln-receive, without its coin's id — and the same coin can reach the mailbox too, which (seeing no movement for that coin) recorded a plain receive as well: two "Received 1,005" rows and a "Payment received! 2,010" (The Daniel). The claim now stamps its coins' ids on the ln-receive, the mailbox backfill counts them, and lnFoldedIds leaves a receive of a claimed coin out of history, the celebration, the arkMovements hook and the LN tagging — derived at read time, never deleted, so a synced copy can't bring the twin back. Claims recorded before the stamp match by amount within ten minutes. tools/ln-receive-twin-test.js</title>
<updated>2026-10-09T23:24:58Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-09T23:24:58Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=20369cae83fe02968ac4318f3b8f4e9dcbbaa1cf'/>
<id>urn:sha1:20369cae83fe02968ac4318f3b8f4e9dcbbaa1cf</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
</content>
</entry>
<entry>
<title>Ark: a Lightning payment's HTLC vtxo is never a coin to spend. The reconcile pass held an in-flight action's inputs but not its HTLC outputs, so between two quick zaps it took the first zap's HTLC coin for an unheld 'pending' orphan, the server called it unspent, and it came back 'spendable' — the second zap chose it as its input and the server refused the policy ("not spendable as a round, offboard or arkoor input (policy: server-htlc-send-v1)"). HTLC outputs are now held with their action, _free() refuses any non-pubkey coin whatever its state (records learn their policy from their bytes), and a pass heals HTLC coins an earlier pass freed</title>
<updated>2026-10-09T08:43:15Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-09T08:43:15Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=817cc4a2dc0c7d343864da594aeb3c32b3459ffb'/>
<id>urn:sha1:817cc4a2dc0c7d343864da594aeb3c32b3459ffb</id>
<content type='text'>
Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Coins in another device's renewal are busy here too: the renewal sliver names its inputs, and ArkManager._free / freeCoins exclude coins an in-flight remote renewal holds from balance (counted pending), send/LN/offboard/exit selection, auto-renew, the backstop and the coins page (greyed with the round). Freed the moment that renewal reads finished, failed or lapsed</title>
<updated>2026-10-08T20:48:00Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-08T20:48:00Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=175e513273bfb2a362f9a08e3da5d5460a1d91c0'/>
<id>urn:sha1:175e513273bfb2a362f9a08e3da5d5460a1d91c0</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A renewal refused for 'insufficient refresh fee' re-reads the server's fee schedule and re-prices instead of resubmitting the same underpaying set on every sync; if the new fee leaves under 330 sats (or the price didn't change) it fails and frees the coins. Backstop registration re-reads the schedule on the same refusal</title>
<updated>2026-10-08T20:41:24Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-08T20:41:24Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=fcd023fb4b33404eb62afceba0c0232f8b25f200'/>
<id>urn:sha1:fcd023fb4b33404eb62afceba0c0232f8b25f200</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A finished renewal adopted twice no longer shows 'Renewal in progress' forever: once its done action is pruned, a re-read round breadcrumb adopted it again as a rescue at step 'issued', whose spent inputs had lost their bytes, so every sync threw. A round counts as claimed when its 'Renewed' movement or its fresh coins are already in the wallet; the breadcrumb and rescueParticipation skip it, and a stuck issued action retires without a row</title>
<updated>2026-10-08T20:00:41Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-08T20:00:41Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=b0c6e8b7d0340f5ef64ddeef0f7b0c0531cb87f1'/>
<id>urn:sha1:b0c6e8b7d0340f5ef64ddeef0f7b0c0531cb87f1</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Ark: a double-tapped zap no longer spends one coin twice</title>
<updated>2026-10-04T15:58:34Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-04T15:58:34Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=7421218e987b0053f1ddbefaddc2c9ecfd664954'/>
<id>urn:sha1:7421218e987b0053f1ddbefaddc2c9ecfd664954</id>
<content type='text'>
A reconcile pass that began before the first zap took its coin handed
it back as spendable (the server still said so) while the zap was in
flight; the second zap picked it and the server refused: 'vtxo …
already spent'. Coins whose state changed during the pass are left
alone. And a payment refused for an already-spent coin now reconciles
and pays once more instead of failing with the raw error.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
</content>
</entry>
<entry>
<title>Renewing asks first, and a renewal links to its round's transaction</title>
<updated>2026-10-03T23:05:42Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-03T23:05:42Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=202dced76eb8617c094686ef86caa979c0074320'/>
<id>urn:sha1:202dced76eb8617c094686ef86caa979c0074320</id>
<content type='text'>
- The coins page's Renew button opens a confirmation instead of renewing
  at once: how many coins, their amount, the fee, and what is left to
  spend meanwhile — with a red notice when that is nothing (the button
  selects every coin by default, which is how a user locked their whole
  balance for an hour on 2026-10-03). It says the coins can't be spent
  until the round's transaction confirms and that a renewal can't be
  cancelled; the wallet renews for free near expiry anyway. The inline
  notice from 328f2db moves into it.
- A renewal keeps its round's transaction id as soon as the round has
  run (before it confirms): the in-progress card on the coins page links
  to it, and the finished renewal's history row carries it, so its
  detail shows the id with View/Copy like any on-chain movement.
  Renewals finished before this change have no id recorded.

tools/ark/renew-confirm-ui-test.js, tools/ark/renew-txid-test.js

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
</content>
</entry>
<entry>
<title>A Lightning payment that can't be covered says why, not 'Payment failed'</title>
<updated>2026-10-03T23:00:39Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-03T23:00:39Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=328f2db9af46cda473318bb3eada0f6e83bb42f1'/>
<id>urn:sha1:328f2db9af46cda473318bb3eada0f6e83bb42f1</id>
<content type='text'>
A user renewed all ten of their coins (55,611 sats) from the coins page,
tried to pay a 55,300-sat invoice three minutes later, and was told only
'Payment failed'. Nothing had failed: the renewal's round ran at once,
but its coins stay unspendable until the round's transaction confirms
on-chain, and that block took 64 minutes. The quote found no spendable
coin and gave up with the generic message; nothing reached the server.

- The quote now tells apart (lnShortfall): money held by another payment
  (wait, as before — now by sum, not one coin covering it all), money a
  renewal holds ('Nothing was sent. N sats are being renewed…'), and a
  real shortfall ('needs X sats with its fee, Y available'). Coins leaving
  in an offboard or exit are never waited for.
- The manager's 'insufficient ark balance' names a renewal too.
- The coins page says before the tap that renewed coins can't be spent
  until the round confirms, and that renewing every coin leaves nothing
  to pay with meanwhile.

tools/ark/ln-shortfall-test.js

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
</content>
</entry>
<entry>
<title>NWC: lookup_invoice, so BTCPay Server can connect</title>
<updated>2026-10-02T14:19:29Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-02T14:19:29Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=e8d82b8b23c271aa57134d762e14fd6dcbed9c7a'/>
<id>urn:sha1:e8d82b8b23c271aa57134d762e14fd6dcbed9c7a</id>
<content type='text'>
BTCPay's NWC connector requires get_info, make_invoice, lookup_invoice
and list_transactions; we never offered lookup_invoice, so it refused the
connection string.

- ArkManager.lnLookup answers lookup_invoice from wallet state (by hash or
  bolt11, either direction; pending/settled/expired/failed, preimage once
  claimed). A retry's several actions on one hash defer to the furthest.
- The open app pushes a pending receive along before answering, so a
  merchant polling sees it settle.
- The service worker now answers make_invoice and lookup_invoice too, and
  claims a paid invoice's HTLCs during the lookup: a BTCPay sale settles
  with the wallet closed. Its list_transactions reports receives as well.
- get_info and the 13194 info event list the new method.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
</content>
</entry>
</feed>
