Skip to content

feat: shared non-Yield+ groundwork#5502

Draft
therealemjy wants to merge 1 commit intofeat/yield-plus-pr01-query-clientfrom
feat/yield-plus-pr02-shared-groundwork
Draft

feat: shared non-Yield+ groundwork#5502
therealemjy wants to merge 1 commit intofeat/yield-plus-pr01-query-clientfrom
feat/yield-plus-pr02-shared-groundwork

Conversation

@therealemjy
Copy link
Copy Markdown
Member

Jira ticket(s)

VPD-634
VPD-632
VPD-629
VPD-640
VPD-633
VPD-638
VPD-637
VPD-643
VPD-635
VPD-639

Changes

  • extract reusable balance, slider, value update, placeholder, and submit button building blocks\n- move common form validation and generic table extensibility into shared code reused by existing market flows

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 9, 2026

🦋 Changeset detected

Latest commit: 738e712

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 Patch

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

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 9, 2026

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

Project Deployment Actions Updated (UTC)
dapp-preview Ready Ready Preview Apr 10, 2026 9:06am
dapp-testnet Ready Ready Preview Apr 10, 2026 9:06am
venus.io Ready Ready Preview Apr 10, 2026 9:06am

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

Coverage Report for ./apps/evm

Status Category Percentage Covered / Total
🔵 Lines 76.6% 38735 / 50562
🔵 Statements 76.6% 38735 / 50562
🔵 Functions 58.99% 610 / 1034
🔵 Branches 71.16% 4429 / 6224
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
apps/evm/src/components/index.ts 100% 100% 100% 100%
apps/evm/src/components/Apy/index.tsx 100% 90.62% 100% 100%
apps/evm/src/components/Apy/PrimeBadge/PrimeApy/index.tsx 100% 0% 100% 100%
apps/evm/src/components/AvailableBalance/index.tsx 100% 100% 100% 100%
apps/evm/src/components/BalanceUpdates/index.tsx 100% 86.95% 100% 100%
apps/evm/src/components/ButtonGroup/index.tsx 100% 87.5% 100% 100%
apps/evm/src/components/Cell/index.tsx 100% 50% 100% 100%
apps/evm/src/components/CellGroup/index.tsx 100% 85.71% 100% 100%
apps/evm/src/components/LabeledSlider/index.tsx 100% 0% 100% 100%
apps/evm/src/components/LabeledValueUpdate/index.tsx 100% 85.71% 100% 100%
apps/evm/src/components/LayeredValues/index.tsx 100% 100% 100% 100%
apps/evm/src/components/SelectTokenTextField/index.tsx 100% 80% 100% 100%
apps/evm/src/components/Table/index.tsx 88.88% 81.81% 0% 88.88% 60-68, 113-118, 146, 176-179
apps/evm/src/components/Table/styles.ts 87.8% 95.23% 80% 87.8% 1, 55-62, 75-89
apps/evm/src/components/Table/TableCards/index.tsx 89.62% 91.66% 33.33% 89.62% 59-70, 117
apps/evm/src/components/Tabs/index.tsx 90.78% 92.3% 0% 90.78% 35-43, 66
apps/evm/src/components/TextField/index.tsx 98.01% 88.88% 100% 98.01% 52-55
apps/evm/src/components/TokenIcon/index.tsx 86.66% 27.27% 100% 86.66% 38-41
apps/evm/src/components/TokenListWrapper/index.tsx 85.6% 87.5% 66.66% 85.6% 85-89, 123-136
apps/evm/src/components/TokenTextField/index.tsx 80.51% 72.72% 100% 80.51% 71-75, 89-103
apps/evm/src/constants/swap.ts 100% 0% 100% 100%
apps/evm/src/containers/MarketTable/index.tsx 94.25% 72.72% 66.66% 94.25% 97-105, 199
apps/evm/src/containers/Placeholder/index.tsx 0% 0% 0% 0% 1-54
apps/evm/src/containers/SwapDetails/index.tsx 99.11% 81.81% 100% 99.11% 87
apps/evm/src/containers/TxFormSubmitButton/index.tsx 100% 94.73% 100% 100%
apps/evm/src/hooks/usePrevious/index.ts 87.5% 50% 100% 87.5% 1
apps/evm/src/pages/Dashboard/index.tsx 85.33% 20% 100% 85.33% 40, 55-58, 63-66, 72-74
apps/evm/src/pages/Market/MarketHistory/Card/CapThreshold/index.tsx 99.21% 50% 100% 99.21% 79
apps/evm/src/pages/Market/OperationForm/index.tsx 83.51% 33.33% 25% 83.51% 86-105
apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx 94.34% 91.56% 84.61% 94.34% 148-151, 271-281, 312-321
apps/evm/src/pages/Market/OperationForm/BoostForm/SubmitSection/index.tsx 100% 80% 0% 100%
apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx 90% 50% 100% 90% 1, 75-79
apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts 99.46% 96.55% 100% 99.46% 1
apps/evm/src/pages/Market/OperationForm/BorrowForm/useForm/index.tsx 87.87% 50% 100% 87.87% 1, 90-98
apps/evm/src/pages/Market/OperationForm/BorrowForm/useForm/useFormValidation.ts 98.07% 92.3% 100% 98.07% 1
apps/evm/src/pages/Market/OperationForm/Footer/index.tsx 100% 80% 100% 100%
apps/evm/src/pages/Market/OperationForm/OperationDetails/index.tsx 87.87% 20% 100% 87.87% 29-33
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx 96.52% 93.47% 90% 96.52% 162-165, 297-307, 376
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx 100% 80% 0% 100%
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/index.tsx 93.97% 84.21% 100% 93.97% 1, 112-116
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts 99.07% 96.55% 100% 99.07% 1
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithWalletBalanceForm/index.tsx 97.45% 91% 87.5% 97.45% 100, 186, 476-486, 499
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithWalletBalanceForm/useForm/index.tsx 95.12% 80% 100% 95.12% 1, 122-127
apps/evm/src/pages/Market/OperationForm/Repay/RepayWithWalletBalanceForm/useForm/useFormValidation/index.ts 91.17% 88.23% 100% 91.17% 1, 90-95
apps/evm/src/pages/Market/OperationForm/SupplyForm/index.tsx 90.86% 85.33% 77.77% 90.86% 101, 195, 333-348, 359-360, 385-386, 443-453, 468, 507-510
apps/evm/src/pages/Market/OperationForm/SupplyForm/useForm/index.tsx 88.23% 50% 100% 88.23% 1, 95-103
apps/evm/src/pages/Market/OperationForm/SupplyForm/useForm/useFormValidation.ts 98.61% 93.75% 100% 98.61% 1
apps/evm/src/pages/Market/OperationForm/WithdrawForm/SubmitSection/index.tsx 100% 88.88% 100% 100%
apps/evm/src/pages/Market/OperationForm/WithdrawForm/useForm/index.tsx 87.69% 50% 100% 87.69% 3, 89-97
apps/evm/src/pages/Market/OperationForm/WithdrawForm/useForm/useFormValidation.ts 98.27% 93.75% 100% 98.27% 1
apps/evm/src/pages/Markets/Tabs/EMode/EModeGroup/index.tsx 100% 87.5% 100% 100%
apps/evm/src/types/index.ts 98.07% 88.88% 100% 98.07% 9
apps/evm/src/utilities/index.ts 100% 100% 100% 100%
apps/evm/src/utilities/restService.ts 90.9% 56.25% 100% 90.9% 1, 56, 62, 68-70, 93
apps/evm/src/utilities/safeLazyLoad/index.tsx 94.11% 0% 100% 94.11% 17
Generated in workflow #13163 for commit 738e712 by the Vitest Coverage Report Action

