fix(perps): missing latest funding payments in Activity#28671
fix(perps): missing latest funding payments in Activity#28671abretonc7s merged 21 commits intomainfrom
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. |
Automated fix-bug run — TAT-2057
Worker reportFix Report — TAT-2057: Don't see latest funding payments in ActivitySummary
Root CauseFile: The original const rawFunding = await infoClient.userFunding({
user: userAddress,
startTime: Date.now() - 365 * 24 * 60 * 60 * 1000,
endTime: undefined,
});HyperLiquid's The oscillation between two cutoff dates on consecutive refreshes was caused by Reproduction CommitSHA: Added Changes
Fix DetailDivided the 365-day range into 30-day windows (~13 chunks), fetched all in parallel via const chunks: { start: number; end: number }[] = [];
let chunkEnd = finalEndTime;
while (chunkEnd > finalStartTime) {
const chunkStart = Math.max(finalStartTime, chunkEnd - pageWindowMs);
chunks.push({ start: chunkStart, end: chunkEnd });
chunkEnd = chunkStart;
}
const pages = await Promise.all(
chunks.map((chunk) => infoClient.userFunding({ user: userAddress, startTime: chunk.start, endTime: chunk.end }))
);
const allRaw = pages.flatMap((page) => page ?? []);
allRaw.sort((a, b) => a.time - b.time);Test PlanUnit tests: Recipe validation (account 0x316BDE, 1174 records):
CI gates: lint (0 errors), lint:tsc (0 errors), format:check (pass) ✅ Evidence
TicketTAT-2057 — https://consensyssoftware.atlassian.net/browse/TAT-2057 |
…issing latest payments HyperLiquid userFunding API returns records ascending (oldest first) and caps each call at 500 records. A single 365-day window silently drops the most recent payments for accounts with >500 funding events. Replace the single call with parallel 30-day window fetches via Promise.all. Each window stays well under the cap, guaranteeing the most recent records are always present regardless of history length. Fixes TAT-2057
- Merge duplicate perps-controller imports (no-duplicate-imports) - Move PAGE_WINDOW_MS/MAX_LOOKBACK_MS to module level (exhaustive-deps) - Remove dead startTime/endTime from useCallback dep array - Apply prettier formatting to all changed files
7609ee6 to
eac26df
Compare
…nding - Fix early return guard: check cursorEndTime instead of cursorStartTime so the last partial funding window is fetched rather than silently dropped (365d / 30d = 12.17 pages; ~5 days were previously skipped) - Deduplicate transactions by id when merging in loadMoreFunding to prevent boundary-timestamp duplicates from HyperLiquid's inclusive API ranges
- Add try/catch so API rejections don't propagate as unhandled promise rejections through FlashList's fire-and-forget onEndReached callback - Add fetchGenerationRef counter bumped on every fetchAllTransactions; loadMoreFunding captures it before the await and discards results if a concurrent refresh has reset the cursor, preventing stale cursor writes and stale data being appended after pull-to-refresh
Replace O(n²) reduce+findIndex and inline Set+filter with a single shared deduplicateById function for consistent, efficient dedup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sort only once in the mergedTransactions memo (the final output). Remove duplicate sorts from fetchAllTransactions, loadMoreFunding, and transformFundingToTransactions — they were all overwritten by the downstream sort anyway. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…_MS constant Replace localeCompare with plain string comparison for ASCII coin symbols. Move minSplitWindowMs to PERPS_TRANSACTIONS_HISTORY_CONSTANTS for discoverability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Regarding the Bugbot finding in usePerpsTransactionHistory.ts:325-327, I agree with keeping this PR scoped to TAT-2057 and Im not asking it to solve every historical gap pagination case.
My concern is that the empty-window stop is itself a new optimization/tradeoff to reduce extra API calls, which is somewhat separate from the core recent funding fix.
Because of that behavior, the current implementation does not fully match the PR description/comments: phrases like "on demand older history" and "max lookback remains 365 days" read as though users can continue paging back through that full range, but in practice pagination stops at the first empty 30 day window and older funding beyond a gap becomes unreachable.
Im fine with keeping that trade-off in this PR if that is the intended product decision. In that case, I think the PR description and relevant code comments should be narrowed so they reflect the actual behavior rather than implying full 365 day reachability across gaps.
Update DEFAULT_FUNDING_HISTORY_DAYS comment to reflect actual behavior: 365 days is a max ceiling, not a guaranteed range. Initial load fetches only the most recent 30-day window, and pagination stops at the first empty window — users with activity gaps may not reach the full lookback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Empty 30-day windows (no open positions during that period) now advance the cursor instead of terminating pagination, so users with activity gaps can still reach older funding history within the 365-day lookback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
Tag selection rationale:
No other tags are needed as changes are isolated to Perps functionality with no impact on accounts, identity, network, swaps, or other features. Performance Test Selection: |
after.mp4Updated proof of work after changes |
|
✅ E2E Fixture Validation — Schema is up to date |
|
geositta
left a comment
There was a problem hiding this comment.
This looks good now. The followup change resolves the earlier pagination concern by skipping empty 30 day funding windows instead of stopping permanently, and the updated comments/tests match that behavior.
I am comfortable approving from here, thanks!



