import type { ChainType, RouteExtended } from '@lifi/sdk' import { useAccount } from '@lifi/wallet-management' import { useEthereumContext } from '@lifi/widget-provider' import { useChain } from '../hooks/useChain.js' import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js' import { useFieldValues } from '../stores/form/useFieldValues.js' import { useIsContractAddress } from './useIsContractAddress.js' export const useToAddressRequirements = ( route?: RouteExtended ): { requiredToAddress: boolean requiredToChainType: ChainType | undefined accountNotDeployedAtDestination: boolean accountDeployedAtDestination: boolean toAddress: string | undefined isFromContractAddress: boolean | undefined isToContractAddress: boolean | undefined isLoading: boolean isFetched: boolean } => { const { requiredUI, hiddenUI } = useWidgetConfig() const [formFromChainId, formToChainId, formToAddress] = useFieldValues( 'fromChain', 'toChain', 'toAddress' ) const { isDelegationDesignatorCode } = useEthereumContext() const fromChainId = route?.fromChainId ?? formFromChainId const toChainId = route?.toChainId ?? formToChainId const { chain: fromChain } = useChain(fromChainId) const { chain: toChain } = useChain(toChainId) const { account } = useAccount({ chainType: fromChain?.chainType, }) const fromAddress = route?.fromAddress ?? account.address const toAddress = route ? route.fromAddress !== route.toAddress ? route.toAddress : formToAddress : formToAddress const { isContractAddress: isFromContractAddress, contractCode: fromContractCode, isLoading: isFromContractLoading, isFetched: isFromContractFetched, } = useIsContractAddress(account.address, fromChain?.id, account.chainType) const { isContractAddress: isToContractAddress, isLoading: isToContractLoading, isFetched: isToContractFetched, } = useIsContractAddress(toAddress, toChain?.id, toChain?.chainType) const isDifferentChainType = fromChain && toChain && fromChain.chainType !== toChain.chainType // We don't want to block transfers for EIP-7702 accounts since they are designed // to maintain EOA-like properties while delegating execution. const fromContractCodeHasDelegationIndicator = isDelegationDesignatorCode?.(fromContractCode) const isCrossChainContractAddress = isFromContractAddress && fromChainId !== toChainId && !fromContractCodeHasDelegationIndicator const requiredToAddress = Boolean( (isDifferentChainType || isCrossChainContractAddress || requiredUI?.toAddress) && !hiddenUI?.toAddress ) const accountNotDeployedAtDestination = Boolean( isFromContractAddress && !fromContractCodeHasDelegationIndicator && !isToContractAddress && fromAddress?.toLowerCase() === toAddress?.toLowerCase() ) const accountDeployedAtDestination = Boolean( isFromContractAddress && isToContractAddress && !fromContractCodeHasDelegationIndicator && fromAddress?.toLowerCase() === toAddress?.toLowerCase() ) return { requiredToAddress, requiredToChainType: toChain?.chainType, accountNotDeployedAtDestination, accountDeployedAtDestination, toAddress, isFromContractAddress, isToContractAddress, isLoading: isFromContractLoading || isToContractLoading, isFetched: isFromContractFetched && isToContractFetched, } }