diff --git a/CLAUDE.md b/CLAUDE.md
index 1c415341010..4beb4e217f3 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -79,6 +79,13 @@
- Avoid `let` variable assignments - prefer `const` with inline IIFE switch statements or extract to functions for conditional logic
- For static JSX icon elements (e.g., ``) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
+### CLI Tool Preferences
+- Prefer `rg` (ripgrep) over `grep` for searching - it's faster and respects .gitignore
+- Use `jq` for querying and manipulating JSON files instead of reading entire files into context
+ - Example: `jq '.yieldXYZ | keys' src/assets/translations/en/main.json` to list keys
+ - Example: `jq '.someKey.nested' file.json` to extract specific values
+- This is especially important for large JSON files (like generated data or translation files) to avoid context bloat and improve performance
+
### Git & Version Control
- Never commit changes unless explicitly requested
- When creating commits, follow the Git Safety Protocol (see session notes)
@@ -96,6 +103,7 @@
- Add English copy to `src/assets/translations/en/main.json` (find appropriate section)
- Ignore other language translation files - only update English
- Use the translation hook: `useTranslate()` from `react-polyglot`
+- **Both steps required**: Translations must be (1) added to `en/main.json` AND (2) consumed via `translate('key')` - missing either step results in untranslated strings showing raw keys
### Feature Flags
- Feature flags are stored in Redux state under `preferences.featureFlags`
diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json
index 6250b7e04d9..c324d311341 100644
--- a/src/assets/translations/en/main.json
+++ b/src/assets/translations/en/main.json
@@ -2672,12 +2672,7 @@
"yieldXYZ": {
"pageTitle": "Yields",
"pageSubtitle": "Discover and manage yield opportunities across multiple chains",
- "enter": "Enter",
- "exit": "Exit",
- "enterAsset": "Enter %{asset}",
- "actions": {
- "restake": "Restake"
- },
+ "actions": {},
"yield": "Yield",
"apy": "APY",
"apr": "APR",
@@ -2689,12 +2684,17 @@
"noYields": "No yield opportunities available",
"connectWallet": "Connect a wallet to view yields",
"stats": "Stats",
- "minEnter": "Min Enter",
+ "minStake": "Min Stake",
+ "minDeposit": "Min Deposit",
"rewardSchedule": "Reward Schedule",
- "gasToken": "Gas Token",
- "entering": "Entering...",
- "exiting": "Exiting...",
- "unstaking": "Unstaking",
+ "staking": "Staking...",
+ "unstaking": "Unstaking...",
+ "depositing": "Depositing...",
+ "withdrawing": "Withdrawing...",
+ "stakingPending": "Staking",
+ "unstakingPending": "Unstaking",
+ "depositingPending": "Depositing",
+ "withdrawingPending": "Withdrawing",
"availableDate": "available %{date}",
"withdrawable": "Withdrawable",
"type": "Type",
@@ -2707,13 +2707,9 @@
"maxApy": "Max APY",
"nativeStaking": "Native Staking",
"validator": "Validator",
- "entered": "Entered",
+ "staked": "Staked",
"claimable": "Claimable",
"loadingQuote": "Loading Quote...",
- "selectValidator": "Select Validator",
- "allValidators": "All Validators",
- "myValidators": "My Validators",
- "noValidatorsFound": "No validators found",
"preferred": "Preferred",
"pending": "Pending",
"ready": "Ready",
@@ -2729,16 +2725,11 @@
"allTypes": "All Types",
"showAll": "Show All",
"searchValidator": "Search for validator",
- "enterYourToken": "Enter your %{symbol} to start earning yield securely.",
- "noActiveValidators": "You don't have any active validators yet.",
"success": "Success!",
"transactions": "Transactions",
"currentApy": "Current APY",
"estYearlyEarnings": "Est. Yearly Earnings",
- "allPositions": "All Positions",
"switch": "Switch",
- "enterSymbol": "Enter %{symbol}",
- "exitSymbol": "Exit %{symbol}",
"claimSymbol": "Claim %{symbol}",
"stakeSymbol": "Stake %{symbol}",
"unstakeSymbol": "Unstake %{symbol}",
@@ -2754,12 +2745,10 @@
"market": "market",
"markets": "markets",
"protocol": "protocol",
- "protocols": "protocols",
"chain": "chain",
"chains": "chains",
"reward": "Reward",
"assetYields": "%{asset} Yields",
- "opportunitiesAvailable": "%{count} opportunities available",
"noYieldsMatchingFilters": "No yields found matching filters.",
"activePositions": "Active Positions",
"acrossPositions": "Across %{count} positions",
@@ -2774,15 +2763,15 @@
"recommendedForYou": "Recommended for you",
"earn": "Earn",
"myBalance": "My Balance",
- "balanceByAccount": "Balance by Account",
"providers": "Providers",
- "successEnter": "You successfully entered %{amount} %{symbol}",
- "successExit": "You successfully exited %{amount} %{symbol}",
+ "successStaked": "You successfully staked %{amount} %{symbol}",
+ "successUnstaked": "You successfully unstaked %{amount} %{symbol}",
+ "successDeposited": "You successfully deposited %{amount} %{symbol}",
+ "successWithdrawn": "You successfully withdrew %{amount} %{symbol}",
"successClaim": "You successfully claimed %{amount} %{symbol}",
"viewPosition": "View Position",
"via": "via",
"resetAllowance": "Reset Allowance",
- "transactionNumber": "Transaction %{number}",
"loading": {
"signInWallet": "Sign in Wallet",
"waiting": "Waiting",
@@ -2830,10 +2819,7 @@
"otherYields": "Other %{symbol} Yields",
"availableToDeposit": "Available to Deposit",
"availableToDepositTooltip": "This is the amount of %{symbol} in your wallet that you can deposit into this yield opportunity.",
- "potentialEarningsAmount": "%{amount}/yr at %{apy}% APY",
- "depositNow": "Deposit Now",
- "strategyInfo": "Strategy Info",
- "overview": "Overview"
+ "getAsset": "Get %{symbol}"
},
"earn": {
"enterFrom": "Enter from",
diff --git a/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx b/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
index e9cfbc29688..e82fb192ffa 100644
--- a/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
+++ b/src/components/MultiHopTrade/components/Earn/EarnConfirm.tsx
@@ -9,7 +9,7 @@ import { EarnRoutePaths } from './types'
import { Amount } from '@/components/Amount/Amount'
import { bnOrZero } from '@/lib/bignumber/bignumber'
import { DEFAULT_NATIVE_VALIDATOR_BY_CHAIN_ID } from '@/lib/yieldxyz/constants'
-import { getTransactionButtonText } from '@/lib/yieldxyz/utils'
+import { getTransactionButtonText, getYieldActionLabelKeys } from '@/lib/yieldxyz/utils'
import { GradientApy } from '@/pages/Yields/components/GradientApy'
import { TransactionStepsList } from '@/pages/Yields/components/TransactionStepsList'
import { YieldAssetFlow } from '@/pages/Yields/components/YieldAssetFlow'
@@ -157,14 +157,25 @@ export const EarnConfirm = memo(() => {
return translate('yieldXYZ.resetAllowance')
}
// Before execution starts, use the first CREATED transaction from quoteData
+ const yieldType = selectedYield?.mechanics.type
const firstCreatedTx = quoteData?.transactions?.find(tx => tx.status === 'CREATED')
if (firstCreatedTx) {
- return getTransactionButtonText(firstCreatedTx.type, firstCreatedTx.title)
+ return getTransactionButtonText(firstCreatedTx.type, firstCreatedTx.title, yieldType)
}
// Fallback states
if (isLoading) return translate('common.loadingText')
- return translate('yieldXYZ.enter')
- }, [activeStepIndex, transactionSteps, isUsdtResetRequired, quoteData, isLoading, translate])
+ if (!yieldType) return translate('common.deposit')
+ const actionLabelKeys = getYieldActionLabelKeys(yieldType)
+ return translate(actionLabelKeys.enter)
+ }, [
+ activeStepIndex,
+ transactionSteps,
+ isUsdtResetRequired,
+ quoteData,
+ isLoading,
+ translate,
+ selectedYield?.mechanics.type,
+ ])
const providerInfo = useMemo(() => {
if (selectedValidator) {
@@ -297,9 +308,7 @@ export const EarnConfirm = memo(() => {
{providerInfo && (
- {selectedValidator
- ? translate('yieldXYZ.validator')
- : translate('yieldXYZ.provider')}
+ {translate(selectedValidator ? 'yieldXYZ.validator' : 'yieldXYZ.provider')}
diff --git a/src/lib/yieldxyz/types.ts b/src/lib/yieldxyz/types.ts
index d4197dc0627..3f00a467e2c 100644
--- a/src/lib/yieldxyz/types.ts
+++ b/src/lib/yieldxyz/types.ts
@@ -30,6 +30,15 @@ export enum ActionIntent {
Manage = 'manage',
}
+export type YieldType =
+ | 'staking'
+ | 'native-staking'
+ | 'pooled-staking'
+ | 'liquid-staking'
+ | 'restaking'
+ | 'vault'
+ | 'lending'
+
export enum ActionStatus {
Canceled = 'CANCELED',
Created = 'CREATED',
@@ -230,7 +239,7 @@ export type YieldEntryLimits = {
}
export type YieldMechanics = {
- type: string
+ type: YieldType
requiresValidatorSelection: boolean
rewardSchedule: string
rewardClaiming: string
diff --git a/src/lib/yieldxyz/utils.test.ts b/src/lib/yieldxyz/utils.test.ts
index 1935ac4258c..037b94343e6 100644
--- a/src/lib/yieldxyz/utils.test.ts
+++ b/src/lib/yieldxyz/utils.test.ts
@@ -4,8 +4,10 @@ import { SHAPESHIFT_COSMOS_VALIDATOR_ADDRESS } from './constants'
import type { AugmentedYieldDto, ValidatorDto } from './types'
import {
ensureValidatorApr,
+ formatYieldTxTitle,
getTransactionButtonText,
getYieldActionLabelKeys,
+ getYieldSuccessMessageKey,
isStakingYieldType,
resolveYieldInputAssetIcon,
searchValidators,
@@ -19,10 +21,20 @@ describe('getTransactionButtonText', () => {
expect(getTransactionButtonText('claim-rewards', undefined)).toBe('Claim')
})
- it('should fallback to parsing title when type is unknown', () => {
+ it('should use vault terminology (deposit/withdraw) by default', () => {
expect(getTransactionButtonText(undefined, 'Approve token')).toBe('Approve')
- expect(getTransactionButtonText(undefined, 'Deposit ETH transaction')).toBe('Enter')
+ expect(getTransactionButtonText(undefined, 'Deposit ETH transaction')).toBe('Deposit')
expect(getTransactionButtonText(undefined, 'Claim rewards')).toBe('Claim')
+ expect(getTransactionButtonText('DEPOSIT', undefined)).toBe('Deposit')
+ expect(getTransactionButtonText('WITHDRAW', undefined)).toBe('Withdraw')
+ })
+
+ it('should use staking terminology when yieldType is staking', () => {
+ expect(getTransactionButtonText('STAKE', undefined, 'staking')).toBe('Stake')
+ expect(getTransactionButtonText('UNSTAKE', undefined, 'staking')).toBe('Unstake')
+ expect(getTransactionButtonText('DEPOSIT', undefined, 'liquid-staking')).toBe('Stake')
+ expect(getTransactionButtonText('WITHDRAW', undefined, 'liquid-staking')).toBe('Unstake')
+ expect(getTransactionButtonText(undefined, 'Deposit ETH', 'native-staking')).toBe('Stake')
})
it('should return Confirm as final fallback', () => {
@@ -266,9 +278,9 @@ describe('getYieldActionLabelKeys', () => {
})
})
- it('should return restake/unstake for restaking yield types', () => {
+ it('should return stake/unstake for restaking yield types', () => {
expect(getYieldActionLabelKeys('restaking')).toEqual({
- enter: 'yieldXYZ.actions.restake',
+ enter: 'defi.stake',
exit: 'defi.unstake',
})
})
@@ -286,17 +298,6 @@ describe('getYieldActionLabelKeys', () => {
exit: 'common.withdraw',
})
})
-
- it('should return deposit/withdraw for unknown yield types', () => {
- expect(getYieldActionLabelKeys('unknown')).toEqual({
- enter: 'common.deposit',
- exit: 'common.withdraw',
- })
- expect(getYieldActionLabelKeys('')).toEqual({
- enter: 'common.deposit',
- exit: 'common.withdraw',
- })
- })
})
describe('isStakingYieldType', () => {
@@ -311,7 +312,54 @@ describe('isStakingYieldType', () => {
it('should return false for non-staking yield types', () => {
expect(isStakingYieldType('vault')).toBe(false)
expect(isStakingYieldType('lending')).toBe(false)
- expect(isStakingYieldType('unknown')).toBe(false)
- expect(isStakingYieldType('')).toBe(false)
+ })
+})
+
+describe('formatYieldTxTitle', () => {
+ it('should use vault terminology by default', () => {
+ expect(formatYieldTxTitle('Deposit ETH', 'ETH')).toBe('Deposit ETH')
+ expect(formatYieldTxTitle('Withdraw ETH transaction', 'ETH')).toBe('Withdraw ETH')
+ expect(formatYieldTxTitle('Approve ETH', 'ETH')).toBe('Approve ETH')
+ })
+
+ it('should use staking terminology when yieldType is staking', () => {
+ expect(formatYieldTxTitle('Deposit ETH', 'ETH', 'staking')).toBe('Stake ETH')
+ expect(formatYieldTxTitle('Withdraw ETH', 'ETH', 'liquid-staking')).toBe('Unstake ETH')
+ expect(formatYieldTxTitle('Exit ETH', 'ETH', 'native-staking')).toBe('Unstake ETH')
+ expect(formatYieldTxTitle('Unstake ETH', 'ETH', 'pooled-staking')).toBe('Unstake ETH')
+ })
+
+ it('should preserve unknown titles', () => {
+ expect(formatYieldTxTitle('Custom action', 'ETH')).toBe('Custom action')
+ expect(formatYieldTxTitle('Custom action', 'ETH', 'staking')).toBe('Custom action')
+ })
+})
+
+describe('getYieldSuccessMessageKey', () => {
+ it('should return staking success keys for staking yield types', () => {
+ expect(getYieldSuccessMessageKey('staking', 'enter')).toBe('successStaked')
+ expect(getYieldSuccessMessageKey('staking', 'exit')).toBe('successUnstaked')
+ expect(getYieldSuccessMessageKey('native-staking', 'enter')).toBe('successStaked')
+ expect(getYieldSuccessMessageKey('liquid-staking', 'exit')).toBe('successUnstaked')
+ expect(getYieldSuccessMessageKey('pooled-staking', 'enter')).toBe('successStaked')
+ })
+
+ it('should return staking success key for restaking yield types', () => {
+ expect(getYieldSuccessMessageKey('restaking', 'enter')).toBe('successStaked')
+ expect(getYieldSuccessMessageKey('restaking', 'exit')).toBe('successUnstaked')
+ })
+
+ it('should return vault success keys for vault/lending yield types', () => {
+ expect(getYieldSuccessMessageKey('vault', 'enter')).toBe('successDeposited')
+ expect(getYieldSuccessMessageKey('vault', 'exit')).toBe('successWithdrawn')
+ expect(getYieldSuccessMessageKey('lending', 'enter')).toBe('successDeposited')
+ expect(getYieldSuccessMessageKey('lending', 'exit')).toBe('successWithdrawn')
+ })
+
+ it('should return successClaim for claim and manage actions', () => {
+ expect(getYieldSuccessMessageKey('staking', 'claim')).toBe('successClaim')
+ expect(getYieldSuccessMessageKey('vault', 'claim')).toBe('successClaim')
+ expect(getYieldSuccessMessageKey('staking', 'manage')).toBe('successClaim')
+ expect(getYieldSuccessMessageKey('vault', 'manage')).toBe('successClaim')
})
})
diff --git a/src/lib/yieldxyz/utils.ts b/src/lib/yieldxyz/utils.ts
index 4e02ee855a6..ec55769eae3 100644
--- a/src/lib/yieldxyz/utils.ts
+++ b/src/lib/yieldxyz/utils.ts
@@ -6,76 +6,110 @@ import {
SHAPESHIFT_COSMOS_VALIDATOR_ADDRESS,
YIELD_NETWORK_TO_CHAIN_ID,
} from './constants'
-import type { AugmentedYieldDto, ValidatorDto, YieldIconSource } from './types'
+import type { AugmentedYieldDto, ValidatorDto, YieldIconSource, YieldType } from './types'
export const yieldNetworkToChainId = (network: string): ChainId | undefined => {
if (!isSupportedYieldNetwork(network)) return undefined
return YIELD_NETWORK_TO_CHAIN_ID[network]
}
-const TX_TITLE_PATTERNS: [RegExp, string][] = [
- [/approv/i, 'Approve'],
- [/supply|deposit|enter/i, 'Enter'],
- [/withdraw|exit|unstake|undelegate/i, 'Exit'],
- [/claim/i, 'Claim'],
- [/stake|delegate/i, 'Enter'],
- [/bridge/i, 'Bridge'],
- [/swap/i, 'Swap'],
+type TxTitlePattern = {
+ pattern: RegExp
+ staking: string
+ vault: string
+}
+
+const TX_TITLE_PATTERNS: TxTitlePattern[] = [
+ { pattern: /approv/i, staking: 'Approve', vault: 'Approve' },
+ { pattern: /supply|deposit|enter/i, staking: 'Stake', vault: 'Deposit' },
+ { pattern: /withdraw|exit/i, staking: 'Unstake', vault: 'Withdraw' },
+ { pattern: /unstake|undelegate/i, staking: 'Unstake', vault: 'Withdraw' },
+ { pattern: /claim/i, staking: 'Claim', vault: 'Claim' },
+ { pattern: /stake|delegate/i, staking: 'Stake', vault: 'Deposit' },
+ { pattern: /bridge/i, staking: 'Bridge', vault: 'Bridge' },
+ { pattern: /swap/i, staking: 'Swap', vault: 'Swap' },
]
-// Map of transaction types to user-friendly button labels
-// These should match the action verbs shown in the step row (without the asset symbol)
-// Yield.xyz uses Enter/Exit terminology consistently
-const TX_TYPE_TO_LABEL: Record = {
- APPROVE: 'Approve',
- APPROVAL: 'Approve',
- DELEGATE: 'Enter', // Monad uses DELEGATE for staking
- UNDELEGATE: 'Exit', // Monad uses UNDELEGATE for unstaking
- STAKE: 'Enter',
- UNSTAKE: 'Exit',
- DEPOSIT: 'Enter',
- WITHDRAW: 'Exit',
- SUPPLY: 'Enter',
- EXIT: 'Exit',
- ENTER: 'Enter',
- BRIDGE: 'Bridge',
- SWAP: 'Swap',
- CLAIM: 'Claim',
- CLAIM_REWARDS: 'Claim',
- TRANSFER: 'Transfer',
+type TxTypeLabels = {
+ staking: string
+ vault: string
+}
+
+const TX_TYPE_TO_LABELS: Record = {
+ APPROVE: { staking: 'Approve', vault: 'Approve' },
+ APPROVAL: { staking: 'Approve', vault: 'Approve' },
+ DELEGATE: { staking: 'Stake', vault: 'Deposit' },
+ UNDELEGATE: { staking: 'Unstake', vault: 'Withdraw' },
+ STAKE: { staking: 'Stake', vault: 'Deposit' },
+ UNSTAKE: { staking: 'Unstake', vault: 'Withdraw' },
+ DEPOSIT: { staking: 'Stake', vault: 'Deposit' },
+ WITHDRAW: { staking: 'Unstake', vault: 'Withdraw' },
+ SUPPLY: { staking: 'Stake', vault: 'Deposit' },
+ EXIT: { staking: 'Unstake', vault: 'Withdraw' },
+ ENTER: { staking: 'Stake', vault: 'Deposit' },
+ BRIDGE: { staking: 'Bridge', vault: 'Bridge' },
+ SWAP: { staking: 'Swap', vault: 'Swap' },
+ CLAIM: { staking: 'Claim', vault: 'Claim' },
+ CLAIM_REWARDS: { staking: 'Claim', vault: 'Claim' },
+ TRANSFER: { staking: 'Transfer', vault: 'Transfer' },
+}
+
+type TerminologyKey = 'staking' | 'vault'
+
+const isStakingType = (yieldType: YieldType): boolean => {
+ switch (yieldType) {
+ case 'staking':
+ case 'native-staking':
+ case 'pooled-staking':
+ case 'liquid-staking':
+ case 'restaking':
+ return true
+ case 'vault':
+ case 'lending':
+ return false
+ default:
+ // This shouldn't happen but satisfies exhaustiveness check
+ assertNever(yieldType)
+ return false
+ }
}
/**
* Gets a clean button label from a transaction type or title.
- * Used for the main CTA button in the yield action modal.
+ * Uses yield-type-aware terminology (stake/unstake vs deposit/withdraw).
*/
export const getTransactionButtonText = (
type: string | undefined,
title: string | undefined,
+ yieldType?: YieldType,
): string => {
- // First try to use the transaction type directly
+ const labelKey: TerminologyKey = yieldType && isStakingType(yieldType) ? 'staking' : 'vault'
+
if (type) {
const normalized = type.toUpperCase().replace(/[_-]/g, '_')
- if (TX_TYPE_TO_LABEL[normalized]) {
- return TX_TYPE_TO_LABEL[normalized]
- }
- // Fallback: capitalize the type
+ const labels = TX_TYPE_TO_LABELS[normalized]
+ if (labels) return labels[labelKey]
return type.charAt(0).toUpperCase() + type.slice(1).toLowerCase()
}
- // Fall back to parsing the title
if (title) {
- const match = TX_TITLE_PATTERNS.find(([pattern]) => pattern.test(title))
- if (match) return match[1]
+ const match = TX_TITLE_PATTERNS.find(p => p.pattern.test(title))
+ if (match) return match[labelKey]
}
return 'Confirm'
}
-export const formatYieldTxTitle = (title: string, assetSymbol: string): string => {
+export const formatYieldTxTitle = (
+ title: string,
+ assetSymbol: string,
+ yieldType?: YieldType,
+): string => {
+ const labelKey: TerminologyKey = yieldType && isStakingType(yieldType) ? 'staking' : 'vault'
+
const normalized = title.replace(/ transaction$/i, '').toLowerCase()
- const match = TX_TITLE_PATTERNS.find(([pattern]) => pattern.test(normalized))
- if (match) return `${match[1]} ${assetSymbol}`
+ const match = TX_TITLE_PATTERNS.find(p => p.pattern.test(normalized))
+ if (match) return `${match[labelKey]} ${assetSymbol}`
return normalized.charAt(0).toUpperCase() + normalized.slice(1)
}
@@ -166,41 +200,140 @@ export type YieldActionLabelKeys = {
exit: string
}
+const assertNever = (value: never): never => {
+ throw new Error(`Unhandled yield type: ${value}`)
+}
+
/**
* Gets the appropriate translation keys for yield actions based on yield type.
*
* Yield types and their terminology:
- * - staking, native-staking, pooled-staking, liquid-staking → Stake/Unstake
- * - restaking → Restake/Unstake
- * - vault, lending, and others → Deposit/Withdraw
+ * - staking, native-staking, pooled-staking, liquid-staking, restaking → Stake/Unstake
+ * - vault, lending → Deposit/Withdraw
*/
-export const getYieldActionLabelKeys = (yieldType: string): YieldActionLabelKeys => {
+export const getYieldActionLabelKeys = (yieldType: YieldType): YieldActionLabelKeys => {
switch (yieldType) {
case 'staking':
case 'native-staking':
case 'pooled-staking':
case 'liquid-staking':
+ case 'restaking':
return { enter: 'defi.stake', exit: 'defi.unstake' }
+ case 'vault':
+ case 'lending':
+ return { enter: 'common.deposit', exit: 'common.withdraw' }
+ default:
+ return assertNever(yieldType)
+ }
+}
+
+export type YieldLoadingStateKeys = {
+ enter: string
+ exit: string
+}
+
+export const getYieldLoadingStateKeys = (yieldType: YieldType): YieldLoadingStateKeys => {
+ switch (yieldType) {
+ case 'staking':
+ case 'native-staking':
+ case 'pooled-staking':
+ case 'liquid-staking':
case 'restaking':
- return { enter: 'yieldXYZ.actions.restake', exit: 'defi.unstake' }
+ return { enter: 'yieldXYZ.staking', exit: 'yieldXYZ.unstaking' }
case 'vault':
case 'lending':
+ return { enter: 'yieldXYZ.depositing', exit: 'yieldXYZ.withdrawing' }
default:
- return { enter: 'common.deposit', exit: 'common.withdraw' }
+ return assertNever(yieldType)
}
}
-const STAKING_YIELD_TYPES = new Set([
- 'staking',
- 'native-staking',
- 'pooled-staking',
- 'liquid-staking',
- 'restaking',
-])
+export type YieldHeadingKeys = {
+ enter: string
+ exit: string
+}
-/**
- * Checks if a yield type uses staking terminology (stake/unstake).
- */
-export const isStakingYieldType = (yieldType: string): boolean => {
- return STAKING_YIELD_TYPES.has(yieldType)
+export const getYieldHeadingKeys = (yieldType: YieldType): YieldHeadingKeys => {
+ switch (yieldType) {
+ case 'staking':
+ case 'native-staking':
+ case 'pooled-staking':
+ case 'liquid-staking':
+ case 'restaking':
+ return { enter: 'yieldXYZ.stakeSymbol', exit: 'yieldXYZ.unstakeSymbol' }
+ case 'vault':
+ case 'lending':
+ return { enter: 'yieldXYZ.depositSymbol', exit: 'yieldXYZ.withdrawSymbol' }
+ default:
+ return assertNever(yieldType)
+ }
+}
+
+export type YieldPendingStatusKeys = {
+ enter: string
+ exit: string
+}
+
+export const getYieldPendingStatusKeys = (yieldType: YieldType): YieldPendingStatusKeys => {
+ switch (yieldType) {
+ case 'staking':
+ case 'native-staking':
+ case 'pooled-staking':
+ case 'liquid-staking':
+ case 'restaking':
+ return { enter: 'yieldXYZ.stakingPending', exit: 'yieldXYZ.unstakingPending' }
+ case 'vault':
+ case 'lending':
+ return { enter: 'yieldXYZ.depositingPending', exit: 'yieldXYZ.withdrawingPending' }
+ default:
+ return assertNever(yieldType)
+ }
+}
+
+export const getYieldMinAmountKey = (yieldType: YieldType): string => {
+ switch (yieldType) {
+ case 'staking':
+ case 'native-staking':
+ case 'pooled-staking':
+ case 'liquid-staking':
+ case 'restaking':
+ return 'yieldXYZ.minStake'
+ case 'vault':
+ case 'lending':
+ return 'yieldXYZ.minDeposit'
+ default:
+ return assertNever(yieldType)
+ }
+}
+
+export const isStakingYieldType = (yieldType: YieldType): boolean => {
+ return isStakingType(yieldType)
+}
+
+export type YieldSuccessMessageKey =
+ | 'successStaked'
+ | 'successUnstaked'
+ | 'successDeposited'
+ | 'successWithdrawn'
+ | 'successClaim'
+
+export const getYieldSuccessMessageKey = (
+ yieldType: YieldType,
+ action: 'enter' | 'exit' | 'claim' | 'manage',
+): YieldSuccessMessageKey => {
+ if (action === 'claim' || action === 'manage') return 'successClaim'
+
+ switch (yieldType) {
+ case 'staking':
+ case 'native-staking':
+ case 'pooled-staking':
+ case 'liquid-staking':
+ case 'restaking':
+ return action === 'enter' ? 'successStaked' : 'successUnstaked'
+ case 'vault':
+ case 'lending':
+ return action === 'enter' ? 'successDeposited' : 'successWithdrawn'
+ default:
+ return assertNever(yieldType)
+ }
}
diff --git a/src/pages/Yields/components/YieldActionModal.tsx b/src/pages/Yields/components/YieldActionModal.tsx
index e29bfc1d100..219afc0aff5 100644
--- a/src/pages/Yields/components/YieldActionModal.tsx
+++ b/src/pages/Yields/components/YieldActionModal.tsx
@@ -16,7 +16,14 @@ import {
SHAPESHIFT_VALIDATOR_NAME,
} from '@/lib/yieldxyz/constants'
import type { AugmentedYieldDto } from '@/lib/yieldxyz/types'
-import { getTransactionButtonText, isStakingYieldType } from '@/lib/yieldxyz/utils'
+import {
+ getTransactionButtonText,
+ getYieldActionLabelKeys,
+ getYieldHeadingKeys,
+ getYieldLoadingStateKeys,
+ getYieldSuccessMessageKey,
+ isStakingYieldType,
+} from '@/lib/yieldxyz/utils'
import { GradientApy } from '@/pages/Yields/components/GradientApy'
import { TransactionStepsList } from '@/pages/Yields/components/TransactionStepsList'
import { YieldAssetFlow } from '@/pages/Yields/components/YieldAssetFlow'
@@ -132,13 +139,10 @@ export const YieldActionModal = memo(function YieldActionModal({
providers,
])
- const chainId = useMemo(() => yieldItem.chainId ?? '', [yieldItem.chainId])
+ const chainId = yieldItem.chainId ?? ''
const feeAsset = useAppSelector(state => selectFeeAssetByChainId(state, chainId))
- const assetAvatarSrc = useMemo(
- () => assetLogoURI ?? yieldItem.token.logoURI,
- [assetLogoURI, yieldItem.token.logoURI],
- )
+ const assetAvatarSrc = assetLogoURI ?? yieldItem.token.logoURI
const aprFormatted = useMemo(
() => `${bnOrZero(yieldItem.rewardRate.total).times(100).toFixed(2)}%`,
@@ -185,16 +189,25 @@ export const YieldActionModal = memo(function YieldActionModal({
if (activeStepIndex >= 0 && transactionSteps[activeStepIndex]?.loadingMessage) {
return transactionSteps[activeStepIndex].loadingMessage
}
- if (action === 'enter') return translate('yieldXYZ.entering')
- if (action === 'exit') return translate('yieldXYZ.exiting')
+ const loadingKeys = getYieldLoadingStateKeys(yieldItem.mechanics.type)
+ if (action === 'enter') return translate(loadingKeys.enter)
+ if (action === 'exit') return translate(loadingKeys.exit)
return translate('common.claiming')
- }, [isQuoteLoading, action, translate, activeStepIndex, transactionSteps])
+ }, [
+ isQuoteLoading,
+ action,
+ translate,
+ activeStepIndex,
+ transactionSteps,
+ yieldItem.mechanics.type,
+ ])
const buttonText = useMemo(() => {
- // Use the current step's type/title for a clean button label (e.g., "Enter", "Exit", "Approve")
+ const yieldType = yieldItem.mechanics.type
+ // Use the current step's type/title for a clean button label (e.g., "Stake", "Unstake", "Approve")
if (activeStepIndex >= 0 && transactionSteps[activeStepIndex]) {
const step = transactionSteps[activeStepIndex]
- return getTransactionButtonText(step.type, step.originalTitle)
+ return getTransactionButtonText(step.type, step.originalTitle, yieldType)
}
// USDT reset required before other transactions
if (isUsdtResetRequired) {
@@ -203,24 +216,31 @@ export const YieldActionModal = memo(function YieldActionModal({
// Before execution starts, use the first CREATED transaction from quoteData
const firstCreatedTx = quoteData?.transactions?.find(tx => tx.status === 'CREATED')
if (firstCreatedTx) {
- return getTransactionButtonText(firstCreatedTx.type, firstCreatedTx.title)
+ return getTransactionButtonText(firstCreatedTx.type, firstCreatedTx.title, yieldType)
}
- // Fallback to action-based text
- if (action === 'enter') return translate('yieldXYZ.enter')
- if (action === 'exit') return translate('yieldXYZ.exit')
+ // Fallback to action-based text using yield-type-aware labels
+ const actionLabelKeys = getYieldActionLabelKeys(yieldType)
+ if (action === 'enter') return translate(actionLabelKeys.enter)
+ if (action === 'exit') return translate(actionLabelKeys.exit)
return translate('common.claim')
- }, [action, translate, activeStepIndex, transactionSteps, quoteData, isUsdtResetRequired])
+ }, [
+ action,
+ translate,
+ activeStepIndex,
+ transactionSteps,
+ quoteData,
+ isUsdtResetRequired,
+ yieldItem.mechanics.type,
+ ])
const modalHeading = useMemo(() => {
- if (action === 'enter') return translate('yieldXYZ.enterSymbol', { symbol: assetSymbol })
- if (action === 'exit') return translate('yieldXYZ.exitSymbol', { symbol: assetSymbol })
+ const headingKeys = getYieldHeadingKeys(yieldItem.mechanics.type)
+ if (action === 'enter') return translate(headingKeys.enter, { symbol: assetSymbol })
+ if (action === 'exit') return translate(headingKeys.exit, { symbol: assetSymbol })
return translate('yieldXYZ.claimSymbol', { symbol: assetSymbol })
- }, [action, assetSymbol, translate])
+ }, [action, assetSymbol, translate, yieldItem.mechanics.type])
- const networkAvatarSrc = useMemo(
- () => feeAsset?.networkIcon ?? feeAsset?.icon,
- [feeAsset?.networkIcon, feeAsset?.icon],
- )
+ const networkAvatarSrc = feeAsset?.networkIcon ?? feeAsset?.icon
const assetFlowDirection = action === 'exit' ? 'exit' : 'enter'
@@ -279,32 +299,17 @@ export const YieldActionModal = memo(function YieldActionModal({
)}
>
)}
- {showValidatorRow && (
-
-
- {translate('yieldXYZ.validator')}
-
-
-
-
- {vaultMetadata.name}
-
-
-
- )}
- {!showValidatorRow && (
-
-
- {translate('yieldXYZ.provider')}
+
+
+ {translate(showValidatorRow ? 'yieldXYZ.validator' : 'yieldXYZ.provider')}
+
+
+
+
+ {vaultMetadata.name}
-
-
-
- {vaultMetadata.name}
-
-
- )}
+
{translate('yieldXYZ.network')}
@@ -347,11 +352,10 @@ export const YieldActionModal = memo(function YieldActionModal({
[animatedAvatarRow, statsContent, displaySteps],
)
- const successMessageKey = useMemo(() => {
- if (action === 'enter') return 'successEnter' as const
- if (action === 'exit') return 'successExit' as const
- return 'successClaim' as const
- }, [action])
+ const successMessageKey = useMemo(
+ () => getYieldSuccessMessageKey(yieldItem.mechanics.type, action),
+ [yieldItem.mechanics.type, action],
+ )
const successProviderInfo = useMemo(
() => (vaultMetadata ? { name: vaultMetadata.name, logoURI: vaultMetadata.logoURI } : null),
diff --git a/src/pages/Yields/components/YieldAvailableToDeposit.tsx b/src/pages/Yields/components/YieldAvailableToDeposit.tsx
index cf998872508..fe0b5675e47 100644
--- a/src/pages/Yields/components/YieldAvailableToDeposit.tsx
+++ b/src/pages/Yields/components/YieldAvailableToDeposit.tsx
@@ -1,11 +1,27 @@
import { InfoOutlineIcon } from '@chakra-ui/icons'
-import { Box, Card, CardBody, Flex, Heading, HStack, Text, Tooltip, VStack } from '@chakra-ui/react'
-import { memo, useMemo } from 'react'
+import {
+ Box,
+ Button,
+ Card,
+ CardBody,
+ Flex,
+ Heading,
+ HStack,
+ Text,
+ Tooltip,
+ VStack,
+} from '@chakra-ui/react'
+import { memo, useCallback, useMemo } from 'react'
import { useTranslate } from 'react-polyglot'
import { Amount } from '@/components/Amount/Amount'
+import { useTradeNavigation } from '@/components/MultiHopTrade/hooks/useTradeNavigation'
+import { KeyManager } from '@/context/WalletProvider/KeyManager'
+import { useFeatureFlag } from '@/hooks/useFeatureFlag/useFeatureFlag'
+import { useWallet } from '@/hooks/useWallet/useWallet'
import { bnOrZero } from '@/lib/bignumber/bignumber'
import type { AugmentedYieldDto } from '@/lib/yieldxyz/types'
+import { selectWalletType } from '@/state/slices/localWalletSlice/selectors'
import { selectPortfolioCryptoBalanceBaseUnitByFilter } from '@/state/slices/selectors'
import { useAppSelector } from '@/state/store'
@@ -17,6 +33,19 @@ type YieldAvailableToDepositProps = {
export const YieldAvailableToDeposit = memo(
({ yieldItem, inputTokenMarketData }: YieldAvailableToDepositProps) => {
const translate = useTranslate()
+ const { navigateToTrade } = useTradeNavigation()
+ const {
+ state: { isConnected },
+ } = useWallet()
+ const isLedgerReadOnlyEnabled = useFeatureFlag('LedgerReadOnly')
+ const walletType = useAppSelector(selectWalletType)
+ const isLedgerReadOnly = isLedgerReadOnlyEnabled && walletType === KeyManager.Ledger
+
+ // Either wallet is physically connected, or it's a Ledger in read-only mode
+ const hasWallet = useMemo(
+ () => isConnected || isLedgerReadOnly,
+ [isConnected, isLedgerReadOnly],
+ )
const inputToken = yieldItem.inputTokens[0]
const inputTokenAssetId = inputToken?.assetId ?? ''
@@ -46,13 +75,63 @@ export const YieldAvailableToDeposit = memo(
const hasAvailableBalance = availableBalance.gt(0)
- if (!inputTokenPrecision) return null
+ const handleGetAsset = useCallback(() => {
+ navigateToTrade(inputTokenAssetId)
+ }, [navigateToTrade, inputTokenAssetId])
+
+ if (!inputTokenPrecision || !hasWallet) return null
const tooltipLabel = translate('yieldXYZ.availableToDepositTooltip', {
symbol: yieldItem.token.symbol,
})
- if (!hasAvailableBalance) return null
+ if (!hasAvailableBalance) {
+ return (
+
+
+
+
+
+
+ {translate('yieldXYZ.availableToDeposit')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
return (
diff --git a/src/pages/Yields/components/YieldEnterModal.tsx b/src/pages/Yields/components/YieldEnterModal.tsx
index 3ea4266d513..5ac534b1401 100644
--- a/src/pages/Yields/components/YieldEnterModal.tsx
+++ b/src/pages/Yields/components/YieldEnterModal.tsx
@@ -29,7 +29,14 @@ import {
SHAPESHIFT_VALIDATOR_NAME,
} from '@/lib/yieldxyz/constants'
import type { AugmentedYieldDto } from '@/lib/yieldxyz/types'
-import { getTransactionButtonText, isStakingYieldType } from '@/lib/yieldxyz/utils'
+import {
+ getTransactionButtonText,
+ getYieldActionLabelKeys,
+ getYieldHeadingKeys,
+ getYieldMinAmountKey,
+ getYieldSuccessMessageKey,
+ isStakingYieldType,
+} from '@/lib/yieldxyz/utils'
import { GradientApy } from '@/pages/Yields/components/GradientApy'
import { TransactionStepsList } from '@/pages/Yields/components/TransactionStepsList'
import { YieldExplainers } from '@/pages/Yields/components/YieldExplainers'
@@ -357,12 +364,21 @@ export const YieldEnterModal = memo(
if (isSubmitting && transactionSteps.length > 0) {
const activeStep = transactionSteps.find(s => s.status !== 'success')
- if (activeStep) return getTransactionButtonText(activeStep.type, activeStep.originalTitle)
+ if (activeStep)
+ return getTransactionButtonText(
+ activeStep.type,
+ activeStep.originalTitle,
+ yieldItem.mechanics.type,
+ )
}
if (activeStepIndex >= 0 && transactionSteps[activeStepIndex]) {
const currentStep = transactionSteps[activeStepIndex]
- return getTransactionButtonText(currentStep.type, currentStep.originalTitle)
+ return getTransactionButtonText(
+ currentStep.type,
+ currentStep.originalTitle,
+ yieldItem.mechanics.type,
+ )
}
if (isUsdtResetRequired) {
@@ -370,9 +386,15 @@ export const YieldEnterModal = memo(
}
const firstCreatedTx = quoteData?.transactions?.find(tx => tx.status === 'CREATED')
- if (firstCreatedTx) return getTransactionButtonText(firstCreatedTx.type, firstCreatedTx.title)
-
- return translate('yieldXYZ.enterAsset', { asset: inputTokenAsset?.symbol })
+ if (firstCreatedTx)
+ return getTransactionButtonText(
+ firstCreatedTx.type,
+ firstCreatedTx.title,
+ yieldItem.mechanics.type,
+ )
+
+ const actionLabelKeys = getYieldActionLabelKeys(yieldItem.mechanics.type)
+ return `${translate(actionLabelKeys.enter)} ${inputTokenAsset?.symbol ?? ''}`
}, [
isConnected,
isQuoteActive,
@@ -383,12 +405,14 @@ export const YieldEnterModal = memo(
quoteData,
translate,
inputTokenAsset?.symbol,
+ yieldItem.mechanics.type,
])
+ const headingKeys = getYieldHeadingKeys(yieldItem.mechanics.type)
const modalTitle = useMemo(() => {
if (step === ModalStep.Success) return translate('common.success')
- return translate('yieldXYZ.enterAsset', { asset: inputTokenAsset?.symbol })
- }, [translate, inputTokenAsset?.symbol, step])
+ return translate(headingKeys.enter, { symbol: inputTokenAsset?.symbol })
+ }, [translate, inputTokenAsset?.symbol, step, headingKeys.enter])
const percentButtons = useMemo(
() => (
@@ -482,7 +506,7 @@ export const YieldEnterModal = memo(
{minDeposit && bnOrZero(minDeposit).gt(0) && (
- {translate('yieldXYZ.minEnter')}
+ {translate(getYieldMinAmountKey(yieldItem.mechanics.type))}
(
),
[
@@ -598,6 +625,7 @@ export const YieldEnterModal = memo(
yieldItem.id,
accountId,
hookHandleClose,
+ successMessageKey,
],
)
diff --git a/src/pages/Yields/components/YieldForm.tsx b/src/pages/Yields/components/YieldForm.tsx
index ead0f0557cf..33019235efc 100644
--- a/src/pages/Yields/components/YieldForm.tsx
+++ b/src/pages/Yields/components/YieldForm.tsx
@@ -27,6 +27,8 @@ import { YieldBalanceType } from '@/lib/yieldxyz/types'
import {
getTransactionButtonText,
getYieldActionLabelKeys,
+ getYieldMinAmountKey,
+ getYieldSuccessMessageKey,
isStakingYieldType,
} from '@/lib/yieldxyz/utils'
import { GradientApy } from '@/pages/Yields/components/GradientApy'
@@ -433,12 +435,21 @@ export const YieldForm = memo(
if (isSubmitting && transactionSteps.length > 0) {
const activeStep = transactionSteps.find(s => s.status !== 'success')
- if (activeStep) return getTransactionButtonText(activeStep.type, activeStep.originalTitle)
+ if (activeStep)
+ return getTransactionButtonText(
+ activeStep.type,
+ activeStep.originalTitle,
+ yieldItem.mechanics.type,
+ )
}
if (activeStepIndex >= 0 && transactionSteps[activeStepIndex]) {
const currentStep = transactionSteps[activeStepIndex]
- return getTransactionButtonText(currentStep.type, currentStep.originalTitle)
+ return getTransactionButtonText(
+ currentStep.type,
+ currentStep.originalTitle,
+ yieldItem.mechanics.type,
+ )
}
if (isUsdtResetRequired) {
@@ -446,7 +457,12 @@ export const YieldForm = memo(
}
const firstCreatedTx = quoteData?.transactions?.find(tx => tx.status === 'CREATED')
- if (firstCreatedTx) return getTransactionButtonText(firstCreatedTx.type, firstCreatedTx.title)
+ if (firstCreatedTx)
+ return getTransactionButtonText(
+ firstCreatedTx.type,
+ firstCreatedTx.title,
+ yieldItem.mechanics.type,
+ )
const actionLabelKeys = getYieldActionLabelKeys(yieldItem.mechanics.type)
if (action === 'enter') {
@@ -566,7 +582,7 @@ export const YieldForm = memo(
{minDeposit && bnOrZero(minDeposit).gt(0) && action === 'enter' && (
- {translate('yieldXYZ.minEnter')}
+ {translate(getYieldMinAmountKey(yieldItem.mechanics.type))}
walletDispatch({ type: WalletActions.SET_WALLET_MODAL, payload: true }),
+ [walletDispatch],
+ )
const { chainId } = yieldItem
const { accountId: contextAccountId, accountNumber } = useYieldAccount()
@@ -201,6 +209,7 @@ export const YieldPositionCard = memo(
const handleExit = useCallback(() => navigateToAction('exit'), [navigateToAction])
const actionLabelKeys = getYieldActionLabelKeys(yieldItem.mechanics.type)
+ const pendingStatusKeys = getYieldPendingStatusKeys(yieldItem.mechanics.type)
const enterLabel = translate(actionLabelKeys.enter)
const exitLabel = translate(actionLabelKeys.exit)
@@ -213,7 +222,7 @@ export const YieldPositionCard = memo(
- {translate('yieldXYZ.entering')}
+ {translate(pendingStatusKeys.enter)}
{formatBalance(enteringBalance)}
@@ -225,7 +234,7 @@ export const YieldPositionCard = memo(
)
- }, [hasEntering, translate, formatBalance, enteringBalance])
+ }, [hasEntering, translate, formatBalance, enteringBalance, pendingStatusKeys.enter])
const unstakingSection = useMemo(() => {
if (!hasExiting) return null
@@ -245,7 +254,7 @@ export const YieldPositionCard = memo(
- {translate('yieldXYZ.unstaking')}
+ {translate(pendingStatusKeys.exit)}
@@ -265,7 +274,7 @@ export const YieldPositionCard = memo(
)
})
- }, [hasExiting, exitingEntries, translate])
+ }, [hasExiting, exitingEntries, translate, pendingStatusKeys.exit])
const withdrawableSection = useMemo(() => {
if (!hasWithdrawable) return null
@@ -360,7 +369,49 @@ export const YieldPositionCard = memo(
claimableSection,
])
- if (!accountId) return null
+ if (!accountId) {
+ return (
+
+
+
+
+ {translate('yieldXYZ.myPosition')}
+
+
+
+
+
+ {translate('yieldXYZ.totalValue')}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
if (isBalancesLoading) {
return (
diff --git a/src/pages/Yields/components/YieldSuccess.tsx b/src/pages/Yields/components/YieldSuccess.tsx
index 578a2837473..3a1cd81fe92 100644
--- a/src/pages/Yields/components/YieldSuccess.tsx
+++ b/src/pages/Yields/components/YieldSuccess.tsx
@@ -10,6 +10,8 @@ import { useConfetti } from '../hooks/useConfetti'
import type { TransactionStep } from '../hooks/useYieldTransactionFlow'
import { TransactionStepsList } from './TransactionStepsList'
+import type { YieldSuccessMessageKey } from '@/lib/yieldxyz/utils'
+
type ProviderInfo = {
name: string
logoURI: string | undefined
@@ -24,7 +26,7 @@ type YieldSuccessProps = {
accountId?: AccountId
onDone: () => void
showConfetti?: boolean
- successMessageKey?: 'successEnter' | 'successExit' | 'successClaim'
+ successMessageKey?: YieldSuccessMessageKey
}
export const YieldSuccess = memo(
@@ -37,7 +39,7 @@ export const YieldSuccess = memo(
accountId,
onDone,
showConfetti = true,
- successMessageKey = 'successEnter',
+ successMessageKey = 'successStaked',
}: YieldSuccessProps) => {
const translate = useTranslate()
const navigate = useNavigate()
diff --git a/src/pages/Yields/hooks/useYieldTransactionFlow.ts b/src/pages/Yields/hooks/useYieldTransactionFlow.ts
index ac0c2266c4c..624c02092fc 100644
--- a/src/pages/Yields/hooks/useYieldTransactionFlow.ts
+++ b/src/pages/Yields/hooks/useYieldTransactionFlow.ts
@@ -186,7 +186,7 @@ export const useYieldTransactionFlow = ({
const yieldChainId = yieldItem?.chainId
const { accountId: contextAccountId, accountNumber: contextAccountNumber } = useYieldAccount()
- const derivedAccountId = useAppSelector(state => {
+ const accountId = useAppSelector(state => {
if (accountIdProp) return accountIdProp
if (contextAccountId) return contextAccountId
if (!yieldChainId) return undefined
@@ -194,8 +194,6 @@ export const useYieldTransactionFlow = ({
return selectAccountIdByAccountNumberAndChainId(state)[contextAccountNumber]?.[yieldChainId]
})
- const accountId = derivedAccountId
-
const feeAsset = useAppSelector(state =>
yieldChainId ? selectFeeAssetByChainId(state, yieldChainId) : undefined,
)
@@ -221,12 +219,12 @@ export const useYieldTransactionFlow = ({
if (!yieldItem || !userAddress || !yieldChainId) return null
if (action !== 'manage' && !amount) return null
- const fields =
- action === 'enter'
- ? yieldItem.mechanics.arguments.enter.fields
- : action === 'exit'
- ? yieldItem.mechanics.arguments.exit.fields
- : []
+ const getFields = () => {
+ if (action === 'enter') return yieldItem.mechanics.arguments.enter.fields
+ if (action === 'exit') return yieldItem.mechanics.arguments.exit.fields
+ return []
+ }
+ const fields = getFields()
const fieldNames = new Set(fields.map(field => field.name))
const args: Record = {}
@@ -356,7 +354,11 @@ export const useYieldTransactionFlow = ({
...quoteData.transactions
.filter(tx => tx.status === TransactionStatus.Created)
.map((tx, i) => ({
- title: formatYieldTxTitle(tx.title || `Transaction ${i + 1}`, assetSymbol),
+ title: formatYieldTxTitle(
+ tx.title || `Transaction ${i + 1}`,
+ assetSymbol,
+ yieldItem?.mechanics.type,
+ ),
originalTitle: tx.title || '',
type: tx.type,
status: 'pending' as const,
@@ -369,6 +371,7 @@ export const useYieldTransactionFlow = ({
transactionSteps,
quoteData,
assetSymbol,
+ yieldItem?.mechanics.type,
isAllowanceCheckPending,
isUsdtResetRequired,
translate,
@@ -400,19 +403,27 @@ export const useYieldTransactionFlow = ({
}
const isApproval = tx.title?.toLowerCase().includes('approv')
- const actionType = isApproval
- ? ActionType.Approve
- : action === 'enter'
- ? ActionType.Deposit
- : action === 'exit'
- ? ActionType.Withdraw
- : ActionType.Claim
-
- const displayType = isApproval
- ? GenericTransactionDisplayType.Approve
- : action === 'manage'
- ? GenericTransactionDisplayType.Claim
- : GenericTransactionDisplayType.Yield
+
+ type GenericActionType =
+ | typeof ActionType.Approve
+ | typeof ActionType.Deposit
+ | typeof ActionType.Withdraw
+ | typeof ActionType.Claim
+
+ const getActionType = (): GenericActionType => {
+ if (isApproval) return ActionType.Approve
+ if (action === 'enter') return ActionType.Deposit
+ if (action === 'exit') return ActionType.Withdraw
+ return ActionType.Claim
+ }
+ const actionType = getActionType()
+
+ const getDisplayType = (): GenericTransactionDisplayType => {
+ if (isApproval) return GenericTransactionDisplayType.Approve
+ if (action === 'manage') return GenericTransactionDisplayType.Claim
+ return GenericTransactionDisplayType.Yield
+ }
+ const displayType = getDisplayType()
// TODO(gomes): handle claim notifications - there's more logic TBD here (e.g. unbonding periods).
// For now, KISS and simply don't handle claims in action center.
@@ -439,7 +450,7 @@ export const useYieldTransactionFlow = ({
accountId,
message:
typeMessagesMap[actionType] ??
- formatYieldTxTitle(tx.title || 'Transaction', assetSymbol),
+ formatYieldTxTitle(tx.title || 'Transaction', assetSymbol, yieldItem.mechanics.type),
amountCryptoPrecision: amount,
contractName: yieldItem.metadata.name,
chainName: yieldItem.network,
@@ -759,7 +770,11 @@ export const useYieldTransactionFlow = ({
}
steps.push(
...transactions.map((tx, i) => ({
- title: formatYieldTxTitle(tx.title || `Transaction ${i + 1}`, assetSymbol),
+ title: formatYieldTxTitle(
+ tx.title || `Transaction ${i + 1}`,
+ assetSymbol,
+ yieldItem?.mechanics.type,
+ ),
originalTitle: tx.title || '',
type: tx.type,
status: 'pending' as const,
@@ -802,6 +817,7 @@ export const useYieldTransactionFlow = ({
assetSymbol,
translate,
showErrorToast,
+ yieldItem?.mechanics.type,
])
return useMemo(