Skip to content

feat(rewards): add campaign portfolio endpoints and UI#27797

Closed
VGR-GIT wants to merge 8 commits into
rwds-1104-ondo-leaderboardfrom
rwds-campaign-portfolio-endpoints
Closed

feat(rewards): add campaign portfolio endpoints and UI#27797
VGR-GIT wants to merge 8 commits into
rwds-1104-ondo-leaderboardfrom
rwds-campaign-portfolio-endpoints

Conversation

@VGR-GIT
Copy link
Copy Markdown
Contributor

@VGR-GIT VGR-GIT commented Mar 23, 2026

Summary

WIP - This PR is very much subject to change.

Adds campaign portfolio support to the Rewards feature:

  • getCampaignPortfolio endpoint in RewardsController
  • useCampaignPortfolio hook for fetching portfolio data
  • RewardsCampaignPortfolio component to display user positions

CHANGELOG entry: feat(rewards): add campaign portfolio endpoints and UI component

Test plan

  • Unit tests passing
  • Manual testing pending

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:getOndoCampaignPortfolio action backed by RewardsDataService:getOndoCampaignPortfolio (with 5‑minute caching and persisted campaignPortfolio state).

Introduces useCampaignPortfolio and a RewardsCampaignPortfolio list component (skeleton/error/empty/success states) and conditionally renders it in OndoCampaignDetailsView only when the user is opted in and campaign.type === CampaignType.ONDO_HOLDING. Also updates rewards Redux to store/select portfolios and improves 401 handling for getCampaigns and getCampaignParticipantStatus, 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.

@github-actions
Copy link
Copy Markdown
Contributor

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.

@metamaskbot metamaskbot added the team-rewards Rewards team label Mar 23, 2026
}> = ({ position }) => {
const assetId = position.tokenAddresses[0] ?? '';

return (
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Note: we should evaluate if we can show this better and maybe even redirect to the appropriate rwa page/view if tapped

VGR-GIT and others added 5 commits March 25, 2026 08:35
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>
@VGR-GIT VGR-GIT force-pushed the rwds-campaign-portfolio-endpoints branch from cdfc5d4 to a0d6d5a Compare March 25, 2026 09:29
@VGR-GIT VGR-GIT marked this pull request as ready for review March 25, 2026 09:30
@VGR-GIT VGR-GIT requested a review from a team as a code owner March 25, 2026 09:30
@VGR-GIT VGR-GIT changed the base branch from main to rwds-1104-ondo-leaderboard March 25, 2026 09:30
…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>
@metamaskbot metamaskbot added the INVALID-PR-TEMPLATE PR's body doesn't match template label Mar 25, 2026
hasError: false,
refetch: jest.fn(),
});
const { getByTestId } = render(<CampaignDetailsView />);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

VGR-GIT and others added 2 commits March 25, 2026 10:49
- 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>
@VGR-GIT VGR-GIT force-pushed the rwds-campaign-portfolio-endpoints branch from 599baeb to 5926404 Compare March 25, 2026 09:50
@github-actions
Copy link
Copy Markdown
Contributor

🔍 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.

View GitHub Actions results

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

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}%
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

@github-actions
Copy link
Copy Markdown
Contributor

E2E Fixture Validation — Schema is up to date
17 value mismatches detected (expected — fixture represents an existing user).
View details

@VGR-GIT VGR-GIT force-pushed the rwds-1104-ondo-leaderboard branch from 56d515e to 8533129 Compare March 25, 2026 10:37
@VGR-GIT VGR-GIT closed this Mar 25, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

INVALID-PR-TEMPLATE PR's body doesn't match template size-XL team-rewards Rewards team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants