From 91909748dc2e05b01f772476f08e66c45fdb3405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Miko=C5=82ajczyk?= Date: Mon, 29 Jul 2024 13:28:05 +0200 Subject: [PATCH 1/3] [HOTFIX]: lock/unlock glm multisig fix --- client/src/api/calls/safeTransactions.ts | 19 ++++++++ .../Earn/EarnGlmLock/EarnGlmLock.tsx | 44 ++++++++++++++++--- .../ModalOnboarding/ModalOnboarding.tsx | 2 +- client/src/hooks/queries/useIsContract.ts | 2 +- 4 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 client/src/api/calls/safeTransactions.ts diff --git a/client/src/api/calls/safeTransactions.ts b/client/src/api/calls/safeTransactions.ts new file mode 100644 index 0000000000..d396aa317b --- /dev/null +++ b/client/src/api/calls/safeTransactions.ts @@ -0,0 +1,19 @@ +import { GenericAbortSignal } from 'axios'; + +import env from 'env'; +import apiService from 'services/apiService'; + +export type Response = { + results: any[]; +}; + +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..337cb4dbc6 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,10 @@ 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 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 +55,15 @@ 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 { data: depositsValue, refetch: refetchDeposit } = useDepositValue(); + const { refetch: refetchEstimatedEffectiveDeposit } = useEstimatedEffectiveDeposit(); + const { refetch: refetchLockedSummaryLatest } = useLockedSummaryLatest(); useEffect(() => { if (transactionReceipt && !isLoadingTransactionReceipt) { @@ -106,19 +112,34 @@ const EarnGlmLock: FC = ({ currentMode, onCurrentModeChange, o }; const onSuccess = async ({ hash, value }): Promise => { + if (isContract) { + const id = setInterval(async () => { + const nextSafeTransactions = await apiGetSafeTransactions(address!); + if (nextSafeTransactions.results.find(t => t.safeTxHash === hash && t.transactionHash)) { + clearInterval(id); + Promise.all([ + refetchDeposit(), + refetchEstimatedEffectiveDeposit(), + refetchLockedSummaryLatest(), + ]).then(() => { + 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 +180,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({ From 31c22eae259734f39988508de358f15aadb7cb00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Miko=C5=82ajczyk?= Date: Mon, 29 Jul 2024 14:40:57 +0200 Subject: [PATCH 2/3] multisig lock eth tx + history refetch --- client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx b/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx index 337cb4dbc6..3a966b3735 100644 --- a/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx +++ b/client/src/components/Earn/EarnGlmLock/EarnGlmLock.tsx @@ -18,6 +18,7 @@ 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'; @@ -61,6 +62,7 @@ const EarnGlmLock: FC = ({ currentMode, onCurrentModeChange, o const { data: availableFundsGlm } = useAvailableFundsGlm(); const { data: projectsEpoch } = useProjectsEpoch(); + const { refetch: refetchHistory } = useHistory(); const { data: depositsValue, refetch: refetchDeposit } = useDepositValue(); const { refetch: refetchEstimatedEffectiveDeposit } = useEstimatedEffectiveDeposit(); const { refetch: refetchLockedSummaryLatest } = useLockedSummaryLatest(); @@ -115,13 +117,19 @@ const EarnGlmLock: FC = ({ currentMode, onCurrentModeChange, o if (isContract) { const id = setInterval(async () => { const nextSafeTransactions = await apiGetSafeTransactions(address!); - if (nextSafeTransactions.results.find(t => t.safeTxHash === hash && t.transactionHash)) { + 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); }); } From 0d5115b24ca3c0b6140dc6ab861b67a37b90b6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Miko=C5=82ajczyk?= Date: Mon, 29 Jul 2024 14:46:10 +0200 Subject: [PATCH 3/3] safe transactions type --- client/src/api/calls/safeTransactions.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/api/calls/safeTransactions.ts b/client/src/api/calls/safeTransactions.ts index d396aa317b..562d60f6cf 100644 --- a/client/src/api/calls/safeTransactions.ts +++ b/client/src/api/calls/safeTransactions.ts @@ -4,7 +4,10 @@ import env from 'env'; import apiService from 'services/apiService'; export type Response = { - results: any[]; + results: { + safeTxHash: string; + transactionHash?: string; + }[]; }; export async function apiGetSafeTransactions(