<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinosv3.git/src/features/gifts.js, branch fdroid-v1.8</title>
<subtitle>coinos v3 — bitcoin, Ark, Lightning and nostr wallet (web + Android)</subtitle>
<id>https://git.coinos.io/coinosv3.git/atom?h=fdroid-v1.8</id>
<link rel='self' href='https://git.coinos.io/coinosv3.git/atom?h=fdroid-v1.8'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/'/>
<updated>2026-09-16T04:56:18Z</updated>
<entry>
<title>Gift detail links the coin behind the gift, and the claim once claimed.</title>
<updated>2026-09-16T04:56:18Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-16T04:56:18Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=b58e3dc1eb2a578f1cae441d8bba9503bec94567'/>
<id>urn:sha1:b58e3dc1eb2a578f1cae441d8bba9503bec94567</id>
<content type='text'>
An unclaimed on-chain gift has no transaction of its own yet — its
funding transaction is presigned and only broadcast when someone claims.
The coin it's locked against is on-chain from the start, so the detail
page now links that outpoint's transaction on the block explorer, and
the claim transaction once it exists.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01JuwQqNWtDJcxPWtEm9134z
</content>
</entry>
<entry>
<title>A gift locked from Savings shows under Savings, not Spending.</title>
<updated>2026-09-15T04:58:33Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-15T04:58:33Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=a493b12aca18a670296f0f7142ad041b87ec1b69'/>
<id>urn:sha1:a493b12aca18a670296f0f7142ad041b87ec1b69</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix the on-chain gift front-running vulnerability architecturally: ephemeral-key (v2) gifts.</title>
<updated>2026-09-07T01:43:50Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-07T01:43:50Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=2e492ec499264ba84ec8cad30f788eff28556269'/>
<id>urn:sha1:2e492ec499264ba84ec8cad30f788eff28556269</id>
<content type='text'>
The old on-chain gift presigned a SIGHASH_NONE/SINGLE spend of the sender's own coin — a blank cheque whose claimer output isn't committed, so anyone (from the link, or a mempool watcher once a claim broadcast) could redirect the presigned input to their own address via a higher-fee tx. A sweeper bot had been front-running coinos gift links for ~a month; it drained a real 5000-sat gift ("claimed! → empty wallet"). Root-caused via chain + code forensics: theft tx input0 sighash = SINGLE.

New design (v2, lazy ephemeral key): the sender presigns a FULLY COMMITTED (SIGHASH_ALL) funding tx paying the gift to a throwaway key E, and puts E's private key in the link. The claimer broadcasts the funding tx, then a fresh SIGHASH_ALL sweep of E into their own wallet. Both txs commit to every output, so neither is redirectable in the mempool — redirecting needs E's key, which lives only in the link (the intended bearer property: holding the link is the only way to claim). Lazy: the funding tx isn't broadcast until claim, so an unclaimed gift moves no coins and is revoked for free by spending the still-reserved funding coin. Sender pays the funding fee (from change / the swept total); claimer pays the sweep fee (from the gift).

- gifts-wallet.js: _buildGiftPsbt now builds+signs the ephemeral funding tx (coin -&gt; E + change, SIGHASH_ALL); new GIFT_MAGIC_V2 codec (parseLazyGift/_encodeLazyGift: [magic][E priv:32][le32 len][funding tx]); giftClaimTxs returns the {funding, sweep} pair; giftOutpoints/previewGift read E's output; isRetiredGift flags the old v1 (compact + legacy PSBT) links. Fee threaded through _selectGiftCoins/createGift/createGiftAll/createGiftFromSplit.
- gifts.js doClaim: broadcast funding (tolerating "already in mempool" from a co-holder/retry) then sweep; refuse retired v1 links with a clear message; verifyClaimWon now watches E's output.
- i18n: giftChainWarn reworded (safe bearer link funding a fresh on-chain wallet); giftRetired added.

