import { NativeStackScreenProps } from '@react-navigation/native-stack' import BigNumber from 'bignumber.js' import React, { useEffect, useRef } from 'react' import { useAsync } from 'react-async-hook' import { Trans, useTranslation } from 'react-i18next' import { StyleSheet, Text, View } from 'react-native' import { SafeAreaView } from 'react-native-safe-area-context' import walletJumpstart from 'src/abis/IWalletJumpstart' import AppAnalytics from 'src/analytics/AppAnalytics' import { JumpstartEvents } from 'src/analytics/Events' import BackButton from 'src/components/BackButton' import BottomSheet, { BottomSheetModalRefType } from 'src/components/BottomSheet' import Button, { BtnSizes, BtnTypes } from 'src/components/Button' import DataFieldWithCopy from 'src/components/DataFieldWithCopy' import { NotificationVariant } from 'src/components/InLineNotification' import LineItemRow from 'src/components/LineItemRow' import Toast from 'src/components/Toast' import TokenDisplay from 'src/components/TokenDisplay' import TokenIcon, { IconSize } from 'src/components/TokenIcon' import CustomHeader from 'src/components/header/CustomHeader' import Checkmark from 'src/icons/Checkmark' import Logo from 'src/images/Logo' import { fetchClaimStatus } from 'src/jumpstart/fetchClaimStatus' import { jumpstartReclaimStatusSelector } from 'src/jumpstart/selectors' import { jumpstartReclaimErrorDismissed, jumpstartReclaimStarted } from 'src/jumpstart/slice' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import { StackParamList } from 'src/navigator/types' import { useDispatch, useSelector } from 'src/redux/hooks' import Colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' import { Shadow, Spacing, getShadowStyle } from 'src/styles/styles' import variables from 'src/styles/variables' import { useTokenInfo } from 'src/tokens/hooks' import { feeCurrenciesSelector } from 'src/tokens/selectors' import TransactionDetails from 'src/transactions/feed/TransactionDetails' import FeeRowItem from 'src/transactions/feed/detailContent/FeeRowItem' import { FeeType, TokenTransactionTypeV2 } from 'src/transactions/types' import Logger from 'src/utils/Logger' import { TransactionRequest, prepareTransactions } from 'src/viem/prepareTransactions' import { getSerializablePreparedTransaction } from 'src/viem/preparedTransactionSerialization' import EstimatedNetworkFee from 'src/walletConnect/screens/EstimatedNetworkFee' import { walletAddressSelector } from 'src/web3/selectors' import { Address, Hash, encodeFunctionData } from 'viem' const TAG = 'JumpstartTransactionDetailsScreen' type Props = NativeStackScreenProps function JumpstartTransactionDetailsScreen({ route }: Props) { const { transaction } = route.params const parsedAmount = new BigNumber(transaction.amount.value).abs() const isDeposit = transaction.type === TokenTransactionTypeV2.Sent const jumpstartContractAddress = transaction.address const networkId = transaction.networkId const tokenAmount = transaction.amount const { t } = useTranslation() const dispatch = useDispatch() const token = useTokenInfo(transaction.amount.tokenId) const walletAddress = useSelector(walletAddressSelector) const feeCurrencies = useSelector((state) => feeCurrenciesSelector(state, networkId)) const reclaimStatus = useSelector(jumpstartReclaimStatusSelector) const bottomSheetRef = useRef(null) useEffect(() => { if (reclaimStatus === 'success' || reclaimStatus === 'error') { bottomSheetRef.current?.close() } }, [reclaimStatus]) const fetchClaimData = useAsync( async () => { if (!isDeposit) { return null } const { claimed, beneficiary, index } = await fetchClaimStatus( jumpstartContractAddress as Address, networkId, transaction.transactionHash as Hash ) if (claimed) { return { claimed: true } } const reclaimTx: TransactionRequest = { from: walletAddress as Address, to: jumpstartContractAddress as Address, value: BigInt(0), data: encodeFunctionData({ abi: walletJumpstart.abi, functionName: 'reclaimERC20', args: [beneficiary, BigInt(index)], }), } const preparedTransactions = await prepareTransactions({ feeCurrencies, baseTransactions: [reclaimTx], origin: 'jumpstart-claim', }) switch (preparedTransactions.type) { case 'need-decrease-spend-amount-for-gas': // fallthrough on purpose case 'not-enough-balance-for-gas': throw new Error('Not enough balance for gas') case 'possible': return { preparedTransaction: getSerializablePreparedTransaction( preparedTransactions.transactions[0] ), claimed: false, } } }, [], { onSuccess: (result) => { if (result) { AppAnalytics.track(JumpstartEvents.jumpstart_claim_status_fetch_success, { networkId, depositTxHash: transaction.transactionHash, claimed: result.claimed, }) } }, onError: (error) => { AppAnalytics.track(JumpstartEvents.jumpstart_claim_status_fetch_error, { networkId, depositTxHash: transaction.transactionHash, }) Logger.warn(TAG, 'Failed to fetch escrow data', error) }, } ) const handleReclaimPress = () => { AppAnalytics.track(JumpstartEvents.jumpstart_reclaim_press, { networkId, depositTxHash: transaction.transactionHash, }) if (reclaimStatus === 'error') { dispatch(jumpstartReclaimErrorDismissed()) } bottomSheetRef.current?.snapToIndex(0) } const handleConfirmReclaim = () => { AppAnalytics.track(JumpstartEvents.jumpstart_reclaim_start, { networkId, depositTxHash: transaction.transactionHash, }) if (!reclaimTx) { Logger.warn(TAG, 'Reclaim transaction is not set') return } dispatch( jumpstartReclaimStarted({ reclaimTx, networkId, tokenAmount, depositTxHash: transaction.transactionHash, }) ) } const handleContactSupport = () => { AppAnalytics.track(JumpstartEvents.jumpstart_reclaim_contact_support) navigate(Screens.SupportContact) } const handleDismissReclaimError = () => { AppAnalytics.track(JumpstartEvents.jumpstart_reclaim_dismiss_error, { networkId, depositTxHash: transaction.transactionHash, }) dispatch(jumpstartReclaimErrorDismissed()) } const reclaimTx = fetchClaimData.result?.preparedTransaction const isClaimed = fetchClaimData.result?.claimed || reclaimStatus === 'success' const title = transaction.type === TokenTransactionTypeV2.Sent ? t('feedItemJumpstartTitle') : t('feedItemJumpstartReceivedSubtitle') if (!token) { // should never happen Logger.error(TAG, 'Token is undefined') return null } return ( } /> navigate(Screens.JumpstartEnterAmount)} > {isDeposit && (