Skip to content

feat: kleros identity badge#535

Merged
antoncoding merged 7 commits into
masterfrom
kleros-identity-tags
May 20, 2026
Merged

feat: kleros identity badge#535
antoncoding merged 7 commits into
masterfrom
kleros-identity-tags

Conversation

@antoncoding
Copy link
Copy Markdown
Owner

@antoncoding antoncoding commented May 20, 2026

Summary by CodeRabbit

  • New Features

    • Account profiles now show Kleros Scout address tags and badge UI in borrower/supplier tables and oracle info.
    • Tags include tooltips with source details and optional "View Tag Source" links.
    • Account actions menu can include additional contextual links (e.g., linked-vault, tag source).
  • Documentation

    • Technical overview updated to list Account contract tags with a 6‑hour refresh cadence.

Review Change Stack

Closes #536

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 20, 2026

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

Project Deployment Actions Updated (UTC)
monarch Ready Ready Preview, Comment May 20, 2026 2:46pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

@antoncoding has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 8 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2288db67-e089-4fb3-8eed-95c2741c14f6

📥 Commits

Reviewing files that changed from the base of the PR and between 6488622 and 5840622.

📒 Files selected for processing (1)
  • src/components/shared/account-identity.tsx
📝 Walkthrough

Walkthrough

Adds Kleros Scout address tag types and fetch, a React Query hook, KlerosTagBadge UI, AccountActionsPopover extraLinks support, and wires tags into AccountIdentity, market-detail tables, and oracle UI; docs updated.

Changes

Kleros Address Tags Feature

Layer / File(s) Summary
Data types, normalization, and Scout API fetch
src/data-sources/kleros/address-tags.ts
Exports types KlerosAddressTag and KlerosAddressTagsByKey, key/label/address utilities, response parsing that maps Scout /api/address-tags response into keyed tag objects, and fetchKlerosAddressTags with AbortController timeout and error logging.
React Query hook
src/hooks/queries/useKlerosAddressTagsQuery.ts
Implements useKlerosAddressTagsQuery hook with memoized normalized addresses, keyed by chainId, conditional fetch when chainId and addresses are present, configured stale/cache times and placeholder data.
KlerosTagBadge component
src/components/shared/kleros-tag-badge.tsx
New shared badge component rendering a tooltip with Kleros logo, fixed "Source: Kleros Scout" text, optional publicNote, and truncated label.
AccountActionsPopover extraLinks support
src/components/shared/account-actions-popover.tsx
Extended component props with optional extraLinks array, refactored link navigation to use window.open/location.assign instead of Next.js router, filters hrefs and selects external vs internal icons.
AccountIdentity Kleros tag integration
src/components/shared/account-identity.tsx
Accepts optional klerosTag prop, computes klerosLabel when no vault name, renders KlerosTagBadge in badge/compact/full variants, builds actionLinks including linked-vault and "View Tag Source" links, and adjusts vault URL routing.
Table and oracle component wiring
src/features/market-detail/components/borrowers-table.tsx, src/features/market-detail/components/suppliers-table.tsx, src/features/markets/components/oracle/MarketOracle/OracleTypeInfo.tsx
BorrowersTable and SuppliersTable batch-fetch Kleros tags for visible user addresses and pass per-user tags to AccountIdentity rows. OracleTypeInfo displays Kleros badge next to oracle address.
Technical documentation
docs/TECHNICAL_OVERVIEW.md
Updated dynamic data table to document account contract tags sourced from Kleros Scout with 6h stale window and useKlerosAddressTagsQuery hook.

Sequence Diagram(s):

sequenceDiagram
  participant Client
  participant useKlerosAddressTagsQuery
  participant fetchKlerosAddressTags
  participant KlerosScoutAPI
  participant AccountIdentity
  Client->>useKlerosAddressTagsQuery: request tags for addresses
  useKlerosAddressTagsQuery->>fetchKlerosAddressTags: POST normalized addresses
  fetchKlerosAddressTags->>KlerosScoutAPI: HTTP POST /api/kleros/address-tags
  KlerosScoutAPI-->>fetchKlerosAddressTags: tags response
  fetchKlerosAddressTags-->>useKlerosAddressTagsQuery: tags map
  useKlerosAddressTagsQuery-->>AccountIdentity: provide klerosTag
  AccountIdentity->>AccountIdentity: render KlerosTagBadge when present
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • antoncoding/monarch#332: Modifies AccountActionsPopover dropdown menu behavior to add new "DeBank" view menu item, overlapping with this PR's popover enhancements.
  • antoncoding/monarch#294: Refactors AccountActionsPopover to use DropdownMenu, related to this PR's extension with extraLinks.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: kleros identity badge' directly matches the main change—adding Kleros badge display to the account identity component and related UI updates.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kleros-identity-tags

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 added feature request Specific feature ready to be implemented ui User interface labels May 20, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request integrates the Kleros Scout API to display address tags and project metadata for Ethereum addresses throughout the application. It introduces a new API route for proxying requests to Kleros, a custom React Query hook for data fetching, and UI enhancements to components like AccountIdentity and AccountActionsPopover to render these tags. Review feedback identifies a potential type-mismatch issue in the API route's chain ID validation and recommends using Next.js client-side routing instead of full page reloads for internal links within the account actions menu.

