Skip to content

feat: rfox v3#11668

Merged
kaladinlight merged 13 commits intodevelopfrom
rfox-v3-update
Jan 26, 2026
Merged

feat: rfox v3#11668
kaladinlight merged 13 commits intodevelopfrom
rfox-v3-update

Conversation

@kaladinlight
Copy link
Copy Markdown
Contributor

@kaladinlight kaladinlight commented Jan 15, 2026

Description

Update rfox to v3 showing rewards in usdc and using new affiliate revenue endpoint.

Issue (if applicable)

closes #11632
closes #11669
closes https://linear.app/shapeshift-dao/issue/PROD-99/metadata-clarifying

Risk

High Risk PRs Require 2 approvals

Low

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Ensure accurate display of stats/rewards
  • Spot check stake/unstake/claim functionality remains unchanged and accurate
  • Ensure no reference to change address or rune reward address exists anymore

Engineering

☝️

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

☝️

Screenshots (if applicable)

image image

Summary by CodeRabbit

  • New Features

    • LP sunset warning added for the Arbitrum WETH/FOX rewards program.
    • Affiliate revenue now fetched from a configurable external USD endpoint.
  • Changes

    • Fox and RFOX experiences consolidated into a single Fox ecosystem route; navigation simplified.
    • Several RFOX pages, widgets, and multi-step flows streamlined or removed to simplify staking, claim, and address-change UX.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Removed Fox/RFOX feature flags and standalone Fox/RFOX pages; unified Fox navigation to /fox-ecosystem; replaced Rune-based affiliate revenue queries with a USD-based affiliate revenue endpoint and adapted reward hooks, helpers, and displays.

Changes

