diff options
| author | Adam Soltys <[email protected]> | 2026-07-05 09:05:20 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-07-05 09:05:20 -0700 |
| commit | f9fc0bb3e38c3387f8af5d151aa03d83376ba9cc (patch) | |
| tree | 4f7754e3b6b0be893e4c21acc8a881e9347d32b0 /src/ark/proto.js | |
| parent | db7e70fac51e16c7f389e031a80355b2d9d0f57e (diff) | |
| download | coinosv3-f9fc0bb3e38c3387f8af5d151aa03d83376ba9cc.tar.gz coinosv3-f9fc0bb3e38c3387f8af5d151aa03d83376ba9cc.zip | |
Collaborative offboard: move the ark balance back on-chain
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]>
Diffstat (limited to 'src/ark/proto.js')
| -rw-r--r-- | src/ark/proto.js | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/src/ark/proto.js b/src/ark/proto.js index 1cbc0ef..ae2342e 100644 --- a/src/ark/proto.js +++ b/src/ark/proto.js @@ -364,7 +364,11 @@ export function decodeVtxo(bytes) { export async function getArkInfo(ark) { const data = await grpcCall(ark, 'bark_server.ArkService/GetArkInfo', new Uint8Array(0)); // Fee schedules a server never sends (or sends all-zero) mean "free". - const info = { boardFees: {}, refreshFees: { baseFeeSat: 0, ppmExpiryTable: [] } }; + const info = { + boardFees: {}, + refreshFees: { baseFeeSat: 0, ppmExpiryTable: [] }, + offboardFees: { baseFeeSat: 0, fixedAdditionalVb: 0, ppmExpiryTable: [] }, + }; for (const { field, value } of pbFields(data)) { if (field === 1) info.network = td.decode(value); if (field === 2) info.serverPubkey = hex.encode(value); @@ -374,6 +378,7 @@ export async function getArkInfo(ark) { if (field === 10) info.requiredBoardConfirmations = Number(value); if (field === 13) info.minBoardAmountSat = Number(value); if (field === 16) info.mailboxPubkey = hex.encode(value); + if (field === 20) info.maxOffboardInputs = Number(value); if (field === 18) { // FeeSchedule for (const f of pbFields(value)) { if (f.field === 1) { // board @@ -385,6 +390,22 @@ export async function getArkInfo(ark) { } info.boardFees = b; } + if (f.field === 2) { // offboard + const ob = { baseFeeSat: 0, fixedAdditionalVb: 0, ppmExpiryTable: [] }; + for (const g of pbFields(f.value)) { + if (g.field === 1) ob.baseFeeSat = Number(g.value); + if (g.field === 2) ob.fixedAdditionalVb = Number(g.value); + if (g.field === 3) { + const e = { thresholdBlocks: 0, ppm: 0 }; + for (const h of pbFields(g.value)) { + if (h.field === 1) e.thresholdBlocks = Number(h.value); + if (h.field === 2) e.ppm = Number(h.value); + } + ob.ppmExpiryTable.push(e); + } + } + info.offboardFees = ob; + } if (f.field === 3) { // refresh const rf = { baseFeeSat: 0, ppmExpiryTable: [] }; for (const g of pbFields(f.value)) { |
