aboutsummaryrefslogtreecommitdiffstats
path: root/src/ark/proto.js
Commit message (Collapse)AuthorAgeFilesLines
* The renewal happens whether or not anyone opens the app.Adam Soltys2026-09-131-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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
* Ark: persist vtxo bytes as base64 (a third smaller than hex); hex still ↵Adam Soltys2026-09-101-1/+11
| | | | | | | | | | | | | | | | | | 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
* A round's output can no longer strand: every refresh asks the server to drop ↵Adam Soltys2026-08-291-0/+6
| | | | | | | its unlock hash in the mailbox, and any device that finds such a breadcrumb with no matching action adopts the claim itself (input ids now read from the status response — the rescue needs no operator). History learns to tell the whole truth and nothing more: coins the server saw spent elsewhere get a folded row (skipping coins a known renewal consumed), renewals fold across devices on their unlock hash and appear only when they cost something, and a rescue records the fee the round actually took. The account page keeps its header icons when reached from an open wallet; the messages page folds the control/guestbook replay once per burst instead of painting every intermediate state — no more blinking messages from superseded ban lists or member counts crawling to their total, which now paints from last session's settled figure Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019WboeoetMF3MTmgT7Ew8yi
* hal speaks pver 5: preimages prove their size, and fees round up as oneAdam Soltys2026-08-051-8/+20
| | | | | | | | | | 0.6.0 servers require the new hashlock clauses (OP_SIZE 32 guard) for Lightning and rounds. New policies/transitions carry the v1 scripts and type bytes; _v0 variants keep old vtxos reconstructing and exiting. The retired third-party HTLC policy is dropped (upstream took 0x08). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M5kFodm9azZJVTQxnkDdKe
* Ark gifts go down to 1 sat; negative amounts can't OOM the encoderAdam Soltys2026-08-041-0/+3
| | | | | | | | | | | | | | | | | | Regtest-proven (tools/ark/dust-gift-test.js): the ASP cosigns all-dust arkoor sends, so a sub-dust bearer vtxo sweeps to its claimer fine, and dust folds into rounds alongside bigger siblings. The 330-sat gift floor guarded a failure that can't happen — dropped to 1 sat. The experiment also caught a live bug: refresh() of a balance smaller than the round fee computed a negative output amount, and pbWriter's varint sign-extends negatives into an infinite loop — auto-refresh would OOM the tab of any wallet too small to renew. varint now throws on negatives and refresh() refuses cleanly, before marking coins pending, when balance minus fee is under the server's 330-sat output minimum. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
* Client support for third-party HTLC vtxos (trustless swap bridges)Adam Soltys2026-07-311-0/+6
| | | | | | | | | | | | | | | | | | Speaks the proposed VtxoPolicy::Htlc (type byte 0x08): policy encode/decode, two-leaf taproot (claimer-with-preimage / refunder-after-expiry), preimage field on the arkoor cosign request, and GetHtlcPreimage. ArkManager gains the swap primitives: htlcLock (lock funds claimable only against a payment hash, refundable by us after expiry), htlcClaim (reveal the preimage), htlcCosignRefund (hand an unclaimable HTLC back — the server constrains the outputs to the refunder, so this is safe to expose publicly) and acceptHtlcRefund. tools/ark/htlc-bridge-test.js drives a full submarine swap between two independent wallets against a patched captaind, and asserts the ASP rejects both a wrong-preimage claim and a preimage-less spend to the bridge itself. Co-Authored-By: Claude Fable 5 <[email protected]>
* Add Ark <-> Lightning via the ASP (captaind-native submarine swaps)Adam Soltys2026-07-311-0/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | The ASP is the HTLC counterparty (second.tech's protocol), so no external swap provider is needed: paying a bolt11 converts pubkey vtxos into ServerHtlcSend vtxos the server can only claim by revealing the invoice preimage; receiving grants ServerHtlcRecv vtxos claimed by revealing ours. Failure paths cosign the HTLC back (revocation) — proven end-to-end against regtest captaind, which independently derives the HTLC taproots. - ark/lightning.js: bolt11 decode, lightning fee schedules, all pay/receive gRPC-web wrappers (cosign, initiate, status, revocation, hold-invoice receive flow, anti-DoS attestation) - ark/send.js: arkoor builder generalized to policy outputs (pubkey / serverHtlcSend / serverHtlcRecv), two-leaf taproot trees, HTLC clause scripts, reusable per-part cosign helpers for package RPCs - ark/manager.js: ln-pay and ln-recv crash-safe action state machines (deterministic receive preimages from the seed, chain 5), mailbox lightning notifications, unpayable-invoice -> instant revocation - proto.js: lightning ArkInfo fields + mailbox lightning message decode - validate/refresh: policy-aware vtxo validation and reconstruction - features: bolt11 routes via ark when the balance covers it (Boltz stays the fallback), lightning-invoice receive on the Ark pane - tools/ark/ln-test.js: harness proving HTLC cosign + revocation against captaind; manager-test.js updated for the consolidated bc-container chain Co-Authored-By: Claude Fable 5 <[email protected]>
* Collaborative offboard: move the ark balance back on-chainAdam Soltys2026-07-051-1/+22
| | | | | | | | | | | | | | | | | | | | PrepareOffboard/FinishOffboard against captaind — per-input ownership attestations, connector-based musig forfeits (with the deterministic fanout tx when there is more than one input), and fee math that mirrors the server bit-for-bit (weight fee rounds up, ppm-by-expiry rounds down) since it rejects any other net amount. The receive pane gains a 'Move back on-chain' button that withdraws everything to the wallet's own fresh address; the incoming tx is labeled 'Ark withdrawal' in History and the ark side records the movement. Crash-safe: the txid persists before FinishOffboard and resume asks GetVtxoStatus whether the forfeits landed (the server broadcasts the tx itself). Also fixes boarding to applySentTx after broadcasting the funding tx — without it the spent coin lingered in the utxo set (a second board double-spent it), and the post-board scan() could resurrect it by racing the explorer's indexing. Co-Authored-By: Claude Fable 5 <[email protected]>
* Ark: recover from stale vtxo stateAdam Soltys2026-07-041-1/+20
| | | | | | | | | | Match captaind's actual 'not spendable' error so a crashed or foreign spend fails the action instead of retrying forever, and reconcile locally-spendable vtxos against the server (GetVtxoStatus + ownership attestation) when an ark address lands in the send form. boardFee now treats absent proto3 fee fields as zero (Second's signet boards free). Co-Authored-By: Claude Fable 5 <[email protected]>
* Ark: real-time receives over the SubscribeMailbox gRPC streamAdam Soltys2026-07-041-18/+68
| | | | | | | | | | | | grpcStream() parses gRPC-web frames incrementally off fetch's body stream; the manager keeps a long-lived SubscribeMailbox subscription (auto-reconnect, 3s backoff) whose messages flow through the same duplicate-safe processing as the poll. Receives now land the moment the sender delivers (~sub-second) instead of on the next poll; the poll stays as fallback and to drive in-flight boards/refreshes. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QFAcD4V284DvYZZHP7Rxxy
* Ark: native-JS protocol client + persistent ArkManagerAdam Soltys2026-07-031-0/+408
Speaks Second's bark/captaind Ark protocol directly from the browser — gRPC-web over fetch with hand-rolled protobuf, no wasm, no new deps (crypto via the existing @scure/@noble stack incl. btc-signer's BIP-327 musig2 module). src/ark: - proto.js transport, ark address codec, mailbox blinding/auth, VTXO ProtocolEncoding v2 decode - send.js arkoor send: checkpoint+arkoor txs, BIP-341 sighashes, MuSig2 cosign ceremony, signed-VTXO assembly - board.js onchain -> ark: funding taproot, exit-tx cosign - refresh.js delegated round (hArk): participation, tx-chain reconstruction, hash-locked leaf cosign, forfeit swap - validate.js receive-side verification: chain must land on the vtxo point, anchor checked onchain, every transition sig verified - manager.js persistent wallet layer: storage-checkpointed step-machine actions (send/board/refresh) that survive crashes, mailbox sync with validation, multi-input consolidation refresh tools/ark: end-to-end regtest tests (receive, send, board, refresh, manager incl. crash-mid-send + resume), all passing against captaind with the bark CLI as counterparty. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QFAcD4V284DvYZZHP7Rxxy