Cohort / File(s) Summary
Environment & Config
\.env, src/config.ts, src/vite-env.d.ts
Removed three Fox-related feature flags; added VITE_AFFILIATE_REVENUE_URL validator and typed env var.
Routing & Header
src/Routes/RoutesCommon.tsx, src/components/Layout/Header/Header.tsx
Removed /rfox/* and /fox routes/imports; hardcoded Fox navigation to /fox-ecosystem.
Pages Removed
src/pages/Fox/FoxPage.tsx, src/pages/RFOX/RFOX.tsx, src/pages/RFOX/Widget.tsx
Deleted standalone Fox and RFOX page components and exports.
RFOX Components Removed
src/pages/RFOX/components/AddressSelection.tsx, src/pages/RFOX/components/ChangeAddress/*, src/pages/RFOX/components/Faq/*, src/pages/RFOX/components/History/*, src/pages/RFOX/components/Overview/*, src/pages/RFOX/components/RFOXHeader.tsx, src/pages/RFOX/components/Overview/StakingInfoItem.tsx, ...
Removed address-change flows, FAQ, history, overview/staking UI, header, and many RFOX subcomponents.
Fox UI Updates
src/pages/Fox/components/RFOXSection.tsx, src/pages/Fox/components/RFOXSimulator.tsx, src/pages/Fox/components/FoxTokenHeader.tsx
Switched RUNE references to USDC-on-Arbitrum, updated market-data usage, changed displays to fiat, removed feature-flag branches, added LP sunset warning.
Affiliate Revenue — Query & Hooks
src/pages/RFOX/hooks/useAffiliateRevenueQuery.ts (deleted), src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts (added), src/pages/RFOX/hooks/useCurrentEpochRewardsQuery.ts, src/pages/RFOX/hooks/helpers.ts, src/pages/RFOX/hooks/useLifetimeRewardsQuery.ts
Replaced BigInt Rune revenue flow with USD-based affiliate revenue hook; added USD query, renamed helpers to USDC flow, and adapted dependent queries.
Staking / Stake Flow
src/pages/RFOX/components/Stake/*, src/pages/RFOX/components/Stake/hooks/useRfoxStake.tsx, src/pages/RFOX/components/Stake/types.ts, src/pages/RFOX/constants.ts
Removed manual/rune address inputs, introduced STUB_RUNE_ADDRESS, simplified props/types, updated IPFS hash constant.
Claim Flow
src/pages/RFOX/components/Claim/*, src/pages/RFOX/components/Claim/types.ts
Removed feature-flagged navigation and setStepIndex usages; hardcoded navigation to /fox-ecosystem; simplified props.
Misc UI Navigation
src/components/StakingVaults/EarnOpportunities.tsx, src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx, src/components/Layout/Header/ActionCenter/components/RfoxClaimActionCard.tsx, src/pages/Explore/Explore.tsx
Removed feature-flag checks; unified rFOX navigation to /fox-ecosystem.
State, Tests & Translations
src/state/slices/preferencesSlice/preferencesSlice.ts, src/test/mocks/store.ts, src/assets/translations/en/main.json
Removed Fox-related feature flags from preferences and test mocks; updated translations (e.g., RFOX.totalSymbolBurnRFOX.totalBurn, added LP sunset warning).
Types & Helpers
src/pages/RFOX/types.ts, src/pages/RFOX/helpers.ts, src/hooks/useActionCenterSubscribers/useGenericTransactionSubscriber.tsx
Updated Epoch types to revenue/USD fields; removed selectRuneAddress; updated affiliate revenue import to USD variant.

Sequence Diagram(s)

sequenceDiagram
  participant UI as UI Component
  participant Hook as useAffiliateRevenueUsdQuery
  participant Query as ReactQuery
  participant Axios as Axios HTTP
  participant API as Affiliate Revenue API

  UI->>Hook: call useAffiliateRevenueUsdQuery(start,end)
  Hook->>Query: build queryKey & queryFn
  Query->>Axios: execute GET to VITE_AFFILIATE_REVENUE_URL?start=YYYY-MM-DD&end=YYYY-MM-DD
  Axios->>API: HTTP request
  API-->>Axios: { totalUsd }
  Axios-->>Query: response { totalUsd }
  Query-->>Hook: resolved affiliateRevenueUsd
  Hook-->>UI: returns affiliateRevenueUsd (number)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

high risk

Suggested reviewers

  • gomesalexandre

Poem

🐰

I hopped through flags and routes today,
Merged the paths to one clear way,
Rune turned to dollars, helpers renewed,
Stubbed an address and warnings queued,
A cheerful hop — Fox finds its bay!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'feat: rfox v3' is vague and generic, failing to convey the scope of substantial changes involved in this refactor. Consider a more descriptive title such as 'feat: update rFOX to v3 with USDC rewards and new revenue endpoint' to better summarize the primary changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The code changes comprehensively address all objectives: removes rune reward address references, converts rewards to USDC, integrates new affiliate revenue endpoint, marks wETH/FOX as unstake-only, removes LP calculator, updates display calculations, and includes new IPFS metadata hash.
Out of Scope Changes check ✅ Passed All changes are scoped to rFOX v3 migration and affiliate revenue integration. No unrelated refactoring or feature additions detected beyond the stated objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 rfox-v3-update

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.

@kaladinlight kaladinlight linked an issue Jan 21, 2026 that may be closed by this pull request
@kaladinlight kaladinlight marked this pull request as ready for review January 21, 2026 20:50
@kaladinlight kaladinlight requested a review from a team as a code owner January 21, 2026 20:50
Copy link
Copy Markdown
Contributor

@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

Caution

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

⚠️ Outside diff range comments (2)
src/pages/RFOX/components/Stake/hooks/useRfoxStake.tsx (1)

192-199: Remove errors?.manualRuneAddress checks—the field is never used in the form.

The manualRuneAddress field is defined in AddressSelectionValues type but is never registered, set, or validated in the form. It only appears in defaultFormValues composition through the type definition, but is never actually initialized or populated. This means errors?.manualRuneAddress will always be undefined, making the validation checks at lines 192 and 315 dead code that can be safely removed.

src/pages/RFOX/hooks/useCurrentEpochRewardsQuery.ts (1)

43-103: Fix USD↔user‑currency mismatch in USDC conversion.

affiliateRevenueUsd is explicitly USD, but selectMarketDataByAssetIdUserCurrency returns a user‑currency price. Dividing USD by a non‑USD price inflates/deflates rewards for non‑USD users. Use a USD‑denominated USDC price or convert the USD total into user currency before dividing. If the endpoint already represents USDC‑denominated USD totals, you can skip the price conversion and go straight to base units.

🐛 Suggested fix (treat USD as USDC 1:1; or swap in USD‑priced market data)
-  const usdcMarketData = useAppSelector(state =>
-    selectMarketDataByAssetIdUserCurrency(state, usdcOnArbitrumOneAssetId),
-  )
-
   const combine = useCallback(
     (
       queries: [
         UseQueryResult<Epoch[], Error>,
         UseQueryResult<bigint, Error>,
         UseQueryResult<number, Error>,
@@
-        if (
-          !epochHistory ||
-          !currentEpochRewardUnits ||
-          !affiliateRevenueUsd ||
-          !currentEpochMetadata ||
-          !usdcAsset ||
-          !usdcMarketData
-        )
+        if (
+          !epochHistory ||
+          !currentEpochRewardUnits ||
+          !affiliateRevenueUsd ||
+          !currentEpochMetadata ||
+          !usdcAsset
+        )
           return 0n
@@
-        const affiliateRevenueUsdcBaseUnit = toBaseUnit(
-          bn(affiliateRevenueUsd).div(usdcMarketData.price),
-          usdcAsset.precision,
-        )
+        const affiliateRevenueUsdcBaseUnit = toBaseUnit(
+          bn(affiliateRevenueUsd),
+          usdcAsset.precision,
+        )
@@
-    [currentEpochMetadata, stakingAssetId, stakingAssetAccountId, usdcAsset, usdcMarketData],
+    [currentEpochMetadata, stakingAssetId, stakingAssetAccountId, usdcAsset],
   )
🤖 Fix all issues with AI agents
In `@src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts`:
- Around line 44-49: The try/catch is incorrectly placed around the simple
property access (data.totalUsd) so it never catches network/parse errors; move
the try/catch to wrap the axios.get call and the response parsing in
useAffiliateRevenueUsdQuery (i.e., the code that calls axios.get and assigns
response.data), catch and log the actual error (include the error object) and
then throw a descriptive Error('Error parsing affiliate revenue') so failures
during the HTTP request or JSON parsing are handled correctly.
🧹 Nitpick comments (7)
src/pages/RFOX/types.ts (1)

53-60: Consider type aliases for USD strings and revenue maps.

Using a descriptive alias can improve clarity and reduce accidental misuse across the file (and related types).

♻️ Suggested refactor
+export type UsdAmount = string
+export type RevenueByService = Record<string, UsdAmount>
+
 export type Epoch = {
   /** The epoch number for this epoch */
   number: number