@therealemjy
Copy link
Copy Markdown
Member Author

@greptile

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 10, 2026

Greptile Summary

This PR extracts shared UI building blocks (LabeledSlider, LabeledValueUpdate, AvailableBalance, TxFormSubmitButton, Placeholder) and moves common form validation and type definitions (CommonTxFormErrorCode, TxFormError) into shared locations, replacing the local OperationForm/types.ts. The Table component gains renderRowControl, renderRowFooter, and tableLayout props, and its card-view layout is rewritten inline (removing the dedicated MarketCard component in favour of a generic card renderer).

Confidence Score: 4/5

Two real defects worth addressing before merge: silent skip of swap/health-factor validations when all mutations are VAI, and a potential runtime crash in calculateUserMaxBorrowTokens when borrowCapTokens is undefined.

The PR is a well-structured refactoring that correctly extracts shared components and moves types to global scope. However, widening useCommonValidation's input type from AssetBalanceMutation[] to BalanceMutation[] introduces a latent P1 defect where pool-level swap/health-factor validations are silently bypassed when all mutations are VAI type. Additionally, calculateUserMaxBorrowTokens calls .minus() on borrowCapTokens without a null guard, which is a crash risk on markets without a borrow cap.

apps/evm/src/hooks/useCommonValidation/index.ts and apps/evm/src/utilities/calculateUserMaxBorrowTokens/index.tsx

