Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/cowswap-frontend/src/locales/en-US.po
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,7 @@ msgstr "Edit code"
msgid "Select an {accountProxyLabelString} to check for available refunds {chain}"
msgstr "Select an {accountProxyLabelString} to check for available refunds {chain}"

#: apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/index.tsx
#: apps/cowswap-frontend/src/modules/twap/pure/PrimaryActionButton/index.tsx
msgid "Unsupported wallet"
msgstr "Unsupported wallet"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ export function TwapFormWarnings({ localFormValidation, isConfirmationModal }: T
return (
<>
{(() => {
if (localFormValidation === TwapFormState.TX_BUNDLING_NOT_SUPPORTED) {
if (
localFormValidation === TwapFormState.WALLET_NOT_SUPPORTED ||
localFormValidation === TwapFormState.TX_BUNDLING_NOT_SUPPORTED
) {
return <UnsupportedWalletWarning isSafeViaWc={isSafeViaWc} chainId={chainId} account={account} />
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { ReactNode } from 'react'

import { getSafeAccountUrl } from '@cowprotocol/core'
import { SupportedChainId } from '@cowprotocol/cow-sdk'
import { ExternalLink, InlineBanner, StatusColorVariant } from '@cowprotocol/ui'

import { Trans } from '@lingui/react/macro'

import { UNSUPPORTED_WALLET_LINK } from 'modules/twap/const'
import { UNSUPPORTED_WALLET_LINK } from 'modules/twap'

export interface UnsupportedWalletWarningProps {
chainId: SupportedChainId
account?: string
/**
* If true, we want to suggest the user to try the Safe web app, because their wallet connection did not confirm tx bundling.
*/
isSafeViaWc: boolean
}

// TODO: Add proper return type annotation
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function UnsupportedWalletWarning({ isSafeViaWc, chainId, account }: UnsupportedWalletWarningProps) {
export function UnsupportedWalletWarning({ isSafeViaWc, chainId, account }: UnsupportedWalletWarningProps): ReactNode {
if (isSafeViaWc && account) {
return (
<InlineBanner bannerType={StatusColorVariant.Info}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export function TwapFormWidget({ tradeWarnings }: TwapFormWidget): ReactNode {

useEffect(() => {
if (account && verification) {
if (localFormValidation === TwapFormState.TX_BUNDLING_NOT_SUPPORTED) {
if (localFormValidation === TwapFormState.WALLET_NOT_SUPPORTED) {
cowAnalytics.sendEvent({
category: CowSwapAnalyticsCategory.TWAP,
action: 'non-compatible',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useAtomValue } from 'jotai'

import { useIsTxBundlingSupported, useWalletInfo } from '@cowprotocol/wallet'
import { isSafeAppAtom, isSafeViaWcAtom, useIsTxBundlingSupported, useWalletInfo } from '@cowprotocol/wallet'

import { useGetReceiveAmountInfo } from 'modules/trade'
import { tradeFormValidationContextAtom } from 'modules/tradeFormValidation'
Expand All @@ -26,9 +26,13 @@ export function useTwapFormState(): TwapFormState | null {
const tradeFormValidationContext = useAtomValue(tradeFormValidationContextAtom)

const verification = useFallbackHandlerVerification()
const isSafeApp = useAtomValue(isSafeAppAtom)
const isSafeViaWc = useAtomValue(isSafeViaWcAtom)
const isTxBundlingSupported = useIsTxBundlingSupported()
const isWalletSupported = isSafeApp === null || isSafeViaWc === null ? null : isSafeApp || isSafeViaWc

return getTwapFormState({
isWalletSupported,
isTxBundlingSupported,
verification,
twapOrder,
Expand Down
1 change: 1 addition & 0 deletions apps/cowswap-frontend/src/modules/twap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './hooks/useMapTwapCurrencyInfo'
export * from './hooks/useScaledReceiveAmountInfo'
export * from './hooks/useTwapFormState'
export * from './hooks/useTwapSlippage'
export * from './const'
export { useIsFallbackHandlerRequired } from './hooks/useFallbackHandlerVerification'
export { SetupFallbackHandlerWarning } from './containers/SetupFallbackHandlerWarning'
export * from './updaters/index'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,42 @@ const twapOrder: TWAPOrder = {
}

describe('getTwapFormState()', () => {
it('returns WALLET_NOT_SUPPORTED for a non-Safe wallet', () => {
const result = getTwapFormState({
isWalletSupported: false,
isTxBundlingSupported: true,
verification: ExtensibleFallbackVerification.HAS_NOTHING,
twapOrder,
sellAmountPartFiat: null,
chainId: SupportedChainId.SEPOLIA,
partTime: undefined,
numberOfPartsValue: 1,
tradeFormValidationContext: null,
})

expect(result).toEqual(TwapFormState.WALLET_NOT_SUPPORTED)
})

it('returns TX_BUNDLING_NOT_SUPPORTED for a Safe without batching support', () => {
const result = getTwapFormState({
isWalletSupported: true,
isTxBundlingSupported: false,
verification: ExtensibleFallbackVerification.HAS_NOTHING,
twapOrder,
sellAmountPartFiat: null,
chainId: SupportedChainId.SEPOLIA,
partTime: undefined,
numberOfPartsValue: 1,
tradeFormValidationContext: null,
})

expect(result).toEqual(TwapFormState.TX_BUNDLING_NOT_SUPPORTED)
})

describe('When sell fiat amount is under threshold', () => {
it('And order has buy amount, then should return SELL_AMOUNT_TOO_SMALL', () => {
const result = getTwapFormState({
isWalletSupported: true,
isTxBundlingSupported: true,
verification: ExtensibleFallbackVerification.HAS_DOMAIN_VERIFIER,
twapOrder: { ...twapOrder },
Expand All @@ -43,6 +76,7 @@ describe('getTwapFormState()', () => {

it('And order does NOT have buy amount, then should return null', () => {
const result = getTwapFormState({
isWalletSupported: true,
isTxBundlingSupported: true,
verification: ExtensibleFallbackVerification.HAS_DOMAIN_VERIFIER,
twapOrder: { ...twapOrder, buyAmount: CurrencyAmount.fromRawAmount(COW_SEPOLIA, 0) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { isPartTimeIntervalTooShort } from '../../utils/isPartTimeIntervalTooSho
import { isSellAmountTooSmall } from '../../utils/isSellAmountTooSmall'

export interface TwapFormStateParams {
isWalletSupported: boolean | null
isTxBundlingSupported: boolean | null
verification: ExtensibleFallbackVerification | null
twapOrder: TWAPOrder | null
Expand All @@ -26,6 +27,7 @@ export interface TwapFormStateParams {

export enum TwapFormState {
LOADING_SAFE_INFO = 'LOADING_SAFE_INFO',
WALLET_NOT_SUPPORTED = 'WALLET_NOT_SUPPORTED',
TX_BUNDLING_NOT_SUPPORTED = 'TX_BUNDLING_NOT_SUPPORTED',
SELL_AMOUNT_TOO_SMALL = 'SELL_AMOUNT_TOO_SMALL',
PART_TIME_INTERVAL_TOO_SHORT = 'PART_TIME_INTERVAL_TOO_SHORT',
Expand All @@ -35,6 +37,7 @@ export enum TwapFormState {

export function getTwapFormState(props: TwapFormStateParams): TwapFormState | null {
const {
isWalletSupported,
twapOrder,
isTxBundlingSupported,
verification,
Expand All @@ -45,9 +48,12 @@ export function getTwapFormState(props: TwapFormStateParams): TwapFormState | nu
numberOfPartsValue,
} = props

if (isWalletSupported === false) return TwapFormState.WALLET_NOT_SUPPORTED
if (isTxBundlingSupported === false) return TwapFormState.TX_BUNDLING_NOT_SUPPORTED

if (verification === null || isTxBundlingSupported === null) return TwapFormState.LOADING_SAFE_INFO
if (verification === null || isTxBundlingSupported === null || isWalletSupported === null) {
return TwapFormState.LOADING_SAFE_INFO
}

if (!isFractionFalsy(twapOrder?.buyAmount) && isSellAmountTooSmall(sellAmountPartFiat, chainId)) {
return TwapFormState.SELL_AMOUNT_TOO_SMALL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ const buttonsMap: Record<TwapFormState, (_context: PrimaryActionButtonContext) =
<Trans>Loading...</Trans>
</ButtonPrimary>
),
[TwapFormState.WALLET_NOT_SUPPORTED]: () => (
<ButtonPrimary disabled={true} buttonSize={ButtonSize.BIG}>
<Trans>Unsupported wallet</Trans>
</ButtonPrimary>
),
[TwapFormState.TX_BUNDLING_NOT_SUPPORTED]: () => (
<ButtonPrimary disabled={true} buttonSize={ButtonSize.BIG}>
<Trans>Unsupported wallet</Trans>
Expand Down
Loading
Loading