import React, { useState, useCallback, useEffect, createContext, useContext, useMemo, } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { OnRampSdk, Environment, Context, RegionsService, CryptoCurrency, } from '@consensys/on-ramp-sdk'; import Logger from '../../../../util/Logger'; import { selectedAddressSelector, chainIdSelector, fiatOrdersGetStartedAgg, setFiatOrdersGetStartedAGG, setFiatOrdersRegionAGG, fiatOrdersRegionSelectorAgg, fiatOrdersPaymentMethodSelectorAgg, setFiatOrdersPaymentMethodAGG, } from '../../../../reducers/fiatOrders'; import { Region } from '../types'; import I18n, { I18nEvents } from '../../../../../locales/i18n'; interface IFiatOnRampSDKConfig { POLLING_INTERVAL: number; POLLING_INTERVAL_HIGHLIGHT: number; POLLING_CYCLES: number; } export interface IFiatOnRampSDK { sdk: RegionsService | undefined; sdkError?: Error; selectedRegion: Region | null; setSelectedRegion: (region: Region | null) => void; selectedPaymentMethodId: string | null; setSelectedPaymentMethodId: (paymentMethodId: string | null) => void; selectedAsset: CryptoCurrency | null; setSelectedAsset: (asset: CryptoCurrency) => void; selectedFiatCurrencyId: string | null; setSelectedFiatCurrencyId: (currencyId: string | null) => void; getStarted: boolean; setGetStarted: (getStartedFlag: boolean) => void; selectedAddress: string; selectedChainId: string; appConfig: IFiatOnRampSDKConfig; callbackBaseUrl: string; } interface IProviderProps { value?: T; children?: React.ReactNode | undefined; } const isDevelopment = process.env.NODE_ENV !== 'production'; const VERBOSE_SDK = isDevelopment; export const SDK = OnRampSdk.create( isDevelopment ? Environment.Staging : Environment.Production, Context.Mobile, { verbose: VERBOSE_SDK, locale: I18n.locale, }, ); I18nEvents.addListener('localeChanged', (locale) => { SDK.setLocale(locale); }); export const callbackBaseUrl = isDevelopment ? 'https://on-ramp-content.metaswap-dev.codefi.network/regions/fake-callback' : 'https://on-ramp-content.metaswap.codefi.network/regions/fake-callback'; const appConfig = { POLLING_INTERVAL: 20000, POLLING_INTERVAL_HIGHLIGHT: 10000, POLLING_CYCLES: 3, }; const SDKContext = createContext(undefined); export const FiatOnRampSDKProvider = ({ value, ...props }: IProviderProps) => { const [sdkModule, setSdkModule] = useState(); const [sdkError, setSdkError] = useState(); useEffect(() => { (async () => { try { const sdk = await SDK.regions(); setSdkModule(sdk); } catch (error) { Logger.error( error as Error, `FiatOnRampSDKProvider SDK.regions() failed`, ); setSdkError(error as Error); } })(); }, []); const sdk: RegionsService | undefined = useMemo(() => sdkModule, [sdkModule]); const dispatch = useDispatch(); const INITIAL_SELECTED_REGION: Region | null = useSelector( fiatOrdersRegionSelectorAgg, ); const INITIAL_GET_STARTED: boolean = useSelector(fiatOrdersGetStartedAgg); const selectedAddress: string = useSelector(selectedAddressSelector); const selectedChainId: string = useSelector(chainIdSelector); const INITIAL_PAYMENT_METHOD_ID: string | null = useSelector( fiatOrdersPaymentMethodSelectorAgg, ); const INITIAL_SELECTED_ASSET = null; const [selectedRegion, setSelectedRegion] = useState(INITIAL_SELECTED_REGION); const [selectedAsset, setSelectedAsset] = useState(INITIAL_SELECTED_ASSET); const [selectedPaymentMethodId, setSelectedPaymentMethodId] = useState( INITIAL_PAYMENT_METHOD_ID, ); const [selectedFiatCurrencyId, setSelectedFiatCurrencyId] = useState(null); const [getStarted, setGetStarted] = useState(INITIAL_GET_STARTED); const setSelectedRegionCallback = useCallback( (region) => { setSelectedRegion(region); dispatch(setFiatOrdersRegionAGG(region)); }, [dispatch], ); const setSelectedPaymentMethodIdCallback = useCallback( (paymentMethodId) => { setSelectedPaymentMethodId(paymentMethodId); dispatch(setFiatOrdersPaymentMethodAGG(paymentMethodId)); }, [dispatch], ); const setSelectedAssetCallback = useCallback((asset) => { setSelectedAsset(asset); }, []); const setSelectedFiatCurrencyIdCallback = useCallback((currencyId) => { setSelectedFiatCurrencyId(currencyId); }, []); const setGetStartedCallback = useCallback( (getStartedFlag) => { setGetStarted(getStartedFlag); dispatch(setFiatOrdersGetStartedAGG(getStartedFlag)); }, [dispatch], ); const contextValue: IFiatOnRampSDK = { sdk, sdkError, selectedRegion, setSelectedRegion: setSelectedRegionCallback, selectedPaymentMethodId, setSelectedPaymentMethodId: setSelectedPaymentMethodIdCallback, selectedAsset, setSelectedAsset: setSelectedAssetCallback, selectedFiatCurrencyId, setSelectedFiatCurrencyId: setSelectedFiatCurrencyIdCallback, getStarted, setGetStarted: setGetStartedCallback, selectedAddress, selectedChainId, appConfig, callbackBaseUrl, }; return ; }; export const useFiatOnRampSDK = () => { const contextValue = useContext(SDKContext); return contextValue as IFiatOnRampSDK; }; type NullifyOrPartial = { [P in keyof T]?: T[P] | null }; type PartialParameters = T extends (...args: infer P) => any ? NullifyOrPartial

