aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-28 19:30:11 -0700
committerAdam Soltys <[email protected]>2026-08-28 19:30:11 -0700
commit7721a68f6202db562e68226f06319304bb180970 (patch)
treea80611b147e64f940df855fec308bb752ee16e36 /src
parent12ecbf2bcdd59b6c3a2714c69240cb3be65b7e3e (diff)
downloadcoinosv3-7721a68f6202db562e68226f06319304bb180970.tar.gz
coinosv3-7721a68f6202db562e68226f06319304bb180970.zip
No exit leaves without fare money: starting one now requires Savings to cover the estimated hop fees (named in the refusal), and a mid-flight stall says exactly how many sats the next step needs and that it resumes on its own
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
Diffstat (limited to 'src')
-rw-r--r--src/features/ark.js9
-rw-r--r--src/i18n.js3
2 files changed, 10 insertions, 2 deletions
diff --git a/src/features/ark.js b/src/features/ark.js
index 14ac9c1..81e3351 100644
--- a/src/features/ark.js
+++ b/src/features/ark.js
@@ -1597,6 +1597,13 @@ export function arkFeature(ctx) {
const mgr = await connectArk();
const spendables = mgr.vtxos().filter((v) => v.state === 'spendable');
if (!spendables.length) throw new Error(t('arkNotConnected'));
+ // Fees are paid hop by hop from Savings as the exit unrolls — an exit
+ // that can't fund its hops just stalls at step zero. Refuse to start
+ // one Savings can't carry, with the number on the table.
+ const feeEst = estimateExitFeeSat(mgr);
+ if ((wallet.spendable || 0) < feeEst) {
+ throw new Error(t('arkExitFeeShort', { need: fmtAmount(feeEst), have: fmtAmount(wallet.spendable || 0) }));
+ }
for (const v of spendables) mgr.startExit(v.id);
toast(t('arkExitStarted', { n: spendables.length }));
driveExits(mgr).catch(() => {});
@@ -1650,7 +1657,7 @@ export function arkFeature(ctx) {
mgr._save();
return;
} catch {
- const e = new Error(t('arkExitNoFeeCoin'));
+ const e = new Error(t('arkExitNoFeeCoin', { need: fmtAmount(Math.max(294, feeSat)) }));
e.actionable = true;
throw e;
}
diff --git a/src/i18n.js b/src/i18n.js
index 234c622..4eeca92 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -525,7 +525,8 @@ const STR = {
arkOffboardHistory: 'Moved to Savings',
arkExitBtn: 'Move to Savings without the server',
arkExitStarted: 'Unilateral exit started for {n} coin(s) — broadcasting the exit chain.',
- arkExitNoFeeCoin: 'This needs a little in Savings to pay the mining fees.',
+ arkExitNoFeeCoin: 'Paused: the next step needs about {need} sats in Savings for its mining fee. Top up Savings and it resumes by itself.',
+ arkExitFeeShort: 'Savings can’t cover the exit’s mining fees (about {need} sats needed, {have} available). Top up Savings first.',
preimageLabel: 'Preimage',
copyPreimage: 'Copy preimage',
arkExitSummary: 'Moving {n} sats to Savings on-chain — about {eta} until it lands.',