Skip to content

feat: display APR#227

Merged
antoncoding merged 5 commits intomasterfrom
feat/apr
Dec 8, 2025
Merged

feat: display APR#227
antoncoding merged 5 commits intomasterfrom
feat/apr

Conversation

@antoncoding
Copy link
Owner

@antoncoding antoncoding commented Dec 8, 2025

resolves #206

Summary by CodeRabbit

  • New Features

    • Added a persistent Display Settings toggle to show APR instead of APY; labels update across markets, vaults, positions, charts, tables, and tooltips.
    • Unified rate formatting and APR conversion so displayed rates and labels are consistent throughout the UI.
  • Chores

    • Updated local settings and ignore list to include new config and context files.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Contributor

vercel bot commented Dec 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
monarch Ready Ready Preview Comment Dec 8, 2025 8:43am

@coderabbitai
Copy link

coderabbitai bot commented Dec 8, 2025

📝 Walkthrough

Walkthrough

Adds a persisted global "Show APR Instead of APY" toggle and applies APR conversion + dynamic rate labels across UI. Introduces useRateLabel, RateFormatted, and convertApyToApr; extends MarketsContext; updates charts, tables, tooltips, settings, and many position/vault components.

Changes

Cohort / File(s) Summary
Configuration
​.claude/settings.local.json, .gitignore
Add local settings file to .gitignore and add a Bash allowlist entry in local settings.
Context & persistence
src/contexts/MarketsContext.tsx
Add isAprDisplay + setIsAprDisplay to MarketsContext with localStorage-backed state (settings-apr-display).
Utilities & formatting
src/utils/rateMath.ts, src/hooks/useRateLabel.ts, src/components/common/RateFormatted.tsx
Add convertApyToApr and formatRateAsPercentage; add useRateLabel hook for dynamic "APY"/"APR" labels; add RateFormatted component to render formatted rates.
Settings UI
app/settings/page.tsx
Add Display Settings toggle bound to isAprDisplay/setIsAprDisplay.
Charts & stats
app/market/[chainId]/[marketid]/RateChart.tsx, app/market/[chainId]/[marketid]/components/PositionStats.tsx
Make chart data and computed current/average values APR-aware, memoize chart data, and use dynamic rate labels.
Market tables & tooltip
app/markets/components/APYBreakdownTooltip.tsx, app/markets/components/MarketTableBody.tsx, app/markets/components/marketsTable.tsx
Replace static "APY" labels with dynamic labels via useRateLabel; make tooltip compute totals internally (remove fullAPY prop) and apply APR conversion where appropriate.
Vault views
app/autovault/components/VaultListV2.tsx, app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
Use useMarkets/useRateLabel and convertApyToApr to show APR when enabled; dynamic headers and rate rendering added.
Positions & reports
app/positions/components/*.tsx, app/positions/report/components/ReportTable.tsx
Multiple position components and report table updated to use useRateLabel, RateFormatted, and conditional APR conversion (e.g., SuppliedMarketsDetail, PositionsSummaryTable, RebalanceActionRow, FromMarketsTable, ApyPreview, ReportTable). Some MarketRow props updated where applicable.
Market details & shared blocks
src/components/common/MarketDetailsBlock.tsx, src/components/common/MarketsTableWithSameLoanAsset.tsx
Replace APY helpers with rate-aware helpers and labels; MarketRow / MarketsTableWithSameLoanAsset updated to accept/pass rate labels and isAprDisplay.
Misc UI updates
many table/row components (e.g., app/autovault/.../allocations/MarketView.tsx, app/positions/...)
Widespread label and rendering updates to use rateLabel and conditional conversion; many components import/use useMarkets, useRateLabel, and convertApyToApr.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant SettingsPage
  participant MarketsProvider as MarketsContext
  participant LocalStorage
  participant Consumer

  User->>SettingsPage: toggle "Show APR Instead of APY"
  SettingsPage->>MarketsProvider: setIsAprDisplay(true/false)
  MarketsProvider->>LocalStorage: persist 'settings-apr-display'
  MarketsProvider-->>Consumer: update context (isAprDisplay)
  Consumer->>Consumer: useRateLabel() / convertApyToApr() when rendering
  Consumer-->>User: render updated rate label and values
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • MarketsContext changes and localStorage key/initialization.
    • APYBreakdownTooltip prop removal (fullAPY) and all call sites.
    • Correct and consistent application of convertApyToApr (edge cases: apy ≤ -1, apy === 0).
    • Prop changes to MarketRow / MarketsTableWithSameLoanAsset and any downstream usages that must be updated.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: display APR' clearly and concisely summarizes the main change: adding APR display functionality throughout the application.
Linked Issues check ✅ Passed All requirements from issue #206 are met: APR display option added, APR defined as ln(1+APY), global setting implemented via useMarkets hook and MarketsContext.
Out of Scope Changes check ✅ Passed All changes directly support APR display feature. Config file updates (.claude/settings.local.json, .gitignore) and new context/utility files are necessary infrastructure for the feature.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/apr

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/common/MarketDetailsBlock.tsx (1)

200-214: Label inconsistency: hardcoded "APY" in expanded view.

Line 202 still shows {mode === 'supply' ? 'Supply' : 'Borrow'} APY: regardless of display mode. Should use rateLabel to be consistent with the rest of the feature.

                     <p className="font-zen text-sm opacity-50">
-                        {mode === 'supply' ? 'Supply' : 'Borrow'} APY:
+                        {mode === 'supply' ? 'Supply' : 'Borrow'} {rateLabel}:
                      </p>
app/market/[chainId]/[marketid]/RateChart.tsx (1)

273-290: Sidebar labels still hardcoded as "APY".

"Current Rates" section (lines 274, 280) and "Historical Averages" section (lines 311, 317) show "Supply APY" and "Borrow APY" regardless of display mode. Should use rateLabel for consistency with the chart legend.

                 <div className="flex items-center justify-between">
-                  <span>Supply APY:</span>
+                  <span>Supply {rateLabel}:</span>
                   <span className="font-zen text-sm">
                     {formatPercentage(getCurrentApyValue('supply'))}
                   </span>
                 </div>
                 <div className="flex items-center justify-between">
-                  <span>Borrow APY:</span>
+                  <span>Borrow {rateLabel}:</span>

Same fix needed in the "Historical Averages" section at lines 311 and 317.

🧹 Nitpick comments (1)
src/components/common/RateFormatted.tsx (1)

1-56: Clean reusable component.

Good documentation with examples. The implementation correctly handles APR/APY conversion based on global settings.

One small thing: the React import on line 1 is unused since you're not using React. prefix anywhere.

-import React from 'react';
+import { useMarkets } from '@/hooks/useMarkets';
-import { useMarkets } from '@/hooks/useMarkets';

Or just remove it entirely if JSX transform handles it automatically.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 084735b and 5118c0b.

📒 Files selected for processing (17)
  • .claude/settings.local.json (1 hunks)
  • .gitignore (1 hunks)
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx (5 hunks)
  • app/autovault/components/VaultListV2.tsx (4 hunks)
  • app/market/[chainId]/[marketid]/RateChart.tsx (6 hunks)
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx (4 hunks)
  • app/markets/components/APYBreakdownTooltip.tsx (5 hunks)
  • app/markets/components/MarketTableBody.tsx (3 hunks)
  • app/markets/components/marketsTable.tsx (4 hunks)
  • app/positions/components/SuppliedMarketsDetail.tsx (4 hunks)
  • app/positions/report/components/ReportTable.tsx (5 hunks)
  • app/settings/page.tsx (2 hunks)
  • src/components/common/MarketDetailsBlock.tsx (5 hunks)
  • src/components/common/RateFormatted.tsx (1 hunks)
  • src/contexts/MarketsContext.tsx (4 hunks)
  • src/hooks/useRateLabel.ts (1 hunks)
  • src/utils/rateMath.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Run pnpm format (Prettier) before pushing with 2-space indentation, 100-character width, single quotes, and Tailwind-aware class ordering

Files:

  • src/utils/rateMath.ts
  • app/autovault/components/VaultListV2.tsx
  • src/components/common/RateFormatted.tsx
  • app/positions/report/components/ReportTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/settings/page.tsx
  • src/hooks/useRateLabel.ts
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx
  • app/market/[chainId]/[marketid]/RateChart.tsx
  • app/markets/components/APYBreakdownTooltip.tsx
  • src/contexts/MarketsContext.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use camelCase for helper function names (e.g., formatApr)

Files:

  • src/utils/rateMath.ts
  • src/components/common/RateFormatted.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/hooks/useRateLabel.ts
  • src/contexts/MarketsContext.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

ESLint (Airbnb + Next.js) enforces hook safety and import hygiene

Files:

  • src/utils/rateMath.ts
  • app/autovault/components/VaultListV2.tsx
  • src/components/common/RateFormatted.tsx
  • app/positions/report/components/ReportTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/settings/page.tsx
  • src/hooks/useRateLabel.ts
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx
  • app/market/[chainId]/[marketid]/RateChart.tsx
  • app/markets/components/APYBreakdownTooltip.tsx
  • src/contexts/MarketsContext.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
app/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Next.js routes must live under app/ directory

Files:

  • app/autovault/components/VaultListV2.tsx
  • app/positions/report/components/ReportTable.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/settings/page.tsx
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx
  • app/market/[chainId]/[marketid]/RateChart.tsx
  • app/markets/components/APYBreakdownTooltip.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Use PascalCase for React component file names (e.g., VaultBanner.tsx)

Files:

  • app/autovault/components/VaultListV2.tsx
  • src/components/common/RateFormatted.tsx
  • app/positions/report/components/ReportTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/settings/page.tsx
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx
  • app/market/[chainId]/[marketid]/RateChart.tsx
  • app/markets/components/APYBreakdownTooltip.tsx
  • src/contexts/MarketsContext.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{tsx,jsx}: Keep Tailwind class lists lean and dedupe variants with tailwind-merge
All toggles must use the shared IconSwitch component from @/components/common/IconSwitch for consistent sizing and animation

Files:

  • app/autovault/components/VaultListV2.tsx
  • src/components/common/RateFormatted.tsx
  • app/positions/report/components/ReportTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/settings/page.tsx
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx
  • app/market/[chainId]/[marketid]/RateChart.tsx
  • app/markets/components/APYBreakdownTooltip.tsx
  • src/contexts/MarketsContext.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
src/hooks/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When building on-chain hooks, mirror useERC20Approval and useTransactionWithToast patterns and memoize arrays/objects before using them in effect dependencies to prevent redundant RPC calls

Files:

  • src/hooks/useRateLabel.ts
🧠 Learnings (5)
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to src/**/*.{ts,tsx} : Use camelCase for helper function names (e.g., `formatApr`)

