Skip to content

feat(account-modal): tabbed Assets with token detail, history, staking cards#612

Merged
Agilulfo1820 merged 22 commits into
mainfrom
feat/account-modal-assets-refactor
May 14, 2026
Merged

feat(account-modal): tabbed Assets with token detail, history, staking cards#612
Agilulfo1820 merged 22 commits into
mainfrom
feat/account-modal-assets-refactor

Conversation

@Agilulfo1820

@Agilulfo1820 Agilulfo1820 commented May 14, 2026

Copy link
Copy Markdown
Member

Overview

Turns the AccountModal Assets screen into a full portfolio view: a balance header with quick actions, Token and Staking tabs, per-token detail pages, an aggregated transaction history, and protocol-specific staking cards. Adds the supporting data layer — on-chain price-change derivation, VeChain indexer pagination, .vet domain resolution — and a new tracked token (VVET).


What's new

🎨 Assets surface

  • Balance header with Send / Swap / History actions and a 24h change badge.
  • Token / Staking tabs (Chakra Tabs, local state).
  • Search input restored inline with the Manage custom tokens pencil icon.
  • Restyled AssetButton rows: card-shaped, two-line layout (symbol + amount on the left, currency value + 24h badge on the right).

🪙 Token detail screen

  • Large balance + USD equivalent + 24h change.
  • Swap / Send / Receive actions preselect the token.
  • Non-transferable tokens (VOT3) keep their detail screen but Send and Swap are disabled.
  • Token-history preview (last 5 transfers) with a See all link that opens the filtered full history.

📜 Transaction history & detail

  • Aggregated history list grouped by day, paginated via the VeChain indexer.
  • Per-transaction detail with date, status, From/To, hash, and View on explorer.
  • .vet domain resolution for From/To, with humanAddress fallback.
  • Copy buttons next to From, To, and Hash.
  • Sparkles placeholder icon for transfers received from 0x000…000 (mints/rewards), in both list and detail.
  • Long token symbols (e.g. variableDebtVechainVTHO) truncate cleanly instead of overflowing.

🥩 Staking tab

Cards render only when the wallet has positions in that protocol.

  • Stargate — one row per NFT, supplied VET, delegation status.
  • VeBetter (Navigators) — staked B3TR (if user is a navigator) or delegated amount + navigator address (if user is a citizen).
  • BetterSwap LP — factory event scan + per-pair balanceOf, one row per pair.
  • Juicy Finance (new) — Aave v3 fork. Supplied + borrowed per asset, net USD value, and a colored Health rate tag.
  • Shared StakingCard shell with logo, total, optional tag, rows, and a compact Go to platform button.

📈 24h price change (on-chain only)

  • New useOraclePriceChanges24h scans OracleVechainEnergy ValueUpdate events in a ~5h window centered on the block ~24h ago and computes ±% per supported feed.
  • useTokenPrices exposes a priceChanges map keyed by token address (VOT3/veDelegate inherit B3TR; VVET inherits VET; lowercase mirror for indexer responses).
  • New PriceChangeBadge renders ±X.XX% with red/green/muted color and a muted "24h" suffix.
  • Surfaces in AssetButton, TokenDetail, AssetsHeader, and BalanceSection.
  • No external API dependency.

🪙 VVET (Veiled VET / wrapped VET)

  • Added to AppConfig and the token registry, priced 1:1 with VET.
  • Picked up automatically by balances, history, totals, and per-token screens.

💰 Total balance

  • useTotalBalance now sums liquid token values plus Stargate, Navigators, BetterSwap LP, and net Juicy (supplied − borrowed).
  • Reports priceChange24hPct as a USD-weighted average across holdings.

Configuration

New AppConfig fields (mainnet values shown; testnet/solo are populated where available, blank otherwise — cards self-disable):

Field Mainnet
vvetContractAddress 0x45429A2255e7248e57fce99E7239aED3f84B7a53
stargateContractAddress 0x03C557bE98123fdb6faD325328AC6eB77de7248C
stargateNftContractAddress 0x1856c533ac2d94340aaa8544d35a5c1d4a21dee7
navigatorRegistryContractAddress 0xef238e33fc78ecc79beaf8386254a0fc67d048e0
betterSwapFactoryAddress 0x5970DcBeBAc33e75eFf315C675f1d2654f7bF1f5
juicyPoolAddress 0x00Bd212704A8816264607a7110cCabe70219D5aB

Registrazione.schermo.2026-05-14.alle.17.10.37.mov

Closes #560
Closes #564
Closes #562
Closes #565
Closes #561
Closes #566

Summary by CodeRabbit

  • New Features
    • Added token detail views with individual token balance and 24-hour price change indicators.
    • Introduced transaction history view displaying past transfers with detailed transaction information.
    • Added staking position displays for Stargate, Navigators, Juicy Finance, and BetterSwap LP platforms.
    • Enhanced asset section with 24h price change badges and tabbed navigation for tokens and staking.

Review Change Stack

Agilulfo1820 and others added 10 commits May 14, 2026 14:46
…aking cards

Refactor AccountModal Assets into a full portfolio view: balance header
with Send/Swap/History actions, Token/Staking tabs, per-token detail
screen with Swap/Send/Receive, aggregated transfer history backed by the
VeChain indexer, transaction detail screen, and protocol-specific staking
cards for Stargate, VeBetterDAO Navigators, and BetterSwap LP positions.

Adds VVET (wrapped VET) as a tracked token priced 1:1 with VET, and folds
staking positions into useTotalBalance so the portfolio total reflects
the user's full holdings.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- Move Manage Custom Tokens button back inline with the search input;
  shrink the search input height for a tighter Assets header.
- Trim AssetsTabs to just the tab labels.
- Use the bundled BetterSwapLogo for the BetterSwap LP card; switch
  Stargate to the actual product logo; route VVET to the VeChain token
  registry icon and rename the Navigators card to "VeBetter".
- Remove the redundant external-link icon next to the protocol name on
  staking cards and tighten the "Go to platform" button styling.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The indexer doesn't accept the VET sentinel address as a tokenAddress
filter, so filtering by VET was fetching a mixed page and post-filtering
client-side, leaving only a handful of rows per page. Switch to the
indexer's eventType=VET parameter so the page contains only VET
transfers and pagination is meaningful.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Add useOraclePriceChanges24h: reads OracleVechainEnergy's current values
for each supported feed and scans ValueUpdate events in a ~5h window
centered on the block ~24h ago, taking the most recent observation per
feedId as the baseline. Filters by contract address only (the id field
is non-indexed) and decodes args client-side.

useTokenPrices exposes a priceChanges map keyed by token address (VOT3
and veDelegate inherit B3TR's change; VVET inherits VET's). Plumbs
priceChange24hPct through useTokensWithValues and a USD-weighted
portfolio-level change through useTotalBalance.

UI: new common PriceChangeBadge renders +/-X.XX% in semantic
green/red/muted with the "24h" suffix in neutral tertiary text.
Surfaces in AssetButton, the restyled card-shaped asset row,
TokenDetail header, AssetsHeader, and the main BalanceSection.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- New AddressOrDomainLabel wraps useVechainDomain and renders the .vet
  domain when available, falling back to humanAddress otherwise. Used
  for the From/To subtitle on HistoryItemRow and the From/To rows on
  TransactionDetailContent.
- New CopyIconButton wraps the SSR-safe copyToClipboard with a Copy ->
  Check icon transition. Added next to From, To, and Hash on the
  transaction detail screen so users can copy the full underlying
  address / tx ID even when the label is truncated or a domain.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
… keys

groupByDay used a sequential lastKey check, so any non-contiguous
same-day items (e.g. when paginating overlaps a day boundary) produced
multiple groups with the same label and React threw a duplicate-key
error on Load more. Switch to a Map keyed by day label and a Set keyed
by item.id so a transfer can never produce two groups or two rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The VeChain indexer ignores offset/limit and only honors a 0-indexed
`page` parameter (returning ~20 items per page). Previously every Load
More click hit the same page-0 response, and the row dedupe quietly
swallowed the duplicate IDs, so the UI appeared frozen.

- Drop PAGE_SIZE and the offset/limit params.
- Send only `page=<n>`.
- getNextPageParam returns allPages.length (0 -> 1 -> 2 ...) when the
  server reports hasNext.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
isVetTokenAddress treated 'undefined tokenAddress' the same as the VET
sentinel, so opening unfiltered history forced eventType=VET on the
indexer and the user only saw native VET rows. Trigger the VET filter
only when the caller explicitly passes the VET sentinel.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- useTransferHistory now collects every ERC-20 address per page that
  isn't in the known token set (custom tokens + VET/VTHO/B3TR/VOT3/
  veDelegate/VVET), fetches getTokenInfo for them in parallel, and uses
  the real symbol + decimals. Fixes rows that previously displayed as
  e.g. "+100 0x680f" (LP tokens from BetterSwap and other DeFi protocols)
  and corrects the amount when the contract isn't 18 decimals.
- TransactionDetailContent now mirrors HistoryItemRow's behaviour: when
  the transfer was received from 0x000...000 it renders the LuSparkles
  placeholder circle instead of the token logo.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- New useJuicyPosition hook reads the Juicy Finance pool (Aave v3 fork
  at 0x00Bd212704A8816264607a7110cCabe70219D5aB on mainnet): enumerates
  reserves, batches getReserveData + balanceOf on each aToken /
  variableDebt / stableDebt token, and computes supplied + borrowed
  per asset and net USD value. Health factor read from
  getUserAccountData (null when there's no debt).
- New JuicyFinanceCard renders a supplied list, optional borrowed list,
  and a colored health-rate tag; routes to www.juicyfinance.io.
- StakingTab gates on hasPosition; useTotalBalance folds the net Juicy
  position into the portfolio total.
- Local JuicyPoolAbi added in staking/abis.ts (canonical Aave v3 subset
  from vechain/b32).
- HistoryItemRow: split amount and token symbol onto two lines, with
  flexShrink/minW/maxW constraints so long token names
  (jVechainVTHO, variableDebtVechainVTHO, etc.) truncate with an
  ellipsis instead of overflowing the row.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds comprehensive token detail browsing and transaction history viewing to the AccountModal, refactors the Assets tab into a tabbed interface separating tokens and staking positions, and integrates multi-protocol staking position tracking with 24h oracle-based price change visualization across the entire system.

Changes

Account Modal: Token Details, Transaction History, and Staking Positions

Layer / File(s) Summary
Modal content type system and routing
AccountModal.tsx, AccountModal/Types/Types.ts
New modal content variants (token-detail, transaction-history, transaction-detail) added to AccountModalContentTypes union; AccountModal renders new content components based on currentContent.type; support for optional onBack callbacks in swap-token and receive-token variants.
Transfer history types and core hooks
hooks/api/transferHistory/types.ts, hooks/api/transferHistory/useTransferHistory.ts, hooks/api/transferHistory/useTokenTransferHistory.ts, hooks/api/index.ts
Transfer history types (TransferDirection, TransferEventType, IndexerTransfer, TransferHistoryItem) and constants (VET_TOKEN_SENTINEL, VTHO_TOKEN_ADDRESS) defined; useTransferHistory and useTokenTransferHistory hooks implement paginated indexer-based transfer fetching with token metadata resolution; barrel exports added.
Transaction history and detail UI components
AccountModal/Contents/TransactionHistory/*, AccountModal/Contents/TransactionHistory/Components/HistoryItemRow.tsx
HistoryItemRow renders individual transfer rows with directional formatting and token logos; TransactionHistoryContent groups transfers by day with pagination; TransactionDetailContent displays full transaction details with copy buttons, explorer links, and currency conversion.
Token detail content view and integration
AccountModal/Contents/TokenDetail/TokenDetailContent.tsx, AccountModal/Contents/TokenDetail/Components/TokenHistoryPreview.tsx, AccountModal/Contents/TokenDetail/index.ts
TokenDetailContent displays token balance, currency value, and 24h price change badge; includes action buttons for Swap/Send/Receive with proper disabled states; embeds TokenHistoryPreview showing recent transfers with "see all" navigation.
Staking position data hooks for multiple protocols
hooks/api/staking/useStargatePositions.ts, hooks/api/staking/useNavigatorPosition.ts, hooks/api/staking/useBetterSwapLpPositions.ts, hooks/api/staking/useJuicyPosition.ts, hooks/api/staking/abis.ts, hooks/api/staking/index.ts
React Query hooks for fetching staking positions across Stargate (VET staking), Navigators (B3TR delegation), BetterSwap LP, and Juicy Finance; includes batched contract calls, token metadata resolution, USD valuation, and currency conversion; ABI exports for protocol contracts.
Staking card UI components for protocol display
AccountModal/Contents/Assets/Components/StakingCards/*
StakingCard and StakingRow base components provide consistent layout for staking information; protocol-specific cards (StargateCard, NavigatorsCard, JuicyFinanceCard, BetterSwapLpCard) render delegated status, supplied/borrowed assets, and health factors as applicable.
Assets tab refactor with header, tabs, and token/staking views
AccountModal/Contents/Assets/AssetsContent.tsx, AccountModal/Contents/Assets/Components/AssetsHeader.tsx, AccountModal/Contents/Assets/Components/AssetsTabs.tsx, AccountModal/Contents/Assets/Components/TokensTab.tsx, AccountModal/Contents/Assets/Components/StakingTab.tsx
AssetsContent refactored to use tabbed interface (token vs staking); AssetsHeader shows balance, 24h price change badge, and action buttons (Send/Swap/History); TokensTab provides search and selectable token list; StakingTab aggregates all staking positions with conditional card rendering.
24h oracle-based price change system
hooks/api/wallet/useOraclePriceChanges24h.ts, hooks/api/wallet/useTokenPrices.ts, hooks/api/wallet/useTokensWithValues.ts, hooks/api/wallet/useTotalBalance.ts, hooks/api/wallet/index.ts
useOraclePriceChanges24h hook queries oracle contract for 24h feed changes; integrated into useTokenPrices as priceChanges lookup; propagated through useTokensWithValues (per-token) and useTotalBalance (weighted average); enables price-change badges throughout UI.
Common UI components for badges and labels
components/common/PriceChangeBadge.tsx, components/common/AddressOrDomainLabel.tsx, components/common/CopyIconButton.tsx, components/common/index.ts
PriceChangeBadge displays formatted percentage with optional 24h suffix and color coding; AddressOrDomainLabel resolves vechain domains or shows shortened address; CopyIconButton copies to clipboard with icon feedback; all exported from common barrel.
Balance section and asset button updates for price changes
AccountModal/Components/BalanceSection.tsx, components/common/AssetButton.tsx, hooks/api/wallet/useTokenBalances.ts
BalanceSection integrates PriceChangeBadge from useTotalBalance; AssetButton accepts optional priceChange24hPct and renders badge when assets are shown; VVET token balance added to useTokenBalances with conditional gating.
Back navigation improvements for content types
AccountModal/Contents/Receive/ReceiveTokenContent.tsx, AccountModal/Contents/Swap/SwapTokenContent.tsx
ReceiveTokenContent and SwapTokenContent extended with optional onBack callback for custom back navigation; fallback to 'main' content when onBack not provided.
Configuration and application constants
config/index.ts, config/mainnet.ts, config/testnet.ts, config/solo.ts, utils/constants.tsx, languages/en.json
AppConfig type extended with six new contract address fields; mainnet/testnet/solo config files populated with actual or placeholder addresses; TOKEN_LOGOS extended with VVET; English translations expanded with history, transfer, and staking UI labels.
Barrel export updates for new modules
AccountModal/Contents/index.ts, AccountModal/Contents/TransactionHistory/index.ts, hooks/api/staking/index.ts, hooks/api/transferHistory/index.ts
Re-exports added for TokenDetail, TransactionHistory, staking hooks, and transfer history modules; makes new exports discoverable from barrel files.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • vechain/vechain-kit#610: Modifies the same AssetsContent.tsx and token selection flow with refactored UI component wiring.
  • vechain/vechain-kit#578: Also integrates useLocalStorage(LocalStorageKey.SHOW_ASSETS) into Assets display and balance masking logic.
  • vechain/vechain-kit#553: Refactors the same AccountModal.tsx content-rendering flow with animated transitions.

Suggested labels

safe-to-deploy, safe-to-build

Suggested reviewers

  • victorkl400
  • mikeredmond

🐰 In a modal so grand, with tokens to show,
Transactions and staking, the balance will glow!
With badges of price, and histories deep,
Your assets unfold, through tabs that run steep.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: tabbed Assets UI with token detail view, transaction history, and staking cards integration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 feat/account-modal-assets-refactor

CI's @vechain/vechain-kit:build runs tsc with stricter options than
`yarn typecheck` and surfaced four type errors:

- CustomTokenInfo.decimals is typed as string, not number — drop the
  inline cast in useTransferHistory and useJuicyPosition and coerce
  with Number(info.decimals) (fallback 18) instead.
- oracle.read.getLatestValue requires `0x\${string}` — cast the
  PRICE_FEED_IDS value at the call site.
- getEventLogs requires nodeUrl in GetEventsProps — pass network.nodeUrl
  in useOraclePriceChanges24h.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

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

🧹 Nitpick comments (9)
packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts (3)

131-131: 💤 Low value

Remove unused SCALE constant.

The SCALE constant is defined but only referenced via a void statement, indicating incomplete code cleanup.

🧹 Cleanup suggestion
-                // Keep both raw values around in case future callers want them;
-                // for now the percentage is what we expose.
-                void SCALE;

If the constant was intended for future use, consider removing it until needed or add a comment explaining the intended use case.

🤖 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 `@packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts` at
line 131, The unused constant SCALE is defined but only referenced via a no-op
"void SCALE;" which should be removed or documented; delete the SCALE
declaration and the "void SCALE;" line inside useOraclePriceChanges24h (or, if
SCALE is intended for future use, replace the void usage with a comment
explaining its planned purpose) so there are no dead symbols left in the hook.

56-64: ⚡ Quick win

Consider logging contract call failures.

Silent error catching in the getLatestValue calls could mask misconfigurations (wrong feed IDs, network issues, or contract errors). Consider logging failures to aid debugging.

💡 Suggested improvement
                     try {
                         const res = await oracle.read.getLatestValue(feedId as `0x${string}`);
                         const raw = (res as readonly bigint[])[0];
                         return [token, raw] as const;
                     } catch {
+                        console.warn(`Failed to fetch latest price for ${token} (feed ${feedId})`);
                         return [token, null] as const;
                     }
🤖 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 `@packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts` around
lines 56 - 64, The map callback silently swallows errors from
oracle.read.getLatestValue; update the catch block in the feedEntries.map(async
([token, feedId]) => { ... }) callback to log the failure (including token and
feedId and the caught error) before returning [token, null]; use the project's
logger if available (e.g., processLogger or a provided logger), otherwise
fallback to console.error, and keep the behavior of returning [token, null]
unchanged.

95-113: 💤 Low value

Consider logging event decoding failures.

Silent error catching during event decoding could hide malformed events or ABI mismatches. Logging would help diagnose oracle integration issues.

💡 Suggested improvement
                 try {
                     const decoded = viemDecodeEventLog({
                         abi: OracleVechainEnergy__factory.abi,
                         data: event.data.toString() as ViemHex,
                         topics: event.topics.map((t) => t.toString()) as Topics,
                     });
                     if (decoded.eventName !== 'ValueUpdate') continue;
                     const args = decoded.args as unknown as {
                         id: string;
                         value: bigint;
                     };
                     const idKey = args.id.toLowerCase();
                     if (!pastByFeedId.has(idKey)) {
                         pastByFeedId.set(idKey, args.value);
                     }
-                } catch {
+                } catch (err) {
+                    console.warn('Failed to decode ValueUpdate event:', err);
                     // ignore malformed entries
                 }
🤖 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 `@packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts` around
lines 95 - 113, The event-decoding loop swallows all decoding errors, hiding
malformed events or ABI mismatches; update the catch block around
viemDecodeEventLog(...) in the loop (where OracleVechainEnergy__factory.abi,
events, and pastByFeedId are used) to log the failure details and the error
(include event.data, event.topics and the caught error). Use the existing logger
(e.g., processLogger or a module logger) if available, otherwise fallback to
console.warn, so decoding failures are visible for debugging while still
continuing to ignore that single malformed entry.
packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/TransactionDetailContent.tsx (2)

102-102: 💤 Low value

Consider extracting ZERO_ADDRESS to a shared constants file.

The ZERO_ADDRESS constant is defined inline here but represents a well-known Ethereum constant that may be used elsewhere. Consider moving it to a shared constants file (e.g., alongside VET_TOKEN_SENTINEL and VTHO_TOKEN_ADDRESS mentioned in the transfer history types layer).

🤖 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
`@packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/TransactionDetailContent.tsx`
at line 102, Extract the inline ZERO_ADDRESS into the shared constants module
used by the transfer history layer (the same place that exports
VET_TOKEN_SENTINEL and VTHO_TOKEN_ADDRESS); add and export a ZERO_ADDRESS
constant there, then replace the inline declaration in TransactionDetailContent
(referencing ZERO_ADDRESS) with an import from that shared constants module so
all components use the single canonical value.

43-50: 💤 Low value

Consider extracting date formatting helpers to a shared utility.

The formatFullDate helper is defined inline here, and a similar formatDayLabel exists in TransactionHistoryContent.tsx (lines 35-40). Extracting these to a shared dateUtils.ts or similar would reduce duplication and ensure consistent date formatting across the application.

🤖 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
`@packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/TransactionDetailContent.tsx`
around lines 43 - 50, Extract the inline date helpers into a shared utility by
creating a new module (e.g., dateUtils.ts) that exports functions matching the
existing helpers' signatures—move formatFullDate and formatDayLabel into it,
retain the locale and timestamp parameters and Intl.DateTimeFormat options, then
update TransactionDetailContent (replace the local formatFullDate) and
TransactionHistoryContent (replace formatDayLabel) to import these helpers;
ensure existing behavior and formats are preserved and run tests/compile to
confirm no type or import issues.
packages/vechain-kit/src/components/AccountModal/Contents/TokenDetail/TokenDetailContent.tsx (1)

42-42: ⚡ Quick win

Use the centralized VET_TOKEN_SENTINEL constant.

The VET_SENTINEL constant is defined here as '0x', but according to the review context, a VET_TOKEN_SENTINEL constant already exists in the transfer history types layer (packages/vechain-kit/src/hooks/api/transferHistory/types.ts). Import and use the existing constant to avoid duplication.

♻️ Proposed fix
+import { VET_TOKEN_SENTINEL } from '@/hooks';
 import {
     ModalBackButton,
     PriceChangeBadge,
@@ -39,8 +40,6 @@
     token: TokenWithValue;
 };
 
-const VET_SENTINEL = '0x';
-
 const ActionIconButton = ({
     icon,
     label,

Then replace all uses of VET_SENTINEL with VET_TOKEN_SENTINEL (lines 106, 145, 211).

🤖 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
`@packages/vechain-kit/src/components/AccountModal/Contents/TokenDetail/TokenDetailContent.tsx`
at line 42, Replace the local VET_SENTINEL constant with the centralized
VET_TOKEN_SENTINEL: remove the const VET_SENTINEL = '0x' and import
VET_TOKEN_SENTINEL from the transfer-history types module where it is declared,
then replace all usages of VET_SENTINEL inside the TokenDetailContent component
(the places that check or compare token sentinel values) with VET_TOKEN_SENTINEL
to avoid duplication.
packages/vechain-kit/src/hooks/api/staking/useStargatePositions.ts (1)

36-50: ⚡ Quick win

Avoid hardcoded VET sentinel; use shared constant.

'0x' as an inline sentinel is brittle. Import the canonical VET token key/sentinel used across wallet/history hooks to keep pricing lookup consistent.

🤖 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 `@packages/vechain-kit/src/hooks/api/staking/useStargatePositions.ts` around
lines 36 - 50, Replace the inline sentinel const VET_ADDRESS = '0x' in
useStargatePositions with the shared canonical VET constant used by the
wallet/history hooks: import that exported VET token key (the shared VET
constant) at the top of the file and use it in the pricing lookup (vetPriceUsd =
prices[SHARED_VET_CONSTANT] || 0). Update any references to VET_ADDRESS in this
module (e.g., vetPriceUsd) to the imported constant so the stargate price lookup
matches the rest of the app.
packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/NavigatorsCard.tsx (1)

39-43: ⚡ Quick win

Clarify valueInCurrency fallback logic.

Both rows use a fallback of 1 when stakedB3TR + delegatedAmount === 0, which assigns the full totalValueInCurrency to that row. If this denominator-zero case is possible, the fallback produces an arbitrary value (whichever row renders first gets the full value). Consider:

  • If the denominator can never be zero (flags guarantee non-zero amounts), document this assumption or remove the fallback.
  • If zero amounts are possible, fallback to 0 instead of 1 to avoid assigning unearned value:
♻️ Proposed fix
 valueInCurrency={totalValueInCurrency * (
     (stakedB3TR + delegatedAmount) > 0
         ? stakedB3TR / (stakedB3TR + delegatedAmount)
-        : 1
+        : 0
 )}

Apply the same change at line 61.

Also applies to: 57-61

🤖 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
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/NavigatorsCard.tsx`
around lines 39 - 43, The valueInCurrency calculation uses a fallback of 1 when
(stakedB3TR + delegatedAmount) === 0 which assigns the full totalValueInCurrency
arbitrarily; update both occurrences where valueInCurrency is computed (the
expression using totalValueInCurrency * ((stakedB3TR + delegatedAmount) > 0 ?
stakedB3TR / (stakedB3TR + delegatedAmount) : 1) and the similar delegatedAmount
expression) to use 0 as the fallback instead of 1, or alternatively remove the
fallback if you can guarantee the denominator is never zero and document that
assumption in the component (NavigatorsCard / the valueInCurrency calculations
referencing stakedB3TR, delegatedAmount and totalValueInCurrency).
packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/TokensTab.tsx (1)

84-86: ⚡ Quick win

Avoid unsafe type assertion.

The currentCurrency is being cast to SupportedCurrency without runtime validation. If currentCurrency is not actually a valid SupportedCurrency value, this could lead to runtime errors.

Consider removing the type assertion if useCurrency() already returns SupportedCurrency, or add runtime validation:

🛡️ Safer approach without type assertion

If currentCurrency is already typed as SupportedCurrency, remove the assertion:

-                        currentCurrency={
-                            currentCurrency as SupportedCurrency
-                        }
+                        currentCurrency={currentCurrency}
🤖 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
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/TokensTab.tsx`
around lines 84 - 86, The prop currentCurrency is being unsafely cast to
SupportedCurrency in TokensTab.tsx; either remove the type assertion if
useCurrency() already returns SupportedCurrency (i.e., ensure the hook's return
type is corrected), or add a runtime guard before passing it down (create/use an
isSupportedCurrency(value) check or validate against the SupportedCurrency
enum/set and handle the fallback case) so you only pass a validated
SupportedCurrency into the component.
🤖 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
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/AssetsTabs.tsx`:
- Line 31: The onChange handler currently casts Chakra's idx to AssetsTabIndex
which skips runtime validation; change the onChange passed to Tabs so it
validates idx before calling onTabChange: check that idx is a number and within
the valid range for AssetsTabIndex (e.g., 0 <= idx < numberOfTabs or validate
against a known array of allowed indices) and only then call onTabChange(idx as
AssetsTabIndex), otherwise call onTabChange(0) as the safe fallback; reference
the onChange prop on the Tabs component, the onTabChange handler, and the
AssetsTabIndex type when making this change.

In
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/JuicyFinanceCard.tsx`:
- Around line 95-98: The code unsafely casts currentCurrency to
SupportedCurrency before calling formatCompactCurrency (used in
JuicyFinanceCard), which can pass invalid values; add a type guard (e.g.,
isSupportedCurrency(value): value is SupportedCurrency) and validate
currentCurrency before passing it to formatCompactCurrency, and handle the
fallback case (use a default currency or render a safe placeholder) so both the
formatCompactCurrency call at the currentCurrency usage and the duplicate
occurrence later in the component use the validated currency instead of an
unchecked cast.

In
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/TokensTab.tsx`:
- Line 82: The code is unsafely converting token.balance to Number which can
lose precision if TokenWithValue.balance is a string or BigInt; inspect the
TokenWithValue type declaration to confirm the balance type and then fix either:
1) adjust TokensTab.tsx (the place using token.balance and the amount prop) to
accept and handle bigint/string balances using a safe big-number library (e.g.,
BigInt, Big.js, or ethers.BigNumber) and pass a properly formatted
decimal/string to the child component, or 2) change the child component’s amount
prop type to accept string/BigInt and update its internal arithmetic/display to
use big-number handling; ensure TokenWithValue.balance and any consumers are
type-consistent so no implicit Number() conversion occurs.

In `@packages/vechain-kit/src/components/common/AssetButton.tsx`:
- Line 19: The import in AssetButton.tsx uses a relative path for
PriceChangeBadge; update the import to use the repository path alias for
components (e.g., `@components/`...) so it follows the project's alias-import
convention; locate the import statement referencing PriceChangeBadge in
AssetButton (symbol: PriceChangeBadge) and replace the relative path with the
appropriate alias path for the components folder.

In `@packages/vechain-kit/src/components/common/CopyIconButton.tsx`:
- Around line 20-25: The copied-state timer in CopyIconButton's handleClick
schedules a new timeout on every click without clearing prior timers; modify
handleClick to clear any existing timer before creating a new one (store the
timer id in a ref, e.g. timeoutRef.current), then setCopied(true) and assign
timeoutRef.current = setTimeout(...). Also add a useEffect cleanup that clears
timeoutRef.current on unmount to avoid stray timers; update references in
CopyIconButton, handleClick, and the cleanup effect accordingly.

In `@packages/vechain-kit/src/config/testnet.ts`:
- Around line 91-94: Update the three testnet contract address values
(stargateContractAddress, stargateNftContractAddress,
navigatorRegistryContractAddress) to use EIP-55 checksummed addresses instead of
all-lowercase; compute and replace each string with the checksummed form (e.g.,
via ethers.utils.getAddress or another EIP-55 routine) so the values match the
checksummed format used in mainnet.ts.

In `@packages/vechain-kit/src/hooks/api/staking/useBetterSwapLpPositions.ts`:
- Around line 90-114: The hook useBetterSwapLpPositions enables and calls
contracts without validating addresses; update the enabled condition and the
queryFn to use isAddress() checks: ensure address and factoryAddress pass
isAddress() before setting enabled (replace !!address/!!factoryAddress with
isAddress(address) && isAddress(factoryAddress)), and in the pairs handling
filter/validate each pair with isAddress() before mapping into
executeMultipleClausesCall (skip invalid entries or return [] early). Keep the
same symbols (enabled, queryFn, executeMultipleClausesCall, pairs,
UniswapV2Pair__factory) and make sure any address casts to `0x${string}` only
occur after validation.
- Around line 93-99: The query key in useBetterSwapLpPositions uses only
pairs.length which can lead to cache collisions when the pairs list changes but
its length stays the same; update the queryKey (in useBetterSwapLpPositions) to
include a stable representation of the pairs themselves (for example a
deterministic identifier array like pairs.map(p => p.id) or
JSON.stringify(pairs) or similar) instead of or in addition to pairs.length so
React Query discriminates different pair sets and returns correct LP positions.

In `@packages/vechain-kit/src/hooks/api/staking/useNavigatorPosition.ts`:
- Around line 34-38: The code currently does prices[b3trAddress] which can miss
matches if keys are normalized (e.g., lowercased); update useNavigatorPosition
logic to normalize the b3trAddress key the same way the prices map uses (for
example lowercase or checksum) before lookup—specifically normalize the
b3trAddress variable and then use prices[normalizedB3trAddress] (or fallback to
alternate normalizations) to compute b3trPriceUsd; ensure the normalization step
is applied where b3trAddress is read and referenced in this file (symbols:
b3trAddress, prices, b3trPriceUsd).

In `@packages/vechain-kit/src/hooks/api/transferHistory/useTransferHistory.ts`:
- Around line 56-61: The code is hardcoding decimals to 18 when populating
symbolByAddress, causing wrong formatting; update the population logic in
useTransferHistory where symbolByAddress.set(...) is called to use the actual
token decimals (e.g., use the decimals property from the balance object
`b.decimals` or a reliable token metadata lookup) and fall back to a safe
default only if decimals is undefined; ensure this change feeds into the same
path used by formatUnits so amounts are formatted with the correct decimals.

In `@packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts`:
- Line 58: The TypeScript error is caused by passing a plain string `feedId`
into the contract call; update the call site where
`oracle.read.getLatestValue(feedId)` is invoked to cast `feedId` to the typed
address pattern (feedId as `0x${string}`) so the argument matches the contract
signature, and ensure any method name literals used with `oracle.read` are typed
with `as const` per guidelines; specifically locate the `feedId` variable and
the `oracle.read.getLatestValue` invocation and apply the cast and `as const`
typing where appropriate.

In `@packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts`:
- Around line 29-33: The VVET balance query is currently only gated by
config.vvetContractAddress and can run when address is missing; update the
query's enabled condition in the useGetErc20Balance call (the destructured
result vvetBalance / vvetLoading) to require both the contract address and the
wallet address (e.g., enabled: !!config.vvetContractAddress && !!address) so the
hook only runs when all required params are present.

In `@packages/vechain-kit/src/languages/en.json`:
- Around line 458-461: Remove the duplicate JSON translation keys by deleting
the repeated entries "From", "To", and "View on explorer" in the newly added
block; keep the original occurrences earlier in the file and ensure only the
earlier definitions of the keys "From", "To", and "View on explorer" remain so
the JSON object has unique keys and no later overwrites occur.

---

Nitpick comments:
In
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/NavigatorsCard.tsx`:
- Around line 39-43: The valueInCurrency calculation uses a fallback of 1 when
(stakedB3TR + delegatedAmount) === 0 which assigns the full totalValueInCurrency
arbitrarily; update both occurrences where valueInCurrency is computed (the
expression using totalValueInCurrency * ((stakedB3TR + delegatedAmount) > 0 ?
stakedB3TR / (stakedB3TR + delegatedAmount) : 1) and the similar delegatedAmount
expression) to use 0 as the fallback instead of 1, or alternatively remove the
fallback if you can guarantee the denominator is never zero and document that
assumption in the component (NavigatorsCard / the valueInCurrency calculations
referencing stakedB3TR, delegatedAmount and totalValueInCurrency).

In
`@packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/TokensTab.tsx`:
- Around line 84-86: The prop currentCurrency is being unsafely cast to
SupportedCurrency in TokensTab.tsx; either remove the type assertion if
useCurrency() already returns SupportedCurrency (i.e., ensure the hook's return
type is corrected), or add a runtime guard before passing it down (create/use an
isSupportedCurrency(value) check or validate against the SupportedCurrency
enum/set and handle the fallback case) so you only pass a validated
SupportedCurrency into the component.

In
`@packages/vechain-kit/src/components/AccountModal/Contents/TokenDetail/TokenDetailContent.tsx`:
- Line 42: Replace the local VET_SENTINEL constant with the centralized
VET_TOKEN_SENTINEL: remove the const VET_SENTINEL = '0x' and import
VET_TOKEN_SENTINEL from the transfer-history types module where it is declared,
then replace all usages of VET_SENTINEL inside the TokenDetailContent component
(the places that check or compare token sentinel values) with VET_TOKEN_SENTINEL
to avoid duplication.

In
`@packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/TransactionDetailContent.tsx`:
- Line 102: Extract the inline ZERO_ADDRESS into the shared constants module
used by the transfer history layer (the same place that exports
VET_TOKEN_SENTINEL and VTHO_TOKEN_ADDRESS); add and export a ZERO_ADDRESS
constant there, then replace the inline declaration in TransactionDetailContent
(referencing ZERO_ADDRESS) with an import from that shared constants module so
all components use the single canonical value.
- Around line 43-50: Extract the inline date helpers into a shared utility by
creating a new module (e.g., dateUtils.ts) that exports functions matching the
existing helpers' signatures—move formatFullDate and formatDayLabel into it,
retain the locale and timestamp parameters and Intl.DateTimeFormat options, then
update TransactionDetailContent (replace the local formatFullDate) and
TransactionHistoryContent (replace formatDayLabel) to import these helpers;
ensure existing behavior and formats are preserved and run tests/compile to
confirm no type or import issues.

In `@packages/vechain-kit/src/hooks/api/staking/useStargatePositions.ts`:
- Around line 36-50: Replace the inline sentinel const VET_ADDRESS = '0x' in
useStargatePositions with the shared canonical VET constant used by the
wallet/history hooks: import that exported VET token key (the shared VET
constant) at the top of the file and use it in the pricing lookup (vetPriceUsd =
prices[SHARED_VET_CONSTANT] || 0). Update any references to VET_ADDRESS in this
module (e.g., vetPriceUsd) to the imported constant so the stargate price lookup
matches the rest of the app.

In `@packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts`:
- Line 131: The unused constant SCALE is defined but only referenced via a no-op
"void SCALE;" which should be removed or documented; delete the SCALE
declaration and the "void SCALE;" line inside useOraclePriceChanges24h (or, if
SCALE is intended for future use, replace the void usage with a comment
explaining its planned purpose) so there are no dead symbols left in the hook.
- Around line 56-64: The map callback silently swallows errors from
oracle.read.getLatestValue; update the catch block in the feedEntries.map(async
([token, feedId]) => { ... }) callback to log the failure (including token and
feedId and the caught error) before returning [token, null]; use the project's
logger if available (e.g., processLogger or a provided logger), otherwise
fallback to console.error, and keep the behavior of returning [token, null]
unchanged.
- Around line 95-113: The event-decoding loop swallows all decoding errors,
hiding malformed events or ABI mismatches; update the catch block around
viemDecodeEventLog(...) in the loop (where OracleVechainEnergy__factory.abi,
events, and pastByFeedId are used) to log the failure details and the error
(include event.data, event.topics and the caught error). Use the existing logger
(e.g., processLogger or a module logger) if available, otherwise fallback to
console.warn, so decoding failures are visible for debugging while still
continuing to ignore that single malformed entry.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: d430c376-73c2-4fec-bfcf-ba3e902371ed

📥 Commits

Reviewing files that changed from the base of the PR and between e6e9ae5 and d3c7a62.

📒 Files selected for processing (51)
  • packages/vechain-kit/src/components/AccountModal/AccountModal.tsx
  • packages/vechain-kit/src/components/AccountModal/Components/BalanceSection.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/AssetsContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/AssetsHeader.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/AssetsTabs.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/BetterSwapLpCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/JuicyFinanceCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/NavigatorsCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/StakingCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingCards/StargateCard.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/StakingTab.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Assets/Components/TokensTab.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Receive/ReceiveTokenContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/Swap/SwapTokenContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/TokenDetail/Components/TokenHistoryPreview.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/TokenDetail/TokenDetailContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/TokenDetail/index.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/Components/HistoryItemRow.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/TransactionDetailContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/TransactionHistoryContent.tsx
  • packages/vechain-kit/src/components/AccountModal/Contents/TransactionHistory/index.ts
  • packages/vechain-kit/src/components/AccountModal/Contents/index.ts
  • packages/vechain-kit/src/components/AccountModal/Types/Types.ts
  • packages/vechain-kit/src/components/common/AddressOrDomainLabel.tsx
  • packages/vechain-kit/src/components/common/AssetButton.tsx
  • packages/vechain-kit/src/components/common/CopyIconButton.tsx
  • packages/vechain-kit/src/components/common/PriceChangeBadge.tsx
  • packages/vechain-kit/src/components/common/index.ts
  • packages/vechain-kit/src/config/index.ts
  • packages/vechain-kit/src/config/mainnet.ts
  • packages/vechain-kit/src/config/solo.ts
  • packages/vechain-kit/src/config/testnet.ts
  • packages/vechain-kit/src/hooks/api/index.ts
  • packages/vechain-kit/src/hooks/api/staking/abis.ts
  • packages/vechain-kit/src/hooks/api/staking/index.ts
  • packages/vechain-kit/src/hooks/api/staking/useBetterSwapLpPositions.ts
  • packages/vechain-kit/src/hooks/api/staking/useJuicyPosition.ts
  • packages/vechain-kit/src/hooks/api/staking/useNavigatorPosition.ts
  • packages/vechain-kit/src/hooks/api/staking/useStargatePositions.ts
  • packages/vechain-kit/src/hooks/api/transferHistory/index.ts
  • packages/vechain-kit/src/hooks/api/transferHistory/types.ts
  • packages/vechain-kit/src/hooks/api/transferHistory/useTokenTransferHistory.ts
  • packages/vechain-kit/src/hooks/api/transferHistory/useTransferHistory.ts
  • packages/vechain-kit/src/hooks/api/wallet/index.ts
  • packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokenPrices.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTokensWithValues.ts
  • packages/vechain-kit/src/hooks/api/wallet/useTotalBalance.ts
  • packages/vechain-kit/src/languages/en.json
  • packages/vechain-kit/src/utils/constants.tsx

Comment thread packages/vechain-kit/src/components/common/AssetButton.tsx
Comment thread packages/vechain-kit/src/components/common/CopyIconButton.tsx Outdated
Comment thread packages/vechain-kit/src/hooks/api/staking/useNavigatorPosition.ts
Comment thread packages/vechain-kit/src/hooks/api/transferHistory/useTransferHistory.ts Outdated
Comment thread packages/vechain-kit/src/hooks/api/wallet/useOraclePriceChanges24h.ts Outdated
Comment thread packages/vechain-kit/src/hooks/api/wallet/useTokenBalances.ts
Comment thread packages/vechain-kit/src/languages/en.json Outdated
- aria-label on the action buttons in AssetsHeader and TokenDetail now
  uses the translated string (matches the visible text), not the raw
  English key.
- Row's CopyIconButton aria-label uses t('Copy') instead of a hardcoded
  English prefix; Row pulls its own useTranslation hook.
- Add the 'Copy' key to en.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Size Change: +586 kB (+7.42%) 🔍

Total Size: 8.47 MB

Filename Size Change
packages/vechain-kit/dist/index-CWViOs1U.d.mts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index-CWViOs1U.d.mts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index-D5_NsdUt.d.cts 0 B -158 kB (removed) 🏆
packages/vechain-kit/dist/index-D5_NsdUt.d.cts.map 0 B -45 kB (removed) 🏆
packages/vechain-kit/dist/index-I8fe7GR2.d.cts 0 B -5.63 kB (removed) 🏆
packages/vechain-kit/dist/index-I8fe7GR2.d.cts.map 0 B -2.99 kB (removed) 🏆
packages/vechain-kit/dist/index-tOhiWQE1.d.mts 0 B -158 kB (removed) 🏆
packages/vechain-kit/dist/index-tOhiWQE1.d.mts.map 0 B -45 kB (removed) 🏆
packages/vechain-kit/dist/index.cjs 1.11 MB +65.8 kB (+6.29%) 🔍
packages/vechain-kit/dist/index.cjs.map 2.7 MB +214 kB (+8.63%) 🔍
packages/vechain-kit/dist/index.d.cts 22.9 kB +1.9 kB (+9.09%) 🔍
packages/vechain-kit/dist/index.d.mts 22.9 kB +1.9 kB (+9.09%) 🔍
packages/vechain-kit/dist/index.mjs 1.07 MB +61.5 kB (+6.09%) 🔍
packages/vechain-kit/dist/index.mjs.map 2.64 MB +208 kB (+8.58%) 🔍
packages/vechain-kit/dist/utils-B3mmhtVy.cjs 0 B -26.2 kB (removed) 🏆
packages/vechain-kit/dist/utils-B3mmhtVy.cjs.map 0 B -65.3 kB (removed) 🏆
packages/vechain-kit/dist/utils-fXJ3K1K6.mjs 0 B -21.1 kB (removed) 🏆
packages/vechain-kit/dist/utils-fXJ3K1K6.mjs.map 0 B -64.6 kB (removed) 🏆
packages/vechain-kit/dist/index-BjQrND59.d.mts 5.63 kB +5.63 kB (new file) 🆕
packages/vechain-kit/dist/index-BjQrND59.d.mts.map 2.99 kB +2.99 kB (new file) 🆕
packages/vechain-kit/dist/index-D4WlZaQd.d.mts 170 kB +170 kB (new file) 🆕
packages/vechain-kit/dist/index-D4WlZaQd.d.mts.map 46.9 kB +46.9 kB (new file) 🆕
packages/vechain-kit/dist/index-D8WXkNBA.d.cts 170 kB +170 kB (new file) 🆕
packages/vechain-kit/dist/index-D8WXkNBA.d.cts.map 46.9 kB +46.9 kB (new file) 🆕
packages/vechain-kit/dist/index-nRf3KRll.d.cts 5.63 kB +5.63 kB (new file) 🆕
packages/vechain-kit/dist/index-nRf3KRll.d.cts.map 2.99 kB +2.99 kB (new file) 🆕
packages/vechain-kit/dist/utils-DJKLAzLP.cjs 27.2 kB +27.2 kB (new file) 🆕
packages/vechain-kit/dist/utils-DJKLAzLP.cjs.map 67.2 kB +67.2 kB (new file) 🆕
packages/vechain-kit/dist/utils-KYzX9d5n.mjs 22.1 kB +22.1 kB (new file) 🆕
packages/vechain-kit/dist/utils-KYzX9d5n.mjs.map 66.5 kB +66.5 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size
packages/vechain-kit/dist/assets 4.1 kB
packages/vechain-kit/dist/assets-BL24r-Yp.mjs 51.3 kB
packages/vechain-kit/dist/assets-BL24r-Yp.mjs.map 74.1 kB
packages/vechain-kit/dist/assets-DNJsQD7_.cjs 58.5 kB
packages/vechain-kit/dist/assets-DNJsQD7_.cjs.map 75.5 kB
packages/vechain-kit/dist/assets/index.cjs 716 B
packages/vechain-kit/dist/assets/index.d.cts 973 B
packages/vechain-kit/dist/assets/index.d.mts 973 B
packages/vechain-kit/dist/assets/index.mjs 718 B
packages/vechain-kit/dist/utils 4.1 kB
packages/vechain-kit/dist/utils/index.cjs 1.98 kB
packages/vechain-kit/dist/utils/index.d.cts 3.04 kB
packages/vechain-kit/dist/utils/index.d.mts 3.04 kB
packages/vechain-kit/dist/utils/index.mjs 2 kB

compressed-size-action

Agilulfo1820 and others added 10 commits May 14, 2026 16:33
Add translations for the 37 keys introduced by the AccountModal refactor
(Token, Staking, History, Sent, Received, Supplied, Borrowed, Health
rate, Go to platform, Copy, etc.) to every supported locale: de, es,
fr, hi, it, ja, ko, nl, pt, ro, ru, sv, tr, tw, vi, zh.

Also alphabetises all language files (including en.json) case-
insensitively so the per-locale set of keys stays in sync going
forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Token Detail -> tap a history-preview row -> Transaction Detail. The
back button was hardcoded to navigate to the aggregated history screen
instead of returning to Token Detail. Add an optional onBack prop to
both TransactionHistoryContent and TransactionDetailContent, and pass:

- TokenDetail.handleHistoryItem  -> onBack returns to Token Detail.
- TokenDetail.handleSeeAll        -> onBack returns to Token Detail.
- TransactionHistory.handleItemClick -> onBack re-dispatches the same
  history screen with its tokenFilter + parent onBack so further back
  presses still chain correctly.

History screen's back button uses onBack if provided, else falls back
to the Assets list (existing behaviour).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- useTransferHistory: only pre-fill symbolByAddress for known 18-decimal
  tokens (VET, VTHO, B3TR, VOT3, veDelegate, VVET). Custom tokens flow
  through the existing lazy getTokenInfo path so their real decimals are
  honoured.
- useBetterSwapLpPositions: validate factoryAddress / pairs with viem's
  isAddress; build the queryKey from a pairs fingerprint (first + last
  + length) so different sets with equal length get distinct cache
  entries; use the validated pair list throughout the queryFn.
- config: checksum the testnet stargate/stargate-NFT/navigator-registry
  addresses and the mainnet navigator address (EIP-55) to match the
  surrounding style.
- CopyIconButton: store the setTimeout id in a useRef and clear it on
  rapid re-click and on unmount.

Other CodeRabbit suggestions were verified against current code and are
either already covered (oracle feedId cast, prices lowercase mirror,
ERC20 balance hook's internal address guard), pre-existing patterns
across the kit, or no-ops given the surrounding constraints — left
unchanged to keep this diff minimal.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- Refactor the oracle hook into a single useOracleHistory24h query that
  scans 24h of ValueUpdate events once and exposes:
    * useOraclePriceChanges24h -> percent change per feed
    * useTokenPriceHistory24h(token) -> sorted PricePoint[]
  The current spot value is pinned as the closing point so the chart
  always extends to "now" even between sparse oracle updates.
- New usePortfolioPriceHistory24h derives a portfolio sparkline by
  walking the union of feed timestamps and weighting each feed by the
  wallet's current liquid holdings (VVET counted as VET; VOT3 +
  veDelegate counted on the B3TR feed). Cheap and accurate enough for
  a 24h window where holdings rarely change.
- New PriceChart: dependency-free SVG sparkline with a
  green/red/neutral tone, gradient fill, configurable opacity, and
  vector-effect non-scaling-stroke so the line stays crisp regardless
  of container width.
- TokenDetail screen shows the chart full-opacity between balance and
  actions; VVET / VOT3 / veDelegate piggy-back on VET / B3TR.
- BalanceSection (main wallet view) overlays the portfolio chart at
  ~18% opacity behind the balance text, tinted by the day's direction.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The straight-line polyline produced sharp corners between sparse oracle
points. Replace M/L segments with a Catmull-Rom-derived cubic-Bezier
spline: each segment's control points are derived from the surrounding
two points so the curve glides through every observation without
overshooting. The filled area + the existing strokeLinejoin/Linecap
=round still apply.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The Catmull-Rom-to-Bezier smoothing produced control points that
overshot adjacent points whenever neighbouring oracle observations
jumped sharply, causing the line to backtrack on itself. Replace with
Fritsch-Carlson monotone cubic: tangents at each point are the average
of neighbouring slopes (zero at local extrema), then clamped so the
curve is provably monotone within each segment. The curve still passes
through every observation but is guaranteed not to overshoot or
reverse direction between points.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
AssetsHeader now renders the same monotone-cubic portfolio sparkline
between the balance row and the Send/Swap/History actions, mirroring
the per-token chart on TokenDetail. Reuses usePortfolioPriceHistory24h
and PriceChart, tinted by the day's direction. Hidden when balances
are hidden (showAssets=false) or when there's only one observation.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The chart still ships on Assets and TokenDetail; on the main wallet
view (BalanceSection) it competed with the AssetIcons row and didn't
add enough signal at 18% opacity. Removes the underlay layer, the
usePortfolioPriceHistory24h call, the Box wrapper and the now-unused
imports.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
- PriceChart: new interactive prop. When enabled the chart accepts
  mouse/touch input, snaps to the nearest data point, and renders a
  vertical guide line, a marker dot at the active point, and a
  position-aware tooltip with the formatted value and timestamp. New
  formatValue prop lets callers override the value formatter (defaults
  to a 4-decimal USD price; AssetsHeader passes formatCompactCurrency
  so portfolio values render as $4.30K-style).
- TokenDetail and AssetsHeader charts opt in via interactive.
- AssetsHeader actions reordered to [Swap, Send, History] so they match
  the [Swap, Send, Receive] order on TokenDetail.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The chart was only summing liquid token balances, so for wallets where
most value sits in Stargate / Navigators / Juicy / BetterSwap LP, the
sparkline reported a value an order of magnitude smaller than
useTotalBalance's headline number.

usePortfolioPriceHistory24h now also reads useStargatePositions,
useNavigatorPosition, useJuicyPosition, useBetterSwapLpPositions and
maps each into the appropriate price feed:

- Stargate VET supplied   -> VET feed amount.
- Navigator staked B3TR / delegated B3TR -> B3TR feed amount.
- Juicy supplied/borrowed -> per-asset net into VET (via VVET), VTHO,
  or B3TR feeds.
- BetterSwap LP positions -> flat USD offset (their underlying split
  varies per pair, so attributing amounts to specific feeds isn't
  meaningful; the current USD value still contributes to the total).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@Agilulfo1820 Agilulfo1820 merged commit efc2eb1 into main May 14, 2026
7 checks passed
@Agilulfo1820 Agilulfo1820 deleted the feat/account-modal-assets-refactor branch May 14, 2026 15:20
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.

💡 defi - stargate 💡 [EPIC] Implement - DeFi 💡 Implement - history 💡 Create new content for assets 💡 [EPIC] - New assets content UX

1 participant