Skip to content

Delegates to Kubb#1913

Merged
pikonha merged 15 commits into
devfrom
feat/dao-page-delegation-stats
May 26, 2026
Merged

Delegates to Kubb#1913
pikonha merged 15 commits into
devfrom
feat/dao-page-delegation-stats

Conversation

@pikonha
Copy link
Copy Markdown
Member

@pikonha pikonha commented May 18, 2026

Note

Medium Risk
Broad dashboard data-layer swap plus API pagination/count behavior when transfer filters are applied; regressions could affect tables, infinite scroll, and filtered balance history.

Overview
This PR adds server-side from and to filters on GET /accounts/{address}/balances/historical (OpenAPI, GraphQL gateway, repository join on transfer, and count when those filters are set). The dashboard balance history sends buy/sell and custom counterparty filters in the query via useHistoricalBalancesInfinite, so totalCount and pagination match the filtered set instead of client-side filtering.

The holders-and-delegates area is migrated from Apollo GraphQL to kubb-generated @anticapture/client hooks (infinite queries for delegates, balance history, delegation history, proposals activity, account interactions, etc.). Tables expose hasNextPage directly instead of nested pagination objects, and shared pagination types are trimmed.

Delegate proposals activity infinite scroll is fixed: getNextPageParam uses totalProposals from the first page (summary fields are not repeated on later pages). The activity drawer persists user vote filter in the URL via nuqs.

Graph/chart hooks for balance and voting-power history switch to REST with adjusted query params (e.g. fromValue, limit, sort direction).

Reviewed by Cursor Bugbot for commit 39ae1e1. Configure here.

@pikonha pikonha self-assigned this May 18, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
anticapture Ready Ready Preview, Comment May 26, 2026 5:15pm
anticapture-storybook Ready Ready Preview, Comment May 26, 2026 5:15pm

Request Review

@railway-app
Copy link
Copy Markdown

railway-app Bot commented May 18, 2026

🚅 Deployed to the anticapture-pr-1913 environment in anticapture-infra

Service Status Web Updated (UTC)
tempo ✅ Success (View Logs) May 26, 2026 at 5:28 pm
loki ✅ Success (View Logs) Web May 26, 2026 at 5:28 pm
anticapture-mcp-server ✅ Success (View Logs) Web May 26, 2026 at 5:28 pm
grafana ✅ Success (View Logs) Web May 26, 2026 at 5:27 pm
prometheus ✅ Success (View Logs) Web May 26, 2026 at 5:27 pm
alertmanager ✅ Success (View Logs) Web May 26, 2026 at 5:27 pm
otelcol ✅ Success (View Logs) May 26, 2026 at 5:27 pm
gateful 🕛 Waiting for status checks (View Logs) Web May 26, 2026 at 5:27 pm
lil-nouns-api ✅ Success (View Logs) May 26, 2026 at 2:26 am
aave-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
fluid-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
obol-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
nouns-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
scroll-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
gitcoin-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
uniswap-api ✅ Success (View Logs) May 26, 2026 at 2:25 am
shutter-api ✅ Success (View Logs) May 26, 2026 at 2:24 am
ens-api ✅ Success (View Logs) May 26, 2026 at 2:24 am
compound-api ✅ Success (View Logs) May 26, 2026 at 2:24 am
gitcoin-indexer ✅ Success (View Logs) May 25, 2026 at 3:01 pm
aave-indexer ✅ Success (View Logs) May 25, 2026 at 3:01 pm
lil-nouns-indexer ✅ Success (View Logs) May 25, 2026 at 3:01 pm
fluid-indexer ✅ Success (View Logs) May 25, 2026 at 3:01 pm
scroll-indexer ✅ Success (View Logs) May 25, 2026 at 3:00 pm
address-enrichment ✅ Success (View Logs) May 25, 2026 at 3:00 pm
shutter-indexer ✅ Success (View Logs) May 25, 2026 at 3:00 pm
ens-indexer ✅ Success (View Logs) May 25, 2026 at 2:59 pm
compound-indexer ✅ Success (View Logs) May 25, 2026 at 2:59 pm
obol-indexer ✅ Success (View Logs) May 25, 2026 at 2:59 pm
uniswap-indexer ✅ Success (View Logs) May 25, 2026 at 2:59 pm
nouns-indexer ✅ Success (View Logs) May 25, 2026 at 2:59 pm
ens-relayer ✅ Success (View Logs) May 25, 2026 at 2:59 pm
compound-indexer-offchain ✅ Success (View Logs) May 21, 2026 at 2:42 pm
ens-indexer-offchain ✅ Success (View Logs) May 21, 2026 at 2:41 pm
gitcoin-indexer-offchain ✅ Success (View Logs) May 21, 2026 at 2:40 pm
uniswap-indexer-offchain ✅ Success (View Logs) May 21, 2026 at 2:40 pm
api-gateway ✅ Success (View Logs) Web May 18, 2026 at 2:33 pm
erpc ✅ Success (View Logs) Web May 18, 2026 at 2:31 pm
nodeful ✅ Success (View Logs) May 18, 2026 at 2:31 pm
14 services not affected by this PR
  • RabbitMQ
  • RabbitMQ Web UI
  • tailscale-entrance
  • caddy-zero-trust
  • s3manager
  • consumer
  • hyperindex-erpc
  • hyperindex-database
  • hyperindex-sync
  • hyperindex-sync-database
  • hyperindex-hyperrpc-database
  • hyperindex-hyperrpc
  • logic-system
  • dispatcher

