feat(vault): god-mode improvement for the v3 Loans and Activity#2128
feat(vault): god-mode improvement for the v3 Loans and Activity#2128jeremy-babylonlabs wants to merge 2 commits into
Conversation
…y pages Add `loan` and `activity` mock types so the panel drives the two v3 pages that had no injectable state. Loan mocks render as Active Loans rows (four scenarios: borrowable, repay-only, missing liquidity read, pending APR) with the summary totalling the rendered rows; activity mocks render in the feed (nine scenarios covering both flat log rows and the expandable liquidation group card), dated relative to now so the Today / Yesterday group headers apply. Add Loans summary overrides for the states a real position cannot be talked into on demand: a health factor per production band, and the borrow-capacity cards in their loading and error states. The forced health-factor status is derived with the real banding function so it cannot drift from production. Mount the panel once per route subtree (dev/GodModeMount) rather than a copy per page. Overview, Vaults, Loans and Activity now all get the debug sections as well, and the panel keeps its open/dragged position across navigation within a subtree. This replaces the per-page mounts added in #2124. Restyle the liquidation-analysis and position-notification debug sections to the panel's zinc chrome; they were light-theme purple cards sitting inside a fixed dark box. Mock rows are display-only: their ids and symbols resolve to no real reserve or event, both row actions stay disabled, nothing is polled or persisted, and the whole of src/dev is dropped from production builds.
🔐 Commit Signature Verification✅ All 2 commit(s) passed verification
Summary
Required key type: Last verified: 2026-07-23 14:40 UTC |
Greptile SummaryThis PR expands god mode across the v3 Loans and Activity pages. The main changes are:
Confidence Score: 4/5The Activity provider boundary and Loans override composition need fixes before merging.
services/vault/src/router.tsx, services/vault/src/components/pages/Loans.tsx, services/vault/src/hooks/useActivitiesWithPending.ts Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
R[Router] --> A[Aave route subtree]
R --> T[Activity subtree]
A --> AC[AaveConfigProvider]
AC --> PV[PendingVaultsProvider]
PV --> RO[ReorderOverrideProvider]
RO --> GM1[GodModeMount]
T --> AC2[AaveConfigProvider]
AC2 --> RO2[ReorderOverrideProvider]
RO2 --> GM2[GodModeMount]
GM2 -. missing pending-vault context .-> PV
Reviews (1): Last reviewed commit: "feat(vault): god-mode mocks and controls..." | Re-trigger Greptile |
| render on this page. */} | ||
| <ReorderOverrideProvider> | ||
| <Activity /> | ||
| <GodModePanelSlot /> |
There was a problem hiding this comment.
Activity Mount Misses Required Provider
When the position-notification debug flags are enabled on /activity, this mount renders PositionNotificationsDebugPanel outside the PendingVaultsProvider used by the main Aave subtree. Its pending or activating-vault context access can then throw instead of rendering the panel.
| const shownCapacityLoading = | ||
| borrowCapacityOverride?.loading || isBorrowCapacityLoading; | ||
| const shownCapacityError = | ||
| borrowCapacityOverride?.error ?? borrowCapacityError; |
There was a problem hiding this comment.
Forced State Retains Live Failure
The override fields are combined independently with live state. Selecting Error while the live request is loading keeps the loader active, while selecting Loading during a live error retains that error, so the panel does not show the forced state.
| const shownCapacityLoading = | |
| borrowCapacityOverride?.loading || isBorrowCapacityLoading; | |
| const shownCapacityError = | |
| borrowCapacityOverride?.error ?? borrowCapacityError; | |
| const shownCapacityLoading = borrowCapacityOverride | |
| ? borrowCapacityOverride.loading | |
| : isBorrowCapacityLoading; | |
| const shownCapacityError = borrowCapacityOverride | |
| ? borrowCapacityOverride.error | |
| : borrowCapacityError; |
| // With mocks injected there is something to render immediately, so the | ||
| // page must not sit on its spinner waiting for a query that, disconnected, | ||
| // will never resolve. | ||
| isLoading: demo && demo.rows.length > 0 ? false : isLoading, |
There was a problem hiding this comment.
When demo injection has hideReal enabled but contains no Activity mocks, the merged result is intentionally an empty demo-only feed. This condition still inherits the live query's loading state, so a disconnected Activity page can remain on its spinner instead of showing the empty feed.
| isLoading: demo && demo.rows.length > 0 ? false : isLoading, | |
| isLoading: | |
| demo && (demo.hideReal || demo.rows.length > 0) ? false : isLoading, |
… with it A forced borrow-capacity state was combined with the live one field by field, so selecting Error while the live read was loading kept the loader on screen and selecting Loading during a live error kept the error — the forced state never rendered. It now replaces the live pair wholesale. Hide-real with zero activity mocks is a deliberate empty demo-only feed, but it still inherited the live query's loading state, leaving a disconnected Activity page on its spinner. The demo now short-circuits the loading state whenever it governs the feed. Also record, at the Activity mount, the panel's audited context dependency set (AaveConfig, ReorderOverride, ActivatingVaults) and why PendingVaults is deliberately not duplicated there.
gbarkhatov
left a comment
There was a problem hiding this comment.
Approving. This is a well-structured, thoroughly tested extension of the dev-only god-mode tooling, and it stays clear of every critical value-movement path in CLAUDE.md. Nice touches: the health-factor status is re-derived with the real banding function (can't drift from prod), the borrow-capacity snapshots keep a stable identity for useSyncExternalStore, forced summary states replace the live state wholesale, and mock rows are provably action-inert with non-colliding ids.
Two inline notes below — one worth fixing (a stale comment), one optional dev-only nit.
Two non-blocking observations, no change required:
-
PR-description precision.
useActivitiesWithPending.tsandLoans.tsxstatically import fromdev/demoDeposit, so that module (and itsLOAN_SCENARIOS/ACTIVITY_SCENARIOSdata) sits in the production import graph and relies on Rollup DCE of theimport.meta.env.DEVdead branches to be stripped. "The whole ofsrc/devis dropped from production builds" is strictly true only for the dynamically-importedGodModeMount; the statically-imported demo hooks are inert-but-present (same pre-existing pattern asuseDemoLoan/useDemoCollateral). Functionally fine. -
useActivitiesWithPendingisLoadingflip (intended). When connected with the live query still loading and activity mocks injected,isLoadingflips tofalseimmediately, suppressing the real feed's spinner so real rows appear afterward. This is deliberate and already documented in the code comment — noting only for visibility.
|
|
||
| The page reads the indexer's activity list directly and does not | ||
| consume the demo store, so the panel drives theme, the protocol-status | ||
| / max-vaults overrides and the shared mock list here — no mock rows |
There was a problem hiding this comment.
This comment is now stale and contradicts the code. Activity → useActivitiesWithPending → useDemoActivity() merges demo rows into the returned feed, so mock activity rows do render on this page — including while disconnected. Activity.tsx's own comment says exactly that ("demo rows are merged in by this hook … so the feed can be exercised without a wallet"), and the PR description lists nine activity scenarios rendering here.
The rationale above about which providers are / aren't mounted is correct and worth keeping — please just fix this last sentence so it states that Activity renders mock rows via the demo store, rather than the opposite.
| /** Unit a mock item's amount is denominated in: BTC everywhere except loans, | ||
| * whose amount is the borrowed stablecoin. */ | ||
| function amountUnit(type: DemoType): string { | ||
| return type === "loan" ? "USDC" : "BTC"; |
There was a problem hiding this comment.
Dev-only nit: the amount field is labelled Amount (BTC) for activity mocks, but the Borrow and Repay activity scenarios ignore the amount arg and hard-code DEMO_ACTIVITY_DEBT_AMOUNT (USDC) — so for those two the control has no effect and the unit doesn't match the value the row shows. Deposit / withdraw / redeem / liquidation activity rows do use the amount as BTC, so the label is right for them. Low priority; if you want it tidy, derive the unit per activity scenario (and/or disable the field where it's inert). Not blocking.
Add
loanandactivitymock types so the panel drives the two v3 pages that had no injectable state. Loan mocks render as Active Loans rows (four scenarios: borrowable, repay-only, missing liquidity read, pending APR) with the summary totalling the rendered rows; activity mocks render in the feed (nine scenarios covering both flat log rows and the expandable liquidation group card), dated relative to now so the Today / Yesterday group headers apply.Add Loans summary overrides for the states a real position cannot be talked into on demand: a health factor per production band, and the borrow-capacity cards in their loading and error states. The forced health-factor status is derived with the real banding function so it cannot drift from production.
Mount the panel once per route subtree (dev/GodModeMount) rather than a copy per page. Overview, Vaults, Loans and Activity now all get the debug sections as well, and the panel keeps its open/dragged position across navigation within a subtree. This replaces the per-page mounts added in #2124.
Restyle the liquidation-analysis and position-notification debug sections to the panel's zinc chrome; they were light-theme purple cards sitting inside a fixed dark box.
Mock rows are display-only: their ids and symbols resolve to no real reserve or event, both row actions stay disabled, nothing is polled or persisted, and the whole of src/dev is dropped from production builds.