From 66f9bc79b621c42520810b4176f040db3670e229 Mon Sep 17 00:00:00 2001 From: Escelit Date: Sat, 30 May 2026 10:40:20 +0100 Subject: [PATCH] feat: Safe Max button with configurable HF floor (#6) - Add Safe Max button next to leverage slider; snaps to highest leverage where projected HF >= user-configured floor - Add HF floor input in settings dropdown (default 1.2, min 1.01) - Persist floor value in localStorage under safeMaxHfFloor key --- frontend/index.html | 5 +++++ frontend/src/main.ts | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/frontend/index.html b/frontend/index.html index f904f23..87163c1 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -55,6 +55,10 @@

Important Disclaimer

@@ -396,6 +400,7 @@

Open Position

× +
Conservative diff --git a/frontend/src/main.ts b/frontend/src/main.ts index fcc1ceb..8d1deda 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -324,6 +324,21 @@ const MIN_HF_NORMAL = 1.01; const MIN_HF_EXPERT = 1.00001; function minHF() { return expertMode ? MIN_HF_EXPERT : MIN_HF_NORMAL; } +// ── Safe Max HF floor ──────────────────────────────────────────────────────── + +const HF_FLOOR_KEY = "safeMaxHfFloor"; +const HF_FLOOR_DEFAULT = 1.2; + +function getHfFloor(): number { + const raw = localStorage.getItem(HF_FLOOR_KEY); + const v = raw ? parseFloat(raw) : HF_FLOOR_DEFAULT; + return isFinite(v) && v >= 1.01 ? v : HF_FLOOR_DEFAULT; +} + +function setHfFloor(v: number) { + localStorage.setItem(HF_FLOOR_KEY, String(v)); +} + // ── Demo mode ──────────────────────────────────────────────────────────────── let demoMode = false; @@ -2709,6 +2724,39 @@ $("vault-rebalance-btn").addEventListener("click", async () => { } }); +// ── Safe Max button ─────────────────────────────────────────────────────────── + +function applySafeMax() { + const slider = $("leverage-slider") as HTMLInputElement; + const numIn = $("leverage-input") as HTMLInputElement; + const rs = reserves.find(r => r.asset.id === selectedAsset.id); + const c = rs ? rs.cFactor : selectedAsset.cFactor; + const l = rs?.lFactor ?? 1; + const floor = getHfFloor(); + const maxSlider = parseFloat(slider.max); + + // Walk down from slider max in 0.1 steps to find highest leverage with HF >= floor + let best = 1.0; + for (let lev = maxSlider; lev >= 1.0; lev = Math.round((lev - 0.1) * 10) / 10) { + if (hfForLeverage(lev, c, l) >= floor) { best = lev; break; } + } + + slider.value = String(best); + numIn.value = best.toFixed(1); + updatePreview(); +} + +$("safe-max-btn").addEventListener("click", applySafeMax); + +// HF floor input (settings dropdown) +const hfFloorInput = $("hf-floor-input") as HTMLInputElement; +hfFloorInput.value = String(getHfFloor()); +hfFloorInput.addEventListener("change", () => { + const v = parseFloat(hfFloorInput.value); + if (isFinite(v) && v >= 1.01) setHfFloor(v); + else hfFloorInput.value = String(getHfFloor()); // revert invalid +}); + // ── Auto-reconnect saved wallet ────────────────────────────────────────────── (async () => { // Restore network preference