diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json
index 09d19a4adbb..65904b2069b 100644
--- a/src/assets/translations/en/main.json
+++ b/src/assets/translations/en/main.json
@@ -2802,6 +2802,7 @@
"depositsDisabledDescription": "Deposits are temporarily unavailable for this yield opportunity.",
"withdrawalsDisabled": "Withdrawals Disabled",
"withdrawalsDisabledDescription": "Withdrawals are temporarily unavailable for this yield opportunity.",
+ "noActiveBalanceToExit": "No active balance available to unstake.",
"noAvailableYields": "No yield opportunities available for your assets",
"connectWalletAvailable": "Connect a wallet to see yields available for your assets",
"aboutProvider": "About %{provider}",
diff --git a/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx b/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
index e3328675b08..93ad42cd741 100644
--- a/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
+++ b/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
@@ -367,7 +367,11 @@ export const EarnConfirm = memo(() => {
{selectedYield && (
-
+
)}
diff --git a/src/pages/Yields/components/YieldEnterModal.tsx b/src/pages/Yields/components/YieldEnterModal.tsx
index 11b492c8acd..c52d39b7419 100644
--- a/src/pages/Yields/components/YieldEnterModal.tsx
+++ b/src/pages/Yields/components/YieldEnterModal.tsx
@@ -665,6 +665,7 @@ export const YieldEnterModal = memo(
{stepsToShow.length > 0 && }
diff --git a/src/pages/Yields/components/YieldExplainers.tsx b/src/pages/Yields/components/YieldExplainers.tsx
index d1657b526bf..0777dfae5a5 100644
--- a/src/pages/Yields/components/YieldExplainers.tsx
+++ b/src/pages/Yields/components/YieldExplainers.tsx
@@ -15,6 +15,7 @@ const infoIcon =
type ExplainerItem = {
icon: ReactNode
textKey: string
+ relevance: 'enter' | 'exit' | 'both'
}
const getYieldExplainers = (selectedYield: AugmentedYieldDto): ExplainerItem[] => {
@@ -29,31 +30,40 @@ const getYieldExplainers = (selectedYield: AugmentedYieldDto): ExplainerItem[] =
textKey: outputTokenSymbol
? 'earn.explainers.liquidStakingReceive'
: 'earn.explainers.liquidStakingTrade',
+ relevance: 'enter' as const,
+ },
+ { icon: giftIcon, textKey: 'earn.explainers.rewardsSchedule', relevance: 'enter' as const },
+ {
+ icon: infoIcon,
+ textKey: 'earn.explainers.liquidStakingWithdraw',
+ relevance: 'both' as const,
},
- { icon: giftIcon, textKey: 'earn.explainers.rewardsSchedule' },
- { icon: infoIcon, textKey: 'earn.explainers.liquidStakingWithdraw' },
]
case 'native-staking':
case 'pooled-staking':
case 'staking':
return [
- { icon: giftIcon, textKey: 'earn.explainers.rewardsSchedule' },
- { icon: infoIcon, textKey: 'earn.explainers.stakingUnbonding' },
+ { icon: giftIcon, textKey: 'earn.explainers.rewardsSchedule', relevance: 'enter' as const },
+ { icon: infoIcon, textKey: 'earn.explainers.stakingUnbonding', relevance: 'both' as const },
]
case 'restaking':
return [
- { icon: giftIcon, textKey: 'earn.explainers.restakingYield' },
- { icon: infoIcon, textKey: 'earn.explainers.restakingWithdraw' },
+ { icon: giftIcon, textKey: 'earn.explainers.restakingYield', relevance: 'enter' as const },
+ {
+ icon: infoIcon,
+ textKey: 'earn.explainers.restakingWithdraw',
+ relevance: 'both' as const,
+ },
]
case 'vault':
return [
- { icon: giftIcon, textKey: 'earn.explainers.vaultYield' },
- { icon: infoIcon, textKey: 'earn.explainers.vaultWithdraw' },
+ { icon: giftIcon, textKey: 'earn.explainers.vaultYield', relevance: 'enter' as const },
+ { icon: infoIcon, textKey: 'earn.explainers.vaultWithdraw', relevance: 'both' as const },
]
case 'lending':
return [
- { icon: giftIcon, textKey: 'earn.explainers.lendingYield' },
- { icon: infoIcon, textKey: 'earn.explainers.lendingWithdraw' },
+ { icon: giftIcon, textKey: 'earn.explainers.lendingYield', relevance: 'enter' as const },
+ { icon: infoIcon, textKey: 'earn.explainers.lendingWithdraw', relevance: 'both' as const },
]
default:
return []
@@ -63,48 +73,58 @@ const getYieldExplainers = (selectedYield: AugmentedYieldDto): ExplainerItem[] =
type YieldExplainersProps = {
selectedYield: AugmentedYieldDto
sellAssetSymbol?: string
+ action: 'enter' | 'exit' | 'claim'
}
-export const YieldExplainers = memo(({ selectedYield, sellAssetSymbol }: YieldExplainersProps) => {
- const translate = useTranslate()
+export const YieldExplainers = memo(
+ ({ selectedYield, sellAssetSymbol, action }: YieldExplainersProps) => {
+ const translate = useTranslate()
- const explainers = useMemo(() => getYieldExplainers(selectedYield), [selectedYield])
+ const actionRelevance = action === 'enter' ? 'enter' : 'exit'
+ const explainers = useMemo(
+ () =>
+ getYieldExplainers(selectedYield).filter(
+ e => e.relevance === actionRelevance || e.relevance === 'both',
+ ),
+ [selectedYield, actionRelevance],
+ )
- const rewardSchedule = selectedYield.mechanics.rewardSchedule
- const outputSymbol = selectedYield.outputToken?.symbol
+ const rewardSchedule = selectedYield.mechanics.rewardSchedule
+ const outputSymbol = selectedYield.outputToken?.symbol
- const cooldownDays = useMemo(() => {
- const seconds = selectedYield.mechanics.cooldownPeriod?.seconds
- if (!seconds) return undefined
- return Math.ceil(seconds / 86400)
- }, [selectedYield.mechanics.cooldownPeriod?.seconds])
+ const cooldownDays = useMemo(() => {
+ const seconds = selectedYield.mechanics.cooldownPeriod?.seconds
+ if (!seconds) return undefined
+ return Math.ceil(seconds / 86400)
+ }, [selectedYield.mechanics.cooldownPeriod?.seconds])
- const symbol = outputSymbol ?? sellAssetSymbol ?? ''
+ const symbol = outputSymbol ?? sellAssetSymbol ?? ''
- const translatedExplainers = useMemo(() => {
- if (explainers.length === 0) return []
- return explainers.map(explainer => ({
- icon: explainer.icon,
- text: translate(explainer.textKey, {
- symbol,
- schedule: rewardSchedule ?? '',
- days: cooldownDays ?? '',
- }),
- }))
- }, [explainers, translate, symbol, rewardSchedule, cooldownDays])
+ const translatedExplainers = useMemo(() => {
+ if (explainers.length === 0) return []
+ return explainers.map(explainer => ({
+ icon: explainer.icon,
+ text: translate(explainer.textKey, {
+ symbol,
+ schedule: rewardSchedule ?? '',
+ days: cooldownDays ?? '',
+ }),
+ }))
+ }, [explainers, translate, symbol, rewardSchedule, cooldownDays])
- if (translatedExplainers.length === 0) return null
+ if (translatedExplainers.length === 0) return null
- return (
-
- {translatedExplainers.map((explainer, index) => (
-
- {explainer.icon}
-
- {explainer.text}
-
-
- ))}
-
- )
-})
+ return (
+
+ {translatedExplainers.map((explainer, index) => (
+
+ {explainer.icon}
+
+ {explainer.text}
+
+
+ ))}
+
+ )
+ },
+)
diff --git a/src/pages/Yields/components/YieldForm.tsx b/src/pages/Yields/components/YieldForm.tsx
index e257f1c0fcb..d703cc942ee 100644
--- a/src/pages/Yields/components/YieldForm.tsx
+++ b/src/pages/Yields/components/YieldForm.tsx
@@ -10,6 +10,7 @@ import {
Icon,
Skeleton,
Text,
+ VStack,
} from '@chakra-ui/react'
import type { AccountId } from '@shapeshiftoss/caip'
import { useQueryClient } from '@tanstack/react-query'
@@ -515,23 +516,27 @@ export const YieldForm = memo(
const statsContent = useMemo(
() => (
-
-
-
- {translate('yieldXYZ.currentApy')}
-
-
- {apyDisplay}
-
-
- {hasAmount && (
-
+ {action === 'enter' && (
+
+
+ {translate('yieldXYZ.currentApy')}
+
+
+ {apyDisplay}
+
+
+ )}
+ {action === 'enter' && hasAmount && (
+
{translate('yieldXYZ.estYearlyEarnings')}
@@ -546,7 +551,7 @@ export const YieldForm = memo(
)}
{isStaking && maybeSelectedValidatorMetadata && (
-
+
{translate('yieldXYZ.validator')}
@@ -563,7 +568,7 @@ export const YieldForm = memo(
)}
{(!isStaking || !maybeSelectedValidatorMetadata) && maybeProviderMetadata && (
-
+
{translate('yieldXYZ.provider')}
@@ -580,7 +585,7 @@ export const YieldForm = memo(
)}
{minDeposit && bnOrZero(minDeposit).gt(0) && action === 'enter' && (
-
+
{translate(getYieldMinAmountKey(yieldItem.mechanics.type))}
@@ -593,7 +598,7 @@ export const YieldForm = memo(
)}
-
+
),
[
translate,
@@ -757,7 +762,11 @@ export const YieldForm = memo(
)}
{!isClaimAction && statsContent}
{!isClaimAction && (
-
+
)}
{stepsToShow.length > 0 && }
diff --git a/src/pages/Yields/components/YieldPositionCard.tsx b/src/pages/Yields/components/YieldPositionCard.tsx
index d928bc3be44..f162cef8eaa 100644
--- a/src/pages/Yields/components/YieldPositionCard.tsx
+++ b/src/pages/Yields/components/YieldPositionCard.tsx
@@ -12,6 +12,7 @@ import {
HStack,
Skeleton,
Text,
+ Tooltip,
VStack,
} from '@chakra-ui/react'
import { fromAccountId } from '@shapeshiftoss/caip'
@@ -105,6 +106,17 @@ export const YieldPositionCard = memo(
const withdrawableBalance = balancesByType?.[YieldBalanceType.Withdrawable]
const claimableBalance = balancesByType?.[YieldBalanceType.Claimable]
+ const hasActiveBalance = Boolean(
+ activeBalance && bnOrZero(activeBalance.aggregatedAmount).gt(0),
+ )
+
+ const isExitDisabled = !yieldItem.status.exit || !hasActiveBalance
+
+ const exitDisabledTitle = useMemo(() => {
+ if (!yieldItem.status.exit) return translate('yieldXYZ.withdrawalsDisabledDescription')
+ if (!hasActiveBalance) return translate('yieldXYZ.noActiveBalanceToExit')
+ }, [hasActiveBalance, translate, yieldItem.status.exit])
+
const claimAction = useMemo(
() =>
claimableBalance?.pendingActions?.find(action =>
@@ -505,24 +517,21 @@ export const YieldPositionCard = memo(
{enterLabel}
{hasAnyPosition && (
-
+
+
+
)}