Applied to files:

  • src/utils/rateMath.ts
  • src/components/common/RateFormatted.tsx
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to src/hooks/**/*.{ts,tsx} : When building on-chain hooks, mirror `useERC20Approval` and `useTransactionWithToast` patterns and memoize arrays/objects before using them in effect dependencies to prevent redundant RPC calls

Applied to files:

  • app/autovault/components/VaultListV2.tsx
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 63
File: app/markets/components/MarketRowDetail.tsx:49-52
Timestamp: 2024-10-12T09:23:16.495Z
Learning: When rendering oracle feeds in `ExpandedMarketDetail` (`app/markets/components/MarketRowDetail.tsx`), prefer explicit rendering over iterating keys when dealing with a small number of feeds.

Applied to files:

  • app/positions/report/components/ReportTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.

Applied to files:

  • src/components/common/MarketDetailsBlock.tsx
  • app/markets/components/MarketTableBody.tsx
  • app/markets/components/marketsTable.tsx
  • app/settings/page.tsx
  • app/market/[chainId]/[marketid]/components/PositionStats.tsx
  • app/market/[chainId]/[marketid]/RateChart.tsx
  • app/markets/components/APYBreakdownTooltip.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
📚 Learning: 2024-11-20T07:21:06.756Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 83
File: app/settings/page.tsx:8-16
Timestamp: 2024-11-20T07:21:06.756Z
Learning: In `app/settings/page.tsx`, the default value for `usePermit2` is intentionally set to `true`.

