aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-17 23:01:52 -0700
committerAdam Soltys <[email protected]>2026-08-17 23:01:52 -0700
commit7303700f279f1e9abbeddfd50ef3693e616ae1fa (patch)
tree75217043fb7b2f19665c3cfec2f280edf917cf6a
parent0d63ae440f4296fcf44e818dca989ff7b135de74 (diff)
downloadcoinosv3-7303700f279f1e9abbeddfd50ef3693e616ae1fa.tar.gz
coinosv3-7303700f279f1e9abbeddfd50ef3693e616ae1fa.zip
One tap grows the Spending side: same seed, named Spending, no wizard — and deliberate latches carry timestamps so the phantom-healer only eats the legacy booleans
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JtaatFfAbx91Nh3xqKVqKz
-rw-r--r--src/app.js23
1 files changed, 14 insertions, 9 deletions
diff --git a/src/app.js b/src/app.js
index 6f87821..0746160 100644
--- a/src/app.js
+++ b/src/app.js
@@ -2879,7 +2879,7 @@ function onboardScreen() {
const spendReady = claimedNow || (featureHook('spendingSat') || 0) > 0
|| (getNetwork() === 'mainnet' && named);
if (spendReady) {
- if (acc && !acc.spendingSetup) { acc.spendingSetup = true; persistAccounts(); }
+ if (acc && !acc.spendingSetup) { acc.spendingSetup = Date.now(); persistAccounts(); }
ui.account = 'spending';
try { localStorage.setItem(ACCOUNT_KEY, 'spending'); } catch {}
}
@@ -3002,9 +3002,10 @@ function spendingActive() {
if (acc?.kind === 'spending') return true;
if (acc?.spendingSetup) {
// Self-heal a flag latched by the old cross-network name leak: off
- // mainnet, a Spending side with zero balance AND no ark history was
- // never really set up — drop it. A real receive re-latches instantly.
- if (getNetwork() !== 'mainnet' && !(featureHook('spendingSat') || 0)
+ // mainnet, a LEGACY boolean flag (`true` — the buggy era's value; every
+ // deliberate latch since carries a timestamp) with zero balance and no
+ // ark history was never really set up — drop it.
+ if (acc.spendingSetup === true && getNetwork() !== 'mainnet' && !(featureHook('spendingSat') || 0)
&& !(featureHook('arkMovements') || []).length) {
delete acc.spendingSetup;
persistAccounts();
@@ -3019,7 +3020,7 @@ function spendingActive() {
const evident = (featureHook('spendingSat') || 0) > 0 || (!!addr && !/^npub1/.test(addr));
// Latch demonstrated use onto the record, so the Wallets list keeps showing
// this seed's Spending side even while it's locked or not the active one.
- if (evident && acc && !acc.spendingSetup) { acc.spendingSetup = true; persistAccounts(); }
+ if (evident && acc && !acc.spendingSetup) { acc.spendingSetup = Date.now(); persistAccounts(); }
return evident;
}
// ---- the flat wallet model -------------------------------------------------
@@ -3146,11 +3147,15 @@ function balanceCard() {
...(hasSpending ? featureAll('balanceActions') : []).map((a2) =>
h('button', { class: 'btn-sm', style: 'margin-top:10px', onClick: a2.onClick }, a2.label)),
// A seed with only a Savings side is one tap from growing a Spending one:
- // the offer sits right on the balance card, not hidden behind Add wallet.
- // (Single-purpose Savings wallets keep their purpose — Add wallet covers
- // them; watch-only can't spend at all.)
+ // the offer sits right on the balance card, and the tap simply DOES it —
+ // same seed, a "Spending" side appears, no wizard in the way. (Explicit
+ // latches carry a timestamp; the self-heal only eats the legacy booleans.)
!hasSpending && !kindLocked && featureHook('arkReady') && !wallet.watchOnly && acc0 && acc0.type === 'full'
- ? h('button', { class: 'btn-sm', style: 'margin-top:10px', onClick: () => { ui.onbError = ''; ui.onb = { step: 'spend' }; render(); } }, t('spendSetup'))
+ ? h('button', { class: 'btn-sm', style: 'margin-top:10px', onClick: () => {
+ acc0.spendingSetup = Date.now();
+ persistAccounts();
+ setAccountSel('spending', 'right');
+ } }, t('spendSetup'))
: null,
// A feature can unfold UI right on the card (ark's inline move panel).
(() => {