Skip to content

Conversation

@victorkl400
Copy link
Collaborator

@victorkl400 victorkl400 commented Dec 10, 2025

Description

Refactors token handling to use VeChain's official token registry instead of hardcoded token lists. This change makes the the code more maintainable and automatically supports new tokens as they're added to the registry.

Key Changes:

  • New useTokenRegistry hook: Fetches tokens dynamically from VeChain's official token registry (main.json/test.json) with icon URL resolution and 24-hour caching
  • Simplified useTokenBalances: Replaced individual token balance queries with a unified approach that fetches balances for all registry tokens
  • Removed hardcoded constants: Eliminated TOKEN_LOGOS and TOKEN_LOGO_COMPONENTS from constants

Docs

This brings some refactor to return types, so we may need to align docs or keep the return type keys the same.

eg.

/// BEFORE:  `useTokenBalances` used to have a return like:

export type WalletTokenBalance = TokenRegistryInfo & {
    balance: string;
};

/// AFTER:  `useTokenBalances` will consistently extends other types

export type WalletTokenBalance = TokenRegistryInfo & {
    balance: TokenBalance;
};

//Meaning it will come from:

const example = {

address: "0x12397129312bijsab....",
balance: 100
//...

}

//TO

const example = {

address: "0x12397129312bijsab....",
balance: {
original: 100000000000000000000,
scaled: "100",
formatted "100.0"
}
//...

}

Demo

Screen.Recording.2026-01-02.at.11.17.27.mov

@victorkl400 victorkl400 self-assigned this Dec 10, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

📝 Walkthrough

Walkthrough

The PR introduces a new token registry hook that fetches and caches VeChain token registry data, and refactors the token balances hook to use a registry-driven, batched approach instead of hard-coded token addresses. Token metadata support and VTHO energy representation are now included.

Changes

Cohort / File(s) Summary
New Token Registry Hook
packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts
Adds new useTokenRegistry() hook with TokenRegistryInfo interface, fetchTokenRegistry() and getTokenRegistryQueryKey() functions. Fetches and validates token registry JSON from network-specific URLs with configurable caching (1h stale, 24h garbage collection) and retry logic.
Registry-Driven Token Balances
packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts
Refactors hook to use registry-driven, batched approach via useTokenRegistry and useQueries. Removes hard-coded contract addresses (B3TR, VOT3, veDelegate, USDGLO). Adds token metadata (name, decimals) to WalletTokenBalance type. Updates VET/VTHO balance handling and error states.
Export Addition
packages/vechain-kit/src/hooks/api/wallet/index.ts
Adds public re-export of new useTokenRegistry hook.

Sequence Diagram

sequenceDiagram
    participant Component
    participant useTokenBalances
    participant useTokenRegistry
    participant QueryAPI
    participant RegistryURL

    Component->>useTokenBalances: Call hook (address, tokens)
    useTokenBalances->>useTokenRegistry: Read registry (with context)
    useTokenRegistry->>RegistryURL: Fetch registry JSON
    RegistryURL-->>useTokenRegistry: Return TokenRegistryInfo[]
    useTokenRegistry-->>useTokenBalances: Registry data + loading
    
    rect rgb(220, 240, 255)
    Note over useTokenBalances: For each registry token
    useTokenBalances->>QueryAPI: Batch fetch ERC20 balances<br/>(useQueries)
    QueryAPI-->>useTokenBalances: Token balances + metadata
    end
    
    useTokenBalances->>useTokenBalances: Aggregate VET + VTHO<br/>+ registry tokens
    useTokenBalances-->>Component: Formatted token balances[]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20-25 minutes

  • Registry hook logic: Review fetchTokenRegistry validation, error handling, and retry configuration; verify network type enforcement
  • Integration complexity: Examine how useTokenRegistry is integrated into useTokenBalances; verify useQueries batching setup
  • Type changes: Confirm WalletTokenBalance type extension (name, decimals) is applied consistently
  • VTHO handling: Verify VTHO is correctly sourced from VET energy and deduplicated in final balance aggregation
  • Caching strategy: Validate staleTime (1h) and gcTime (24h) configuration meet performance requirements

Poem

🐰 A registry born to guide the way,
Token metadata shines bright today,
Batched queries dance, no more hard-code,
VTHO and VET harmonize their flow,
Dynamic tokens bloom, bright and new!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feat: Token Registry Usage' is directly related to the main changes, which introduce token registry functionality and update hooks to use the registry for balance fetching.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@victorkl400 victorkl400 marked this pull request as draft December 10, 2025 09:52
@github-actions
Copy link