: never; interface config { method: T; onMount?: boolean; } /** * useSDKMethod is a hook to conveniently call OnRampSdk.regions methods. * * @param config The method name or an object with the method name and a boolean onMount flag. * @param params The parameters to pass to the method. * @returns An array with an object with data, an error and a loading flag, and a function to call the method. * * @example * // Calling `getDefaultFiatCurrency` method * const [{ isFetching, error, data }] = useSDKMethod('getDefaultFiatCurrency', '/regions/cl'); * * @example * // Calling `getDefaultFiatCurrency` method and get the function * const [{ isFetching, error, data }, getDefaultFiatCurrency] = useSDKMethod('getDefaultFiatCurrency', '/regions/cl'); * // `getDefaultFiatCurrency` will be called with the same parameters * // by default (`/regions/cl` in this case) * const defaultCLFiatCurrency = await getDefaultFiatCurrency(); * // Parameters can be overridden * const defaultARFiatCurrency = await getDefaultFiatCurrency('/regions/ar'); * // The return and error of these calls will be reflected in the returned object of the hook */ export function useSDKMethod( config: T | config, ...params: PartialParameters ): [ { data: Awaited> | null; error: string | null; isFetching: boolean; }, ( ...customParams: PartialParameters | [] ) => Promise | ReturnType, ] { const { sdk }: { sdk: RegionsService } = useFiatOnRampSDK() as any; const [data, setData] = useState > | null>(null); const [error, setError] = useState(null); const [isFetching, setIsFetching] = useState(true); const stringifiedParams = useMemo(() => JSON.stringify(params), [params]); const method = typeof config === 'string' ? config : config.method; const onMount = typeof config === 'string' ? true : config.onMount ?? true; const query = useCallback( async (...customParams: PartialParameters | []) => { if ( (customParams.length > 0 && customParams.some((param) => !param)) || (customParams.length === 0 && params.length > 0 && params.some((param) => !param)) ) { return; } try { setIsFetching(true); setError(null); setData(null); if (sdk) { const response = await sdk[method]( // @ts-expect-error spreading params error ...(customParams.length > 0 ? customParams : params), ); // @ts-expect-error response type error setData(response); return response; } } catch (responseError) { Logger.error(responseError as Error, `useSDKMethod::${method} failed`); setError((responseError as Error).message); } finally { setIsFetching(false); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [method, stringifiedParams, sdk], ); useEffect(() => { if (onMount) { query(); } else { setIsFetching(false); } }, [query, onMount]); return [{ data, error, isFetching }, query]; } export const withFiatOnRampSDK = (Component: React.FC) => (props: any) => ( ); export default SDKContext;