diff --git a/apps/cowswap-frontend/src/locales/en-US.po b/apps/cowswap-frontend/src/locales/en-US.po index 1851d51806c..175977fa5c9 100644 --- a/apps/cowswap-frontend/src/locales/en-US.po +++ b/apps/cowswap-frontend/src/locales/en-US.po @@ -5105,6 +5105,10 @@ msgstr "Order Creation Failed" msgid "This wallet is not yet supported" msgstr "This wallet is not yet supported" +#: apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx +msgid "The token pair is constrained" +msgstr "The token pair is constrained" + #: apps/cowswap-frontend/src/modules/affiliate/containers/AffiliatePartnerCodeInfo.tsx #: apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/ReceiptModal.modal.tsx msgid "Created" diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx b/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx index d8f336a8409..2ac1c4ec272 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx @@ -403,4 +403,7 @@ export const tradeButtonsMap: Record ) }, + [TradeFormValidation.WidgetConstrainedTokenPair]: { + text: The token pair is constrained, + }, } diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.test.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.test.ts index ddb09670eae..684412c2910 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.test.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.test.ts @@ -32,6 +32,7 @@ describe('validateTradeForm - xStock logic', () => { recipient: '0x123', isQuoteBasedOrder: true, tradeType: TradeType.SWAP, + slippage: null, }, tradeQuote: { isLoading: false } as unknown as TradeQuoteState, isOnline: true, @@ -48,12 +49,13 @@ describe('validateTradeForm - xStock logic', () => { intermediateTokenToBeImported: false, isAccountProxyLoading: false, isProxySetupValid: true, - customTokenError: null, + customTokenError: undefined, isRestrictedForCountry: false, isBalancesLoading: false, isBundlingSupported: true, isInputCurrencyXstock: false, isOutputCurrencyXstock: false, + injectedWidgetParams: {}, } test('shows xStock minimum trade size for sell orders when xStock sell amount is below $10', () => { diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts index b323f5d90f6..03ee0a66924 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.ts @@ -1,5 +1,5 @@ -import { getIsNativeToken, isFractionFalsy, isSellOrder } from '@cowprotocol/common-utils' -import { isEvmChain } from '@cowprotocol/cow-sdk' +import { getCurrencyAddress, getIsNativeToken, isFractionFalsy, isSellOrder } from '@cowprotocol/common-utils' +import { areAddressesEqual, isEvmChain } from '@cowprotocol/cow-sdk' import { TradeType } from 'modules/trade' import { getIsFastQuote, isQuoteExpired } from 'modules/tradeQuote' @@ -90,6 +90,21 @@ export function validateTradeForm(context: TradeFormValidationContext): TradeFor return [TradeFormValidation.XstockMinimumTradeSize] } + if (injectedWidgetParams.tokenPairConstraints && inputCurrency && outputCurrency) { + const isTradeConstrained = injectedWidgetParams.tokenPairConstraints.some((rule) => { + return ( + rule.sell.chainId === inputCurrency.chainId && + areAddressesEqual(rule.sell.address, getCurrencyAddress(inputCurrency)) && + rule.buy.chainId === outputCurrency.chainId && + areAddressesEqual(rule.buy.address, getCurrencyAddress(outputCurrency)) + ) + }) + + if (isTradeConstrained) { + validations.push(TradeFormValidation.WidgetConstrainedTokenPair) + } + } + if (!isWrapUnwrap && tradeQuote.error) { if (inputAmountIsNotSet) { validations.push(TradeFormValidation.InputAmountNotSet) diff --git a/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts b/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts index 4f93b8683aa..af1b29b148a 100644 --- a/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts +++ b/apps/cowswap-frontend/src/modules/tradeFormValidation/types.ts @@ -116,4 +116,5 @@ export enum TradeFormValidation { // Widget controlled DisableTradeWithUnknownPriceImpact, DisableTradeWithHighPriceImpact, + WidgetConstrainedTokenPair, } diff --git a/libs/widget-lib/src/types.ts b/libs/widget-lib/src/types.ts index 69f5c472882..e269d59c303 100644 --- a/libs/widget-lib/src/types.ts +++ b/libs/widget-lib/src/types.ts @@ -450,6 +450,14 @@ export interface CowSwapWidgetParams { whenPriceImpactIsHigherThan?: number } + /** + * Disables trading of specific token pair + */ + tokenPairConstraints?: { + sell: { address: string; chainId: SupportedChainId } + buy: { address: string; chainId: SupportedChainId } + }[] + hooks?: Partial<{ onBeforeApproval(payload: OnApprovalPayload): WidgetHookResult onBeforeWrapOrUnwrap(payload: OnTradeParamsPayload): WidgetHookResult