Applied to files:

  • app/settings/page.tsx
🧬 Code graph analysis (14)
app/autovault/components/VaultListV2.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/components/common/RateFormatted.tsx (2)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
app/positions/report/components/ReportTable.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/components/common/MarketDetailsBlock.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
app/markets/components/MarketTableBody.tsx (3)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/markets/components/APYBreakdownTooltip.tsx (1)
  • APYCell (83-114)
src/components/common/RateFormatted.tsx (1)
  • RateFormatted (38-56)
app/markets/components/marketsTable.tsx (1)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/settings/page.tsx (2)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/components/common/IconSwitch.tsx (1)
  • IconSwitch (89-201)
src/hooks/useRateLabel.ts (1)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
app/market/[chainId]/[marketid]/components/PositionStats.tsx (4)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
app/markets/components/APYBreakdownTooltip.tsx (1)
  • APYBreakdownTooltip (21-81)
app/market/[chainId]/[marketid]/RateChart.tsx (4)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/types.ts (1)
  • TimeseriesDataPoint (347-350)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
app/markets/components/APYBreakdownTooltip.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/contexts/MarketsContext.tsx (1)
src/hooks/useLocalStorage.ts (1)
  • useLocalStorage (4-66)
app/positions/components/SuppliedMarketsDetail.tsx (2)
src/components/common/RateFormatted.tsx (1)
  • RateFormatted (38-56)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