github-actions bot commented Dec 10, 2025

🚀 Preview environment deployed!

Preview URL: https://preview.vechainkit.vechain.org/feattoken-registry

Copy link

@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: 0

🧹 Nitpick comments (2)
packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts (1)

66-78: Consider always including VTHO balance.

Currently, VTHO is only added if it exists in the registry. If the registry is incomplete or VTHO is missing, users won't see their VTHO balance (VET energy). Consider either:

  1. Always including VTHO with a fallback when not in registry, or
  2. Documenting that VTHO visibility depends on registry inclusion.

Apply this diff if you want to always include VTHO:

-        const vthoToken = registryTokens?.find(
-            (t) => t.symbol.toLowerCase() === 'vtho',
-        );
-        if (vthoToken) {
-            allBalances.push({
-                address: vthoToken.address,
-                symbol: vthoToken.symbol,
-                name: vthoToken.name,
-                balance: vetData?.energy || '0',
-                decimals: vthoToken.decimals,
-            });
-        }
+        const vthoToken = registryTokens?.find(
+            (t) => t.symbol.toLowerCase() === 'vtho',
+        );
+        // Always include VTHO (VET energy)
+        allBalances.push({
+            address: vthoToken?.address || '0x0000000000000000000000000000456E65726779',
+            symbol: 'VTHO',
+            name: vthoToken?.name || 'VeThor',
+            balance: vetData?.energy || '0',
+            decimals: vthoToken?.decimals || 18,
+        });
packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts (1)

61-68: Consider validating token data structure.

The code validates that the response is an array but doesn't verify that items have the required fields (address, symbol, name, decimals). Consider adding basic validation to ensure data integrity.

Apply this diff to add item validation:

         // Validate that we received an array
         if (!Array.isArray(data)) {
             throw new Error('Invalid token registry format: expected an array');
         }
+
+        // Validate that items have required fields
+        for (const item of data) {
+            if (
+                typeof item !== 'object' ||
+                !item.address ||
+                !item.symbol ||
+                !item.name ||
+                typeof item.decimals !== 'number'
+            ) {
+                throw new Error(
+                    'Invalid token registry format: items must have address, symbol, name, and decimals',
+                );
+            }
+        }
 
         return data as TokenRegistryInfo[];
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deac832 and cd91a37.

📒 Files selected for processing (3)
  • packages/vechain-kit/src/hooks/api/wallet/index.ts (1 hunks)
  • packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts (1 hunks)
  • packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/migration-guide-to-v2.mdc)

**/*.{ts,tsx}: In VeChain Kit Version 2, use useThor instead of useConnex for contract interactions
For single contract read operations, use the useCallClause hook with the pattern: import dependencies, define ABI and method as const, create query key function using getCallClauseQueryKeyWithArgs, and wrap with useCallClause including data transformation in the select option
For multiple parallel contract calls, use the executeMultipleClausesCall utility wrapped in a useQuery hook with the pattern: define query key function, use executeMultipleClausesCall in queryFn mapping items to clause objects, and transform results
For transaction building and sending, use the useBuildTransaction hook with a clauseBuilder function that returns an array of clauses with optional comment fields describing the transaction action
Always provide an arguments array for contract calls, even when no parameters are required - use an empty array for parameter-less functions to enable TypeScript type checking
Always conditionally enable queries using the enabled property to prevent unnecessary contract calls, checking for all required parameters: enabled: !!requiredParam && !!otherRequiredParam
Use the select option in useCallClause or transform data in queryFn to handle data transformation, particularly for converting BigInt values to strings and normalizing contract return data
Maintain consistent query key patterns: use getCallClauseQueryKeyWithArgs for contract calls with arguments and getCallClauseQueryKey for calls without arguments to ensure proper caching and invalidation
Use TypeScript as const assertions for method names and as 0x${string}`` assertions for Ethereum addresses to ensure type safety in contract interactions

Files:

  • packages/vechain-kit/src/hooks/api/wallet/index.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts
🧠 Learnings (1)
📚 Learning: 2025-12-01T13:01:33.771Z
Learnt from: CR
Repo: vechain/vechain-kit PR: 0
File: .cursor/rules/migration-guide-to-v2.mdc:0-0
Timestamp: 2025-12-01T13:01:33.771Z
Learning: Applies to **/*.{ts,tsx} : In VeChain Kit Version 2, use `useThor` instead of `useConnex` for contract interactions

Applied to files:

  • packages/vechain-kit/src/hooks/api/wallet/index.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts
🧬 Code graph analysis (2)
packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts (2)
packages/vechain-kit/src/config/network.ts (1)
  • NETWORK_TYPE (6-6)
packages/vechain-kit/src/providers/VeChainKitProvider.tsx (1)
  • useVeChainKitConfig (204-210)
packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts (5)
packages/vechain-kit/src/providers/VeChainKitProvider.tsx (1)
  • useVeChainKitConfig (204-210)
packages/vechain-kit/src/hooks/thor/accounts/useAccountBalance.ts (1)
  • useAccountBalance (26-34)
packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts (1)
  • useTokenRegistry (106-135)
packages/vechain-kit/src/hooks/api/wallet/useGetErc20Balance.ts (1)
  • getErc20BalanceQueryKey (7-10)
packages/vechain-kit/src/utils/formattingUtils.tsx (1)
  • formatTokenBalance (95-103)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e-test
  • GitHub Check: build-size-check
  • GitHub Check: Lint & Build
  • GitHub Check: deploy
🔇 Additional comments (10)
packages/vechain-kit/src/hooks/api/wallet/index.ts (1)

17-17: LGTM! Clean public API extension.

The new export properly extends the public API surface for the token registry hook.

packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts (5)

1-18: LGTM! Type extension is backward compatible.

The imports align with the registry-driven refactor, and the optional name and decimals fields maintain backward compatibility.


23-27: LGTM! Registry-driven token list.

The refactor correctly fetches VET balance with energy and obtains the token list from the registry.


80-95: LGTM! Proper deduplication and metadata inclusion.

The logic correctly skips VTHO to avoid duplication and includes full token metadata from the registry.


98-103: LGTM! Comprehensive loading state.

The useMemo dependencies and loading state correctly track all async data sources.


29-49: The getErc20Balance usage from @vechain/contract-getters v1.0.3 is correct.

The implementation follows the expected API signature: getErc20Balance(tokenAddress, address, { networkUrl }) returns an array with the balance as the first element. The pattern used across useGetErc20Balance.ts, useTokenBalances.ts, and useGetCustomTokenBalances.ts is consistent and correct. No changes needed.

packages/vechain-kit/src/hooks/api/wallet/useTokenRegistry.ts (4)

1-25: LGTM! Comprehensive token metadata interface.

The TokenRegistryInfo interface is well-structured with required fields and optional metadata.


78-81: LGTM! Proper query key factory.

The query key correctly scopes the cache by network type.


106-134: LGTM! Well-configured React Query hook.

The hook properly:

  • Guards execution with enabled: !!network.type
  • Validates network type in queryFn
  • Configures appropriate caching (1h staleTime, 24h gcTime)
  • Implements smart retry logic (skip validation errors, retry network failures)

35-38: No action needed; solo network registry mapping is correct.

The solo network (a local development environment) correctly maps to test.json since no separate registry exists for local networks. The VeChain token registry only serves main.json and test.json for public networks at vechain.github.io/token-registry; solo.json does not exist (404 confirmed). The current implementation appropriately treats solo as a development/test network.

@github-actions
Copy link

github-actions bot commented Dec 10, 2025

Size Change: +6.54 kB (+0.11%)

Total Size: 5.77 MB

