Skip to content

Conversation

@vutuanlinh2k2
Copy link
Contributor

@vutuanlinh2k2 vutuanlinh2k2 commented Jan 26, 2026

Summary

  • Add operator delegation mode checks for restaking operations
  • Display operator delegation mode in tables (both tangle-dapp and tangle-shared-ui)
  • Deprecate rewards hooks pending RewardsManager integration
  • Update ABI definitions for multiAssetDelegation and related contracts
  • Remove TNT_CORE_CONTRACT_UPDATES tracking doc

Video

CleanShot.2026-01-26.at.22.19.04.mp4

(note: the flicker in the operator table at the end of the video is already fixed)

Test plan

  • Verify operator delegation mode is displayed correctly in operator tables
  • Test delegate page with operators in different delegation modes
  • Confirm deprecated rewards hooks are properly marked and don't break existing functionality

🤖 Generated with Claude Code

vutuanlinh2k2 and others added 5 commits January 26, 2026 18:45
Implements Group 1 of TNT Core contract updates - delegation permission
checks. Operators can now set delegation modes (Open, Whitelist, Disabled)
and the UI respects these settings when delegating.

- Add useCanDelegate hook for single operator eligibility check
- Add useCanDelegateToOperators hook for batch operator checks
- Add useOperatorDelegationModes hook for batch mode fetching
- Update delegate page to check permissions before allowing delegation
- Show delegation mode badges on operator selection
- Disable non-delegatable operators in selection modal
- Sync ABI files with new delegation functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… integration

Rewards functionality has been moved to a separate RewardsManager contract
in TNT Core. These hooks are temporarily deprecated until the new contract
integration is implemented.

- Deprecate useClaimDelegatorRewardsTx with no-op for API compatibility
- Remove rewards fetching from useUserRestakingStats
- Update local testnet fixtures
- Update credits tree data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add delegation mode column to operator tables showing Open/Whitelist/Self Only
badges. Updates Operator interface and GraphQL query to include delegationMode
field from indexer.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vutuanlinh2k2 vutuanlinh2k2 self-assigned this Jan 26, 2026
@claude
Copy link

claude bot commented Jan 26, 2026

Claude finished @vutuanlinh2k2's task —— View job


PR Review: Operator Delegation Mode Support

I'll provide a comprehensive review of this PR focusing on code quality, potential issues, performance, and security considerations.

Todo List:

  • Read repository guidelines from CLAUDE.md
  • Review core operator delegation mode implementation
  • Examine new hooks and data fetching logic
  • Check ABI updates and contract changes
  • Review UI components and table updates
  • Assess rewards hooks deprecation approach
  • Check for potential bugs and security issues
  • Evaluate performance implications
  • Provide final review summary with specific feedback

Code Quality Review

Strengths

  1. Well-structured hooks architecture - The three new hooks (useCanDelegate, useOperatorDelegationModes, useCanDelegateToOperators) follow a clean separation of concerns pattern and provide excellent TypeScript typing.

  2. Proper error handling - All hooks use Promise.allSettled for batch operations and gracefully handle contract call failures.

  3. Performance optimizations - Appropriate use of useMemo for expensive operations and batched contract calls to minimize RPC requests.

  4. Consistent code style - Follows the repository's guidelines with arrow functions, proper TypeScript usage, and descriptive variable names.

  5. Good documentation - Comprehensive JSDoc comments with examples in the new hooks.

⚠️ Issues and Concerns

Security & Logic Issues

  1. Type safety concern in delegation mode handling (libs/tangle-shared-ui/src/components/tables/Operators/index.tsx:160-166):
const mode: DelegationMode =
  rawMode === DelegationMode.Open
    ? DelegationMode.Open
    : rawMode === DelegationMode.Whitelist
      ? DelegationMode.Whitelist
      : DelegationMode.Disabled;

This logic assumes any non-Open/non-Whitelist value equals Disabled, but doesn't validate if rawMode is actually a valid enum value. Consider adding explicit validation.

  1. Potential race condition in delegation info loading - The operator table shows delegation buttons before delegation info is fully loaded, which could lead to confusing UI states.

  2. Error boundary missing - New hooks don't have proper error boundaries, so contract failures could crash components.

