diff --git a/client/src/api/calls/safeTransactions.ts b/client/src/api/calls/safeTransactions.ts new file mode 100644 index 0000000000..562d60f6cf --- /dev/null +++ b/client/src/api/calls/safeTransactions.ts @@ -0,0 +1,22 @@ +import { GenericAbortSignal } from 'axios'; + +import env from 'env'; +import apiService from 'services/apiService'; + +export type Response = { + results: { + safeTxHash: string; + transactionHash?: string; + }[]; +}; + +export async function apiGetSafeTransactions( + address: string, + signal?: GenericAbortSignal, +): Promise { + return apiService + .get(`${env.safeEndpoint}api/v1/safes/${address}/all-transactions/`, { + signal, + }) + .then(({ data }) => data); +} diff --git a/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx b/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx index f9983c4c24..3a966b3735 100644 --- a/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx +++ b/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx @@ -3,6 +3,7 @@ import React, { FC, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useAccount, useWalletClient, usePublicClient, useWaitForTransactionReceipt } from 'wagmi'; +import { apiGetSafeTransactions } from 'api/calls/safeTransactions'; import EarnGlmLockBudget from 'components/Earn/EarnGlmLock/EarnGlmLockBudget'; import EarnGlmLockNotification from 'components/Earn/EarnGlmLock/EarnGlmLockNotification'; import EarnGlmLockStepper from 'components/Earn/EarnGlmLock/EarnGlmLockStepper'; @@ -16,8 +17,11 @@ import useMediaQuery from 'hooks/helpers/useMediaQuery'; import useLock from 'hooks/mutations/useLock'; import useUnlock from 'hooks/mutations/useUnlock'; import useDepositValue from 'hooks/queries/useDepositValue'; +import useEstimatedEffectiveDeposit from 'hooks/queries/useEstimatedEffectiveDeposit'; +import useHistory from 'hooks/queries/useHistory'; import useIsContract from 'hooks/queries/useIsContract'; import useProjectsEpoch from 'hooks/queries/useProjectsEpoch'; +import useLockedSummaryLatest from 'hooks/subgraph/useLockedSummaryLatest'; import toastService from 'services/toastService'; import useTransactionLocalStore from 'store/transactionLocal/store'; import { parseUnitsBigInt } from 'utils/parseUnitsBigInt'; @@ -52,12 +56,16 @@ const EarnGlmLock: FC = ({ currentMode, onCurrentModeChange, o */ const [valueToDepose, setValueToDepose] = useState(BigInt(0)); const [step, setStep] = useState(1); + const [intervalId, setIntervalId] = useState(null); const [isCryptoOrFiatInputFocused, setIsCryptoOrFiatInputFocused] = useState(true); const buttonUseMaxRef = useRef(null); const { data: availableFundsGlm } = useAvailableFundsGlm(); const { data: projectsEpoch } = useProjectsEpoch(); - const { data: depositsValue } = useDepositValue(); + const { refetch: refetchHistory } = useHistory(); + const { data: depositsValue, refetch: refetchDeposit } = useDepositValue(); + const { refetch: refetchEstimatedEffectiveDeposit } = useEstimatedEffectiveDeposit(); + const { refetch: refetchLockedSummaryLatest } = useLockedSummaryLatest(); useEffect(() => { if (transactionReceipt && !isLoadingTransactionReceipt) { @@ -106,19 +114,40 @@ const EarnGlmLock: FC = ({ currentMode, onCurrentModeChange, o }; const onSuccess = async ({ hash, value }): Promise => { + if (isContract) { + const id = setInterval(async () => { + const nextSafeTransactions = await apiGetSafeTransactions(address!); + const safeTransaction = nextSafeTransactions.results.find( + t => t.safeTxHash === hash && t.transactionHash, + ); + + if (safeTransaction) { + clearInterval(id); + Promise.all([ + refetchDeposit(), + refetchEstimatedEffectiveDeposit(), + refetchLockedSummaryLatest(), + refetchHistory(), + ]).then(() => { + setTransactionHashForEtherscan(safeTransaction.transactionHash); + setStep(3); + }); + } + }, 2000); + setIntervalId(id); + return; + } addTransactionPending({ eventData: { amount: value, transactionHash: hash, }, - isMultisig: isContract, + isMultisig: !!isContract, // GET /history uses seconds. Normalization here. timestamp: Math.floor(Date.now() / 1000).toString(), type: currentMode, }); - if (!isContract) { - setTransactionHashForEtherscan(hash); - } + setTransactionHashForEtherscan(hash); }; const onReset: OnReset = ({ setFieldValue, newMode = 'lock' }) => { @@ -159,6 +188,15 @@ const EarnGlmLock: FC = ({ currentMode, onCurrentModeChange, o const isLockingApproved = approvalState === ApprovalState.APPROVED; const isApprovalKnown = approvalState !== ApprovalState.UNKNOWN; + useEffect(() => { + return () => { + if (!intervalId) { + return; + } + clearInterval(intervalId); + }; + }, [intervalId]); + return ( = ({ currentMode, onCurrentModeChange, o buttonUseMaxRef={buttonUseMaxRef} className={styles.element} currentMode={currentMode} - isLoading={isLoadingTransactionReceipt || props.isSubmitting} + isLoading={ + isLoadingTransactionReceipt || props.isSubmitting || (!!isContract && step === 2) + } onClose={onCloseModal} onInputsFocusChange={setIsCryptoOrFiatInputFocused} onReset={onReset} diff --git a/client/src/components/shared/ModalOnboarding/ModalOnboarding.tsx b/client/src/components/shared/ModalOnboarding/ModalOnboarding.tsx index 5d3abca13d..195c36f710 100644 --- a/client/src/components/shared/ModalOnboarding/ModalOnboarding.tsx +++ b/client/src/components/shared/ModalOnboarding/ModalOnboarding.tsx @@ -50,7 +50,7 @@ const ModalOnboarding = (): ReactElement => { const { isAllocateOnboardingAlwaysVisible } = useSettingsStore(state => ({ isAllocateOnboardingAlwaysVisible: state.data.isAllocateOnboardingAlwaysVisible, })); - const isContract = useIsContract(); + const { data: isContract } = useIsContract(); const [isUserTOSAcceptedInitial, setIsUserTOSAcceptedInitial] = useState(isUserTOSAccepted); diff --git a/client/src/hooks/queries/useIsContract.ts b/client/src/hooks/queries/useIsContract.ts index e9c8d22912..b1054eaf4f 100644 --- a/client/src/hooks/queries/useIsContract.ts +++ b/client/src/hooks/queries/useIsContract.ts @@ -1,7 +1,7 @@ import { UseQueryResult } from '@tanstack/react-query'; import { useAccount, useBytecode } from 'wagmi'; -export default function useIsContract(): UseQueryResult { +export default function useIsContract(): UseQueryResult { const { address } = useAccount(); return useBytecode({