Description
Root cause
The Activity page was not showing the most recent funding payments for accounts with many open positions.
HyperLiquidProvider.getFunding()made a single API call for the full 365-day history window; HyperLiquid's API silently caps responses at 500 records (oldest-first), so the most recent payments were dropped.Fix
getFunding()now defaults to fetching only the most recent 30-day window instead of 365 days. For windows exceeding the 500-record cap,fetchWindowWithAutoSplitrecursively halves the window until every sub-window is under the cap.time+coincomposite key (not hash — HyperLiquid funding records all share a zero hash).loadMoreFundinginusePerpsTransactionHistoryloads the next 30-day page when the user scrolls to the bottom of the Funding tab. Max lookback remains 365 days.PerpsTransactionsViewauto-triggersloadMoreFundingto fetch the next older window.deduplicateByIdhelper (O(n) Set) replaces O(n²) reduce+findIndex. Redundant intermediate sorts removed — single sort pass inmergedTransactionsmemo.Changes
HyperLiquidProvider.tsgetFunding()defaults to 30-day window;fetchWindowWithAutoSplitfor cap-safe fetching; boundary dedup bytime+coin(not hash)usePerpsTransactionHistory.tsloadMoreFunding,hasFundingMore,isFetchingMoreFunding); ref-based lock to prevent double-fire; generation counter to discard stale results; shareddeduplicateByIdhelper; preserve data on error; stable sort by asset; removed redundant intermediate sortsPerpsTransactionsView.tsxonEndReached → loadMoreFundingon Funding tab; auto-advance effect when Funding tab is empty;ActivityIndicatorspinner inListFooterComponenttransactionTransforms.tstransformFundingToTransactions— sorting centralized in consumer (mergedTransactionsmemo)transactionsHistoryConfig.tsFUNDING_HISTORY_PAGE_WINDOW_DAYS,FUNDING_HISTORY_API_LIMIT,MIN_SPLIT_WINDOW_MSconstantsPerpsTransactionsView.styles.tsloadMoreContainerstylePerps.testIds.tsFUNDING_LOAD_MORE_SPINNERtestIDusePerpsTransactionHistory.test.tsloadMoreFundingtests (happy path, empty result, error handling, exhausted cursor, dedup); 93% new code coverageHyperLiquidProvider.test.tstransactionTransforms.test.tsPerpsTransactionsView.test.tsx,usePerpsHomeData.test.tsChangelog
CHANGELOG entry: Fixed missing recent perpetuals funding payments —
getFundingnow fetches the most recent 30-day window by default (1 API call) and loads older history on demand as the user scrolls, replacing the previous 365-day call that silently dropped recent records past the 500-record cap.Related issues
Fixes: TAT-2057
Manual testing steps
```gherkin
Feature: On-demand funding history pagination
Scenario: AC1 — Activity shows most recent funding payments (1 API call)
Given the user has an account with perpetuals positions
When the user navigates to Activity > Perps > Funding tab
Then the most recent funding payments appear (457 records in 30-day window)
And only 1 getFunding API call is made (visible in Metro logs)
Scenario: AC2 — Consecutive fetches return consistent results
Given the user is on the Funding tab
When getFunding is called twice with the same time window
Then both calls return identical record counts and latest timestamps
Scenario: AC3 — Scrolling to bottom loads older history
Given the user is on the Funding tab with recent data loaded
When the user scrolls to the bottom of the Funding list
Then a loading spinner appears at the bottom
And a second API call fetches the next 30-day window
And older funding entries appear in the list
Scenario: AC4 — Pull-to-refresh failure preserves existing data
Given the user has funding data loaded
When the API returns an error during pull-to-refresh
Then existing funding entries remain visible
And no empty state is shown
Scenario: AC5 — Refresh resets to fresh recent data
Given the user pulls to refresh on the Funding tab
Then the cursor resets and the most recent 30-day window is re-fetched (1 call)
```
Screenshots/Recordings
Latest funding entries
Consecutive fetch consistency
Video
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Changes funding-history fetching and pagination logic in both the HyperLiquid provider and UI hook; regressions could hide funding rows or cause extra API calls/spinners if cursor/generation handling is wrong.
Overview
Fixes missing recent perps funding payments by changing
HyperLiquidProvider.getFunding()to fetch funding in 30‑day pages (defaulting to the most recent window) and auto-splitting any window that hits the API record cap, with boundary deduping.Adds cursor-based on-demand funding pagination to
usePerpsTransactionHistory(loadMoreFunding,hasFundingMore,isFetchingMoreFunding) with deduping, stable sorting, and refresh/error behavior that preserves already-loaded data.PerpsTransactionsViewwires infinite scroll + an empty-list auto-advance for the Funding tab and shows a footer spinner, with updated constants/test IDs and expanded tests to cover the new behavior.Reviewed by Cursor Bugbot for commit c7506b5. Bugbot is set up for automated code reviews on this repo. Configure here.