Performance Issues

  1. Excessive contract calls (libs/tangle-shared-ui/src/data/restake/useCanDelegateToOperators.ts:91-124):
    Each operator requires 3 contract calls (canDelegate, getDelegationMode, isWhitelisted). For 100 operators = 300 RPC calls. Consider:

    • Implementing a batch contract call function
    • Adding circuit breakers for large operator lists
    • Implementing progressive loading
  2. Stale time inconsistency - Different hooks use different stale times (30s vs 60s), which could cause data inconsistencies.

Code Quality Issues

  1. Inconsistent type casting (libs/tangle-shared-ui/src/data/restake/useCanDelegate.ts:100,106):
}) as Promise<number>,
}) as Promise<boolean>,

The ABI should provide proper types to avoid as casting. Consider generating typed contracts.

  1. Magic numbers - staleTime: 30_000 appears multiple times. Should be extracted to a constant.

  2. Incomplete deprecation (apps/tangle-dapp/src/data/restaking/useClaimDelegatorRewardsTx.ts:28):
    The deprecated hook sets status to ERROR and logs a warning, but this could break existing UI flows. Consider returning a more graceful state.

Potential Bugs

  1. Map key inconsistency (apps/tangle-dapp/src/components/tables/OperatorsTable.tsx:46):
const info = delegationInfo.get(operator.id as Address);

Casting string to Address without validation could cause mismatched keys if casing differs.

  1. Missing null checks in operator data transformation - Several places assume data exists without proper null/undefined guards.

  2. GraphQL BigInt parsing (libs/tangle-shared-ui/src/data/graphql/useOperators.ts:118-120):

restakingStake: raw.restakingStake ? BigInt(raw.restakingStake) : null,

No validation that the string is a valid BigInt, could throw runtime errors.

UI/UX Issues

  1. Disabled button tooltips - Good UX with disabled state explanations, but tooltips could be clearer about what actions users can take.

  2. Loading states - Tables show loading, but individual delegation buttons don't indicate their loading state for permission checks.

Architecture Feedback

  1. Good separation of concerns - Delegation logic properly separated from UI components.

  2. Hook composition - Smart use of composition where useCanDelegateToOperators builds on useCanDelegate.

  3. Contract interface evolution - Proper handling of ABI updates and backwards compatibility.

Recommendations

  1. Add batch contract calling - Implement multicall pattern to reduce RPC load
  2. Standardize cache times - Use consistent stale times across related hooks
  3. Add error boundaries - Wrap components using new hooks with error boundaries
  4. Improve type safety - Generate typed contracts instead of using as casting
  5. Add integration tests - Complex delegation logic needs end-to-end testing
  6. Consider pagination - For large operator lists, implement progressive loading

Minor Issues

  • Remove unused imports in several files
  • Some components could benefit from memo() for performance
  • Consider extracting magic numbers to constants

Summary

This is a solid implementation of operator delegation modes with good architecture and TypeScript usage. The main concerns are around performance optimization for large operator lists and some type safety improvements. The deprecation handling is appropriate but could be more graceful.

The code demonstrates good understanding of React patterns and blockchain integration best practices. With the performance optimizations and type safety improvements addressed, this would be production-ready.

Overall Assessment: Approve with recommendations

@vutuanlinh2k2
Copy link
Contributor Author

Response to Claude's Review

Thanks for the detailed review! I've analyzed each issue raised and here's my assessment:

Issues We'll Address

  1. Stale time inconsistency ✅ - Valid. useOperatorDelegationModes uses 60s while other hooks use 30s. Will standardize.

  2. Map key casing ✅ - Valid edge case. Will add .toLowerCase() normalization when looking up delegation info to prevent potential mismatches.

  3. BigInt parsing safety ✅ - Valid. Will add try-catch wrapper for BigInt() conversions in GraphQL parsing to handle unexpected data gracefully.