@railway-app railway-app Bot temporarily deployed to anticapture-infra / anticapture-pr-1913 May 18, 2026 14:25 Destroyed
@pikonha pikonha marked this pull request as ready for review May 21, 2026 12:58
@pikonha pikonha requested a review from isadorable-png as a code owner May 21, 2026 12:58
Copy link
Copy Markdown
Collaborator

🎨 UI Review

Automated review · No Figma reference found · Preview · No spec linked
ℹ️ Path A — Reviewed without a Figma reference. ClickUp MCP was unavailable during this run. Review grounded in diff analysis.
ℹ️ Scope: Pure data-layer migration (GraphQL → Kubb REST client). No layout, styling, or copy changes to validate.


This PR migrates all features/holders-and-delegates/ data hooks from Apollo/GraphQL to the Kubb-generated REST SDK. The six .tsx UI files that changed (DelegationTable.tsx, Delegates.tsx, DelegateProposalsActivity.tsx, ProposalsTable.tsx, VotingPowerHistoryTable.tsx, VoteCompositionTable.tsx) received only import swaps and hook return-value destructuring updates — JSX render trees are entirely untouched.


✅ Nothing to flag — fully validated

  • Zero CSS/Tailwind class changes across all files.
  • No new UI components or pages added.
  • No user-visible copy changes.
  • hasNextPage / fetchNextPage / isFetchingNextPage correctly threaded to existing loading states and infinite-scroll sentinels.
  • New types.ts re-export shim preserves internal import stability — no consumer changes required.
  • The migration is invisible to users; visual output should be identical before and after.

Review by @isadorable-png · automated UI review


_Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Collaborator

🎨 UI Review

Automated review · No Figma reference found · Spec: not linked · Preview: SAML-protected (no bypass token configured)
ℹ️ Path A — Reviewed without a Figma reference. Grounded in diff analysis + UX-expert evaluation.

This is a data-layer refactoring (Apollo GraphQL → REST/React Query) for the holders-and-delegates section. 23 files changed, almost entirely hook rewrites. Two behavioral changes worth flagging:


Delegate Proposals Activity

Vote filter state now URL-persisted ← note for author

  • DelegateProposalsActivity.tsx — the vote filter (all / yes / no / abstain / no_vote) moved from local useState to useQueryState (nuqs).
  • The filter is now reflected in the URL, making it shareable and bookmark-friendly. This is a UX improvement — confirm it's intentional.
  • When a user shares a delegate URL, the recipient will land on the same filtered view. Check that this is the desired behaviour for direct-link sharing. [Code-only]

Balance + Delegation History Graphs

Graph data may differ from before ← question for author

  • useBalanceHistoryGraph and useDelegateDelegationHistoryGraph both now:
    • Filter out zero-value entries with fromValue: "1" (zero-delta rows were previously included in the chart)
    • Fetch up to limit: 1000 entries
    • Request data in ascending order from the API instead of descending + client-side .sort()
  • The chart lines may look different if zero-delta events were previously rendered.
  • Question: Is fromValue: "1" intentional to clean up flat/noisy chart lines, or a side-effect of the migration? [Code-only]

Regression check

  • useDelegateshasNextPage boolean replaces pagination.hasNextPage; the "Load more" trigger is functionally identical. ✓
  • VotingPowerHistoryTableorderBy prop dropped from the hook call (hook no longer accepts it, was already defaulting to timestamp). ✓
  • useAccountInteractionsDatatotalCount type changes from bigint to number; displayed value unchanged. ✓
  • No - lines removing visible UI elements outside what's accounted for by the migration. ✓

