diff options
| author | Adam Soltys <[email protected]> | 2026-08-29 07:05:47 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-29 07:05:47 -0700 |
| commit | dd011c2c98033637829d83fc320ab4fdce4ede8c (patch) | |
| tree | 67be07e6e8480354bfd60589ca68dbcaeac0c409 /src/ark/refresh.js | |
| parent | c4b566651d6afac2c48c88611094cfa71c16289b (diff) | |
| download | coinosv3-dd011c2c98033637829d83fc320ab4fdce4ede8c.tar.gz coinosv3-dd011c2c98033637829d83fc320ab4fdce4ede8c.zip | |
A round's output can no longer strand: every refresh asks the server to drop 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
Diffstat (limited to 'src/ark/refresh.js')
| -rw-r--r-- | src/ark/refresh.js | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/src/ark/refresh.js b/src/ark/refresh.js index 40c6faa..2894977 100644 --- a/src/ark/refresh.js +++ b/src/ark/refresh.js @@ -291,8 +291,11 @@ export function participationAttestation(inputVtxoIdRaw, outputs, vtxoPrivkey) { return schnorr.sign(msg, vtxoPrivkey); } -// inputs: [{ vtxo, keys }] — each input's attestation is signed by its own key -export async function submitRoundParticipation(ark, { inputs, outputs }) { +// inputs: [{ vtxo, keys }] — each input's attestation is signed by its own key. +// mailboxId: when given, the server posts a recovery breadcrumb (the unlock +// hash) to that mailbox once the round runs — any device of this wallet can +// then claim the output even if the action that submitted it is lost. +export async function submitRoundParticipation(ark, { inputs, outputs, mailboxId }) { const w = pbWriter(); for (const { vtxo, keys } of inputs) { const iv = pbWriter(); @@ -306,6 +309,7 @@ export async function submitRoundParticipation(ark, { inputs, outputs }) { vr.bytesField(2, concatBytes(Uint8Array.of(0x00), o.userPubkey)); w.bytesField(3, vr.finish()); } + if (mailboxId) w.bytesField(4, mailboxId); const resp = await grpcCall(ark, 'bark_server.ArkService/SubmitRoundParticipation', w.finish()); for (const { field, value } of pbFields(resp)) if (field === 1) return value; // unlock_hash throw new Error('no unlock hash in response'); @@ -315,12 +319,16 @@ export async function roundParticipationStatus(ark, unlockHash) { const w = pbWriter(); w.bytesField(1, unlockHash); const resp = await grpcCall(ark, 'bark_server.ArkService/RoundParticipationStatus', w.finish()); - const out = { status: 0, outputVtxos: [] }; + const out = { status: 0, outputVtxos: [], inputVtxoIds: [] }; for (const { field, value } of pbFields(resp)) { if (field === 1) out.status = Number(value); if (field === 2) out.fundingTx = value; if (field === 3) out.outputVtxos.push(value); if (field === 4) out.unlockPreimage = value; + if (field === 5 && value.length === 36) { // input vtxo ids (LE txid + LE vout) + const vout = value[32] | (value[33] << 8) | (value[34] << 16) | (value[35] << 24); + out.inputVtxoIds.push(`${hex.encode(value.slice(0, 32).reverse())}:${vout}`); + } } return out; } |