Issues That Are Actually Fine

  1. Type safety in DelegationMode handling - This is intentional defensive coding. The enum only has 3 values (0=Disabled, 1=Whitelist, 2=Open), and defaulting unknown values to Disabled is the safest behavior as it prevents unauthorized delegation.

  2. "Race condition" in delegation loading - This is a documented design choice (see comment on line 255: "canDelegate undefined means we don't have the info yet (backwards compat)"). Buttons remain enabled while loading for backwards compatibility.

  3. Error boundary missing - The hooks properly handle errors via Promise.allSettled and expose errors through React Query's error property. Error boundaries are a component-level concern.

  4. Incomplete deprecation (ERROR status) - This is intentional. The hook is deprecated and should signal failure. The JSDoc clearly documents this behavior.

  5. Type casting (as Promise<...>) - Standard pattern when using viem's readContract without generated typed contracts. Works correctly.

Low Priority (Won't Fix Now)

  1. Excessive contract calls - Valid observation but standard practice. Will optimize with multicall if performance becomes an issue.

  2. Magic numbers - Minor style preference, low impact.

Will push fixes for items 1-3 shortly.

vutuanlinh2k2 and others added 4 commits January 26, 2026 21:58
- Standardize stale time across delegation hooks using CACHE_CONFIG.DELEGATION
- Normalize address casing in OperatorsTable for consistent Map lookups
- Add safeBigInt helper to prevent crashes on invalid GraphQL data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reset notification tracking state when active EVM address changes to
avoid showing notifications for already-persisted transactions when
switching MetaMask accounts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sort operators in the table the same way as the select operator modal:
Open > Whitelist (whitelisted) > Whitelist (not whitelisted) > Self Only

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vutuanlinh2k2
Copy link
Contributor Author

@claude please review my recent changes

@claude
Copy link

claude bot commented Jan 26, 2026

Claude finished @vutuanlinh2k2's task —— View job


Review of Recent Changes ✅

I've reviewed your recent changes focusing on the fixes you mentioned implementing.

Todo List:

  • Review stale time consistency fixes
  • Check map key casing normalization
  • Examine BigInt parsing safety improvements
  • Look for any new issues in recent changes
  • Provide overall assessment of the fixes

Assessment of Fixes

1. ✅ Stale Time Consistency Fixed

  • Added comprehensive CACHE_CONFIG constant with standardized cache times (libs/tangle-shared-ui/src/constants/cacheConfig.ts)
  • All delegation-related hooks now use CACHE_CONFIG.DELEGATION.staleTime (30 seconds)
  • Excellent organization with semantic cache categories (STATIC, PROTOCOL, ASSETS, etc.)

2. ✅ Map Key Casing Normalization Fixed

  • Added .toLowerCase() normalization in OperatorsTable.tsx:47 when looking up delegation info
  • Query keys in hooks also normalize addresses with operators.map((op) => op.toLowerCase()).sort()
  • This prevents the edge case where mixed case addresses could cause lookup mismatches

3. ✅ BigInt Parsing Safety Fixed

  • Implemented safeBigInt() helper function in useOperators.ts:109-116 with proper try-catch
  • All BigInt conversions now use this safe wrapper, returning null on invalid input
  • Much safer than the previous direct BigInt() calls that could throw runtime errors

Additional Quality Improvements Noticed

Code Organization:

  • Smart delegation mode handling with proper enum validation (index.tsx:161-166)
  • Consistent use of the standardized cache config across all hooks
  • Good separation of concerns with the new delegation permission system

Performance:

  • Proper address normalization in query keys for consistent caching
  • Batch contract calls with Promise.allSettled for resilient error handling

Type Safety:

  • Better delegation mode type checking while maintaining backward compatibility
  • Comprehensive TypeScript interfaces for the new delegation system

No New Issues Found

The recent changes are well-implemented and address all the concerns raised in my previous review. The code quality has actually improved with:

  • Better error handling patterns
  • More consistent caching strategy
  • Safer data parsing
  • Better type definitions

Summary

All three promised fixes have been successfully implemented with good attention to detail. The cache configuration system is particularly well-designed and will benefit the entire codebase. The changes maintain backwards compatibility while fixing the identified issues.

Status: All review concerns addressed ✅


@drewstone drewstone merged commit e5f681d into v2 Jan 26, 2026
2 checks passed
@drewstone drewstone deleted the linh/feat/operator-mode branch January 26, 2026 16:27
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.

3 participants