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.`}