🔇 Additional comments (28)
.claude/settings.local.json (1)

31-32: Clarify scope: is this permission related to the APR feature?

The new permission "Bash(oracle ask:*)" doesn't appear to connect to the APR display feature described in the PR objectives. Confirm whether this is intentional or an incidental change that should be excluded from this PR.

.gitignore (1)

53-55: Good call ignoring local configuration files.

These entries prevent committing local development artifacts. In particular, ignoring .claude/settings.local.json ensures user-specific tool configs don't pollute the repo.

src/utils/rateMath.ts (1)

1-40: APR conversion and formatting look correct

convertApyToApr matches the specified APR = ln(1 + APY) definition with sensible edge-case handling, and formatRateAsPercentage is straightforward and consistent with the rest of the PR.

app/markets/components/APYBreakdownTooltip.tsx (1)

26-64: APR/APY toggle and breakdown math are consistent

Using isAprDisplay + useRateLabel for labels and convertApyToApr(baseAPY / 100) * 100 to switch the base rate into APR while leaving reward APRs as-is keeps the units aligned (baseRateValue and rewardTotal are both percentages). Tooltip content tracks the same mode, so behavior here looks sound.

app/markets/components/marketsTable.tsx (1)

59-61: Dynamic supply/borrow headers wired correctly

Using useRateLabel with prefix: 'Supply' | 'Borrow' for the sortable column labels cleanly hooks the table headers into the global APR/APY display mode.

Also applies to: 153-169

app/markets/components/MarketTableBody.tsx (1)

50-52: Borrow/supply rate columns now fully APR/APY-aware

useRateLabel-driven data-labels plus APYCell for supply and RateFormatted for borrow cleanly hook both columns into the global APR/APY toggle, including mobile labels.

Also applies to: 206-217

src/hooks/useRateLabel.ts (1)

1-65: Hook API and memoization look solid

useRateLabel cleanly exposes label/short/description based on isAprDisplay, with stable memoization keys and enough flexibility via prefix/suffix for all current call sites.

src/contexts/MarketsContext.tsx (1)

37-43: Global APR display flag is correctly wired and persisted

isAprDisplay/setIsAprDisplay are added to the context, persisted via useLocalStorage('settings-apr-display', false), and properly included in the memoized value. This gives a single, global switch for APR vs APY that the rest of the PR builds on.

Also applies to: 69-71, 320-363

app/positions/report/components/ReportTable.tsx (4)

16-23: Imports look good.

New imports for APR display feature are correctly placed and used throughout the component.


74-78: APR conversion logic is correct.

The conditional conversion and dynamic label usage follow the established pattern from other components.


136-143: Grouped rate conversion follows the same pattern.

Consistent implementation with MarketSummaryBlock above.


203-204: Summary section correctly uses dynamic label and converted rate.

