diff --git a/src/components/wallet/LoanSimulator.tsx b/src/components/wallet/LoanSimulator.tsx
index 839b187..3300e22 100644
--- a/src/components/wallet/LoanSimulator.tsx
+++ b/src/components/wallet/LoanSimulator.tsx
@@ -641,8 +641,73 @@ export default function LoanSimulator({ mode = "borrow", collateralType = "WBTC"
{/* Input Field */}
{mode === "simulate" ? (
- /* Sandbox Mode - Collateral Type Selector + Collateral Input + Borrow Slider */
+ /* Sandbox Mode - Borrow Slider + Collateral Type Selector + Collateral Input */
+ {/* Borrow Amount Slider */}
+
+
+
+
+ Borrow Amount (USDT)
+
+
+
+
+
+ {formatCurrency(parsedInput, 0, "$", false)}
+
+
+
+
setInputValue(e.target.value)}
+ disabled={maxBorrow <= 0}
+ className={cn(
+ "w-full h-2 rounded-full appearance-none cursor-pointer bg-white/10",
+ "[&::-webkit-slider-thumb]:appearance-none",
+ "[&::-webkit-slider-thumb]:w-5",
+ "[&::-webkit-slider-thumb]:h-5",
+ "[&::-webkit-slider-thumb]:rounded-full",
+ "[&::-webkit-slider-thumb]:bg-amber-500",
+ "[&::-webkit-slider-thumb]:shadow-lg",
+ "[&::-webkit-slider-thumb]:border-2",
+ "[&::-webkit-slider-thumb]:border-white/20",
+ "[&::-moz-range-thumb]:w-5",
+ "[&::-moz-range-thumb]:h-5",
+ "[&::-moz-range-thumb]:rounded-full",
+ "[&::-moz-range-thumb]:bg-amber-500",
+ "[&::-moz-range-thumb]:border-2",
+ "[&::-moz-range-thumb]:border-white/20",
+ "disabled:opacity-50"
+ )}
+ style={{
+ background: maxBorrow > 0
+ ? `linear-gradient(to right, rgb(245 158 11) 0%, rgb(245 158 11) ${(parsedInput / maxBorrow) * 100}%, rgba(255,255,255,0.1) ${(parsedInput / maxBorrow) * 100}%, rgba(255,255,255,0.1) 100%)`
+ : "rgba(255,255,255,0.1)"
+ }}
+ />
+
+ $0
+ {formatCurrency(maxBorrow, 0, "$", false)}
+
+
+ {maxBorrow <= 0 && parsedSandboxCollateral === 0 && (
+
+ Enter collateral amount to enable borrowing
+
+ )}
+
+
{/* Collateral Type Selector */}
- {/* Borrow Amount Slider */}
-
-
-
-
- Borrow Amount (USDT)
-
-
-
-
-
- {formatCurrency(parsedInput, 0, "$", false)}
-
-
-
-
setInputValue(e.target.value)}
- disabled={maxBorrow <= 0}
- className={cn(
- "w-full h-2 rounded-full appearance-none cursor-pointer bg-white/10",
- "[&::-webkit-slider-thumb]:appearance-none",
- "[&::-webkit-slider-thumb]:w-5",
- "[&::-webkit-slider-thumb]:h-5",
- "[&::-webkit-slider-thumb]:rounded-full",
- "[&::-webkit-slider-thumb]:bg-amber-500",
- "[&::-webkit-slider-thumb]:shadow-lg",
- "[&::-webkit-slider-thumb]:border-2",
- "[&::-webkit-slider-thumb]:border-white/20",
- "[&::-moz-range-thumb]:w-5",
- "[&::-moz-range-thumb]:h-5",
- "[&::-moz-range-thumb]:rounded-full",
- "[&::-moz-range-thumb]:bg-amber-500",
- "[&::-moz-range-thumb]:border-2",
- "[&::-moz-range-thumb]:border-white/20",
- "disabled:opacity-50"
- )}
- style={{
- background: maxBorrow > 0
- ? `linear-gradient(to right, rgb(245 158 11) 0%, rgb(245 158 11) ${(parsedInput / maxBorrow) * 100}%, rgba(255,255,255,0.1) ${(parsedInput / maxBorrow) * 100}%, rgba(255,255,255,0.1) 100%)`
- : "rgba(255,255,255,0.1)"
- }}
- />
-
- $0
- {formatCurrency(maxBorrow, 0, "$", false)}
-
-
- {maxBorrow <= 0 && parsedSandboxCollateral === 0 && (
-
- Enter collateral amount to enable borrowing
-
- )}
-
) : (
<>
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index faf252e..5296904 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -28,10 +28,10 @@ export function formatAmount(
const abs = Math.abs(num);
// Tiny positive numbers: show '< 0.0001' for values > 0 and < 0.0001
if (abs > 0 && abs < 0.0001) return `< 0.0001`;
- // Cap maximum decimals to 4 to avoid very long fractional displays
+ // Cap decimals to valid range (0-4) and ensure min <= max
const maxDecimals = Math.min(4, Math.max(0, decimals));
return num.toLocaleString("en-US", {
- minimumFractionDigits: 2,
+ minimumFractionDigits: Math.min(2, maxDecimals),
maximumFractionDigits: maxDecimals,
});
}
@@ -51,9 +51,10 @@ export function formatCurrency(
return `${currencySymbol}${abbreviateNumber(num, 1)}`;
}
// For smaller numbers, show with requested decimals (no grouping abbreviation)
+ const safeDecimals = Math.max(0, decimals);
return `${currencySymbol}${num.toLocaleString("en-US", {
- minimumFractionDigits: decimals,
- maximumFractionDigits: decimals,
+ minimumFractionDigits: safeDecimals,
+ maximumFractionDigits: safeDecimals,
})}`;
}
@@ -64,9 +65,10 @@ export function formatPercent(
if (value === null || value === undefined) return `0%`;
const num = Number(value);
if (!Number.isFinite(num)) return `0%`;
+ const safeDecimals = Math.max(0, decimals);
return `${Number(value).toLocaleString("en-US", {
- minimumFractionDigits: decimals,
- maximumFractionDigits: decimals,
+ minimumFractionDigits: safeDecimals,
+ maximumFractionDigits: safeDecimals,
})}%`;
}
diff --git a/test/lib/utils.test.ts b/test/lib/utils.test.ts
index f17fbb5..e8ddee2 100644
--- a/test/lib/utils.test.ts
+++ b/test/lib/utils.test.ts
@@ -80,6 +80,21 @@ describe("formatAmount", () => {
it("should respect custom decimals", () => {
expect(formatAmount(1.123456, 2)).toBe("1.12");
});
+
+ it("should not throw RangeError when decimals is 0", () => {
+ expect(() => formatAmount(100000, 0)).not.toThrow();
+ expect(formatAmount(100000, 0)).toBe("100,000");
+ });
+
+ it("should not throw RangeError when decimals is 1", () => {
+ expect(() => formatAmount(1234.5, 1)).not.toThrow();
+ expect(formatAmount(1234.5, 1)).toBe("1,234.5");
+ });
+
+ it("should not throw RangeError when decimals is negative", () => {
+ expect(() => formatAmount(1234, -1)).not.toThrow();
+ expect(formatAmount(1234, -1)).toBe("1,234");
+ });
});
describe("formatCurrency", () => {
@@ -110,6 +125,16 @@ describe("formatCurrency", () => {
it("should not abbreviate when disabled", () => {
expect(formatCurrency(5000, 2, "$", false)).toBe("$5,000.00");
});
+
+ it("should not throw RangeError when decimals is 0", () => {
+ expect(() => formatCurrency(100, 0)).not.toThrow();
+ expect(formatCurrency(100, 0, "$", false)).toBe("$100");
+ });
+
+ it("should not throw RangeError when decimals is negative", () => {
+ expect(() => formatCurrency(100, -1)).not.toThrow();
+ expect(formatCurrency(100, -1, "$", false)).toBe("$100");
+ });
});
describe("formatPercent", () => {
@@ -132,6 +157,11 @@ describe("formatPercent", () => {
it("should respect custom decimals", () => {
expect(formatPercent(33.3333, 1)).toBe("33.3%");
});
+
+ it("should not throw RangeError when decimals is negative", () => {
+ expect(() => formatPercent(50, -1)).not.toThrow();
+ expect(formatPercent(50, -1)).toBe("50%");
+ });
});
describe("maskString", () => {