Commit f285cd7
fix(perps): missing latest funding payments in Activity (#28671)
## **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
- **Initial load — 1 API call**: `getFunding()` now defaults to fetching
only the most recent 30-day window instead of 365 days. For windows
exceeding the 500-record cap, `fetchWindowWithAutoSplit` recursively
halves the window until every sub-window is under the cap.
- **Boundary dedup by time+coin**: Adjacent chunk windows share boundary
timestamps; dedup uses `time+coin` composite key (not hash — HyperLiquid
funding records all share a zero hash).
- **On-demand older history**: A cursor-based `loadMoreFunding` in
`usePerpsTransactionHistory` loads the next 30-day page when the user
scrolls to the bottom of the Funding tab. Max lookback remains 365 days.
- **Auto-advance on empty**: When the Funding tab is empty after initial
load (no funding in the most recent 30 days), `PerpsTransactionsView`
auto-triggers `loadMoreFunding` to fetch the next older window.
- **Error resilience**: Transient API failures during pull-to-refresh
preserve existing loaded data instead of wiping to empty state.
- **Stable sort**: Secondary sort by asset name ensures deterministic
ordering when multiple coins share the same funding timestamp.
- **Performance**: Shared `deduplicateById` helper (O(n) Set) replaces
O(n²) reduce+findIndex. Redundant intermediate sorts removed — single
sort pass in `mergedTransactions` memo.
- **Rate limit improvement**: 1 API call per navigation/refresh vs 13
previously — ~50 loads/min safe vs 3.
### Changes
| File | Change |
|---|---|
| `HyperLiquidProvider.ts` | `getFunding()` defaults to 30-day window;
`fetchWindowWithAutoSplit` for cap-safe fetching; boundary dedup by
`time+coin` (not hash) |
| `usePerpsTransactionHistory.ts` | Cursor pagination
(`loadMoreFunding`, `hasFundingMore`, `isFetchingMoreFunding`);
ref-based lock to prevent double-fire; generation counter to discard
stale results; shared `deduplicateById` helper; preserve data on error;
stable sort by asset; removed redundant intermediate sorts |
| `PerpsTransactionsView.tsx` | Wired `onEndReached → loadMoreFunding`
on Funding tab; auto-advance effect when Funding tab is empty;
`ActivityIndicator` spinner in `ListFooterComponent` |
| `transactionTransforms.ts` | Removed sort from
`transformFundingToTransactions` — sorting centralized in consumer
(`mergedTransactions` memo) |
| `transactionsHistoryConfig.ts` | Added
`FUNDING_HISTORY_PAGE_WINDOW_DAYS`, `FUNDING_HISTORY_API_LIMIT`,
`MIN_SPLIT_WINDOW_MS` constants |
| `PerpsTransactionsView.styles.ts` | Added `loadMoreContainer` style |
| `Perps.testIds.ts` | Added `FUNDING_LOAD_MORE_SPINNER` testID |
| `usePerpsTransactionHistory.test.ts` | 5 new `loadMoreFunding` tests
(happy path, empty result, error handling, exhausted cursor, dedup); 93%
new code coverage |
| `HyperLiquidProvider.test.ts` | Tests for parallel pagination,
auto-split, null page handling, explicit time range forwarding |
| `transactionTransforms.test.ts` | Updated sort test to reflect
consumer-side sorting |
| `PerpsTransactionsView.test.tsx`, `usePerpsHomeData.test.ts` | Updated
mocks for new hook API surface |
## **Changelog**
CHANGELOG entry: Fixed missing recent perpetuals funding payments —
`getFunding` now 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](https://consensyssoftware.atlassian.net/browse/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
| Before | After |
|---|---|
| <img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/28671/before-ac1-funding-latest.png"
alt="Latest funding entries before" width="360" /> | <img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/28671/after-ac1-funding-latest.png"
alt="Latest funding entries after" width="360" /> |
### Consecutive fetch consistency
| Before | After |
|---|---|
| <img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/28671/before-ac2-funding-consistent.png"
alt="Funding consistency before" width="360" /> | <img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/28671/after-ac2-funding-consistent.png"
alt="Funding consistency after" width="360" /> |
### Video
- Before video:
[before.mp4](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/28671/before.mp4)
- After video:
[after.mp4](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/28671/after.mp4)
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test changes)
- [ ] I confirm that this PR addresses all items listed in the
description
[TAT-2057]:
https://consensyssoftware.atlassian.net/browse/TAT-2057?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!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.
`PerpsTransactionsView` wires 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.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c7506b5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>1 parent 845825f commit f285cd7
12 files changed
Lines changed: 743 additions & 70 deletions
File tree
- app
- components/UI/Perps
- Views/PerpsTransactionsView
- hooks
- utils
- controllers/perps
- constants
- providers
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
759 | 759 | | |
760 | 760 | | |
761 | 761 | | |
| 762 | + | |
762 | 763 | | |
763 | 764 | | |
764 | 765 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
92 | 96 | | |
93 | 97 | | |
Lines changed: 30 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
178 | 181 | | |
179 | 182 | | |
180 | 183 | | |
| |||
299 | 302 | | |
300 | 303 | | |
301 | 304 | | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
302 | 308 | | |
303 | 309 | | |
304 | 310 | | |
| |||
318 | 324 | | |
319 | 325 | | |
320 | 326 | | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
321 | 330 | | |
322 | 331 | | |
323 | 332 | | |
| |||
350 | 359 | | |
351 | 360 | | |
352 | 361 | | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
353 | 365 | | |
354 | 366 | | |
355 | 367 | | |
| |||
368 | 380 | | |
369 | 381 | | |
370 | 382 | | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
371 | 386 | | |
372 | 387 | | |
373 | 388 | | |
| |||
426 | 441 | | |
427 | 442 | | |
428 | 443 | | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
429 | 447 | | |
430 | 448 | | |
431 | 449 | | |
| |||
459 | 477 | | |
460 | 478 | | |
461 | 479 | | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
462 | 483 | | |
463 | 484 | | |
464 | 485 | | |
| |||
477 | 498 | | |
478 | 499 | | |
479 | 500 | | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
480 | 504 | | |
481 | 505 | | |
482 | 506 | | |
| |||
499 | 523 | | |
500 | 524 | | |
501 | 525 | | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
502 | 529 | | |
503 | 530 | | |
504 | 531 | | |
| |||
614 | 641 | | |
615 | 642 | | |
616 | 643 | | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
617 | 647 | | |
618 | 648 | | |
619 | 649 | | |
| |||
Lines changed: 55 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
4 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
5 | 16 | | |
6 | 17 | | |
7 | 18 | | |
| |||
77 | 88 | | |
78 | 89 | | |
79 | 90 | | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
80 | 94 | | |
81 | 95 | | |
82 | 96 | | |
| |||
194 | 208 | | |
195 | 209 | | |
196 | 210 | | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
197 | 233 | | |
198 | 234 | | |
199 | 235 | | |
| |||
490 | 526 | | |
491 | 527 | | |
492 | 528 | | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
493 | 540 | | |
494 | 541 | | |
495 | 542 | | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
496 | 549 | | |
497 | 550 | | |
498 | 551 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
302 | 302 | | |
303 | 303 | | |
304 | 304 | | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
305 | 308 | | |
306 | 309 | | |
307 | 310 | | |
| |||
897 | 900 | | |
898 | 901 | | |
899 | 902 | | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
900 | 906 | | |
901 | 907 | | |
902 | 908 | | |
| |||
Lines changed: 132 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
588 | 588 | | |
589 | 589 | | |
590 | 590 | | |
591 | | - | |
592 | | - | |
593 | 591 | | |
594 | 592 | | |
595 | 593 | | |
| |||
608 | 606 | | |
609 | 607 | | |
610 | 608 | | |
| 609 | + | |
611 | 610 | | |
612 | 611 | | |
613 | | - | |
614 | | - | |
615 | 612 | | |
616 | 613 | | |
617 | 614 | | |
| |||
1369 | 1366 | | |
1370 | 1367 | | |
1371 | 1368 | | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
| 1408 | + | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
| 1452 | + | |
| 1453 | + | |
| 1454 | + | |
| 1455 | + | |
| 1456 | + | |
| 1457 | + | |
| 1458 | + | |
| 1459 | + | |
| 1460 | + | |
| 1461 | + | |
| 1462 | + | |
| 1463 | + | |
| 1464 | + | |
| 1465 | + | |
| 1466 | + | |
| 1467 | + | |
| 1468 | + | |
| 1469 | + | |
| 1470 | + | |
| 1471 | + | |
| 1472 | + | |
| 1473 | + | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
1372 | 1500 | | |
1373 | 1501 | | |
1374 | 1502 | | |
| |||
0 commit comments