Skip to content

fix(scan): repoint contract leaderboard to real indexer data#96

Merged
github-actions[bot] merged 1 commit into
mainfrom
fix/scan-contract-leaderboard
Jun 8, 2026
Merged

fix(scan): repoint contract leaderboard to real indexer data#96
github-actions[bot] merged 1 commit into
mainfrom
fix/scan-contract-leaderboard

Conversation

@satyakwok

@satyakwok satyakwok commented Jun 8, 2026

Copy link
Copy Markdown
Member

Problem

The contract leaderboard's By Calls / By Gas Used tabs crashed on open (/leaderboard/contract/calls is also the default landing for the Contract category). The pages fetched /contracts/stats expecting calls + gas_used per contract, but the indexer never tracks those aggregates — the native block view carries no receipt, so transactions.contract_address is never populated. The missing fields hit formatNumber(undefined).toLocaleString() and took down the whole render via the error boundary.

Fix

Repoint the two tabs to the orderings the indexer actually serves:

  • Recently Deployed/contracts/recent (newest first)
  • Pioneers/contracts/pioneers (earliest first)

Both render rank, address, first/last seen block, and code hash through a shared ContractRanking component. The old /calls and /gas paths stay as redirects so existing links don't 404. Drops the now-unused ContractStat type, fetchContractStats, and useContractStats.

Verification

  • tsc --noEmit clean
  • Both /contracts/recent and /contracts/pioneers return 200 with the expected shape on testnet
  • Browser-checked all three URLs (recent, pioneers, and the redirecting calls): rows render, no console errors, no error boundary

Summary by CodeRabbit

  • New Features
    • Added "Recently Deployed" and "Pioneers" contract leaderboards to replace previous "Top by Calls" and "Top by Gas Used" views.
    • Updated contract leaderboard navigation menu and tabs accordingly.

The contract leaderboard's "by calls" / "by gas" tabs crashed on open:
they fetched /contracts/stats expecting calls + gas_used per contract,
but the indexer never tracks those aggregates (the native block view
carries no receipt, so contract_address is never populated). The missing
fields hit formatNumber(undefined).toLocaleString() and took down the
whole render via the error boundary.

Repoint the two tabs to the orderings the indexer actually serves:
- Recently Deployed -> /contracts/recent (newest first)
- Pioneers          -> /contracts/pioneers (earliest first)

Both render rank, address, first/last seen block, and code hash through a
shared ContractRanking component. The old /calls and /gas paths stay as
redirects so existing links don't 404. Drops the now-unused ContractStat
type, fetchContractStats, and useContractStats.
@github-actions github-actions Bot enabled auto-merge (squash) June 8, 2026 09:51
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request refactors the contract leaderboard section by replacing stats-based sorting ("top by calls," "top by gas") with deployment-order leaderboards ("recently deployed," "pioneers"). The old client-side leaderboard pages are converted to server-side redirects. A new shared ContractRanking component handles pagination and rendering for both ordering modes, powered by updated API fetchers and a new useContractList hook. Navigation surfaces (layout tabs and header dropdown) are updated to point to the new routes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: repointing the contract leaderboard from broken endpoints to real indexer data.
Description check ✅ Passed The description includes Problem, Fix, and Verification sections that match the template structure and thoroughly explain the changes, rationale, and testing performed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/scan-contract-leaderboard

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/scan/components/leaderboard/ContractRanking.tsx`:
- Around line 30-35: When the dataset changes the existing page state can point
past the new totalPages causing paged to be empty; add an effect that
recalculates totalPages (using data?.length and PAGE_SIZE) and clamps/resets
page via setPage to Math.min(Math.max(1, page), totalPages) (or to 1 when
totalPages is 0) so the current page is valid; implement this behavior wherever
you manage pagination state (references: page, setPage, totalPages, paged,
useMemo, PAGE_SIZE, and the data prop).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b8cf5c59-0929-447a-94dc-f1fa1a67a723

📥 Commits

Reviewing files that changed from the base of the PR and between c6ee82b and e0f04a7.

📒 Files selected for processing (10)
  • apps/scan/app/[locale]/leaderboard/contract/calls/page.tsx
  • apps/scan/app/[locale]/leaderboard/contract/gas/page.tsx
  • apps/scan/app/[locale]/leaderboard/contract/layout.tsx
  • apps/scan/app/[locale]/leaderboard/contract/page.tsx
  • apps/scan/app/[locale]/leaderboard/contract/pioneers/page.tsx
  • apps/scan/app/[locale]/leaderboard/contract/recent/page.tsx
  • apps/scan/components/layout/header.tsx
  • apps/scan/components/leaderboard/ContractRanking.tsx
  • apps/scan/lib/api.ts
  • apps/scan/lib/hooks.ts

Comment on lines +30 to +35
const [page, setPage] = useState(1);

const totalPages = Math.max(1, Math.ceil((data?.length ?? 0) / PAGE_SIZE));
const paged = useMemo(
() => (data ?? []).slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE),
[data, page],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset/clamp page when the contract list shrinks to avoid blank tables.

Line 30 keeps prior page state across dataset changes. If the user is on a later page and the new data has fewer pages, Line 34 slices to an empty array while (data?.length ?? 0) > 0, so the table renders with no rows and no empty-state message.

Suggested fix
-import { useMemo, useState } from "react";
+import { useEffect, useMemo, useState } from "react";
@@
   const totalPages = Math.max(1, Math.ceil((data?.length ?? 0) / PAGE_SIZE));
+  useEffect(() => {
+    setPage((p) => Math.min(p, totalPages));
+  }, [totalPages]);
+
   const paged = useMemo(
     () => (data ?? []).slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE),
     [data, page],
   );

Also applies to: 52-77, 98-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/scan/components/leaderboard/ContractRanking.tsx` around lines 30 - 35,
When the dataset changes the existing page state can point past the new
totalPages causing paged to be empty; add an effect that recalculates totalPages
(using data?.length and PAGE_SIZE) and clamps/resets page via setPage to
Math.min(Math.max(1, page), totalPages) (or to 1 when totalPages is 0) so the
current page is valid; implement this behavior wherever you manage pagination
state (references: page, setPage, totalPages, paged, useMemo, PAGE_SIZE, and the
data prop).

@github-actions github-actions Bot merged commit 29d6408 into main Jun 8, 2026
7 checks passed
@satyakwok satyakwok deleted the fix/scan-contract-leaderboard branch June 8, 2026 10:01
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.

1 participant