diff options
| author | Adam Soltys <[email protected]> | 2026-10-01 17:10:36 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-01 17:10:36 -0700 |
| commit | 5c661b68c61d53a4684e47c2f306ce43cc76c1c0 (patch) | |
| tree | 74972845e7adfa7ab79309e83f740084f948c3ce /src/ark/manager.js | |
| parent | 08929aa42cdc74c3fe29007ceee3c2f8e06e6667 (diff) | |
| download | coinosv3-5c661b68c61d53a4684e47c2f306ce43cc76c1c0.tar.gz coinosv3-5c661b68c61d53a4684e47c2f306ce43cc76c1c0.zip | |
Sending on-chain from Spending states the fee and minimum up front.
The form asks the ASP for a co-operative offboard quote (mining share +
service fee, minimum = fee + dust) for the address on screen, disables
Send for a balance below it and points to Lightning. A too-small amount
reads in words instead of the manager's internal error, and the
unilateral-exit note only appears when co-operation actually failed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
Diffstat (limited to 'src/ark/manager.js')
| -rw-r--r-- | src/ark/manager.js | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/src/ark/manager.js b/src/ark/manager.js index b0985de..4b65b27 100644 --- a/src/ark/manager.js +++ b/src/ark/manager.js @@ -696,6 +696,23 @@ export class ArkManager { return action; } + // What a cooperative offboard to `spk` would cost right now, before any + // coin is touched: the miners' share at the ASP's current rate plus its + // service fee, and the smallest balance that still lands above dust. + async offboardQuote(spk, vtxoIds) { + const inputs = vtxoIds + ? vtxoIds.map((id) => this._vtxo(id)).filter(Boolean) + : this.state.vtxos.filter((v) => v.state === 'spendable'); + const tip = await this.chain.tipHeight(); + const satVkb = await getOffboardFeeRate(this.arkUrl); + const parts = offboardFeeParts({ + spkLen: spk.length, satVkb, fees: this.info.offboardFees, tip, + inputs: (inputs.length ? inputs : [{ amountSat: 0, expiryHeight: tip }]) + .map((v) => ({ amountSat: v.amountSat, expiryHeight: v.expiryHeight })), + }); + return { ...parts, minSat: parts.totalSat + P2TR_DUST }; + } + // ---- offboard (collaborative exit: spendable vtxos -> one on-chain output) ---- // Whole vtxos only — there is no change on this path. Default is everything // spendable; vtxoIds selects a subset (the feature splits an exact-amount @@ -721,7 +738,10 @@ export class ArkManager { }); const feeSat = feeParts.totalSat; const netSat = grossSat - feeSat; - if (netSat < P2TR_DUST) throw new Error('ark balance too small to offboard after fees'); + if (netSat < P2TR_DUST) { + throw Object.assign(new Error('ark balance too small to offboard after fees'), + { tooSmall: true, feeSat, minSat: feeSat + P2TR_DUST }); + } const action = { id: `offboard-${Date.now()}`, type: 'offboard', step: 'created', inputIds: inputs.map((v) => v.id), address, spkHex: hex.encode(spk), |
