From 1968cd61f3d2bbed77596880e32c83a4463445ab Mon Sep 17 00:00:00 2001 From: Jonathan Bursztyn Date: Wed, 27 May 2026 13:54:46 +0700 Subject: [PATCH 1/4] feat(vault): show Healthy label when health factor exceeds 50 --- .../src/applications/aave/utils/healthFactorDisplay.ts | 8 ++++++++ services/vault/src/copy.ts | 1 + 2 files changed, 9 insertions(+) diff --git a/services/vault/src/applications/aave/utils/healthFactorDisplay.ts b/services/vault/src/applications/aave/utils/healthFactorDisplay.ts index 00a3b3faa..e8a8a6a65 100644 --- a/services/vault/src/applications/aave/utils/healthFactorDisplay.ts +++ b/services/vault/src/applications/aave/utils/healthFactorDisplay.ts @@ -1,5 +1,7 @@ import type { HealthFactorStatus } from "@babylonlabs-io/ts-sdk/tbv/integrations/aave"; +import { COPY } from "@/copy"; + import { HEALTH_FACTOR_DISPLAY_CAP } from "../constants"; export const HEALTH_FACTOR_COLORS = { @@ -27,6 +29,9 @@ export function getHealthFactorColor( } } +/** Above this value, the health factor is effectively unbounded and shown as "Healthy". */ +export const HEALTH_FACTOR_HEALTHY_THRESHOLD = 50; + export function formatHealthFactor(healthFactor: number | null): string { // null = no debt; non-finite or absurdly high = negligible debt. All render // as "-" ("infinitely healthy") rather than "Infinity" or the scientific @@ -38,5 +43,8 @@ export function formatHealthFactor(healthFactor: number | null): string { ) { return "-"; } + if (healthFactor > HEALTH_FACTOR_HEALTHY_THRESHOLD) { + return COPY.overview.healthFactorHealthy; + } return healthFactor.toFixed(2); } diff --git a/services/vault/src/copy.ts b/services/vault/src/copy.ts index a595f9320..0bb421b9b 100644 --- a/services/vault/src/copy.ts +++ b/services/vault/src/copy.ts @@ -701,6 +701,7 @@ export const COPY = { overview: { heading: "Overview", healthFactorLabel: "Health factor", + healthFactorHealthy: "Healthy", ltvLabel: "Current LTV", totalCollateralValueLabel: "Total collateral value", amountToRepayLabel: "Amount to repay", From 7c084a493a583d2159406c3ae8cf7a3c43bb5118 Mon Sep 17 00:00:00 2001 From: Jonathan Bursztyn Date: Thu, 28 May 2026 05:38:59 +0700 Subject: [PATCH 2/4] feat(vault): revisions --- .../src/applications/aave/utils/healthFactorDisplay.ts | 10 ++++------ services/vault/src/applications/aave/utils/index.ts | 1 + .../vault/src/components/simple/OverviewSection.tsx | 6 +++++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/services/vault/src/applications/aave/utils/healthFactorDisplay.ts b/services/vault/src/applications/aave/utils/healthFactorDisplay.ts index e8a8a6a65..bdb86f999 100644 --- a/services/vault/src/applications/aave/utils/healthFactorDisplay.ts +++ b/services/vault/src/applications/aave/utils/healthFactorDisplay.ts @@ -1,9 +1,8 @@ import type { HealthFactorStatus } from "@babylonlabs-io/ts-sdk/tbv/integrations/aave"; -import { COPY } from "@/copy"; - import { HEALTH_FACTOR_DISPLAY_CAP } from "../constants"; + export const HEALTH_FACTOR_COLORS = { GREEN: "#00E676", AMBER: "#FFC400", @@ -29,7 +28,9 @@ export function getHealthFactorColor( } } -/** Above this value, the health factor is effectively unbounded and shown as "Healthy". */ +/** Above this value, the health factor is effectively unbounded. Callers that show + * a high-HF label (e.g. the Overview row) use this; numeric before/after deltas + * intentionally do not, to preserve the magnitude of the change. */ export const HEALTH_FACTOR_HEALTHY_THRESHOLD = 50; export function formatHealthFactor(healthFactor: number | null): string { @@ -43,8 +44,5 @@ export function formatHealthFactor(healthFactor: number | null): string { ) { return "-"; } - if (healthFactor > HEALTH_FACTOR_HEALTHY_THRESHOLD) { - return COPY.overview.healthFactorHealthy; - } return healthFactor.toFixed(2); } diff --git a/services/vault/src/applications/aave/utils/index.ts b/services/vault/src/applications/aave/utils/index.ts index dacc2bc44..b15ef0eee 100644 --- a/services/vault/src/applications/aave/utils/index.ts +++ b/services/vault/src/applications/aave/utils/index.ts @@ -19,6 +19,7 @@ export type { // Display utilities (frontend-only, not in SDK) export { HEALTH_FACTOR_COLORS, + HEALTH_FACTOR_HEALTHY_THRESHOLD, formatHealthFactor, getHealthFactorColor, } from "./healthFactorDisplay"; diff --git a/services/vault/src/components/simple/OverviewSection.tsx b/services/vault/src/components/simple/OverviewSection.tsx index 615a0ad11..94663a8d5 100644 --- a/services/vault/src/components/simple/OverviewSection.tsx +++ b/services/vault/src/components/simple/OverviewSection.tsx @@ -8,6 +8,7 @@ import { formatHealthFactor, getHealthFactorColor, + HEALTH_FACTOR_HEALTHY_THRESHOLD, type HealthFactorStatus, } from "@/applications/aave/utils"; import { HealthFactorGauge, HeartIcon } from "@/components/shared"; @@ -37,7 +38,10 @@ export function OverviewSection({ return ; } - const healthFactorFormatted = formatHealthFactor(healthFactor); + const healthFactorFormatted = + healthFactor !== null && healthFactor > HEALTH_FACTOR_HEALTHY_THRESHOLD + ? COPY.overview.healthFactorHealthy + : formatHealthFactor(healthFactor); const healthFactorColor = getHealthFactorColor(healthFactorStatus); const showHealthFactor = healthFactor !== null; From 88ac9e0afcaf174df92b46b61622e9e480bc91ef Mon Sep 17 00:00:00 2001 From: Jonathan Bursztyn Date: Tue, 9 Jun 2026 14:22:52 +0700 Subject: [PATCH 3/4] feat(vault): revisions --- .../utils/__tests__/healthFactorDisplay.test.ts | 17 ++++++++++++++++- .../shared/utils/healthFactorGauge.ts | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/services/vault/src/applications/aave/utils/__tests__/healthFactorDisplay.test.ts b/services/vault/src/applications/aave/utils/__tests__/healthFactorDisplay.test.ts index 949204005..0afe8fc87 100644 --- a/services/vault/src/applications/aave/utils/__tests__/healthFactorDisplay.test.ts +++ b/services/vault/src/applications/aave/utils/__tests__/healthFactorDisplay.test.ts @@ -1,7 +1,10 @@ import { describe, expect, it } from "vitest"; import { HEALTH_FACTOR_DISPLAY_CAP } from "../../constants"; -import { formatHealthFactor } from "../healthFactorDisplay"; +import { + formatHealthFactor, + HEALTH_FACTOR_HEALTHY_THRESHOLD, +} from "../healthFactorDisplay"; describe("formatHealthFactor", () => { it("returns '-' when there is no debt (null)", () => { @@ -31,4 +34,16 @@ describe("formatHealthFactor", () => { `${HEALTH_FACTOR_DISPLAY_CAP}.00`, ); }); + + it("returns the raw number for high HF (delta callers depend on this)", () => { + // formatHealthFactor must never substitute a label for high values — + // callers that show deltas (e.g. action review) need the numeric string + // to compute before/after diffs. The label substitution lives at the + // call site, not here. + expect(formatHealthFactor(HEALTH_FACTOR_HEALTHY_THRESHOLD)).toBe("50.00"); + expect(formatHealthFactor(HEALTH_FACTOR_HEALTHY_THRESHOLD + 1)).toBe( + "51.00", + ); + expect(formatHealthFactor(100)).toBe("100.00"); + }); }); diff --git a/services/vault/src/components/shared/utils/healthFactorGauge.ts b/services/vault/src/components/shared/utils/healthFactorGauge.ts index 9214b3d4f..54c809a17 100644 --- a/services/vault/src/components/shared/utils/healthFactorGauge.ts +++ b/services/vault/src/components/shared/utils/healthFactorGauge.ts @@ -2,12 +2,13 @@ import { HEALTH_FACTOR_COLORS, type HealthFactorStatus, } from "@/applications/aave/utils"; +import { COPY } from "@/copy"; export const STATUS_LABELS: Record< Exclude, string > = { - safe: "Healthy", + safe: COPY.overview.healthFactorHealthy, warning: "At Risk", danger: "Liquidatable", } satisfies Record; From 253581ed59a6fce0eb2e99746fc2997a1855213b Mon Sep 17 00:00:00 2001 From: Jonathan Bursztyn Date: Tue, 9 Jun 2026 14:28:18 +0700 Subject: [PATCH 4/4] feat(vault): revisions --- .../tests/unit/deriveContextHash.test.ts | 6 +++--- .../src/applications/aave/utils/healthFactorDisplay.ts | 1 - .../src/context/wallet/VaultWalletConnectionProvider.tsx | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/babylon-wallet-connector/tests/unit/deriveContextHash.test.ts b/packages/babylon-wallet-connector/tests/unit/deriveContextHash.test.ts index 8ef3aea52..6ac913b6a 100644 --- a/packages/babylon-wallet-connector/tests/unit/deriveContextHash.test.ts +++ b/packages/babylon-wallet-connector/tests/unit/deriveContextHash.test.ts @@ -2,10 +2,10 @@ * Unit tests for `deriveContextHash` adapter behavior. * * Tests the shared `unsupportedDeriveContextHash` helper used by every - * non-supporting BTC adapter (OKX, Ledger v1/v2, AppKit, Tomo, + * non-supporting BTC adapter (OKX, Ledger v1/v2, Keystone, AppKit, Tomo, * Injectable fallback) and the injectable wrapper that stubs the method - * when the underlying wallet doesn't implement it. UniSat, OneKey, and - * Keystone implement the method natively instead of using this helper. + * when the underlying wallet doesn't implement it. UniSat and OneKey + * forward to the wallet's native method instead of using this helper. * * The provider classes themselves are not imported here — their * modules transitively pull in SVG asset imports that the unit-test diff --git a/services/vault/src/applications/aave/utils/healthFactorDisplay.ts b/services/vault/src/applications/aave/utils/healthFactorDisplay.ts index bdb86f999..f4e37d332 100644 --- a/services/vault/src/applications/aave/utils/healthFactorDisplay.ts +++ b/services/vault/src/applications/aave/utils/healthFactorDisplay.ts @@ -2,7 +2,6 @@ import type { HealthFactorStatus } from "@babylonlabs-io/ts-sdk/tbv/integrations import { HEALTH_FACTOR_DISPLAY_CAP } from "../constants"; - export const HEALTH_FACTOR_COLORS = { GREEN: "#00E676", AMBER: "#FFC400", diff --git a/services/vault/src/context/wallet/VaultWalletConnectionProvider.tsx b/services/vault/src/context/wallet/VaultWalletConnectionProvider.tsx index 73bd966a2..1edae7132 100644 --- a/services/vault/src/context/wallet/VaultWalletConnectionProvider.tsx +++ b/services/vault/src/context/wallet/VaultWalletConnectionProvider.tsx @@ -21,10 +21,10 @@ import { getNetworkConfigETH } from "@/config/network"; import { logger } from "@/infrastructure"; // Vault deposits require the connected BTC wallet to implement the -// `deriveContextHash` API (see docs/specs/derive-context-hash.md). UniSat, -// OneKey, and Keystone expose a conformant implementation today, so every -// other BTC adapter is gated off here. Re-enable an entry as soon as its -// wallet vendor ships `deriveContextHash`. Each non-conforming adapter still +// `deriveContextHash` API (see docs/specs/derive-context-hash.md). UniSat +// and OneKey expose a conformant implementation today, so every other BTC +// adapter is gated off here. Re-enable an entry as soon as its wallet +// vendor ships `deriveContextHash`. Each non-conforming adapter still // throws `WALLET_METHOD_NOT_SUPPORTED` at the connector layer; this // list just keeps them out of the connection UI in the first place so // users don't pick something that can't complete a deposit.