The rateLabel and displayGroupedRate are applied consistently.

app/settings/page.tsx (2)

28-28: Correctly extracts APR display state from context.

The destructuring is clean and follows the existing pattern for other settings.


90-117: Display Settings section is well-structured.

Uses IconSwitch as required. Clear explanations of APR vs APY. Matches the styling of other settings sections.

Minor note: other toggles in this file use custom icons (GoShield/GoShieldCheck) for visual distinction. This one uses the default butterfly. Intentional?

src/components/common/MarketDetailsBlock.tsx (3)

39-40: Hook usage is correct.

Placed at component level, following React rules.


64-77: Rate helper functions are straightforward.

The conversion logic is correct and consistent with other components.


147-155: Collapsed view correctly uses dynamic rateLabel.

Good implementation with the strikethrough for preview states.

app/market/[chainId]/[marketid]/RateChart.tsx (4)

42-43: Hook setup looks good.

Correctly placed at component level.


51-68: Good use of useMemo for chart data.

Proper memoization with correct dependencies. APR conversion is applied consistently to all data series.


72-100: Helper functions correctly apply APR conversion.

The pattern is consistent across all rate getters.


220-233: Chart legend uses dynamic rateLabel.

Good - matches the display mode setting.

app/autovault/[chainId]/[vaultAddress]/components/allocations/MarketView.tsx (3)

2-3: LGTM!

Imports and hook usage are correct. Renaming short to rateLabel improves readability.

Also applies to: 7-7, 26-27


55-56: LGTM!

Conversion logic correctly handles decimal-to-percentage transformation after optional APR conversion.


42-42: LGTM!

Dynamic label and display value are consistent.

Also applies to: 80-82

app/market/[chainId]/[marketid]/components/PositionStats.tsx (4)

11-11: LGTM!

Using label with prefixes gives contextual labels like "Supply APR" - fits this UI.

Also applies to: 14-14, 56-58


147-159: LGTM!

Rate calculations are correct. baseSupplyAPY is retained for the tooltip while baseSupplyRate handles display conversion.


206-223: LGTM!

Tooltip receives baseSupplyAPY (percentage) and handles its own conversion internally. Display uses pre-converted baseSupplyRate.


226-230: LGTM!

Borrow rate display follows the same pattern as supply.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5118c0b and 3ddfe9c.