Verified: focused crypto test confirms codec round-trip + both inputs signed SIGHASH_ALL (committed). Full regtest end-to-end: funding + sweep both relayed (child accepted spending an unconfirmed parent), mined, claimer address credited the gift. UI morph smoke passes.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
<entry>
<title>Interim safety for on-chain gifts ahead of the crypto redesign. (1) On-chain (Savings) gift creation now shows a hard bearer-risk warning: the presigned input is redirectable, a sweeper bot is actively front-running shared links, so share privately and claim immediately (Spending/ark gifts are unaffected). (2) The false "success" is fixed: a broadcast returning OK was never proof WE won — a higher-fee sweep can evict our claim (the "claimed! → empty wallet" the bot produced). verifyClaimWon now polls the funding coin after broadcast and, if it settles spent by a txid that isn't ours, retracts the celebration and shows the already-taken screen. Full architectural fix (ephemeral-key gifts, non-malleable SIGHASH_ALL claim) is next</title>
<updated>2026-09-07T01:09:16Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-07T01:09:16Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=95cf88f1246118eb6a672a5b4b6545331c9ddef4'/>
<id>urn:sha1:95cf88f1246118eb6a672a5b4b6545331c9ddef4</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
<entry>
<title>On-chain gift claims can no longer strand funds at an address the claimer's backed-up seed doesn't control. A claim into a fresh wallet reportedly paid a DIFFERENT wallet's address than the seed shown for backup (5000-sat gift claimed in incognito → funds landed at an accumulator address the given seed couldn't derive), because the destination was wallet.receive[0] — which can be a stale address a previous account in the session left behind. Now the claim derives THIS wallet's own address fresh from the active seed (never receive[0]), and a hard guard refuses to broadcast unless that address is provably derivable from the wallet whose recovery phrase is about to be handed over — any future seed/wallet divergence becomes a safe error, not lost money</title>
<updated>2026-09-07T00:03:09Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-07T00:03:09Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=dcfabe9165e7b0f48d9d3f645f762b84e6bc48b8'/>
<id>urn:sha1:dcfabe9165e7b0f48d9d3f645f762b84e6bc48b8</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
<entry>
<title>History becomes home: the tab bar slims to Receive | Send (tapping the lit 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</title>
<updated>2026-09-03T02:57:57Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-03T02:57:46Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=52b411947bd6c61cf50c60a27249abeedc26c102'/>
<id>urn:sha1:52b411947bd6c61cf50c60a27249abeedc26c102</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
</content>
</entry>
<entry>
<title>The phone's Back button closes a payment's details instead of teleporting to 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</title>
<updated>2026-08-31T05:32:45Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-31T05:32:45Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=bfe6ee7f93d294e430718a91c96aef815ee6935a'/>
<id>urn:sha1:bfe6ee7f93d294e430718a91c96aef815ee6935a</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
</content>
</entry>
<entry>
<title>A claimed gift shows you the pocket it landed in: an ark gift claim latches the Spending side and selects it on every path into the wallet — backup, verify, skip, or straight in — instead of opening onto an empty Savings face</title>
<updated>2026-08-28T19:49:14Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-28T19:49:14Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=5848cc44129a7ce4450e6bedaf40682f7f3ca4d4'/>
<id>urn:sha1:5848cc44129a7ce4450e6bedaf40682f7f3ca4d4</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
</content>
</entry>
<entry>
<title>Profiles wear their latest notes, each one zappable; a zap with no ark address to land on becomes a gift only their key can open</title>
<updated>2026-08-08T15:21:11Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-08T15:21:11Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=19c14131ce3fc69a06d3c0af8d445b056d703bf9'/>
<id>urn:sha1:19c14131ce3fc69a06d3c0af8d445b056d703bf9</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Spending trusts its own ledger: gifts read persisted ark state, and Savings keeps its pending line to itself</title>
<updated>2026-08-05T18:56:53Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-08-05T18:56:53Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=1307f8930283393fcf987cfa7e5cfa054676396a'/>
<id>urn:sha1:1307f8930283393fcf987cfa7e5cfa054676396a</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01M5kFodm9azZJVTQxnkDdKe
</content>
</entry>
</feed>
