feat(rewards): add campaign portfolio endpoints and UI#27797
Conversation
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
| }> = ({ position }) => { | ||
| const assetId = position.tokenAddresses[0] ?? ''; | ||
|
|
||
| return ( |
There was a problem hiding this comment.
Note: we should evaluate if we can show this better and maybe even redirect to the appropriate rwa page/view if tapped
Add leaderboard functionality for campaigns with: - CampaignLeaderboard component with tier tabs, participant ranking, rate of return display, and user position card - useGetCampaignLeaderboard hook for fetching public leaderboard data - useGetCampaignLeaderboardPosition hook for fetching authenticated user's position - Redux state and selectors for leaderboard management - RewardsController methods for leaderboard API calls with caching - Tests for all new components, hooks, reducers, and selectors Made-with: Cursor
- Add OndoLeaderboardView screen with navigation route (ONDO_LEADERBOARD) - Add OndoLeaderboardPosition component showing rank, tier, rate of return, total deposited, and current value for the connected wallet - Add useOndoLeaderboardPosition hook fetching position data from controller - Refactor CampaignLeaderboard to extract leaderboard list into a dedicated view; move position display out of the details view - Extend RewardsController and rewards-data-service with getLeaderboardPosition action and messenger permissions - Add i18n strings for leaderboard_position namespace Refs: RWDS-1104 Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…leaderboard hooks The campaigns feature flag check is no longer needed in the leaderboard hooks and RewardsController since campaign gating is handled upstream. Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…fixtures The RewardsState type gained 7 new leaderboard-related fields in the campaign leaderboard feature commit. Two test fixtures in index.test.ts (resetRewardsState and persist/REHYDRATE tests) were not updated with these fields, causing TypeScript TS2740 type errors in lint:tsc. Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…fixtures The RewardsController gained campaignLeaderboards and campaignLeaderboardPositions state fields. Three places needed updating: - initial-background-state.json: used by Engine.test.ts initial state check - RewardsController.test.ts: three inline snapshots for includeInStateLogs, persist, and usedInUi metadata-derived state shapes Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
cdfc5d4 to
a0d6d5a
Compare
…view - Update log snapshots to include campaignLeaderboardPositions and campaignLeaderboards fields added to RewardsController state - Add unit tests for RewardsDataService.getOndoCampaignLeaderboard and getOndoCampaignLeaderboardPosition (success, 404 null, error) - Add unit tests for RewardsController.getOndoCampaignLeaderboard and getOndoCampaignLeaderboardPosition (disabled, cache hit/miss, logging) - Add OndoLeaderboardView.test.tsx covering render, navigation, and hook integration Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
| hasError: false, | ||
| refetch: jest.fn(), | ||
| }); | ||
| const { getByTestId } = render(<CampaignDetailsView />); |
There was a problem hiding this comment.
Tests reference undefined CampaignDetailsView component
High Severity
The three new "campaign portfolio" tests render <CampaignDetailsView />, but only OndoCampaignDetailsView is imported in this file. CampaignDetailsView is not defined or imported anywhere in the test, so all three tests will fail. The rest of the test file correctly uses <OndoCampaignDetailsView />.
Additional Locations (2)
- Add getCampaignPortfolio (renamed to getOndoCampaignPortfolio) endpoint in RewardsController - Add useCampaignPortfolio hook for fetching portfolio data - Add RewardsCampaignPortfolio component to display user positions - Remove selectCampaignsRewardsEnabledFlag usage; gated on subscriptionId/campaignId only - Rename all getCampaignPortfolio references to getOndoCampaignPortfolio Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix portfolio URL test assertion: /campaigns/ -> /ondo-gm/ to match implementation - Fix RewardsCampaignPortfolio test mock strings to match en.json values: error_title, error_description, and empty_state all corrected Co-authored-by: VGR-GIT <vangulckrik@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
599baeb to
5926404
Compare
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - base branch is not main or a release branch (base: rwds-1104-ondo-leaderboard) All E2E tests pre-selected. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| } | ||
| > | ||
| {parseFloat(position.unrealizedPnl) >= 0 ? '+' : ''} | ||
| {position.unrealizedPnlPercent}% |
There was a problem hiding this comment.
PnL percent rendered without decimal-to-percentage conversion
High Severity
The unrealizedPnlPercent field is documented as a "decimal ratio" (e.g., "0.0775" for 7.75%) in the type definition, and all backend/controller/service test mocks consistently use this format ('0.0775'). However, the component renders {position.unrealizedPnlPercent}% without multiplying by 100, so users would see +0.0775% instead of +7.75%. The component test uses pre-converted values like '7.75' which masks this mismatch.
Additional Locations (1)
|
✅ E2E Fixture Validation — Schema is up to date |
56d515e to
8533129
Compare


Summary
WIP - This PR is very much subject to change.
Adds campaign portfolio support to the Rewards feature:
getCampaignPortfolioendpoint in RewardsControlleruseCampaignPortfoliohook for fetching portfolio dataRewardsCampaignPortfoliocomponent to display user positionsCHANGELOG entry: feat(rewards): add campaign portfolio endpoints and UI component
Test plan
Made with Cursor
Note
Medium Risk
Adds a new rewards API surface (
getOndoCampaignPortfolio) with caching and new persisted Redux state, plus UI that consumes it; issues could affect rewards data freshness/authorization handling and state persistence.Overview
Adds end-to-end campaign portfolio support for ONDO holding campaigns: a new
RewardsController:getOndoCampaignPortfolioaction backed byRewardsDataService:getOndoCampaignPortfolio(with 5‑minute caching and persistedcampaignPortfoliostate).Introduces
useCampaignPortfolioand aRewardsCampaignPortfoliolist component (skeleton/error/empty/success states) and conditionally renders it inOndoCampaignDetailsViewonly when the user is opted in andcampaign.type === CampaignType.ONDO_HOLDING. Also updates rewards Redux to store/select portfolios and improves 401 handling forgetCampaignsandgetCampaignParticipantStatus, with new i18n strings and unit tests covering controller/service/hook/UI behavior.Written by Cursor Bugbot for commit 5926404. This will update automatically on new commits. Configure here.