📒 Files selected for processing (10)
  • app/autovault/components/VaultListV2.tsx (4 hunks)
  • app/markets/components/MarketTableBody.tsx (3 hunks)
  • app/positions/components/ApyPreview.tsx (2 hunks)
  • app/positions/components/FromMarketsTable.tsx (4 hunks)
  • app/positions/components/PositionsSummaryTable.tsx (4 hunks)
  • app/positions/components/RebalanceActionRow.tsx (3 hunks)
  • app/positions/components/SuppliedMarketsDetail.tsx (6 hunks)
  • app/positions/components/onboarding/SetupPositions.tsx (4 hunks)
  • src/components/common/MarketDetailsBlock.tsx (5 hunks)
  • src/components/common/MarketsTableWithSameLoanAsset.tsx (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/markets/components/MarketTableBody.tsx
🧰 Additional context used
📓 Path-based instructions (6)
app/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Next.js routes must live under app/ directory

Files:

  • app/positions/components/ApyPreview.tsx
  • app/positions/components/RebalanceActionRow.tsx
  • app/positions/components/onboarding/SetupPositions.tsx
  • app/autovault/components/VaultListV2.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
**/*.{ts,tsx,js,jsx,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Run pnpm format (Prettier) before pushing with 2-space indentation, 100-character width, single quotes, and Tailwind-aware class ordering

Files:

  • app/positions/components/ApyPreview.tsx
  • app/positions/components/RebalanceActionRow.tsx
  • app/positions/components/onboarding/SetupPositions.tsx
  • app/autovault/components/VaultListV2.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Use PascalCase for React component file names (e.g., VaultBanner.tsx)

Files:

  • app/positions/components/ApyPreview.tsx
  • app/positions/components/RebalanceActionRow.tsx
  • app/positions/components/onboarding/SetupPositions.tsx
  • app/autovault/components/VaultListV2.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{tsx,jsx}: Keep Tailwind class lists lean and dedupe variants with tailwind-merge
All toggles must use the shared IconSwitch component from @/components/common/IconSwitch for consistent sizing and animation

Files:

  • app/positions/components/ApyPreview.tsx
  • app/positions/components/RebalanceActionRow.tsx
  • app/positions/components/onboarding/SetupPositions.tsx
  • app/autovault/components/VaultListV2.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

ESLint (Airbnb + Next.js) enforces hook safety and import hygiene

Files:

  • app/positions/components/ApyPreview.tsx
  • app/positions/components/RebalanceActionRow.tsx
  • app/positions/components/onboarding/SetupPositions.tsx
  • app/autovault/components/VaultListV2.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use camelCase for helper function names (e.g., formatApr)

Files:

  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
🧠 Learnings (5)
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.

Applied to files:

  • app/positions/components/ApyPreview.tsx
  • app/positions/components/RebalanceActionRow.tsx
  • app/positions/components/onboarding/SetupPositions.tsx
  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to src/hooks/**/*.{ts,tsx} : When building on-chain hooks, mirror `useERC20Approval` and `useTransactionWithToast` patterns and memoize arrays/objects before using them in effect dependencies to prevent redundant RPC calls

Applied to files:

  • app/positions/components/onboarding/SetupPositions.tsx
  • app/autovault/components/VaultListV2.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
📚 Learning: 2024-12-16T02:01:51.219Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 97
File: app/positions/components/onboarding/OnboardingContext.tsx:36-43
Timestamp: 2024-12-16T02:01:51.219Z
Learning: In `app/positions/components/onboarding/OnboardingContext.tsx`, the `defaultStep` variable is no longer needed and can be removed.

Applied to files:

  • app/positions/components/onboarding/SetupPositions.tsx
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 63
File: app/markets/components/MarketRowDetail.tsx:49-52
Timestamp: 2024-10-12T09:23:16.495Z
Learning: When rendering oracle feeds in `ExpandedMarketDetail` (`app/markets/components/MarketRowDetail.tsx`), prefer explicit rendering over iterating keys when dealing with a small number of feeds.

Applied to files:

  • app/positions/components/SuppliedMarketsDetail.tsx
  • app/positions/components/FromMarketsTable.tsx
  • src/components/common/MarketDetailsBlock.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to src/**/*.{ts,tsx} : Use camelCase for helper function names (e.g., `formatApr`)

Applied to files:

  • app/positions/components/FromMarketsTable.tsx
  • app/positions/components/PositionsSummaryTable.tsx
🧬 Code graph analysis (9)
app/positions/components/ApyPreview.tsx (2)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/positions/components/MetricPreview.tsx (1)
  • MetricPreview (17-51)
app/positions/components/RebalanceActionRow.tsx (1)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/positions/components/onboarding/SetupPositions.tsx (1)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/autovault/components/VaultListV2.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
app/positions/components/SuppliedMarketsDetail.tsx (3)
src/utils/types.ts (1)
  • MarketPosition (12-21)
src/components/common/RateFormatted.tsx (1)
  • RateFormatted (38-56)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
app/positions/components/FromMarketsTable.tsx (3)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/balance.ts (1)
  • formatReadable (25-46)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
app/positions/components/PositionsSummaryTable.tsx (4)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/balance.ts (1)
  • formatReadable (25-46)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/components/common/MarketDetailsBlock.tsx (3)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/components/common/MarketsTableWithSameLoanAsset.tsx (4)
app/markets/components/columnVisibility.ts (1)
  • ColumnVisibility (3-12)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
🔇 Additional comments (13)
app/positions/components/ApyPreview.tsx (1)

2-16: APR label wiring into preview looks correct

Importing useRateLabel and passing its short value through to MetricPreview is clean and keeps rate display in sync with the global APR/APY setting. No issues from a hook or typing standpoint.

app/positions/components/SuppliedMarketsDetail.tsx (2)

62-63: Past review feedback addressed.

The data-label is now dynamically set to {rateLabel}, syncing with the APR/APY toggle for narrow layouts.


118-119: Clean hook usage and prop threading.

useRateLabel called at component top level, rateLabel flows consistently to both the table header and row cells via props.

Also applies to: 195-195, 211-211

app/positions/components/RebalanceActionRow.tsx (1)

7-7: LGTM!

Clean integration of the useRateLabel hook. The dynamic label correctly replaces the hardcoded "APY" text in the column header.

Also applies to: 57-58, 164-168

app/positions/components/onboarding/SetupPositions.tsx (1)

13-13: LGTM!

Dynamic rate labeling integrated correctly. The APYCell component should handle the APR/APY conversion internally based on the global isAprDisplay setting.

Also applies to: 22-22, 296-296, 321-323

app/positions/components/PositionsSummaryTable.tsx (1)

26-31: LGTM!

Correct implementation:

  • isAprDisplay flag controls the conversion
  • convertApyToApr applied before percentage multiplication
  • Dynamic label in header and data-label

Also applies to: 163-164, 308-308, 372-376

app/positions/components/FromMarketsTable.tsx (1)

5-9: LGTM!

All APY display paths (current, preview, static) consistently apply the APR conversion when isAprDisplay is true.

Also applies to: 30-31, 66-66, 110-135

src/components/common/MarketsTableWithSameLoanAsset.tsx (3)

20-20: LGTM!

Good setup: useRateLabel with prefixes creates "Supply APR/APY" and "Borrow APR/APY" labels. Props cleanly passed to MarketRow.

Also applies to: 25-25, 432-444, 576-579


521-550: LGTM!

All rate columns (Supply APY, Borrow APY, Rate at Target) consistently apply convertApyToApr when isAprDisplay is true. Data labels match the dynamic rate labels.


1029-1046: LGTM!

Header labels and MarketRow props are wired up correctly.

Also applies to: 1085-1088

app/autovault/components/VaultListV2.tsx (1)

9-10: Approved: Zero APY handling fixed, APR integration looks solid.

The previous concern about zero APY being hidden by truthy checks has been resolved. The current code uses vault.avgApy != null which correctly allows 0 while filtering out null/undefined. The APR conversion logic is properly conditional, and the dynamic labeling is consistent throughout.

Also applies to: 14-14, 23-24, 61-61, 103-109

src/components/common/MarketDetailsBlock.tsx (2)

64-69: LGTM!

The rate calculation correctly applies APR conversion when needed and formats the output consistently.


145-156: LGTM!

The rendering logic consistently uses dynamic rate labels and correctly displays rate transitions in both collapsed and expanded views.

Also applies to: 202-214

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ddfe9c and 31e67fb.

📒 Files selected for processing (2)
  • app/positions/components/PositionsSummaryTable.tsx (5 hunks)
  • src/components/common/MarketsTableWithSameLoanAsset.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
app/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Next.js routes must live under app/ directory

Files:

  • app/positions/components/PositionsSummaryTable.tsx
**/*.{ts,tsx,js,jsx,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Run pnpm format (Prettier) before pushing with 2-space indentation, 100-character width, single quotes, and Tailwind-aware class ordering

Files:

  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Use PascalCase for React component file names (e.g., VaultBanner.tsx)

Files:

  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{tsx,jsx}: Keep Tailwind class lists lean and dedupe variants with tailwind-merge
All toggles must use the shared IconSwitch component from @/components/common/IconSwitch for consistent sizing and animation

Files:

  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

ESLint (Airbnb + Next.js) enforces hook safety and import hygiene

Files:

  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use camelCase for helper function names (e.g., formatApr)

Files:

  • src/components/common/MarketsTableWithSameLoanAsset.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to src/**/*.{ts,tsx} : Use camelCase for helper function names (e.g., `formatApr`)

Applied to files:

  • app/positions/components/PositionsSummaryTable.tsx
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.

Applied to files:

  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to src/hooks/**/*.{ts,tsx} : When building on-chain hooks, mirror `useERC20Approval` and `useTransactionWithToast` patterns and memoize arrays/objects before using them in effect dependencies to prevent redundant RPC calls

Applied to files:

  • app/positions/components/PositionsSummaryTable.tsx
  • src/components/common/MarketsTableWithSameLoanAsset.tsx
📚 Learning: 2025-11-25T14:45:50.416Z
Learnt from: CR
Repo: antoncoding/monarch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T14:45:50.416Z
Learning: Applies to **/*.{tsx,jsx} : All toggles must use the shared `IconSwitch` component from `@/components/common/IconSwitch` for consistent sizing and animation

Applied to files:

  • app/positions/components/PositionsSummaryTable.tsx
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 63
File: app/markets/components/MarketRowDetail.tsx:49-52
Timestamp: 2024-10-12T09:23:16.495Z
Learning: When rendering oracle feeds in `ExpandedMarketDetail` (`app/markets/components/MarketRowDetail.tsx`), prefer explicit rendering over iterating keys when dealing with a small number of feeds.

Applied to files:

  • src/components/common/MarketsTableWithSameLoanAsset.tsx
🧬 Code graph analysis (2)
app/positions/components/PositionsSummaryTable.tsx (4)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
src/utils/balance.ts (1)
  • formatReadable (25-46)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/components/common/MarketsTableWithSameLoanAsset.tsx (4)
app/markets/components/columnVisibility.ts (1)
  • ColumnVisibility (3-12)
src/utils/rateMath.ts (1)
  • convertApyToApr (15-29)
src/contexts/MarketsContext.tsx (1)
  • useMarkets (369-375)
src/hooks/useRateLabel.ts (1)
  • useRateLabel (45-65)
🔇 Additional comments (4)
app/positions/components/PositionsSummaryTable.tsx (1)

163-164: LGTM!

Hook usage is clean. The dynamic rate label retrieval properly supports the APR/APY toggle feature.

src/components/common/MarketsTableWithSameLoanAsset.tsx (3)

432-444: LGTM!

New props are properly typed and enable dynamic APR/APY display throughout the row.


576-579: LGTM!

Rate label generation with prefixes correctly produces dynamic headers that adapt to APR/APY display mode.


1031-1031: LGTM!

Dynamic rate labels are correctly applied to table headers and MarketRow receives all necessary props for APR/APY display.

Also applies to: 1040-1040, 1085-1087

Comment on lines +372 to 377
<td data-label={`${rateLabel} (now)`}>
<div className="flex items-center justify-center">
<span className="font-medium">{formatReadable(avgApy * 100)}%</span>
<span className="font-medium">
{formatReadable((isAprDisplay ? convertApyToApr(avgApy) : avgApy) * 100)}%
</span>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add null check for avgApy before conversion.

If totalWeightedApy can be undefined, this will fail since convertApyToApr expects a number and multiplying undefined by 100 produces NaN.

Consider adding a guard similar to the pattern in MarketsTableWithSameLoanAsset.tsx (lines 525-527):

                    <td data-label={`${rateLabel} (now)`}>
                      <div className="flex items-center justify-center">
-                       <span className="font-medium">
-                         {formatReadable((isAprDisplay ? convertApyToApr(avgApy) : avgApy) * 100)}%
-                       </span>
+                       <span className="font-medium">
+                         {avgApy != null
+                           ? `${formatReadable((isAprDisplay ? convertApyToApr(avgApy) : avgApy) * 100)}%`
+                           : '—'}
+                       </span>
                      </div>
                    </td>
🤖 Prompt for AI Agents
In app/positions/components/PositionsSummaryTable.tsx around lines 372 to 377,
the code assumes avgApy is always defined and calls convertApyToApr and
multiplies by 100 which will produce NaN if avgApy (derived from
totalWeightedApy) is undefined; add a null/undefined guard so that if avgApy is
null/undefined you render a fallback (e.g., "-" or empty string) instead of
performing conversion and multiplication, otherwise perform (isAprDisplay ?
convertApyToApr(avgApy) : avgApy) * 100 and pass the numeric value to
formatReadable — follow the same pattern used in
MarketsTableWithSameLoanAsset.tsx (lines 525-527).

@antoncoding antoncoding merged commit 50ecbdf into master Dec 8, 2025
4 checks passed
@antoncoding antoncoding deleted the feat/apr branch December 8, 2025 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Support displaying APR in addition to APY

1 participant