Validated correct — no change needed

  • BalanceHistoryVariationGraph and BalanceHistoryTable — destructuring updated, visual output unchanged. ✓
  • VoteCompositionTable — import path change only, no visual impact. ✓
  • useProposalsActivitypagination object preserved; pager UI unaffected. ✓

Review by @isadorable-png · automated UI review


Generated by Claude Code

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e690291b20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/dashboard/features/holders-and-delegates/hooks/useBalanceHistory.ts Outdated
Copy link
Copy Markdown
Collaborator

🎨 UI Review

Automated review · Figma: not found — no link in PR body · Preview: SAML-protected (no bypass token)
ℹ️ Path A — Reviewed without a Figma reference — grounded in diff analysis + UX-expert evaluation.

This PR migrates the Holders & Delegates section from GraphQL to Kubb REST. Most changes are hook internals with no visual consequence. Findings below cover the places where rendered output or UX behavior actually changes.


Delegate drawer — Proposals Activity tab

Vote filter now persisted in URL ← confirm param key + reset behavior [Code-only]

DelegateProposalsActivity.tsx — the vote filter tabs (All / Yes / No / Abstain / No Vote) moved from useState to useQueryState:

-  const [userVoteFilter, setUserVoteFilter] = useState<string>("all");
+  const [userVoteFilter, setUserVoteFilter] = useQueryState(
+    "userVoteFilter",
+    parseAsStringEnum(["all", "yes", "no", "abstain", "no_vote"]).withDefault("all"),
+  );

The active filter is now written to ?userVoteFilter=yes in the URL. Verify:

  1. The key userVoteFilter doesn't collide with any existing params on the delegate detail page.
  2. Opening the delegate drawer from a fresh URL (no params) correctly defaults to "All".
  3. Whether it's intentional that closing and reopening the drawer preserves the filter (it now will, since it's in the URL).

Balance History graph — zero-value events excluded + 1000-point cap

fromValue: "1" + limit: 1000 added ← confirm truncation handling [Code-only]

useBalanceHistoryGraph.ts:

+  fromValue: "1",
+  limit: 1000,
  1. Zero-value transfers excluded — flat segments caused by zero-delta events will disappear from the graph. Likely a visual improvement, but confirm with data.
  2. 1000-point cap — token holders with very dense history will see a truncated chart with no indication data was cut off. If hasNextPage is true when the cap is hit, consider a note on the chart (e.g. "Showing last 1000 events").

Delegation History graph — same changes applied

Same fromValue: "1" + limit: 1000 [Code-only]

useDelegateDelegationHistoryGraph.ts — identical pattern. Applies to the Voting Power History graph on the delegate drawer. Same truncation concern applies.


Voting Power History table + Delegation History table — orderBy removed

Column-sort by field may be silently broken ← needs verification [Code-only]

VotingPowerHistoryTable.tsx and DelegationHistoryTable.tsx:

-    orderBy: sortBy,
     orderDirection: sortDirection,

The orderBy field was removed because the new REST hook doesn't expose it. If either table has column-header sort buttons that pass a field name to sortBy, those clicks will now silently have no effect — the table will always use the endpoint's default sort column. Please confirm whether column-sort controls exist; if they do, hide or disable the by-field ones.


Holders & Delegates pie chart — "Others" segment fix

BigInt(0)0 comparison corrected[Code-only]

useAccountInteractionsData.ts:

-  if (othersValue > BigInt(0)) {
+  if (othersValue > 0) {

The previous comparison was a type mismatch (number vs. BigInt), which would evaluate to false in strict JS — the "Others" segment in the interactions pie chart likely never appeared before. This fix should make "Others" show up correctly when applicable. Worth confirming in the preview.


✅ No visual change

  • DelegationTable.tsx, Delegates.tsxpagination.hasNextPage → flat hasNextPage; Load More trigger behavior identical.
  • VoteCompositionTable.tsx — import-source refactor only; no JSX changed.
  • ProposalsTable.tsx — type import change only.
  • BalanceHistoryTable.tsx, BalanceHistoryVariationGraph.tsx — destructuring alias changes; rendering identical.
  • All hooks (useDelegates, useBalanceHistory, useDelegationHistory, useProposalsActivity, useDelegateDelegationHistory) — internal refactors; public data shape preserved.

Review by @isadorable-png — automated UI review


Generated by Claude Code

…tals

The API only returns summary fields (totalProposals, votedProposals, winRate, etc.)
on the first page; subsequent pages return zeros. Reading lastPage.totalProposals
caused getNextPageParam to return undefined after page 1, breaking infinite scroll
on the delegate proposals activity drawer. Switch the next-page check and the
summary metrics to read from the first page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2df53fa420

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/dashboard/features/holders-and-delegates/hooks/useProposalsActivity.ts Outdated
@railway-app railway-app Bot temporarily deployed to anticapture-infra / anticapture-pr-1913 May 21, 2026 19:34 Destroyed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1388c7f00

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/dashboard/features/holders-and-delegates/hooks/useDelegationHistory.ts Outdated
pikonha and others added 2 commits May 26, 2026 08:12
Backend orders by timestamp only, so offset pagination ties or
concurrent inserts can repeat rows on the next page. Dedupe by
transactionHash + delegateAddress + amount + timestamp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The /api/gateful proxy attaches Authorization only when
BLOCKFUL_API_TOKEN is set. Without it, voting-powers (and any
other auth-gated endpoint on the gateful upstream) returns 401,
which surfaces as the "Oops" error state on the Delegates table
and breaks the infinite-scroll e2e.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Temporary debug step that confirms the BLOCKFUL_API_TOKEN secret
reaches the runner and that the upstream accepts it. Will be
removed once the e2e auth wiring is confirmed green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ead3ce7a8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +29 to +31
const loaded = allPages.reduce((s, p) => s + p.proposals.length, 0);
const total = allPages[0]?.totalProposals ?? 0;
return loaded >= total ? undefined : loaded;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Compute proposal pagination offset from unique merged rows

This hook now deduplicates proposals by proposal.id, but getProposalsNextPage still advances skip using the raw number of fetched rows. When the backend returns overlapping pages (possible because proposals activity ordering is not uniquely keyed, e.g. timestamp ties), duplicate rows consume offset space and the next request can skip unseen proposals, causing truncated infinite scroll and hasNextPage turning false too early. Fresh evidence in this commit: deduping is done at lines 72-79, while offset is still based on raw page lengths at lines 29-31.

Useful? React with 👍 / 👎.

orderDirection,
limit,
},
{ query: { getNextPageParam } },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive delegator next offset from deduplicated item count

The infinite query uses the generic getNextPageParam (raw fetched row count), but the hook later removes duplicate delegatorAddress entries before rendering. If pagination overlaps occur (the delegators query orders by non-unique aggregates/timestamps), duplicates will still advance offset and can skip unique delegators on subsequent pages, so users may never see all rows. Fresh evidence in this commit: deduping was reintroduced at lines 45-53, but next-page offset still comes from the raw helper wired at line 42.

Useful? React with 👍 / 👎.

Turbo strips env vars not declared in passThroughEnv before running
a task. The secret was reaching the workflow step (verified via
diagnostic curl: with-token=200, no-token=401) but Turbo dropped it
before launching playwright, so the dev-server proxy ran without an
upstream token and got 401 on every voting-powers call.

Add BLOCKFUL_API_TOKEN to passThroughEnv for the three test:e2e
task definitions, and drop the temporary diagnostic step now that
the root cause is identified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c243eeb5bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +100 to +106
const {
data: transfers,
loading,
fetchNextPage,
error,
hasNextPage,
} = useBalanceHistory({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use fetchingMore for balance-history load-more state

After migrating useBalanceHistory to TanStack infinite queries, loading now only tracks the initial fetch while pagination state is exposed separately as fetchingMore. This destructuring still ignores fetchingMore, so the table continues to use initial-load state for isLoadingMore; with the table's intersection observer guard in shared/components/design-system/table/Table.tsx, that can repeatedly trigger onLoadMore while a next page is already in flight, causing overlapping page fetch calls and unstable infinite-scroll behavior.

Useful? React with 👍 / 👎.

Comment on lines +95 to +101
const { data, isLoading, error, fetchNextPage, hasNextPage } =
useHistoricalVotingPowerByAccountIdInfinite(
daoId.toLowerCase() as HistoricalVotingPowerByAccountIdPathParamsDaoEnumKey,
accountId,
params,
{ query: { getNextPageParam } },
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Surface next-page fetching state in delegation history hook

This hook switched from a locally guarded fetchMore flow to raw useHistoricalVotingPowerByAccountIdInfinite pagination, but it only returns loading: isLoading and does not expose isFetchingNextPage. Consumers that wire infinite scroll via the shared table now lack an in-flight pagination flag, so onLoadMore can fire again before the previous page resolves, leading to repeated next-page invocations under sustained intersection.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1e2680a5cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@railway-app railway-app Bot temporarily deployed to anticapture-infra / anticapture-pr-1913 May 26, 2026 17:27 Destroyed
@pikonha pikonha merged commit 025b931 into dev May 26, 2026
46 checks passed
@pikonha pikonha deleted the feat/dao-page-delegation-stats branch May 26, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants