Skip to content

feat(evm): vault page revamp#5445

Merged
david-sun-venus merged 14 commits intomainfrom
feat/vault-page
Mar 16, 2026
Merged

feat(evm): vault page revamp#5445
david-sun-venus merged 14 commits intomainfrom
feat/vault-page

Conversation

@david-sun-venus
Copy link
Copy Markdown
Contributor

Jira ticket(s)

VEN-730

Changes

  • Vault Page revamp

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 9, 2026

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

Project Deployment Actions Updated (UTC)
dapp-preview Ready Ready Preview Mar 16, 2026 9:22am
dapp-testnet Ready Ready Preview Mar 16, 2026 9:22am
venus.io Ready Ready Preview Mar 16, 2026 9:22am

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 9, 2026

🦋 Changeset detected

Latest commit: 1d449a6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@venusprotocol/evm Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 9, 2026

Greptile Summary

This PR replaces the old Staking page (/staking) with a revamped Vault page (/vaults), introducing a new Overview banner, per-vault filter/search UI, a simplified card for the Dashboard, and a new useGetTokenListUsdPrice batch-price hook. A backward-compatible redirect from /staking/*/vaults/ is included. Previously flagged issues (wrong token decimals for daily emission, hook-after-early-return in Dashboard Vaults, missing translation keys, featuredVault undefined guard) appear to be resolved in this iteration.

Key observations:

  • Mock query key collision (apps/evm/src/clients/api/__mocks__/index.ts): Both useGetTokenListUsdPrice and useGetTokenUsdPrice mocks use the same [FunctionKey.GET_TOKEN_USD_PRICE] key with no discriminant, which can cause incorrect results in tests where both hooks render simultaneously.
  • getVaultMetadata hardcoded for XVS/VAI only (utils/index.tsx): Any future vault with a different staked token gets empty category/curator strings and silently vanishes from filtered views when a non-"All" filter is selected.
  • Shared FunctionKey.GET_TOKEN_USD_PRICE namespace (useGetTokenListUsdPrice.ts): Both the single-token and batch-price hooks share the same React Query function key prefix, meaning any prefix-based cache invalidation will flush both caches unnecessarily. A dedicated GET_TOKEN_LIST_USD_PRICE constant is recommended.

Confidence Score: 3/5

  • Safe to merge with low functional risk to end users, but two issues should be addressed before the next feature build on top of this: the test mock key collision and the vault metadata hardcoding.
  • The core UI and price-calculation logic is sound and previously flagged critical bugs (wrong decimals, hook ordering, missing translations) are resolved. The remaining issues are a test-reliability bug (mock query key collision that can produce flaky tests) and a forward-compatibility gap (getVaultMetadata only covers XVS/VAI), neither of which causes a production regression today but will surface as soon as a new vault type is added or the test suite expands.
  • apps/evm/src/clients/api/mocks/index.ts (mock key collision) and apps/evm/src/pages/Vaults/utils/index.tsx (hardcoded vault metadata)

Important Files Changed

Filename Overview
apps/evm/src/pages/Vaults/index.tsx New Vaults page replacing the old Staking page; correctly guards against undefined/empty vaults before rendering and composes Overview + Vaults sub-components cleanly.
apps/evm/src/pages/Vaults/Overview/index.tsx New Overview component; correctly copies the vaults array before sorting to avoid mutation and guards featuredVault before rendering Banner. TVL reduce uses optional chaining defensively but Vault type guarantees totalStakedMantissa is always a BigNumber.
apps/evm/src/pages/Vaults/utils/index.tsx getVaultMetadata is hardcoded for XVS and VAI only; any future vault with a different staked token gets empty category/curator strings and silently disappears from filtered views when a non-"All" filter is active.
apps/evm/src/clients/api/queries/getTokenListUsdPrice/useGetTokenListUsdPrice.ts New batch price hook; reuses FunctionKey.GET_TOKEN_USD_PRICE, which is the same key namespace as useGetTokenUsdPrice — prefix-based cache invalidation would flush both caches unnecessarily.
apps/evm/src/clients/api/mocks/index.ts The new useGetTokenListUsdPrice mock uses the identical query key as useGetTokenUsdPrice (no discriminant), causing cache collisions in tests that render components using both hooks simultaneously.
apps/evm/src/containers/Vault/hooks/useVaultUsdValues.ts New hook that derives USD values for a vault; correctly uses rewardToken.decimals for dailyEmissionUsdCents and stakedToken.decimals for staked/total values.
apps/evm/src/pages/Dashboard/Vaults/index.tsx Dashboard Vaults section revamped; hooks are correctly called before the early return, rewardToken.decimals used for dailyEarnUsd — previously flagged issues are addressed.

Comments Outside Diff (2)

  1. apps/evm/src/pages/Vaults/utils/index.tsx, line 12-29 (link)

    getVaultMetadata only handles XVS and VAI vaults — new vault types silently disappear from filtered views

    The if / else if block sets category and curator only for XVS and VAI staked tokens. For any other token both fields remain ''. In Vaults/index.tsx, the filter is:

    filterCategory === ALL_OPTION_VALUE || filterCategory === category

    When a user applies any non-"All" filter (e.g. "Stablecoins"), a vault with category = '' will fail both conditions and be hidden — not because it doesn't match, but because it was never categorised. Users would have no way to discover new vault types through the filters.

    Consider either:

    1. Adding a catch-all else branch with sensible defaults, or
    2. Storing metadata in a separate config map keyed by stakedToken.address so new vault types can be registered without changing this utility.
    } else {
      // fallback for future vault types
      category = 'others';
      curator = 'venus';
      curatorLogo = <Icon name="logoMobile" />;
      status = vault.isPaused ? 'paused' : 'active';
    }
  2. apps/evm/src/clients/api/__mocks__/index.ts, line 451-454 (link)

    Mock query key collision with useGetTokenUsdPrice

    Both useGetTokenListUsdPrice and useGetTokenUsdPrice use the identical mock query key [FunctionKey.GET_TOKEN_USD_PRICE] with no additional discriminant. In any test that renders a component calling both hooks simultaneously (e.g. the Dashboard Vaults section), React Query's test cache treats them as the same query — whichever mock runs first, its return value is served to both.

    Concretely:

    • useGetTokenListUsdPrice returns an array (GetTokenListUsdPriceOutput), so .slice() and index-access are expected.
    • useGetTokenUsdPrice returns a plain object (GetTokenUsdPriceOutput).

    When the cache is shared, whichever shape wins first is handed to the other hook, causing either silent undefined results or runtime errors for callers that iterate over the list result.

    The mock query key for useGetTokenListUsdPrice should include a discriminating second element (e.g. the tokens array or a string literal like 'list') to give it a distinct cache entry, matching what the real implementation already does at runtime.

Last reviewed commit: 5d61ff0

Comment thread apps/evm/src/clients/api/queries/useGetVaults/useGetVaiVault.ts Outdated
Comment thread apps/evm/src/clients/api/queries/useGetVaults/useGetVestingVaults/index.ts Outdated
Comment thread apps/evm/src/pages/Staking/index.tsx Outdated
Comment thread apps/evm/src/libs/translations/translations/en.json Outdated
Comment thread apps/evm/src/libs/translations/translations/en.json Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 9, 2026

Coverage Report for ./apps/evm

Status Category Percentage Covered / Total
🔵 Lines 76.07% 36670 / 48200
🔵 Statements 76.07% 36670 / 48200
🔵 Functions 59.03% 601 / 1018
🔵 Branches 71.23% 4346 / 6101
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
apps/evm/src/App/Routes/index.tsx 0% 0% 0% 0% 1-258
apps/evm/src/clients/api/index.ts 0% 0% 0% 0% 1-242
apps/evm/src/clients/api/queries/getTokenListUsdPrice/index.ts 84.84% 25% 100% 84.84% 1, 35-39
apps/evm/src/clients/api/queries/getTokenListUsdPrice/useGetTokenListUsdPrice.ts 0% 0% 0% 0% 1-65
apps/evm/src/clients/api/queries/getTokenUsdPrice/useGetTokenUsdPrice.ts 0% 0% 0% 0% 1-69
apps/evm/src/components/Delimiter/index.tsx 100% 0% 100% 100%
apps/evm/src/components/Icon/icons/ceefu.tsx 11.53% 100% 0% 11.53% 5-28
apps/evm/src/components/Icon/icons/index.ts 100% 100% 100% 100%
apps/evm/src/components/Icon/icons/pendle.tsx 11.53% 100% 0% 11.53% 5-28
apps/evm/src/components/Select/index.tsx 93.38% 75% 50% 93.38% 59, 64, 69, 75-76, 83-85, 91
apps/evm/src/components/StatusLabel/index.tsx 0% 0% 0% 0% 1-38
apps/evm/src/components/TextField/index.tsx 97.97% 88.88% 100% 97.97% 51-54
apps/evm/src/constants/routing.ts 100% 66.66% 100% 100%
apps/evm/src/containers/CopyAddressButton/index.tsx 100% 100% 100% 100%
apps/evm/src/containers/Layout/Header/usePathNodes/index.tsx 92.8% 66.66% 100% 92.8% 72-75, 134-138
apps/evm/src/containers/Layout/NavBar/ClaimRewardsButton/ClaimRewardsContent/index.tsx 97.56% 81.81% 100% 97.56% 40-41
apps/evm/src/containers/Layout/NavBar/useMenuItems/index.tsx 0% 0% 0% 0% 1-114
apps/evm/src/containers/PrimeStatusBanner/index.tsx 92.33% 91.22% 33.33% 92.33% 66-69, 177, 184-190, 211-222, 281
apps/evm/src/containers/TopMarkets/TypeButton/index.tsx 100% 66.66% 100% 100%
apps/evm/src/containers/Vault/VaultCard/index.tsx 100% 100% 100% 100%
apps/evm/src/containers/Vault/VaultCard/Legacy/VaultModals/index.tsx 100% 100% 100% 100%
apps/evm/src/containers/Vault/VaultCard/Simplified/Cell.tsx 100% 0% 100% 100%
apps/evm/src/containers/Vault/VaultCard/Simplified/index.tsx 89.33% 0% 100% 89.33% 33, 66, 76-81
apps/evm/src/containers/Vault/hooks/useVaultUsdValues.ts 74.41% 0% 100% 74.41% 1, 28-32, 35-39
apps/evm/src/pages/Dashboard/index.tsx 86.25% 20% 100% 86.25% 40, 55-58, 63-66, 72-74
apps/evm/src/pages/Dashboard/Guide/index.tsx 79% 60% 0% 79% 47-48, 53-58, 90-104
apps/evm/src/pages/Dashboard/Vaults/index.tsx 98.01% 44.44% 100% 98.01% 94-95
apps/evm/src/pages/Governance/VotingWallet/index.tsx 97.44% 86.2% 28.57% 97.44% 49-50, 79-80, 252
apps/evm/src/pages/Vaults/index.tsx 90.9% 33.33% 100% 90.9% 16-18
apps/evm/src/pages/Vaults/Overview/index.tsx 90.27% 25% 100% 90.27% 47-51, 60, 67
apps/evm/src/pages/Vaults/Overview/Banner/index.tsx 100% 0% 100% 100%
apps/evm/src/pages/Vaults/Vaults/index.tsx 94.44% 14.28% 0% 94.44% 29, 37, 41-43
apps/evm/src/pages/Vaults/Vaults/hooks/useFilterOptions.tsx 89.47% 0% 0% 89.47% 19-21, 25-27
apps/evm/src/pages/Vaults/utils/index.tsx 96.42% 33.33% 100% 96.42% 26
Generated in workflow #12909 for commit 1d449a6 by the Vitest Coverage Report Action

@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

"bannerVaultIllustration": "Vault illustration",
"description": "Yield made simple, returns made real — deposit across multiple vaults and watch your crypto grow <strong>on your terms</strong>.",
"highestApr": "Highest APR",
"title": "Venus Vault",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
"title": "Venus Vault",
"title": "Vaults",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Title is "Venus Vault" from the design:
image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah it's not your responsibility for sure, but it doesn't make sense to use this title if the page is called "Vaults".
@zed-venus I believe the title of the page should match its name in the navigation menu, so it would be "Vaults". What do you think?

Comment thread apps/evm/src/libs/translations/translations/en.json Outdated
Comment thread apps/evm/src/pages/Vaults/index.tsx Outdated
Comment thread apps/evm/src/containers/Vault/VaultCard/Legacy/index.tsx
Comment thread apps/evm/src/containers/Vault/VaultCard/Simplified/index.tsx
Comment thread apps/evm/src/components/Icon/icons/search.tsx Outdated
Comment thread apps/evm/src/pages/Vaults/Vaults/index.tsx Outdated
Comment thread apps/evm/src/clients/api/queries/getTokenUsdPrice/useGetTokenListUsdPrice.ts Outdated
Comment thread apps/evm/src/clients/api/queries/getTokenUsdPrice/useGetTokenListUsdPrice.ts Outdated
Comment thread apps/evm/src/pages/Dashboard/Vaults/index.tsx Outdated
Comment thread apps/evm/src/containers/Vault/VaultCard/Simplified/index.tsx
@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

3 similar comments
@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

Comment thread apps/evm/src/clients/api/queries/getTokenListUsdPrice/index.ts Outdated
Comment thread apps/evm/src/clients/api/queries/getTokenListUsdPrice/useGetTokenListUsdPrice.ts Outdated
"bannerVaultIllustration": "Vault illustration",
"description": "Yield made simple, returns made real — deposit across multiple vaults and watch your crypto grow <strong>on your terms</strong>.",
"highestApr": "Highest APR",
"title": "Venus Vault",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah it's not your responsibility for sure, but it doesn't make sense to use this title if the page is called "Vaults".
@zed-venus I believe the title of the page should match its name in the navigation menu, so it would be "Vaults". What do you think?

Comment thread apps/evm/src/libs/translations/translations/en.json Outdated
Comment thread apps/evm/src/pages/Vaults/index.tsx Outdated
Comment thread apps/evm/src/clients/api/queries/getTokenUsdPrice/useGetTokenUsdPrice.ts Outdated
Comment thread apps/evm/src/containers/Vault/VaultCard/Simplified/index.tsx Outdated
Comment thread apps/evm/src/pages/Dashboard/Vaults/index.tsx Outdated
Comment thread apps/evm/src/pages/Vaults/Overview/index.tsx Outdated
@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

1 similar comment
@david-sun-venus
Copy link
Copy Markdown
Contributor Author

@greptile

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