Add slot filters for addresses' transactions#1024
Conversation
|
@anselsol is attempting to deploy a commit to the Solana Foundation Team on Vercel. A member of the Team first needs to authorize it. |
Greptile SummaryThis PR adds address transaction filters backed by Triton's transaction-history RPC. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (10): Last reviewed commit: "Merge upstream/master into feat/add-slot..." | Re-trigger Greptile |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Hi. Thank you for contribution! |
c5b0b67 to
cc9e865
Compare
The rebase onto upstream master pulled in stricter rules and updated prettier/tailwind config (solana-foundation#1015, solana-foundation#1007): - Prefix test titles with 'should' (vitest/valid-title) - File-level eslint-disable for RegExp test assertions (no-restricted-syntax) - Return undefined instead of null in app/components (unicorn/no-null) - Re-sort the HistoryFilterBar import in TransactionHistoryCard (simple-import-sort) - Reflow imports/JSX and tailwind class order to satisfy prettier Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Gm gm @rogaldh ! Rebased and fixed code for ESLint new rules, I've also ran the full CI locally and it goes through 🤝 |
…ters-for-programs # Conflicts: # app/providers/accounts/history.tsx
askov
left a comment
There was a problem hiding this comment.
Nice migration — the URL ↔ filters ↔ RPC mapping is clean, and the generation-counter pattern for invalidating in-flight requests on filter change is the right primitive (the dropped-stale-write test is exactly the right shape). A few inline notes on things I'm fairly sure are real, mostly around the fallback path and HTTP-level error handling.
| }); | ||
| } | ||
|
|
||
| export function useClearAccountHistories() { |
There was a problem hiding this comment.
nitpick (non-blocking): useClearAccountHistories is exported but I don't see a caller — the existing URL-change handler in HistoryProvider still dispatches { type: ActionType.Clear, url } inline.
suggestion: Delete this hook, or use it in place of the inline dispatch so the public surface of the provider matches what's actually consumed.
|
@askov all your findings are fixed 🤝 |
|
What are the next steps here guys? |
|
|
Gm gm guys, how can I help push this through the finish line? |
Sorry for the long response. Please do a rebase/merge and make sure nothing breaks regarding the UI (there was a huge ui migration, no more e- prefixes for tailwind classes). We will try to merge it as soon as possible |
Reconciled three conflicts: - app/providers/accounts/history.tsx: kept HEAD's filter machinery (HistoryFilters, getTransactionsForAddress, fallback, generation/method-support contexts) and accepted upstream's simpler `Set<string>` InFlightContext typing over HEAD's `Readonly<Set<string>>` wrapper. - app/components/account/HistoryCardComponents.tsx: ported HEAD's actions/subHeader slots onto upstream's new <CardHeader ui="dashkit"> / <CardTitle> components, switching to a vertical layout only when a subHeader (filter chips) is present. - app/components/shared/ui/input.tsx: kept HEAD's calendar-picker-indicator invert rule, applied to upstream's prefix-free Tailwind classes. Also dropped the `e-` Tailwind prefix from HistoryFilterBar.tsx and replaced its Bootstrap chip markup (`badge bg-info-soft`, `btn btn-link`) with the upstream <Badge ui="dashkit" variant="info"> component to match the post- Dashkit-SCSS-removal conventions.
The repo's global stylesheet reverts Tailwind Preflight's button reset, so unstyled <button>s render with native UA chrome (dark background, border, padding) that broke out of the chip's teal pill. Reset bg/border/padding via utility classes (higher specificity than the element-level revert) and inherit text color so the X glyph matches the badge text.
69d6346 to
40541e2
Compare
Upstream extracted HistoryCardHeader/Footer into app/shared/ui/HistoryCard/ and split the transaction history card into BaseTransactionHistoryCard (presentational) + TransactionHistoryCard (container). Reconciled: - Ported the actions/subHeader slots onto the new shared HistoryCardHeader. - Threaded those slots through BaseTransactionHistoryCard as headerActions / headerSubRow so the container can supply the filter trigger and chip row. - Rebuilt TransactionHistoryCard as a container that keeps the filter wiring (filters, hasActiveFilters, resetHistory, clearFilters, filtersSupported) and renders BaseTransactionHistoryCard with the filter UI plugged into the header. - Accepted upstream's gutted HistoryCardComponents.tsx (now only the row type and getTransactionRows; header/footer live at the new location). In history.tsx, reconciled with upstream's empty-page robustness work: - Added fetchSignatures (with empty-first-page retry) and routed it through the getSignaturesForAddress fallback path, where the protection actually applies; the Triton getTransactionsForAddress path is unchanged. - Added the reconcile-time empty-refresh guard, adapted to the existing `append` flag (the equivalent of upstream's `before === undefined`). - Updated history.spec.ts to use `append: true|false` instead of `before`.
Description
The goal of this PR is to provide a way for users of explorer.solana.com to filter an address's transactions — by slot range, block time, and status — without relying on any kind of indexing for the explorer.
To do this, the PR switches the transaction history from the
getSignaturesForAddress+ per-signaturegetTransactionpattern over to Triton'sgetTransactionsForAddressmethod, which combines address-history lookup, filtering, and pagination into a single RPC call.The filter API exposed in the UI maps one-to-one onto the method's
filtersobject, so the explorer's URL params share the same names and shape as the RPC:slot.gte,slot.ltefilters.slot.{gte,lte}blockTime.gte,blockTime.ltefilters.blockTime.{gte,lte}status(succeeded/failed)filters.statusPagination uses the opaque
paginationTokencursor returned by the method (replacing the old trailing-signaturebeforecursor); loading stops once the RPC returns a null token.Graceful degradation on non-Triton/non-Helius endpoints
getTransactionsForAddressis a Triton extension. If the configured RPC endpoint doesn't implement it (the call returns a JSON-RPC "method not found"), the explorer:getSignaturesForAddressso transaction history still loads, andDetection is behavioral (based on the method-not-found response), so it works for Triton, Helius, or any other endpoint that implements the method — no provider allowlist is hardcoded.
How it's implemented in the UI:
Funnel 1: user filters from the UI
slot.gte,slot.lte,blockTime.gte,blockTime.lte,status) and picked up byapp/components/account/history/HistoryFilterBar.tsxfiltersobjectFunnel 2: the URL already contains filter params
https://explorer.solana.com/address/LGDSXVcDx4Ynw7UXavGEe5nwzyUZZ5d3sLkwYk26LUf?slot.gte=375952400
useHistoryFiltersinapp/components/account/history/HistoryFilterBar.tsxfiltersobject, and the active filters render as removable pills above the tableType of change
Screenshots
Testing
app/components/account/history/__tests__/HistoryFilterBar.spec.tsx: tests the filters button, URL param round-tripping, and pills behavior across slot, block-time, and status filtersapp/providers/accounts/__tests__/history.spec.tsx: tests that the provider maps filters onto thegetTransactionsForAddressrequest, threads thepaginationTokencorrectly when loading more (including short pages that still carry a token), discards superseded in-flight responses on filter change, clears only the target address on reset, and falls back togetSignaturesForAddress(disabling filtering) when the method isn't availableRelated Issues
Checklist
build:infoscript to update build information