diff --git a/contracts/loan_manager/src/lib.rs b/contracts/loan_manager/src/lib.rs
index 37b9e7f7..6bd112ce 100644
--- a/contracts/loan_manager/src/lib.rs
+++ b/contracts/loan_manager/src/lib.rs
@@ -569,18 +569,18 @@ impl LoanManager {
}
let remaining_principal = Self::remaining_principal(loan);
- let debt_before_late_fees = remaining_principal
- .checked_add(loan.accrued_interest)
- .expect("debt overflow");
- // Stop accruing fees if principal + interest is fully paid
- if debt_before_late_fees <= 0 {
+ // Stop accruing fees if principal is fully paid
+ if remaining_principal <= 0 {
loan.last_late_fee_ledger = current_ledger;
return 0;
}
let overdue_ledgers = current_ledger - late_fee_start;
- let incremental_fee = debt_before_late_fees
+ // Late fee is calculated on original principal amount only, not remaining debt.
+ // This ensures the 25% late fee cap is meaningful regardless of payment state.
+ let incremental_fee = loan
+ .amount
.checked_mul(Self::late_fee_rate_bps(env) as i128)
.and_then(|value| value.checked_mul(overdue_ledgers as i128))
.and_then(|value| value.checked_div(10_000))
diff --git a/frontend/src/app/[locale]/lend/LendPageClient.tsx b/frontend/src/app/[locale]/lend/LendPageClient.tsx
index cd811d0e..42fa11b1 100644
--- a/frontend/src/app/[locale]/lend/LendPageClient.tsx
+++ b/frontend/src/app/[locale]/lend/LendPageClient.tsx
@@ -37,6 +37,8 @@ import {
getPrecisionError,
parseAmount,
sanitizeAmountInput,
+ formatAmountOnBlur,
+ getAssetDecimals,
} from "../../utils/amount";
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:3001";
@@ -72,8 +74,10 @@ export function LendPageClient() {
const depositPrecisionError = getPrecisionError(depositAmount, "USDC");
const withdrawPrecisionError = getPrecisionError(withdrawAmount, "USDC");
- const depositHelper = buildAmountHelperText(depositAmount, "USDC");
- const withdrawHelper = buildAmountHelperText(withdrawAmount, "USDC");
+ const depositDecimals = getAssetDecimals("USDC");
+ const withdrawDecimals = getAssetDecimals("USDC");
+ const depositHelper = buildAmountHelperText(depositAmount, "USDC", depositDecimals);
+ const withdrawHelper = buildAmountHelperText(withdrawAmount, "USDC", withdrawDecimals);
const handleDeposit = async () => {
const amount = parseAmount(depositAmount);
@@ -312,9 +316,15 @@ export function LendPageClient() {
type="text"
inputMode="decimal"
min="0"
- step="0.0000001"
+ step={Math.pow(10, -depositDecimals)}
value={depositAmount}
onChange={(event) => setDepositAmount(sanitizeAmountInput(event.target.value))}
+ onBlur={(event) => {
+ const formatted = formatAmountOnBlur(event.target.value, "USDC");
+ if (formatted && formatted !== event.target.value) {
+ setDepositAmount(formatted);
+ }
+ }}
aria-invalid={depositPrecisionError ? true : undefined}
className={`w-full rounded-xl border bg-zinc-50 px-3 py-2 text-sm outline-none focus:border-indigo-500 dark:border-zinc-800 dark:bg-zinc-900 ${
depositPrecisionError ? "border-red-500" : "border-zinc-200"
@@ -327,7 +337,9 @@ export function LendPageClient() {
: "text-zinc-500 dark:text-zinc-400"
}`}
>
- {depositPrecisionError ?? depositHelper ?? "Up to 7 decimal places supported."}
+ {depositPrecisionError ??
+ depositHelper ??
+ `Up to ${depositDecimals} decimal places supported.`}