diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx index 42d386dd91..8fa0b836bd 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/AddTokensWidget.tsx @@ -35,14 +35,13 @@ import { Review } from './views/Review'; import { fetchBalances } from './functions/fetchBalances'; import { useTokens } from './hooks/useTokens'; import { useProvidersContext } from '../../context/providers-context/ProvidersContext'; -import { ServiceUnavailableToRegionErrorView } from '../../views/error/ServiceUnavailableToRegionErrorView'; -import { ServiceType } from '../../views/error/serviceTypes'; import { orchestrationEvents } from '../../lib/orchestrationEvents'; import { getRemoteImage } from '../../lib/utils'; import { isValidAddress } from '../../lib/validations/widgetValidators'; import { amountInputValidation } from '../../lib/validations/amountInputValidations'; import { useError } from './hooks/useError'; import { AddTokensErrorTypes } from './types'; +import { ServiceUnavailableErrorView } from '../../views/error/ServiceUnavailableErrorView'; export type AddTokensWidgetInputs = Omit & { config: StrongCheckoutWidgetsConfig; @@ -265,9 +264,15 @@ export default function AddTokensWidget({ )} {viewState.view.type === SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW && ( - sendAddTokensCloseEvent(eventTarget)} + onBackButtonClick={() => { + viewDispatch({ + payload: { + type: ViewActions.GO_BACK, + }, + }); + }} /> )} diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useRiskAssessment.ts b/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useRiskAssessment.ts new file mode 100644 index 0000000000..6c487b525b --- /dev/null +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/hooks/useRiskAssessment.ts @@ -0,0 +1,40 @@ +import { useEffect, useState } from 'react'; +import { AssessmentResult, fetchRiskAssessment } from '@imtbl/checkout-sdk'; +import { useProvidersContext } from '../../../context/providers-context/ProvidersContext'; + +export const useRiskAssessment = () => { + const [riskAssessment, setRiskAssessment] = useState(); + + const { + providersState: { + checkout, fromAddress, toAddress, + }, + } = useProvidersContext(); + + useEffect(() => { + if (!checkout) { + return; + } + + (async () => { + const addresses: string[] = []; + + if (fromAddress) { + addresses.push(fromAddress); + } + + if (toAddress && toAddress !== fromAddress) { + addresses.push(toAddress); + } + + if (addresses.length === 0) { + return; + } + + const assessment = await fetchRiskAssessment(addresses, checkout.config); + setRiskAssessment(assessment); + })(); + }, [checkout, fromAddress, toAddress]); + + return { riskAssessment }; +}; diff --git a/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx b/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx index edae5b7176..3aeef396d8 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-tokens/views/AddTokens.tsx @@ -14,6 +14,7 @@ import { type Checkout, EIP6963ProviderInfo, IMTBLWidgetEvents, + isAddressSanctioned, TokenFilterTypes, type TokenInfo, WalletProviderRdns, @@ -31,6 +32,7 @@ import { useTranslation } from 'react-i18next'; import { SimpleLayout } from '../../../components/SimpleLayout/SimpleLayout'; import { EventTargetContext } from '../../../context/event-target-context/EventTargetContext'; import { + SharedViews, ViewActions, ViewContext, } from '../../../context/view-context/ViewContext'; @@ -66,6 +68,7 @@ import { SquidFooter } from '../components/SquidFooter'; import { getFormattedNumberWithDecimalPlaces } from '../functions/getFormattedNumber'; import { TokenDrawerMenu } from '../components/TokenDrawerMenu'; import { PULSE_SHADOW } from '../utils/animation'; +import { useRiskAssessment } from '../hooks/useRiskAssessment'; interface AddTokensProps { checkout: Checkout; @@ -133,6 +136,8 @@ export function AddTokens({ const [fetchingRoutes, setFetchingRoutes] = useState(false); const [insufficientBalance, setInsufficientBalance] = useState(false); + const { riskAssessment } = useRiskAssessment(); + const selectedAmountUsd = useMemo( () => convertToUsd(tokens, inputValue, selectedToken), [tokens, inputValue, selectedToken], @@ -316,6 +321,20 @@ export function AddTokens({ }, [checkout]); const sendRequestOnRampEvent = () => { + if (!riskAssessment || isAddressSanctioned(riskAssessment)) { + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW, + error: new Error('Sanctioned address'), + }, + }, + }); + + return; + } + track({ userJourney: UserJourney.ADD_TOKENS, screen: 'InputScreen', @@ -349,10 +368,10 @@ export function AddTokens({ }; useEffect(() => { - if (toProvider && payWithCardClicked) { + if (toProvider && riskAssessment && payWithCardClicked) { sendRequestOnRampEvent(); } - }, [toProvider]); + }, [toProvider, riskAssessment, payWithCardClicked]); const handleRouteClick = (route: RouteData) => { setShowOptionsDrawer(false); @@ -371,6 +390,20 @@ export function AddTokens({ const handleReviewClick = () => { if (!selectedRouteData || !selectedToken?.address) return; + if (!riskAssessment || isAddressSanctioned(riskAssessment)) { + viewDispatch({ + payload: { + type: ViewActions.UPDATE_VIEW, + view: { + type: SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW, + error: new Error('Sanctioned address'), + }, + }, + }); + + return; + } + track({ userJourney: UserJourney.ADD_TOKENS, screen: 'InputScreen', @@ -424,7 +457,7 @@ export function AddTokens({ const loading = (routeInputsReady || fetchingRoutes) && !(selectedRouteData || insufficientBalance); - const readyToReview = routeInputsReady && !!toAddress && !!selectedRouteData && !loading; + const readyToReview = routeInputsReady && !!toAddress && !!selectedRouteData && !loading && !!riskAssessment; const handleWalletConnected = ( providerType: 'from' | 'to',