Filename Size Change
packages/vechain-kit/dist/assets-aAdDxPJu.mjs 0 B -50.1 kB (removed) 🏆
packages/vechain-kit/dist/assets-aAdDxPJu.mjs.map 0 B -70.2 kB (removed) 🏆
packages/vechain-kit/dist/assets-DXVXPy3w.cjs 0 B -54.8 kB (removed) 🏆
packages/vechain-kit/dist/assets-DXVXPy3w.cjs.map 0 B -71.6 kB (removed) 🏆
packages/vechain-kit/dist/index--hSO7Xv4.d.mts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index--hSO7Xv4.d.mts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index-BdK1-I9P.d.cts 0 B -151 kB (removed) 🏆
packages/vechain-kit/dist/index-BdK1-I9P.d.cts.map 0 B -43.8 kB (removed) 🏆
packages/vechain-kit/dist/index-D0273BOo.d.mts 0 B -151 kB (removed) 🏆
packages/vechain-kit/dist/index-D0273BOo.d.mts.map 0 B -43.8 kB (removed) 🏆
packages/vechain-kit/dist/index-Y0ktF0Lw.d.cts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index-Y0ktF0Lw.d.cts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index.cjs 611 kB -1.01 kB (-0.16%)
packages/vechain-kit/dist/index.cjs.map 1.87 MB +2.16 kB (+0.12%)
packages/vechain-kit/dist/index.mjs.map 1.82 MB +1.37 kB (+0.08%)
packages/vechain-kit/dist/utils-CNYVq6tT.mjs 0 B -21.2 kB (removed) 🏆
packages/vechain-kit/dist/utils-CNYVq6tT.mjs.map 0 B -63.4 kB (removed) 🏆
packages/vechain-kit/dist/utils-DcAJej3n.cjs 0 B -26.4 kB (removed) 🏆
packages/vechain-kit/dist/utils-DcAJej3n.cjs.map 0 B -63.7 kB (removed) 🏆
packages/vechain-kit/dist/assets-Bb9YN1me.cjs 53.6 kB +53.6 kB (new file) 🆕
packages/vechain-kit/dist/assets-Bb9YN1me.cjs.map 68.7 kB +68.7 kB (new file) 🆕
packages/vechain-kit/dist/assets-CY55M1V1.mjs 49.2 kB +49.2 kB (new file) 🆕
packages/vechain-kit/dist/assets-CY55M1V1.mjs.map 67.4 kB +67.4 kB (new file) 🆕
packages/vechain-kit/dist/index-B-ejnhje.d.mts 152 kB +152 kB (new file) 🆕
packages/vechain-kit/dist/index-B-ejnhje.d.mts.map 44.7 kB +44.7 kB (new file) 🆕
packages/vechain-kit/dist/index-CR7Gmfd5.d.mts 5.26 kB +5.26 kB (new file) 🆕
packages/vechain-kit/dist/index-CR7Gmfd5.d.mts.map 2.8 kB +2.8 kB (new file) 🆕
packages/vechain-kit/dist/index-DDOYnHhJ.d.cts 5.26 kB +5.26 kB (new file) 🆕
packages/vechain-kit/dist/index-DDOYnHhJ.d.cts.map 2.8 kB +2.8 kB (new file) 🆕
packages/vechain-kit/dist/index-DJ0PH2TA.d.cts 152 kB +152 kB (new file) 🆕
packages/vechain-kit/dist/index-DJ0PH2TA.d.cts.map 44.7 kB +44.7 kB (new file) 🆕
packages/vechain-kit/dist/utils-DJXpMvaf.mjs 21 kB +21 kB (new file) 🆕
packages/vechain-kit/dist/utils-DJXpMvaf.mjs.map 66.7 kB +66.7 kB (new file) 🆕
packages/vechain-kit/dist/utils-Dw-6m42l.cjs 28.9 kB +28.9 kB (new file) 🆕
packages/vechain-kit/dist/utils-Dw-6m42l.cjs.map 67 kB +67 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size Change
packages/vechain-kit/dist/assets 4.1 kB 0 B
packages/vechain-kit/dist/assets/index.cjs 675 B -41 B (-5.73%)
packages/vechain-kit/dist/assets/index.d.cts 925 B -48 B (-4.93%)
packages/vechain-kit/dist/assets/index.d.mts 925 B -48 B (-4.93%)
packages/vechain-kit/dist/assets/index.mjs 672 B -46 B (-6.41%)
packages/vechain-kit/dist/index.d.cts 20.6 kB +136 B (+0.66%)
packages/vechain-kit/dist/index.d.mts 20.6 kB +136 B (+0.66%)
packages/vechain-kit/dist/index.mjs 577 kB -913 B (-0.16%)
packages/vechain-kit/dist/utils 4.1 kB 0 B
packages/vechain-kit/dist/utils/index.cjs 1.84 kB -94 B (-4.85%)
packages/vechain-kit/dist/utils/index.d.cts 2.89 kB -84 B (-2.83%)
packages/vechain-kit/dist/utils/index.d.mts 2.89 kB -84 B (-2.83%)
packages/vechain-kit/dist/utils/index.mjs 1.86 kB -95 B (-4.86%)

compressed-size-action

@victorkl400 victorkl400 changed the base branch from main to fix/centralize-urls December 31, 2025 10:42
@victorkl400 victorkl400 marked this pull request as ready for review December 31, 2025 10:46
@victorkl400 victorkl400 marked this pull request as draft January 2, 2026 11:18
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.

2 participants