Important Files Changed

Filename Overview
apps/evm/src/hooks/useCommonValidation/index.ts New shared hook promoting the old OperationForm-scoped version; swap/health-factor checks remain inside the per-mutation loop and are silently skipped when all mutations are VAI type.
apps/evm/src/containers/TxFormSubmitButton/index.tsx Extracted from Footer; correctly wraps ConnectWallet, acknowledgement toggles, and SwapDetails with good test coverage.
apps/evm/src/components/BalanceUpdates/index.tsx Removes simulatedPool dependency and computes simulated balance directly from balanceMutation.amountTokens; simpler but may differ slightly from full-simulation values for complex swap flows.
apps/evm/src/components/Table/index.tsx Replaces rowControlOnClick with renderRowControl/renderRowFooter callbacks; wraps rows in Fragment to support footer rows; cursor-pointer fix now applies to all variants not just secondary.
apps/evm/src/components/LabeledSlider/index.tsx Generic slider replaces the BoostForm-specific RiskSlider; loses color-coded risk visualization and descriptive Low/High risk labels.
apps/evm/src/types/index.ts Promotes CommonTxFormErrorCode and TxFormError from OperationForm-local types to global shared types; adds balanceTokens and label optional fields to AssetBalanceMutation.
apps/evm/src/containers/Placeholder/index.tsx New generic placeholder card with icon, title, description, optional CTA link, and conditional ConnectWallet button.
apps/evm/src/utilities/calculateUserMaxBorrowTokens/index.tsx Moved from BoostForm to shared utilities; assumes borrowCapTokens is non-null without a guard.

Comments Outside Diff (2)

  1. apps/evm/src/hooks/useCommonValidation/index.ts, line 122-160 (link)

    P1 Swap/health-factor checks silently skipped when all mutations are VAI

    The swap price impact, swap quote error, and health factor validations are nested inside the per-mutation for loop after the if (balanceMutation.type === 'vai') { continue; } guard. If balanceMutations is empty or every entry is a VAI mutation, none of these pool-level checks ever execute and the function returns undefined — meaning a swap with priceImpactPercentage >= MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE would silently pass validation.

    The old implementation typed the parameter as AssetBalanceMutation[], making this impossible by construction. Now that the signature accepts BalanceMutation[], the loop can legally skip every iteration. These checks do not depend on the current mutation and should be factored out of the loop (or run before it) so they always execute regardless of mutation type.

    // Before the per-mutation loop:
    if (
      swapPriceImpactPercentage !== undefined &&
      swapPriceImpactPercentage >= MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE
    ) {
      return { code: 'SWAP_PRICE_IMPACT_TOO_HIGH', ... };
    }
    // … other pool-level checks …
    
    for (let b = 0; b < balanceMutations.length; b++) {
      // per-mutation checks only
    }
  2. apps/evm/src/utilities/calculateUserMaxBorrowTokens/index.tsx, line 18-21 (link)

    P1 borrowCapTokens can be undefined.minus() call will throw

    Asset.borrowCapTokens is an optional property (guarded with asset.borrowCapTokens && everywhere else in this PR, including in useCommonValidation). If a market has no borrow cap, borrowedAsset.borrowCapTokens is undefined and calling .minus() on it throws a TypeError at runtime.

    // guard before use
    const marginWithBorrowCapTokens = borrowedAsset.borrowCapTokens
      ? borrowedAsset.borrowCapTokens.minus(borrowedAsset.borrowBalanceTokens)
      : undefined;
    
    return clampToZero({
      value: BigNumber.min(
        userMaxBorrowTokens,
        ...(marginWithBorrowCapTokens !== undefined ? [marginWithBorrowCapTokens] : []),
        borrowedAsset.cashTokens,
      ),
    });

Reviews (1): Last reviewed commit: "feat: shared non-yield+ groundwork" | Re-trigger Greptile

@therealemjy
Copy link
Copy Markdown
Member Author

borrowCapTokens can't be undefined, so this isn't a risk. All markets have a borrow cap.

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.

1 participant