@@
-  /** The total revenue (USD) earned this epoch */
-  totalRevenue: string
+  /** The total revenue (USD) earned this epoch */
+  totalRevenue: UsdAmount
@@
-  /** The revenue (USD) earned (by service) for this epoch */
-  revenue: Record<string, string>
+  /** The revenue (USD) earned (by service) for this epoch */
+  revenue: RevenueByService
@@
-  /** The spot price of reward asset in USD */
-  rewardAssetPriceUsd: string
+  /** The spot price of reward asset in USD */
+  rewardAssetPriceUsd: UsdAmount
 }
@@
 export type EpochDetails = {
@@
-  /** The spot price of asset in USD */
-  assetPriceUsd: string
+  /** The spot price of asset in USD */
+  assetPriceUsd: UsdAmount
src/pages/Fox/components/RFOXSimulator.tsx (3)

65-71: Unused dependencies in estimatedBurn useMemo.

stakingAssetUsdPrice and stakingAsset are in the dependency array but are not used in the calculation - the burn is now a simple percentage of shapeShiftRevenue using epochMetadata.burnRate. These guards can be removed.

♻️ Suggested simplification
  const estimatedBurn = useMemo(() => {
    if (!epochMetadata) return
-   if (!stakingAsset) return
-   if (!stakingAssetUsdPrice) return

    return bnOrZero(shapeShiftRevenue).times(epochMetadata.burnRate).toFixed(2)
- }, [epochMetadata, shapeShiftRevenue, stakingAssetUsdPrice, stakingAsset])
+ }, [epochMetadata, shapeShiftRevenue])

