diff --git a/src/app/trade/components/leverage-widget/index.tsx b/src/app/trade/components/leverage-widget/index.tsx index ea3cabeec..dd8b682f1 100644 --- a/src/app/trade/components/leverage-widget/index.tsx +++ b/src/app/trade/components/leverage-widget/index.tsx @@ -36,34 +36,35 @@ import type { SymbolsByChain } from '@indexcoop/tokenlists' const hiddenLeverageWarnings = [WarningType.flashbots] -// Tokens temporarily disabled for trading, per chain. Symbols are typed -// against the tokenlist so a typo or wrong-chain entry is a compile error. -// Set `mintReason` and/or `redeemReason` to disable the corresponding -// direction; omit a field to leave that direction enabled. +// Tokens flagged for paused markets, per chain. Symbols are typed against +// the tokenlist so a typo or wrong-chain entry is a compile error. +// - `mintReason` blocks the trade button when minting and renders the reason. +// - `redeemWarning` shows an informational banner when redeeming but leaves +// the trade button active (users can still attempt to exit). type DisableEntry< C extends typeof mainnet.id | typeof arbitrum.id | typeof base.id, > = { symbols: readonly SymbolsByChain[] mintReason?: string - redeemReason?: string + redeemWarning?: string } const ETH_MINT_PAUSED_REASON = 'Redemptions for ETH2x and ETH3x on Ethereum and Arbitrum are temporarily paused. Minting is disabled to prevent users from being trapped in positions they cannot exit.' -const ETH_REDEEM_PAUSED_REASON = - 'Redemptions for ETH2x and ETH3x on Ethereum and Arbitrum are temporarily paused due to ongoing issues with Aave. Please check back later.' +const ETH_REDEEM_WARNING = + 'Redemptions for ETH2x and ETH3x on Ethereum and Arbitrum are affected by ongoing issues with Aave and may fail. Please try again later if your transaction does not go through.' const TEMPORARILY_DISABLED_TOKENS_BY_CHAIN = { [mainnet.id]: { symbols: ['ETH2X', 'ETH3x'], mintReason: ETH_MINT_PAUSED_REASON, - redeemReason: ETH_REDEEM_PAUSED_REASON, + redeemWarning: ETH_REDEEM_WARNING, } satisfies DisableEntry, [arbitrum.id]: { symbols: ['ETH2X', 'ETH3X'], mintReason: ETH_MINT_PAUSED_REASON, - redeemReason: ETH_REDEEM_PAUSED_REASON, + redeemWarning: ETH_REDEEM_WARNING, } satisfies DisableEntry, [base.id]: { symbols: ['uSOL2x', 'uSOL3x', 'uSUI2x', 'uSUI3x'], @@ -149,7 +150,7 @@ export function LeverageWidget() { [tradeState], ) - const tradeDisabledReason = useMemo(() => { + const pausedEntry = useMemo(() => { const leverageToken = isMinting ? outputToken : inputToken if (!leverageToken.chainId) return null const entry = TEMPORARILY_DISABLED_TOKENS_BY_CHAIN[ @@ -158,14 +159,18 @@ export function LeverageWidget() { | { symbols: readonly string[] mintReason?: string - redeemReason?: string + redeemWarning?: string } | undefined if (!entry) return null - if (!entry.symbols.includes(leverageToken.symbol)) return null - return (isMinting ? entry.mintReason : entry.redeemReason) ?? null + return entry.symbols.includes(leverageToken.symbol) ? entry : null }, [isMinting, inputToken, outputToken]) + const mintDisabledReason = isMinting + ? (pausedEntry?.mintReason ?? null) + : null + const redeemWarning = !isMinting ? (pausedEntry?.redeemWarning ?? null) : null + return (
)} - {tradeDisabledReason ? ( + {mintDisabledReason ? (
Temporarily Unavailable
-

{tradeDisabledReason}

+

{mintDisabledReason}

) : ( - sendTradeEvent({ type: 'REVIEW' })} - onRefetchQuote={refetchQuote} - /> + <> + {redeemWarning && ( +
+ +

{redeemWarning}

+
+ )} + sendTradeEvent({ type: 'REVIEW' })} + onRefetchQuote={refetchQuote} + /> + )} { - if (flashmintQuote === undefined || isFetchingFlashMintQuote) return + if (isFetchingFlashMintQuote) return + + if (flashmintQuoteError) { + logEvent('Quote Failed', { message: flashmintQuoteError.message }) + sendTradeEvent({ + type: 'QUOTE_NOT_FOUND', + reason: flashmintQuoteError.message || 'Unknown Reason', + }) + return + } + + if (flashmintQuote === undefined) return if (isQuoteError(flashmintQuote)) { logEvent('Quote Failed', flashmintQuote) @@ -121,34 +133,38 @@ export function useQuoteResult(request: QuoteRequest) { sendTradeEvent({ type: 'QUOTE_NOT_FOUND', reason: - get(quoteErrorCode, `${flashmintQuote.type}`) ?? 'Unknown Reason', + get(quoteErrorCode, `${flashmintQuote.type}`) ?? + (flashmintQuote.message || 'Unknown Reason'), }) return } - if (flashmintQuote) { - logEvent('Quote Received', formatQuoteAnalytics(flashmintQuote)) - } - - const quoteResult = { - type: flashmintQuote?.type ?? QuoteType.flashmint, - isAvailable: true, - quote: flashmintQuote, - error: null, - } - - if (quoteResult.quote) { + if (!flashmintQuote) { sendTradeEvent({ - type: 'QUOTE', - inputValue, - quoteResult, - quoteType: flashmintQuote?.type ?? QuoteType.flashmint, + type: 'QUOTE_NOT_FOUND', + reason: 'Quote Not Found', }) + return } + + logEvent('Quote Received', formatQuoteAnalytics(flashmintQuote)) + + sendTradeEvent({ + type: 'QUOTE', + inputValue, + quoteResult: { + type: flashmintQuote.type ?? QuoteType.flashmint, + isAvailable: true, + quote: flashmintQuote, + error: null, + }, + quoteType: flashmintQuote.type ?? QuoteType.flashmint, + }) }, [ chainId, flashmintQuote, + flashmintQuoteError, inputValue, isFetchingFlashMintQuote, logEvent,