Comment thread app/api/kleros/address-tags/route.ts Outdated
}

function parseScoutTag(address: KlerosAddressTag['address'], chainId: number, value: unknown): KlerosAddressTag | null {
if (!isRecord(value) || readText(value.chain_id) !== String(chainId)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The readText helper strictly checks for a string type. If the Scout API returns chain_id as a number (which is common for EVM chain IDs), this check will fail and return null, causing valid tags to be ignored. It's safer to normalize the value to a string before comparison.

Suggested change
if (!isRecord(value) || readText(value.chain_id) !== String(chainId)) {
if (!isRecord(value) || String(value.chain_id) !== String(chainId)) {


import { useCallback, type ReactNode } from 'react';
import { useRouter } from 'next/navigation';
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Since we need to handle internal navigation for app-relative links (like the profile or vault links) without triggering a full page reload, we should restore the useRouter import.

Suggested change
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu';
import { useRouter } from 'next/navigation';
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu';

profileLabel = 'View Portfolio',
}: AccountActionsPopoverProps) {
const router = useRouter();
const toast = useStyledToast();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Re-initialize the router hook to support client-side navigation.

Suggested change
const toast = useStyledToast();
const router = useRouter();
const toast = useStyledToast();

Comment on lines +60 to +69
const handleOpenLink = useCallback((href: string) => {
if (isExternalHref(href)) {
window.open(href, '_blank', 'noopener,noreferrer');
return;
}

if (isAppRelativeHref(href)) {
window.location.assign(href);
}
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using window.location.assign for internal app links causes a full page reload, which breaks the Single Page Application (SPA) experience and is less efficient than using Next.js's client-side routing. Use router.push for app-relative links instead.

Suggested change
const handleOpenLink = useCallback((href: string) => {
if (isExternalHref(href)) {
window.open(href, '_blank', 'noopener,noreferrer');
return;
}
if (isAppRelativeHref(href)) {
window.location.assign(href);
}
}, []);
const handleOpenLink = useCallback((href: string) => {
if (isExternalHref(href)) {
window.open(href, '_blank', 'noopener,noreferrer');
return;
}
if (isAppRelativeHref(href)) {
router.push(href);
}
}, [router]);

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@app/api/kleros/address-tags/route.ts`:
- Around line 129-137: The POST fetch to KLEROS_SCOUT_ADDRESS_TAGS_URL currently
has no timeout and can hang; wrap the call with an AbortController, pass
controller.signal into the fetch options (alongside existing
headers/body/cache), start a setTimeout that calls controller.abort() after a
sensible timeout (e.g., a few seconds), and clear that timer after fetch
resolves or rejects; update the error handling around the fetch/response (where
response is used) to treat an AbortError as a timeout (returning/throwing an
appropriate 504/timeout error). Ensure you reference the existing symbols
KLEROS_SCOUT_ADDRESS_TAGS_URL, normalizedAddresses, chainId, and the local
response variable when implementing this change.

In `@src/components/shared/kleros-tag-badge.tsx`:
- Around line 47-53: The tooltip anchor is a plain <span> so keyboard users
can’t focus it; update the KlerosTagBadge component (the element rendering the
wrapper with className, aria-label, KlerosBadgeLogo and label) to be
keyboard-focusable by replacing the non-focusable span with an
interactive/focusable element (e.g., a <button> or a <span> with tabIndex={0}
and role="button"), preserve the existing aria-label, and ensure the tooltip
library receives focus events (or add an onKeyDown handler to open the tooltip
on Enter/Space) so keyboard users can trigger and read the tooltip content.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e7d85201-8063-4d07-a1e4-968306922ee3

📥 Commits

Reviewing files that changed from the base of the PR and between bad2f3d and ff26df9.

⛔ Files ignored due to path filters (1)
  • public/imgs/kleros-badge.svg is excluded by !**/*.svg
📒 Files selected for processing (10)
  • app/api/kleros/address-tags/route.ts
  • docs/TECHNICAL_OVERVIEW.md
  • src/components/shared/account-actions-popover.tsx
  • src/components/shared/account-identity.tsx
  • src/components/shared/kleros-tag-badge.tsx
  • src/data-sources/kleros/address-tags.ts
  • src/features/market-detail/components/borrowers-table.tsx
  • src/features/market-detail/components/suppliers-table.tsx
  • src/features/markets/components/oracle/MarketOracle/OracleTypeInfo.tsx
  • src/hooks/queries/useKlerosAddressTagsQuery.ts

Comment thread app/api/kleros/address-tags/route.ts Outdated
Comment thread src/components/shared/kleros-tag-badge.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 `@src/data-sources/kleros/address-tags.ts`:
- Line 159: The slice silently drops addresses beyond MAX_ADDRESSES_PER_REQUEST;
update the code around normalizeKlerosAddressList and normalizedAddresses to
detect when addresses.length > MAX_ADDRESSES_PER_REQUEST and emit a clear
warning (e.g., console.warn or the module logger) stating how many addresses
were truncated and which input was trimmed, then proceed to slice; alternatively
(or additionally) add a JSDoc on the containing function mentioning the
MAX_ADDRESSES_PER_REQUEST limit so callers are aware.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: db95ad1e-78f3-4323-b90f-7f706c1fcc64

📥 Commits

Reviewing files that changed from the base of the PR and between ff26df9 and c4076f3.

📒 Files selected for processing (6)
  • docs/TECHNICAL_OVERVIEW.md
  • src/components/shared/account-identity.tsx
  • src/components/shared/kleros-tag-badge.tsx
  • src/data-sources/kleros/address-tags.ts
  • src/features/market-detail/components/borrowers-table.tsx
  • src/features/market-detail/components/suppliers-table.tsx
✅ Files skipped from review due to trivial changes (1)
  • docs/TECHNICAL_OVERVIEW.md

chainId,
signal,
}: FetchKlerosAddressTagsParams): Promise<KlerosAddressTagsByKey> {
const normalizedAddresses = normalizeKlerosAddressList(addresses).slice(0, MAX_ADDRESSES_PER_REQUEST);
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 | 🟡 Minor | ⚡ Quick win

Warn when addresses are silently dropped.

The slice silently truncates to 50 addresses. If a caller passes 100 addresses, the last 50 are ignored with no indication. Add a warning or document this limit in a JSDoc comment.

🔊 Add warning when truncating
 const normalizedAddresses = normalizeKlerosAddressList(addresses).slice(0, MAX_ADDRESSES_PER_REQUEST);
+
+if (normalizedAddresses.length < addresses.length) {
+  console.warn(`[kleros-address-tags] Truncated to ${MAX_ADDRESSES_PER_REQUEST} addresses (received ${addresses.length})`);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizedAddresses = normalizeKlerosAddressList(addresses).slice(0, MAX_ADDRESSES_PER_REQUEST);
const normalizedAddresses = normalizeKlerosAddressList(addresses).slice(0, MAX_ADDRESSES_PER_REQUEST);
if (normalizedAddresses.length < addresses.length) {
console.warn(`[kleros-address-tags] Truncated to ${MAX_ADDRESSES_PER_REQUEST} addresses (received ${addresses.length})`);
}
🤖 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 `@src/data-sources/kleros/address-tags.ts` at line 159, The slice silently
drops addresses beyond MAX_ADDRESSES_PER_REQUEST; update the code around
normalizeKlerosAddressList and normalizedAddresses to detect when
addresses.length > MAX_ADDRESSES_PER_REQUEST and emit a clear warning (e.g.,
console.warn or the module logger) stating how many addresses were truncated and
which input was trimmed, then proceed to slice; alternatively (or additionally)
add a JSDoc on the containing function mentioning the MAX_ADDRESSES_PER_REQUEST
limit so callers are aware.

@antoncoding antoncoding merged commit 117b94c into master May 20, 2026
4 checks passed
@antoncoding antoncoding deleted the kleros-identity-tags branch May 20, 2026 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request Specific feature ready to be implemented ui User interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: show Kleros identity tags in supplier and borrower lists

1 participant