73-82: Unused dependency usdcUsdPrice in estimatedRewards useMemo.

The usdcUsdPrice variable is checked but not used in the calculation. Since rewards are now displayed as fiat via Amount.Fiat, and the calculation yields a USD value directly from revenue and distribution rate, this guard appears unnecessary.

♻️ Suggested simplification
  const estimatedRewards = useMemo(() => {
    if (!epochMetadata) return
    if (!poolShare) return
-   if (!usdcUsdPrice) return

    const distributionRate =
      epochMetadata.distributionRateByStakingContract[getStakingContract(stakingAssetId)] ?? 0

    return bnOrZero(shapeShiftRevenue).times(distributionRate).times(poolShare).toFixed(2)
- }, [epochMetadata, shapeShiftRevenue, usdcUsdPrice, stakingAssetId, poolShare])
+ }, [epochMetadata, shapeShiftRevenue, stakingAssetId, poolShare])

140-140: Redundant Boolean() wrapper.

estimatedBurn !== undefined already evaluates to a boolean; the Boolean() wrapper is unnecessary.

♻️ Suggested fix
- <Skeleton isLoaded={Boolean(estimatedBurn !== undefined)}>
+ <Skeleton isLoaded={estimatedBurn !== undefined}>
src/pages/RFOX/components/Claim/ClaimSelect.tsx (1)

21-24: Remove unused setStepIndex from NoClaimsAvailableProps type.

The setStepIndex prop is defined in the type but never used in the component (line 26 only destructures isError).

♻️ Suggested cleanup
 type NoClaimsAvailableProps = {
   isError?: boolean
-  setStepIndex?: (index: number) => void
 }
src/pages/RFOX/components/Overview/EmissionsPool.tsx (1)

26-29: Unnecessary generic type parameter.

The <string> generic type parameter appears unused since no select function is provided. The hook will return number (the default TotalRevenueUsd type), and the calculation on line 40 uses bn() which accepts numbers.

Consider removing the generic:

♻️ Suggested change
-  const affiliateRevenueUsdQuery = useAffiliateRevenueUsdQuery<string>({
+  const affiliateRevenueUsdQuery = useAffiliateRevenueUsdQuery({
     startTimestamp: currentEpochMetadataQuery.data?.epochStartTimestamp,
     endTimestamp: currentEpochMetadataQuery.data?.epochEndTimestamp,
   })
src/pages/RFOX/hooks/useLifetimeRewardsQuery.ts (1)

54-65: Consider extracting the epoch threshold as a named constant.

The magic number 17 representing the rFOX v3 transition epoch could be more self-documenting as a constant.

♻️ Suggested refactor
+const RFOX_V3_FIRST_EPOCH = 18
+
 const epochRewardUserCurrency = (() => {
   // rFOX v3 updated rewards from rune to usdc
-  if (epoch.number > 17) {
+  if (epoch.number >= RFOX_V3_FIRST_EPOCH) {
     return bn(fromBaseUnit(distribution.amount, usdcAsset?.precision)).times(
       usdcMarketData.price,
     )
   }

Comment thread src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts Outdated
Copy link
Copy Markdown
Contributor

@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

🤖 Fix all issues with AI agents
In `@src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts`:
- Line 41: The constructed URL in useAffiliateRevenueUsdQuery (`const url`) is
missing a forward slash between `baseUrl` and the path; update the URL
construction in useAffiliateRevenueUsdQuery so it inserts a slash (i.e., use
`baseUrl` + "/" + path or template
`${baseUrl}/api/v1/affiliate/revenue?startDate=...`) ensuring `url` is
well-formed when env `baseUrl` has no trailing slash.

Comment thread src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts Outdated
Copy link
Copy Markdown
Contributor

@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

🤖 Fix all issues with AI agents
In `@src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts`:
- Around line 32-33: The current guard in useAffiliateRevenueUsdQuery that
returns skipToken for falsy startTimestamp or endTimestamp incorrectly treats 0
(epoch) as missing; update the check in the function (the condition referencing
startTimestamp, endTimestamp and skipToken) to use nullish checks (e.g.,
startTimestamp == null || endTimestamp == null) or explicit ===
null/===undefined so only null/undefined cause the query to be skipped while
allowing 0 as a valid timestamp.
♻️ Duplicate comments (1)
src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts (1)

34-45: Add explicit error handling for the axios call.

Right now any network/parsing errors bubble without context. Wrapping the request lets you log and surface a more descriptive error.

♻️ Suggested adjustment
   return async () => {
     const baseUrl = getConfig().VITE_AFFILIATE_REVENUE_URL
@@
-    const url = `${baseUrl}/api/v1/affiliate/revenue?startDate=${startDate}&endDate=${endDate}`
-    const { data } = await axios.get<{ totalUsd: number }>(url)
-
-    return data.totalUsd
+    const url = `${baseUrl}/api/v1/affiliate/revenue?startDate=${startDate}&endDate=${endDate}`
+    try {
+      const { data } = await axios.get<{ totalUsd: number }>(url)
+      return data.totalUsd
+    } catch (error) {
+      console.error('Error fetching affiliate revenue:', error)
+      throw new Error('Failed to fetch affiliate revenue')
+    }
   }
#!/bin/bash
# Check existing axios + React Query patterns in hooks for consistency
rg -n "useQuery\\(" src/pages -g'*.ts*' -C2
rg -n "axios\\.get" src/pages -g'*.ts*' -C2

As per coding guidelines, wrap async operations with meaningful error handling.

🧹 Nitpick comments (2)
src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts (2)

37-37: Remove the inline comment in TS hooks.

The current guidance is to avoid adding code comments unless explicitly requested.

♻️ Proposed cleanup
-    // Convert timestamps (in milliseconds) to YYYY-MM-DD format
     const startDate = new Date(startTimestamp).toISOString().split('T')[0]

As per coding guidelines, avoid adding comments in TS/TSX unless requested.


28-31: Add explicit return types for exported functions.

Both getAffiliateRevenueUsdQueryFn and useAffiliateRevenueUsdQuery should declare return types explicitly for TS clarity.

♻️ Suggested typing
-import { skipToken, useQuery } from '@tanstack/react-query'
+import { skipToken, useQuery, type UseQueryResult } from '@tanstack/react-query'
@@
-export const getAffiliateRevenueUsdQueryFn = ({
+export const getAffiliateRevenueUsdQueryFn = ({
   startTimestamp,
   endTimestamp,
-}: UseAffiliateRevenueUsdQueryProps) => {
+}: UseAffiliateRevenueUsdQueryProps): typeof skipToken | (() => Promise<TotalRevenueUsd>) => {
@@
-export const useAffiliateRevenueUsdQuery = <SelectData = TotalRevenueUsd>({
+export const useAffiliateRevenueUsdQuery = <SelectData = TotalRevenueUsd>({
   startTimestamp,
   endTimestamp,
   select,
-}: UseAffiliateRevenueUsdQueryProps<SelectData>) => {
+}: UseAffiliateRevenueUsdQueryProps<SelectData>): UseQueryResult<SelectData, Error> => {

As per coding guidelines, always use explicit return types in TypeScript.

Also applies to: 48-52

Comment thread src/pages/RFOX/hooks/useAffiliateRevenueUsdQuery.ts
@kaladinlight kaladinlight merged commit e8d6369 into develop Jan 26, 2026
4 checks passed
@kaladinlight kaladinlight deleted the rfox-v3-update branch January 26, 2026 18:15
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.

Ecosystem page rFOX Clean Up rFOX v3 web stats update

1 participant