diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5453b81191..89cdd5f129 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -59,6 +59,14 @@ jobs: ELECTRON_ENABLE_LOGGING: true # send console logs to stdout in electron browser NODE_ENV: test + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: cypress-component-${{ matrix.browser }}-${{ matrix.count }} + path: tests/cypress/screenshots + retention-days: 1 + if-no-files-found: error + cypress-component-rpc: name: Cypress component tests with RPC if: github.ref_name == 'main' @@ -88,6 +96,8 @@ jobs: with: name: cypress-rpc path: tests/cypress/screenshots + retention-days: 1 + if-no-files-found: error cypress-e2e: strategy: @@ -98,7 +108,7 @@ jobs: include: - browser: chrome count: 2 - name: Cypress in ${{ matrix.browser }} ${{ matrix.count }} + name: Cypress e2e tests in ${{ matrix.browser }} ${{ matrix.count }} timeout-minutes: 15 runs-on: ubuntu-latest steps: @@ -134,7 +144,7 @@ jobs: - uses: actions/upload-artifact@v4 if: failure() with: - name: cypress-main-${{ matrix.browser }}-${{ matrix.count }} + name: cypress-e2e-${{ matrix.browser }}-${{ matrix.count }} path: tests/cypress/screenshots retention-days: 1 if-no-files-found: error diff --git a/apps/main/src/dao/components/Charts/GaugeWeightHistoryChart/index.tsx b/apps/main/src/dao/components/Charts/GaugeWeightHistoryChart/index.tsx index d811073e45..c6e491666d 100644 --- a/apps/main/src/dao/components/Charts/GaugeWeightHistoryChart/index.tsx +++ b/apps/main/src/dao/components/Charts/GaugeWeightHistoryChart/index.tsx @@ -5,6 +5,7 @@ import ErrorMessage from '@/dao/components/ErrorMessage' import useStore from '@/dao/store/useStore' import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' interface GaugeWeightHistoryChartProps { gaugeAddress: string @@ -21,7 +22,7 @@ const GaugeWeightHistoryChart = ({ gaugeAddress, minHeight }: GaugeWeightHistory useEffect(() => { if (!gaugeWeightHistoryMapper[gaugeAddress]) { - void getHistoricGaugeWeights(gaugeAddress) + getHistoricGaugeWeights(gaugeAddress).catch(errorFallback) } }, [gaugeAddress, gaugeWeightHistoryMapper, getHistoricGaugeWeights]) @@ -33,7 +34,7 @@ const GaugeWeightHistoryChart = ({ gaugeAddress, minHeight }: GaugeWeightHistory message={t`Error fetching historical gauge weights data`} onClick={(e?: MouseEvent) => { e?.stopPropagation() - void getHistoricGaugeWeights(gaugeAddress) + getHistoricGaugeWeights(gaugeAddress).catch(errorFallback) }} /> diff --git a/apps/main/src/dao/components/PageAnalytics/DailyLocksChart/index.tsx b/apps/main/src/dao/components/PageAnalytics/DailyLocksChart/index.tsx index 4fe8ab0aa1..190520f82f 100644 --- a/apps/main/src/dao/components/PageAnalytics/DailyLocksChart/index.tsx +++ b/apps/main/src/dao/components/PageAnalytics/DailyLocksChart/index.tsx @@ -4,6 +4,7 @@ import ErrorMessage from '@/dao/components/ErrorMessage' import useStore from '@/dao/store/useStore' import Box from '@ui/Box' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import Spinner from '../../Spinner' import PositiveAndNegativeBarChart from './PositiveAndNegativeBarChart' @@ -17,7 +18,7 @@ const DailyLocks = () => { useEffect(() => { if (veCrvLocks.locks.length === 0 && veCrvLocks.fetchStatus !== 'ERROR') { - void getVeCrvLocks() + getVeCrvLocks().catch(errorFallback) } }, [getVeCrvLocks, veCrvLocks.locks.length, veCrvLocks.fetchStatus]) diff --git a/apps/main/src/dao/components/PageAnalytics/VeCrvFeesTable/index.tsx b/apps/main/src/dao/components/PageAnalytics/VeCrvFeesTable/index.tsx index 9cda510769..ae8128e746 100644 --- a/apps/main/src/dao/components/PageAnalytics/VeCrvFeesTable/index.tsx +++ b/apps/main/src/dao/components/PageAnalytics/VeCrvFeesTable/index.tsx @@ -5,6 +5,7 @@ import useStore from '@/dao/store/useStore' import Box from '@ui/Box' import { formatDate, formatNumber } from '@ui/utils' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import Spinner from '../../Spinner' import VeCrvFeesChart from '../VeCrvFeesChart' @@ -18,7 +19,7 @@ const VeCrcFees = () => { useEffect(() => { if (veCrvFees.fees.length === 0 && !feesError) { - void getVeCrvFees() + getVeCrvFees().catch(errorFallback) } }, [getVeCrvFees, veCrvFees, feesError]) diff --git a/apps/main/src/dao/components/PageAnalytics/index.tsx b/apps/main/src/dao/components/PageAnalytics/index.tsx index a7c0bf8197..7ed997906c 100644 --- a/apps/main/src/dao/components/PageAnalytics/index.tsx +++ b/apps/main/src/dao/components/PageAnalytics/index.tsx @@ -4,6 +4,7 @@ import useStore from '@/dao/store/useStore' import Box from '@ui/Box' import { t } from '@ui-kit/lib/i18n' import { TabsSwitcher, type TabOption } from '@ui-kit/shared/ui/TabsSwitcher' +import { errorFallback } from '@ui-kit/utils/error.util' import CrvStats from './CrvStats' import DailyLocks from './DailyLocksChart' import HoldersTable from './HoldersTable' @@ -24,7 +25,7 @@ const Analytics = () => { useEffect(() => { if (veCrvHolders.topHolders.length === 0 && veCrvHolders.fetchStatus !== 'ERROR') { - void getVeCrvHolders() + getVeCrvHolders().catch(errorFallback) } }, [getVeCrvHolders, veCrvHolders.topHolders.length, veCrvHolders.fetchStatus]) diff --git a/apps/main/src/dao/components/PageGauge/GaugeVotesTable/index.tsx b/apps/main/src/dao/components/PageGauge/GaugeVotesTable/index.tsx index 31a17bc8be..4967ebeaf4 100644 --- a/apps/main/src/dao/components/PageGauge/GaugeVotesTable/index.tsx +++ b/apps/main/src/dao/components/PageGauge/GaugeVotesTable/index.tsx @@ -9,6 +9,7 @@ import { formatLocaleDate } from '@ui/utils/' import { t } from '@ui-kit/lib/i18n' import { DAO_ROUTES } from '@ui-kit/shared/routes' import { shortenAddress } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' import { GAUGE_VOTES_TABLE_LABELS } from './constants' interface GaugeVotesTableProps { @@ -40,7 +41,7 @@ const GaugeVotesTable = ({ gaugeAddress, tableMinWidth }: GaugeVotesTableProps) // Get user proposal votes useEffect(() => { if (!gaugeVotesMapper[gaugeAddress] && gaugeVotesLoading && !gaugeVotesError) { - void getGaugeVotes(gaugeAddress) + getGaugeVotes(gaugeAddress).catch(errorFallback) } }, [getGaugeVotes, gaugeAddress, gaugeVotesLoading, gaugeVotesError, gaugeVotesMapper]) diff --git a/apps/main/src/dao/components/PageGauges/GaugeListItem/SmallScreenCard.tsx b/apps/main/src/dao/components/PageGauges/GaugeListItem/SmallScreenCard.tsx index 9368bf275e..bf91e46a37 100644 --- a/apps/main/src/dao/components/PageGauges/GaugeListItem/SmallScreenCard.tsx +++ b/apps/main/src/dao/components/PageGauges/GaugeListItem/SmallScreenCard.tsx @@ -12,6 +12,7 @@ import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { t } from '@ui-kit/lib/i18n' import { DAO_ROUTES } from '@ui-kit/shared/routes' import { formatNumber } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' import VoteGaugeField from '../GaugeVoting/VoteGaugeField' import GaugeDetailsSm from './GaugeDetailsSm' import TitleComp from './TitleComp' @@ -45,7 +46,7 @@ const SmallScreenCard = ({ useEffect(() => { if (open && !gaugeWeightHistoryMapper[gaugeData.address]) { - void getHistoricGaugeWeights(gaugeData.address) + getHistoricGaugeWeights(gaugeData.address).catch(errorFallback) } }, [gaugeData.address, gaugeWeightHistoryMapper, getHistoricGaugeWeights, open]) @@ -115,7 +116,7 @@ const SmallScreenCard = ({ message={t`Error fetching historical gauge weights data`} onClick={(e?: MouseEvent) => { e?.stopPropagation() - void getHistoricGaugeWeights(gaugeData.address) + getHistoricGaugeWeights(gaugeData.address).catch(errorFallback) }} /> diff --git a/apps/main/src/dao/components/PageGauges/GaugeListItem/index.tsx b/apps/main/src/dao/components/PageGauges/GaugeListItem/index.tsx index a4c0f4244b..bc4dd9d84a 100644 --- a/apps/main/src/dao/components/PageGauges/GaugeListItem/index.tsx +++ b/apps/main/src/dao/components/PageGauges/GaugeListItem/index.tsx @@ -19,6 +19,7 @@ import IconButton from '@ui/IconButton' import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { t } from '@ui-kit/lib/i18n' import { DAO_ROUTES } from '@ui-kit/shared/routes' +import { errorFallback } from '@ui-kit/utils/error.util' import { Chain } from '@ui-kit/utils/network' type Props = { @@ -69,7 +70,7 @@ const GaugeListItem = ({ useEffect(() => { if (open && !gaugeWeightHistoryMapper[gaugeData.address]) { - void getHistoricGaugeWeights(gaugeData.address) + getHistoricGaugeWeights(gaugeData.address).catch(errorFallback) } }, [gaugeData.address, gaugeWeightHistoryMapper, getHistoricGaugeWeights, open]) @@ -113,7 +114,7 @@ const GaugeListItem = ({ message={t`Error fetching historical gauge weights data`} onClick={(e?: MouseEvent) => { e?.stopPropagation() - void getHistoricGaugeWeights(gaugeData.address) + getHistoricGaugeWeights(gaugeData.address).catch(errorFallback) }} /> diff --git a/apps/main/src/dao/components/PageGauges/GaugeVoting/VoteGaugeField/index.tsx b/apps/main/src/dao/components/PageGauges/GaugeVoting/VoteGaugeField/index.tsx index ba5fdfcdb0..aa2e3501c7 100644 --- a/apps/main/src/dao/components/PageGauges/GaugeVoting/VoteGaugeField/index.tsx +++ b/apps/main/src/dao/components/PageGauges/GaugeVoting/VoteGaugeField/index.tsx @@ -9,6 +9,7 @@ import Button from '@ui/Button' import TooltipIcon from '@ui/Tooltip/TooltipIcon' import { convertToLocaleTimestamp, formatDate, formatNumber } from '@ui/utils' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import { Chain } from '@ui-kit/utils/network' import NumberField from './NumberField' @@ -49,7 +50,7 @@ const VoteGaugeField = ({ powerUsed, userGaugeVoteData, userVeCrv, newVote = fal const handleCastVote = () => { if (!address) return - void castVote(address, gaugeAddress, power) + castVote(address, gaugeAddress, power).catch(errorFallback) } return ( diff --git a/apps/main/src/dao/components/PageProposal/index.tsx b/apps/main/src/dao/components/PageProposal/index.tsx index f7b6ae8cc9..08a7c04fe2 100644 --- a/apps/main/src/dao/components/PageProposal/index.tsx +++ b/apps/main/src/dao/components/PageProposal/index.tsx @@ -19,6 +19,7 @@ import { useWallet } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' import { DAO_ROUTES } from '@ui-kit/shared/routes' import { copyToClipboard } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' import BackButton from '../BackButton' import ProposalVoteStatusBox from '../ProposalVoteStatusBox' import UserBox from '../UserBox' @@ -72,7 +73,7 @@ export const Proposal = ({ proposalId: rProposalId, network }: ProposalUrlParams setSnapshotVeCrv(signer, userAddress, proposal.block, rProposalId) } - void getVeCrv() + getVeCrv().catch(errorFallback) } }, [provider, rChainId, rProposalId, setSnapshotVeCrv, proposal?.block, snapshotVeCrv, userAddress]) diff --git a/apps/main/src/dao/components/PageUser/index.tsx b/apps/main/src/dao/components/PageUser/index.tsx index e34ccf4e01..18908ecb8c 100644 --- a/apps/main/src/dao/components/PageUser/index.tsx +++ b/apps/main/src/dao/components/PageUser/index.tsx @@ -7,6 +7,7 @@ import Box from '@ui/Box' import { useWallet } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' import { TabsSwitcher, type TabOption } from '@ui-kit/shared/ui/TabsSwitcher' +import { errorFallback } from '@ui-kit/utils/error.util' import UserGaugeVotesTable from './UserGaugeVotesTable' import UserHeader from './UserHeader' import UserLocksTable from './UserLocksTable' @@ -51,14 +52,14 @@ const UserPage = ({ routerParams: { userAddress: rUserAddress } }: UserPageProps useEffect(() => { if (Object.keys(allHolders).length === 0 && holdersLoading && !holdersError) { - void getVeCrvHolders() + getVeCrvHolders().catch(errorFallback) } }, [getVeCrvHolders, allHolders, holdersLoading, holdersError]) // Get user ENS useEffect(() => { if (!userMapper[userAddress] && provider) { - void getUserEns(userAddress) + getUserEns(userAddress).catch(errorFallback) } }, [getUserEns, userAddress, userMapper, provider]) diff --git a/apps/main/src/dao/components/PageVeCrv/components/FormLockCreate.tsx b/apps/main/src/dao/components/PageVeCrv/components/FormLockCreate.tsx index a8a40098c9..6a12618353 100644 --- a/apps/main/src/dao/components/PageVeCrv/components/FormLockCreate.tsx +++ b/apps/main/src/dao/components/PageVeCrv/components/FormLockCreate.tsx @@ -22,6 +22,8 @@ import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import dayjs from '@ui-kit/lib/dayjs' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const isSubscribed = useRef(false) @@ -34,7 +36,7 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => const formValues = useStore((state) => state.lockedCrv.formValues) const fetchStepApprove = useStore((state) => state.lockedCrv.fetchStepApprove) const fetchStepCreate = useStore((state) => state.lockedCrv.fetchStepCreate) - const setFormValues = useStore((state) => state.lockedCrv.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.lockedCrv.setFormValues)) const [steps, setSteps] = useState([]) const [txInfoBar, setTxInfoBar] = useState(null) @@ -46,9 +48,9 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => const maxUtcDate = dayjs.utc().add(4, 'year') const updateFormValues = useCallback( - (updatedFormValues: Partial, isFullReset?: boolean) => { + async (updatedFormValues: Partial, isFullReset?: boolean) => { setTxInfoBar(null) - setFormValues(curve, isLoadingCurve, rFormType, updatedFormValues, vecrvInfo, isFullReset) + await setFormValues(curve, isLoadingCurve, rFormType, updatedFormValues, vecrvInfo, isFullReset) }, [curve, isLoadingCurve, vecrvInfo, rFormType, setFormValues], ) @@ -75,7 +77,7 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => days, }, false, - ) + ).catch(errorFallback) }, [currUtcDate, haveSigner, maxUtcDate, minUtcDate, rChainId, updateFormValues], ) @@ -87,7 +89,10 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => if (!value || !unit) { const days = maxUtcDate.diff(currUtcDate, 'd') const calcdUtcDate = calcUnlockTime(curve, 'create', null, days) - updateFormValues({ utcDate: toCalendarDate(calcdUtcDate), utcDateError: '', days, calcdUtcDate: '' }, false) + updateFormValues( + { utcDate: toCalendarDate(calcdUtcDate), utcDateError: '', days, calcdUtcDate: '' }, + false, + ).catch(errorFallback) return maxUtcDate } @@ -95,7 +100,10 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => const days = utcDate.diff(currUtcDate, 'd') const calcdUtcDate = calcUnlockTime(curve, 'create', null, days) - updateFormValues({ utcDate: toCalendarDate(calcdUtcDate), utcDateError: '', days, calcdUtcDate: '' }, false) + updateFormValues( + { utcDate: toCalendarDate(calcdUtcDate), utcDateError: '', days, calcdUtcDate: '' }, + false, + ).catch(errorFallback) return utcDate }, [currUtcDate, maxUtcDate, rChainId, updateFormValues], @@ -185,7 +193,7 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => // onMount useEffect(() => { isSubscribed.current = true - updateFormValues({}, true) + updateFormValues({}, true).catch(errorFallback) return () => { isSubscribed.current = false @@ -223,7 +231,10 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => haveSigner={haveSigner} formType={rFormType} vecrvInfo={vecrvInfo} - handleInpLockedAmt={useCallback((lockedAmt) => updateFormValues({ lockedAmt }, false), [updateFormValues])} + handleInpLockedAmt={useCallback( + (lockedAmt) => updateFormValues({ lockedAmt }, false).catch(errorFallback), + [updateFormValues], + )} {...formValues} /> @@ -254,7 +265,10 @@ const FormLockCreate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => {formStatus.error && ( - updateFormValues({}, false)} /> + updateFormValues({}, false).catch(errorFallback)} + /> )} {txInfoBar} diff --git a/apps/main/src/dao/components/PageVeCrv/components/FormLockCrv.tsx b/apps/main/src/dao/components/PageVeCrv/components/FormLockCrv.tsx index 7e41c9bb0b..5cde0cc38d 100644 --- a/apps/main/src/dao/components/PageVeCrv/components/FormLockCrv.tsx +++ b/apps/main/src/dao/components/PageVeCrv/components/FormLockCrv.tsx @@ -17,6 +17,8 @@ import { type CurveApi, isLoading, notify, useConnection } from '@ui-kit/feature import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const FormLockCrv = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const isSubscribed = useRef(false) @@ -29,7 +31,7 @@ const FormLockCrv = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const formValues = useStore((state) => state.lockedCrv.formValues) const fetchStepApprove = useStore((state) => state.lockedCrv.fetchStepApprove) const fetchStepIncreaseCrv = useStore((state) => state.lockedCrv.fetchStepIncreaseCrv) - const setFormValues = useStore((state) => state.lockedCrv.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.lockedCrv.setFormValues)) const [steps, setSteps] = useState([]) const [txInfoBar, setTxInfoBar] = useState(null) @@ -38,9 +40,9 @@ const FormLockCrv = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const haveSigner = !!signerAddress const updateFormValues = useCallback( - (updatedFormValues: Partial, isFullReset?: boolean) => { + async (updatedFormValues: Partial, isFullReset?: boolean) => { setTxInfoBar(null) - setFormValues(curve, isLoadingCurve, rFormType, updatedFormValues, vecrvInfo, isFullReset) + await setFormValues(curve, isLoadingCurve, rFormType, updatedFormValues, vecrvInfo, isFullReset) }, [curve, isLoadingCurve, vecrvInfo, rFormType, setFormValues], ) @@ -119,7 +121,7 @@ const FormLockCrv = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { // onMount useEffect(() => { isSubscribed.current = true - updateFormValues({}, true) + updateFormValues({}, true).catch(errorFallback) return () => { isSubscribed.current = false @@ -155,7 +157,10 @@ const FormLockCrv = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { haveSigner={haveSigner} formType={rFormType} vecrvInfo={vecrvInfo} - handleInpLockedAmt={useCallback((lockedAmt) => updateFormValues({ lockedAmt }), [updateFormValues])} + handleInpLockedAmt={useCallback( + (lockedAmt) => updateFormValues({ lockedAmt }).catch(errorFallback), + [updateFormValues], + )} {...formValues} /> @@ -172,7 +177,10 @@ const FormLockCrv = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { {formStatus.error && ( - updateFormValues({}, false)} /> + updateFormValues({}, false).catch(errorFallback)} + /> )} {txInfoBar} diff --git a/apps/main/src/dao/components/PageVeCrv/components/FormLockDate.tsx b/apps/main/src/dao/components/PageVeCrv/components/FormLockDate.tsx index c8b70f1406..67318017d4 100644 --- a/apps/main/src/dao/components/PageVeCrv/components/FormLockDate.tsx +++ b/apps/main/src/dao/components/PageVeCrv/components/FormLockDate.tsx @@ -22,6 +22,8 @@ import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import dayjs from '@ui-kit/lib/dayjs' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const isSubscribed = useRef(false) @@ -33,7 +35,7 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const formStatus = useStore((state) => state.lockedCrv.formStatus) const formValues = useStore((state) => state.lockedCrv.formValues) const fetchStepIncreaseTime = useStore((state) => state.lockedCrv.fetchStepIncreaseTime) - const setFormValues = useStore((state) => state.lockedCrv.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.lockedCrv.setFormValues)) const [steps, setSteps] = useState([]) const [txInfoBar, setTxInfoBar] = useState(null) @@ -58,7 +60,7 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const updateFormValues = useCallback( async (updatedFormValues: Partial, isFullReset?: boolean) => { setTxInfoBar(null) - setFormValues(curve, isLoadingCurve, rFormType, updatedFormValues, vecrvInfo, isFullReset) + await setFormValues(curve, isLoadingCurve, rFormType, updatedFormValues, vecrvInfo, isFullReset) }, [curve, isLoadingCurve, vecrvInfo, rFormType, setFormValues], ) @@ -77,7 +79,7 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const fn = networks[rChainId].api.lockCrv.calcUnlockTime const calcdUtcDate = fn(curve, rFormType, currUnlockTime, days) - void updateFormValues( + updateFormValues( { utcDate: toCalendarDate(utcDate), utcDateError, @@ -86,7 +88,7 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { days, }, false, - ) + ).catch(errorFallback) }, [currUnlockTime, currUnlockUtcTime, haveSigner, maxUtcDate, minUtcDate, rChainId, rFormType, updateFormValues], ) @@ -98,10 +100,10 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { if (!value || !unit) { const days = maxUtcDate.diff(currUnlockUtcTime, 'd') const calcdUtcDate = calcUnlockTime(curve, rFormType, currUnlockTime, days) - void updateFormValues( + updateFormValues( { utcDate: toCalendarDate(calcdUtcDate), utcDateError: '', days, calcdUtcDate: '' }, false, - ) + ).catch(errorFallback) return maxUtcDate } @@ -109,7 +111,10 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { const days = utcDate.diff(currUnlockUtcTime, 'd') const calcdUtcDate = calcUnlockTime(curve, rFormType, currUnlockTime, days) - void updateFormValues({ utcDate: toCalendarDate(calcdUtcDate), calcdUtcDate: '', utcDateError: '', days }, false) + updateFormValues( + { utcDate: toCalendarDate(calcdUtcDate), calcdUtcDate: '', utcDateError: '', days }, + false, + ).catch(errorFallback) return calcdUtcDate }, [currUnlockTime, currUnlockUtcTime, maxUtcDate, rChainId, rFormType, updateFormValues], @@ -160,7 +165,7 @@ const FormLockDate = ({ curve, rChainId, rFormType, vecrvInfo }: PageVecrv) => { // onMount useEffect(() => { isSubscribed.current = true - void updateFormValues({}, true) + updateFormValues({}, true).catch(errorFallback) return () => { isSubscribed.current = false diff --git a/apps/main/src/dao/store/createLockedCrvSlice.ts b/apps/main/src/dao/store/createLockedCrvSlice.ts index 40d66982e5..455c9ff60c 100644 --- a/apps/main/src/dao/store/createLockedCrvSlice.ts +++ b/apps/main/src/dao/store/createLockedCrvSlice.ts @@ -19,6 +19,7 @@ import { getErrorMessage } from '@/dao/utils' import { shortenAccount } from '@ui/utils' import { notify, requireLib, useWallet } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -113,7 +114,7 @@ const createLockedCrvSlice = (set: StoreApi['setState'], get: StoreApi { if (usdRate == null) { - void fetchTokenUsdRate({ chainId, tokenAddress }).then(setUsdRate) + fetchTokenUsdRate({ chainId, tokenAddress }).then(setUsdRate).catch(errorFallback) } }, [usdRate, chainId, tokenAddress]) diff --git a/apps/main/src/dex/components/PageCompensation/Page.tsx b/apps/main/src/dex/components/PageCompensation/Page.tsx index 896c68f024..9a1cc4dfb3 100644 --- a/apps/main/src/dex/components/PageCompensation/Page.tsx +++ b/apps/main/src/dex/components/PageCompensation/Page.tsx @@ -14,6 +14,7 @@ import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { isLoading, useConnection, useWallet } from '@ui-kit/features/connect-wallet' import { useParams } from '@ui-kit/hooks/router' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' export const PageCompensation = () => { const { network } = useParams() @@ -38,7 +39,7 @@ export const PageCompensation = () => { // get initial data useEffect(() => { if (!isConnecting && provider) { - void fetchData(provider) + fetchData(provider).catch(errorFallback) } }, [fetchData, isConnecting, provider]) diff --git a/apps/main/src/dex/components/PageCompensation/index.tsx b/apps/main/src/dex/components/PageCompensation/index.tsx index d4f6b389b9..511ab6f2d6 100644 --- a/apps/main/src/dex/components/PageCompensation/index.tsx +++ b/apps/main/src/dex/components/PageCompensation/index.tsx @@ -7,6 +7,7 @@ import type { Balances, EtherContract, VestedTotals } from '@/dex/components/Pag import { CurveApi, ChainId, Provider } from '@/dex/types/main.types' import { getErrorMessage } from '@/dex/utils' import Box from '@ui/Box' +import { errorFallback } from '@ui-kit/utils/error.util' const FormCompensation = ({ rChainId, @@ -98,8 +99,8 @@ const FormCompensation = ({ setVestedTotals({}) if (signerAddress) { - void getBalances(signerAddress, contracts) - void getVestContract(signerAddress, contracts) + getBalances(signerAddress, contracts).catch(errorFallback) + getVestContract(signerAddress, contracts).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [signerAddress]) diff --git a/apps/main/src/dex/components/PageCreatePool/TokensInPool/SelectTokenButton.tsx b/apps/main/src/dex/components/PageCreatePool/TokensInPool/SelectTokenButton.tsx index fbdedf323c..027c11e257 100644 --- a/apps/main/src/dex/components/PageCreatePool/TokensInPool/SelectTokenButton.tsx +++ b/apps/main/src/dex/components/PageCreatePool/TokensInPool/SelectTokenButton.tsx @@ -19,6 +19,7 @@ import { useIsMobile } from '@ui-kit/hooks/useBreakpoints' import { t } from '@ui-kit/lib/i18n' import { TokenIcon } from '@ui-kit/shared/ui/TokenIcon' import { type Address, filterTokens, shortenAddress } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' type Props = { curve: CurveApi @@ -119,7 +120,7 @@ const SelectTokenButton = ({ } } } - void updateUserAddedToken() + updateUserAddedToken().catch(errorFallback) }, [basePools, chainId, curve, filterValue, options, updateUserAddedTokens, userAddedTokens]) const selectedToken = useMemo( diff --git a/apps/main/src/dex/components/PageDashboard/components/FormVecrv.tsx b/apps/main/src/dex/components/PageDashboard/components/FormVecrv.tsx index 4fa1dca601..5a61a71af5 100644 --- a/apps/main/src/dex/components/PageDashboard/components/FormVecrv.tsx +++ b/apps/main/src/dex/components/PageDashboard/components/FormVecrv.tsx @@ -25,6 +25,7 @@ import { notify } from '@ui-kit/features/connect-wallet' import { t, Trans } from '@ui-kit/lib/i18n' import { DAO_ROUTES } from '@ui-kit/shared/routes' import { getInternalUrl } from '@ui-kit/shared/routes' +import { errorFallback } from '@ui-kit/utils/error.util' import { Chain } from '@ui-kit/utils/network' // TODO uncomment locker link code once it is ready @@ -95,7 +96,7 @@ const FormVecrv = () => { type: 'action', content: formStatus.formTypeCompleted ? t`Withdraw CRV Complete` : t`Withdraw CRV`, onClick: () => { - if (curve) void handleBtnClickWithdraw(activeKey, curve, lockedAmount) + if (curve) handleBtnClickWithdraw(activeKey, curve, lockedAmount).catch(errorFallback) }, }, } @@ -148,7 +149,7 @@ const FormVecrv = () => { disabled={!curve} variant="filled" onClick={() => { - if (curve) void handleBtnClickWithdraw(activeKey, curve, lockedAmount) + if (curve) handleBtnClickWithdraw(activeKey, curve, lockedAmount).catch(errorFallback) }} size="medium" > diff --git a/apps/main/src/dex/components/PageDashboard/components/TableCellRewardsTooltip.tsx b/apps/main/src/dex/components/PageDashboard/components/TableCellRewardsTooltip.tsx index 3a01c81fa1..15887f2711 100644 --- a/apps/main/src/dex/components/PageDashboard/components/TableCellRewardsTooltip.tsx +++ b/apps/main/src/dex/components/PageDashboard/components/TableCellRewardsTooltip.tsx @@ -5,6 +5,7 @@ import { RewardCrv } from '@/dex/types/main.types' import { rewardsApyCrvText } from '@/dex/utils/utilsCurvejs' import Box from '@ui/Box' import { FORMAT_OPTIONS, formatNumber } from '@ui/utils' +import { errorFallback } from '@ui-kit/utils/error.util' type Props = { crv?: RewardCrv[] @@ -18,13 +19,13 @@ const TableCellRewardsTooltip = ({ crv = [], userCrvApy, fetchUserPoolBoost }: P useEffect(() => { isSubscribed.current = true - void (async () => { + ;(async () => { const fetchedBoosted = await fetchUserPoolBoost() if (isSubscribed.current) { setBoost(fetchedBoosted) } - })() + })().catch(errorFallback) return () => { isSubscribed.current = false diff --git a/apps/main/src/dex/components/PageDashboard/components/TableHead.tsx b/apps/main/src/dex/components/PageDashboard/components/TableHead.tsx index 8e4f6681b0..7105f4b85b 100644 --- a/apps/main/src/dex/components/PageDashboard/components/TableHead.tsx +++ b/apps/main/src/dex/components/PageDashboard/components/TableHead.tsx @@ -8,12 +8,13 @@ import type { TheadSortButtonProps } from '@ui/Table/TheadSortButton' import IconTooltip from '@ui/Tooltip/TooltipIcon' import { breakpoints } from '@ui/utils' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const TableHead = ({ tableLabel }: { tableLabel: TableLabel }) => { const { isLite, isLoading, formValues, updateFormValues } = useDashboardContext() const handleBtnClickSort = (sortBy: string, sortByOrder: Order) => { - updateFormValues({ sortBy: sortBy as SORT_ID, sortByOrder: sortByOrder as Order }) + updateFormValues({ sortBy: sortBy as SORT_ID, sortByOrder: sortByOrder as Order }).catch(errorFallback) } const props: Omit, 'sortIdKey'> = { diff --git a/apps/main/src/dex/components/PageDashboard/components/TableSortDialog.tsx b/apps/main/src/dex/components/PageDashboard/components/TableSortDialog.tsx index 951eb1f86c..aec73fcb02 100644 --- a/apps/main/src/dex/components/PageDashboard/components/TableSortDialog.tsx +++ b/apps/main/src/dex/components/PageDashboard/components/TableSortDialog.tsx @@ -8,6 +8,7 @@ import OpenDialogButton from '@ui/Dialog/OpenDialogButton' import Icon from '@ui/Icon' import { Radio, RadioGroup } from '@ui/Radio' import { Chip } from '@ui/Typography' +import { errorFallback } from '@ui-kit/utils/error.util' const sortOrder = { asc: { label: 'Ascending', icon: }, @@ -29,7 +30,7 @@ const TableSortDialog = ({ className = '', tableLabel }: Props) => { const handleRadioGroupChange = (val: string) => { const [sortBy, sortByOrder] = val.split('-') - updateFormValues({ sortBy: sortBy as SortId, sortByOrder: sortByOrder as Order }) + updateFormValues({ sortBy: sortBy as SortId, sortByOrder: sortByOrder as Order }).catch(errorFallback) overlayTriggerState.close() } diff --git a/apps/main/src/dex/components/PageDashboard/dashboardContext.ts b/apps/main/src/dex/components/PageDashboard/dashboardContext.ts index 2f2ead4e3c..2d549240dc 100644 --- a/apps/main/src/dex/components/PageDashboard/dashboardContext.ts +++ b/apps/main/src/dex/components/PageDashboard/dashboardContext.ts @@ -14,7 +14,7 @@ type DashboardContextType = { isValidAddress: boolean dashboardDataPoolIds: string[] | undefined dashboardDataMapper: DashboardDataMapper | undefined - updateFormValues: (updatedFormValues: Partial) => void + updateFormValues: (updatedFormValues: Partial) => Promise } export const DashboardContext = createContext(null) diff --git a/apps/main/src/dex/components/PageDashboard/index.tsx b/apps/main/src/dex/components/PageDashboard/index.tsx index 5aca073045..888935db0b 100644 --- a/apps/main/src/dex/components/PageDashboard/index.tsx +++ b/apps/main/src/dex/components/PageDashboard/index.tsx @@ -25,6 +25,7 @@ import { breakpoints } from '@ui/utils' import { useLayoutStore } from '@ui-kit/features/layout' import { useNavigate } from '@ui-kit/hooks/router' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const Dashboard = ({ curve, @@ -74,9 +75,8 @@ const Dashboard = ({ } const updateFormValues = useCallback( - (updatedFormValues: Partial) => { - setFormValues(rChainId, !pageLoaded ? null : curve, poolsMapper, updatedFormValues) - }, + async (updatedFormValues: Partial) => + setFormValues(rChainId, !pageLoaded ? null : curve, poolsMapper, updatedFormValues), [curve, pageLoaded, poolsMapper, rChainId, setFormValues], ) @@ -91,14 +91,14 @@ const Dashboard = ({ // curvejs change useEffect(() => { - updateFormValues({}) + updateFormValues({}).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, !pageLoaded, haveAllPools, poolsMapper]) // signerAddress useEffect(() => { if (signerAddress) { - updateFormValues({ walletAddress: signerAddress }) + updateFormValues({ walletAddress: signerAddress }).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [signerAddress]) diff --git a/apps/main/src/dex/components/PageIntegrations/Page.tsx b/apps/main/src/dex/components/PageIntegrations/Page.tsx index 610dca3c1b..415be88720 100644 --- a/apps/main/src/dex/components/PageIntegrations/Page.tsx +++ b/apps/main/src/dex/components/PageIntegrations/Page.tsx @@ -9,6 +9,7 @@ import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { breakpoints } from '@ui/utils/responsive' import { useParams } from '@ui-kit/hooks/router' import { Trans } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const Page = () => { const { network } = useParams() @@ -17,7 +18,7 @@ const Page = () => { const integrationsTags = useStore((state) => state.integrations.integrationsTags) useEffect(() => { - void init(rChainId) + init(rChainId).catch(errorFallback) }, [init, rChainId]) return ( diff --git a/apps/main/src/dex/components/PagePool/Deposit/components/FieldsDeposit.tsx b/apps/main/src/dex/components/PagePool/Deposit/components/FieldsDeposit.tsx index 1e33b6c262..04ea4908cb 100644 --- a/apps/main/src/dex/components/PagePool/Deposit/components/FieldsDeposit.tsx +++ b/apps/main/src/dex/components/PagePool/Deposit/components/FieldsDeposit.tsx @@ -11,6 +11,7 @@ import type { CurrencyReserves } from '@/dex/types/main.types' import { getChainPoolIdActiveKey } from '@/dex/utils' import Checkbox from '@ui/Checkbox' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import { Amount } from '../../utils' /** @@ -74,7 +75,7 @@ const FieldsDeposit = ({ updatedFormValues: Partial, loadMaxAmount: LoadMaxAmount | null, updatedMaxSlippage: string | null, - ) => void + ) => Promise } & Pick) => { const { data: network } = useNetworkByChain({ chainId: rChainId }) const balancesLoading = useStore((state) => state.user.walletBalancesLoading) @@ -102,7 +103,7 @@ const FieldsDeposit = ({ }, null, null, - ) + ).catch(errorFallback) }, [updateFormValues, isBalancedAmounts, reserves, poolDataCacheOrApi.tokenAddresses], ) @@ -123,7 +124,7 @@ const FieldsDeposit = ({ const afterMaxClick = useCallback( (idx: number) => { const tokenAddress = poolDataCacheOrApi.tokenAddresses[idx] - updateFormValues({ isBalancedAmounts: false }, { tokenAddress, idx }, null) + updateFormValues({ isBalancedAmounts: false }, { tokenAddress, idx }, null).catch(errorFallback) }, [poolDataCacheOrApi.tokenAddresses, updateFormValues], ) @@ -166,7 +167,9 @@ const FieldsDeposit = ({ isDisabled={isDisabled} isSelected={!!formValues.isBalancedAmounts} onChange={(isBalancedAmounts) => - updateFormValues({ isBalancedAmounts: isBalancedAmounts ? 'by-wallet' : false }, null, null) + updateFormValues({ isBalancedAmounts: isBalancedAmounts ? 'by-wallet' : false }, null, null).catch( + errorFallback, + ) } > {t`Add all coins in a balanced proportion`} @@ -190,7 +193,7 @@ const FieldsDeposit = ({ tokenAddress: wrapped.tokenAddresses[idx], value: '', })) - updateFormValues(cFormValues, null, null) + updateFormValues(cFormValues, null, null).catch(errorFallback) } }} > diff --git a/apps/main/src/dex/components/PagePool/Deposit/components/FormDeposit.tsx b/apps/main/src/dex/components/PagePool/Deposit/components/FormDeposit.tsx index 563f47e5b0..4bddf2d7eb 100644 --- a/apps/main/src/dex/components/PagePool/Deposit/components/FormDeposit.tsx +++ b/apps/main/src/dex/components/PagePool/Deposit/components/FormDeposit.tsx @@ -28,6 +28,7 @@ import TxInfoBar from '@ui/TxInfoBar' import { scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const FormDeposit = ({ chainIdPoolId, @@ -68,14 +69,14 @@ const FormDeposit = ({ const haveSigner = !!signerAddress const updateFormValues = useCallback( - ( + async ( updatedFormValues: Partial, loadMaxAmount: LoadMaxAmount | null, updatedMaxSlippage: string | null, ) => { setTxInfoBar(null) setSlippageConfirmed(false) - void setFormValues( + await setFormValues( 'DEPOSIT', curve, poolDataCacheOrApi.pool.id, @@ -206,7 +207,7 @@ const FormDeposit = ({ // curve state change useEffect(() => { if (chainId && poolId) { - updateFormValues({}, null, null) + updateFormValues({}, null, null).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, poolId, signerAddress, seed.isSeed]) @@ -214,7 +215,7 @@ const FormDeposit = ({ // max Slippage useEffect(() => { if (maxSlippage) { - updateFormValues({}, null, maxSlippage) + updateFormValues({}, null, maxSlippage).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -312,7 +313,10 @@ const FormDeposit = ({ > {formStatus.error && ( - updateFormValues({}, null, null)} /> + updateFormValues({}, null, null).catch(errorFallback)} + /> )} {txInfoBar} diff --git a/apps/main/src/dex/components/PagePool/Deposit/components/FormDepositStake.tsx b/apps/main/src/dex/components/PagePool/Deposit/components/FormDepositStake.tsx index de10456eaa..20f578145c 100644 --- a/apps/main/src/dex/components/PagePool/Deposit/components/FormDepositStake.tsx +++ b/apps/main/src/dex/components/PagePool/Deposit/components/FormDepositStake.tsx @@ -30,6 +30,7 @@ import TxInfoBar from '@ui/TxInfoBar' import { scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const FormDepositStake = ({ chainIdPoolId, @@ -71,14 +72,14 @@ const FormDepositStake = ({ const haveSigner = !!signerAddress const updateFormValues = useCallback( - ( + async ( updatedFormValues: Partial, loadMaxAmount: LoadMaxAmount | null, updatedMaxSlippage: string | null, ) => { setTxInfoBar(null) setSlippageConfirmed(false) - void setFormValues( + await setFormValues( 'DEPOSIT_STAKE', curve, poolDataCacheOrApi.pool.id, @@ -209,7 +210,7 @@ const FormDepositStake = ({ // curve state change useEffect(() => { if (chainId && poolId) { - updateFormValues({}, null, null) + updateFormValues({}, null, null).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, poolId, signerAddress, seed.isSeed]) @@ -217,7 +218,7 @@ const FormDepositStake = ({ // max Slippage useEffect(() => { if (maxSlippage) { - updateFormValues({}, null, maxSlippage) + updateFormValues({}, null, maxSlippage).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -312,7 +313,10 @@ const FormDepositStake = ({ > {formStatus.error && ( - updateFormValues({}, null, null)} /> + updateFormValues({}, null, null).catch(errorFallback)} + /> )} {txInfoBar} diff --git a/apps/main/src/dex/components/PagePool/Deposit/components/FormStake.tsx b/apps/main/src/dex/components/PagePool/Deposit/components/FormStake.tsx index 0edb8f24f6..5a36b7b8e5 100644 --- a/apps/main/src/dex/components/PagePool/Deposit/components/FormStake.tsx +++ b/apps/main/src/dex/components/PagePool/Deposit/components/FormStake.tsx @@ -21,6 +21,7 @@ import TxInfoBar from '@ui/TxInfoBar' import { scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const FormStake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, userPoolBalances }: TransferProps) => { const isSubscribed = useRef(false) @@ -47,9 +48,18 @@ const FormStake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us const haveSigner = !!signerAddress const updateFormValues = useCallback( - (updatedFormValues: Partial) => { + async (updatedFormValues: Partial) => { setTxInfoBar(null) - void setFormValues('STAKE', curve, poolDataCacheOrApi.pool.id, poolData, updatedFormValues, null, seed.isSeed, '') + await setFormValues( + 'STAKE', + curve, + poolDataCacheOrApi.pool.id, + poolData, + updatedFormValues, + null, + seed.isSeed, + '', + ) }, [curve, poolData, poolDataCacheOrApi.pool.id, seed.isSeed, setFormValues], ) @@ -141,7 +151,7 @@ const FormStake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us // curve state change useEffect(() => { if (chainId && poolId) { - updateFormValues({}) + updateFormValues({}).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, poolId, signerAddress, seed.isSeed]) @@ -169,7 +179,10 @@ const FormStake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us balanceLoading={balancesLoading} hasError={haveSigner ? new BigNumber(formValues.lpToken).isGreaterThan(balLpToken as string) : false} haveSigner={haveSigner} - handleAmountChange={useCallback((lpToken) => updateFormValues({ lpToken }), [updateFormValues])} + handleAmountChange={useCallback( + (lpToken) => updateFormValues({ lpToken }).catch(errorFallback), + [updateFormValues], + )} disabled={disableForm} /> @@ -200,9 +213,14 @@ const FormStake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us > {formStatus.error === 'lpToken-too-much' ? ( {t`Not enough LP Tokens balances.`} - ) : formStatus.error ? ( - updateFormValues({})} /> - ) : null} + ) : ( + formStatus.error && ( + updateFormValues({}).catch(errorFallback)} + /> + ) + )} {txInfoBar} diff --git a/apps/main/src/dex/components/PagePool/Page.tsx b/apps/main/src/dex/components/PagePool/Page.tsx index e5a0b76d97..0624e18689 100644 --- a/apps/main/src/dex/components/PagePool/Page.tsx +++ b/apps/main/src/dex/components/PagePool/Page.tsx @@ -8,6 +8,7 @@ import type { PoolUrlParams } from '@/dex/types/main.types' import { getPath } from '@/dex/utils/utilsRouter' import { useConnection } from '@ui-kit/features/connect-wallet' import { useNavigate, useParams } from '@ui-kit/hooks/router' +import { errorFallback } from '@ui-kit/utils/error.util' export const PagePool = () => { const push = useNavigate() @@ -35,12 +36,12 @@ export const PagePool = () => { return } if (!isHydrated && curveApi?.chainId === rChainId && haveAllPools && !poolData) { - void (async () => { + ;(async () => { const foundPoolData = await fetchNewPool(curveApi, rPoolId) if (!foundPoolData) { push(reRoutePathname) } - })() + })().catch(errorFallback) } }, [curveApi, fetchNewPool, haveAllPools, network, isHydrated, props, poolData, push, rChainId]) diff --git a/apps/main/src/dex/components/PagePool/PoolDetails/PoolStats/index.tsx b/apps/main/src/dex/components/PagePool/PoolDetails/PoolStats/index.tsx index b3cb6969ce..06c29a0283 100644 --- a/apps/main/src/dex/components/PagePool/PoolDetails/PoolStats/index.tsx +++ b/apps/main/src/dex/components/PagePool/PoolDetails/PoolStats/index.tsx @@ -15,6 +15,7 @@ import ExternalLink from '@ui/Link/ExternalLink' import { breakpoints } from '@ui/utils/responsive' import { useParams } from '@ui-kit/hooks/router' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' type PoolStatsProps = { poolAlert: PoolAlert | null @@ -32,7 +33,7 @@ const PoolStats = ({ curve, routerParams, poolAlert, poolData, poolDataCacheOrAp useEffect(() => { if (curve && poolData && !poolData?.parameters.virtualPrice) { - void fetchPoolStats(curve, poolData) + fetchPoolStats(curve, poolData).catch(errorFallback) } }, [curve, fetchPoolStats, poolData]) diff --git a/apps/main/src/dex/components/PagePool/Swap/index.tsx b/apps/main/src/dex/components/PagePool/Swap/index.tsx index 7bdc01b034..410b39815a 100644 --- a/apps/main/src/dex/components/PagePool/Swap/index.tsx +++ b/apps/main/src/dex/components/PagePool/Swap/index.tsx @@ -42,6 +42,8 @@ import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const { cloneDeep, isNaN, isUndefined } = lodash @@ -82,7 +84,7 @@ const Swap = ({ const fetchStepApprove = useStore((state) => state.poolSwap.fetchStepApprove) const fetchStepSwap = useStore((state) => state.poolSwap.fetchStepSwap) const resetState = useStore((state) => state.poolSwap.resetState) - const setFormValues = useStore((state) => state.poolSwap.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.poolSwap.setFormValues)) const setPoolIsWrapped = useStore((state) => state.pools.setPoolIsWrapped) const { data: networks } = useNetworks() const network = (chainId && networks[chainId]) || null @@ -120,11 +122,11 @@ const Swap = ({ const toToken = selectList.find((x) => x.address.toLocaleLowerCase() == formValues.toAddress) const updateFormValues = useCallback( - (updatedFormValues: Partial, isGetMaxFrom: boolean | null, updatedMaxSlippage: string | null) => { + async (updatedFormValues: Partial, isGetMaxFrom: boolean | null, updatedMaxSlippage: string | null) => { setConfirmedLoss(false) setTxInfoBar(null) - void setFormValues( + await setFormValues( curve, poolDataCacheOrApi.pool.id, poolData, @@ -156,7 +158,7 @@ const Swap = ({ description={`Swapped ${fromAmount} ${fromToken}.`} txHash={scanTxPath(network, resp.hash)} onClose={() => { - updateFormValues({}, null, null) + updateFormValues({}, null, null).catch(errorFallback) }} />, ) @@ -249,11 +251,16 @@ const Swap = ({ [fetchStepApprove, handleSwapClick], ) - const fetchData = useCallback(() => { - if (curve && poolData && isPageVisible && !formStatus.formProcessing && !formStatus.formTypeCompleted) { - updateFormValues({}, null, '') - } - }, [curve, formStatus.formProcessing, formStatus.formTypeCompleted, isPageVisible, poolData, updateFormValues]) + const fetchData = useCallback( + async () => + curve && + poolData && + isPageVisible && + !formStatus.formProcessing && + !formStatus.formTypeCompleted && + (await updateFormValues({}, null, '')), + [curve, formStatus.formProcessing, formStatus.formTypeCompleted, isPageVisible, poolData, updateFormValues], + ) // onMount useEffect(() => { @@ -274,21 +281,21 @@ const Swap = ({ // get user balances useEffect(() => { if (curve && poolId && haveSigner && (isUndefined(userFromBalance) || isUndefined(userToBalance))) { - void fetchUserPoolInfo(curve, poolId, true) + fetchUserPoolInfo(curve, poolId, true).catch(errorFallback) } }, [chainId, poolId, haveSigner, userFromBalance, userToBalance, curve, fetchUserPoolInfo]) // curve state change useEffect(() => { if (chainId && poolId) { - updateFormValues({}, null, null) + updateFormValues({}, null, null).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, poolId, signerAddress, seed.isSeed]) // maxSlippage useEffect(() => { - updateFormValues({}, null, maxSlippage) + updateFormValues({}, null, maxSlippage).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -325,8 +332,10 @@ const Swap = ({ ]) // pageVisible - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(() => fetchData(), [isPageVisible]) + useEffect(() => { + fetchData().catch(errorFallback) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isPageVisible]) // re-fetch data usePageVisibleInterval(() => fetchData(), REFRESH_INTERVAL['1m']) @@ -335,11 +344,13 @@ const Swap = ({ const isDisabled = seed.isSeed === null || seed.isSeed || formStatus.formProcessing const setFromAmount = useCallback( - (value?: Decimal) => updateFormValues({ isFrom: true, fromAmount: value ?? '', toAmount: '' }, null, null), + (value?: Decimal) => + updateFormValues({ isFrom: true, fromAmount: value ?? '', toAmount: '' }, null, null).catch(errorFallback), [updateFormValues], ) const setToAmount = useCallback( - (value?: Decimal) => updateFormValues({ isFrom: false, toAmount: value ?? '', fromAmount: '' }, null, null), + (value?: Decimal) => + updateFormValues({ isFrom: false, toAmount: value ?? '', fromAmount: '' }, null, null).catch(errorFallback), [updateFormValues], ) @@ -369,7 +380,7 @@ const Swap = ({ } value={formValues.fromAmount} onChange={(fromAmount) => { - updateFormValues({ isFrom: true, fromAmount, toAmount: '' }, null, null) + updateFormValues({ isFrom: true, fromAmount, toAmount: '' }, null, null).catch(errorFallback) }} /> { - updateFormValues({ isFrom: true, fromAmount: '', toAmount: '' }, true, null) + updateFormValues({ isFrom: true, fromAmount: '', toAmount: '' }, true, null).catch(errorFallback) }} /> { @@ -405,7 +416,7 @@ const Swap = ({ cFormValues.fromAmount = '' } - updateFormValues(cFormValues, null, '') + updateFormValues(cFormValues, null, '').catch(errorFallback) }} /> } @@ -481,7 +492,7 @@ const Swap = ({ cFormValues.toAddress = formValues.fromAddress cFormValues.toAmount = '' - updateFormValues(cFormValues, null, '') + updateFormValues(cFormValues, null, '').catch(errorFallback) }} size="medium" > @@ -511,7 +522,7 @@ const Swap = ({ } value={formValues.toAmount} onChange={(toAmount) => { - updateFormValues({ isFrom: false, toAmount, fromAmount: '' }, null, '') + updateFormValues({ isFrom: false, toAmount, fromAmount: '' }, null, '').catch(errorFallback) }} /> @@ -610,7 +621,7 @@ const Swap = ({ cFormValues.fromAmount = '' } - updateFormValues(cFormValues, null, '') + updateFormValues(cFormValues, null, '').catch(errorFallback) } }} > @@ -656,7 +667,7 @@ const Swap = ({ { - updateFormValues({}, null, null) + updateFormValues({}, null, null).catch(errorFallback) }} /> diff --git a/apps/main/src/dex/components/PagePool/Withdraw/components/FormClaim.tsx b/apps/main/src/dex/components/PagePool/Withdraw/components/FormClaim.tsx index bb37a1c154..8793a1ecf5 100644 --- a/apps/main/src/dex/components/PagePool/Withdraw/components/FormClaim.tsx +++ b/apps/main/src/dex/components/PagePool/Withdraw/components/FormClaim.tsx @@ -20,6 +20,7 @@ import TxInfoBar from '@ui/TxInfoBar' import { formatNumber, scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { t, Trans } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const FormClaim = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, userPoolBalances }: TransferProps) => { const isSubscribed = useRef(false) @@ -49,7 +50,7 @@ const FormClaim = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us const updateFormValues = useCallback(() => { setTxInfoBar(null) setSlippageConfirmed(false) - void setFormValues('CLAIM', curve, poolDataCacheOrApi.pool.id, poolData, {}, null, seed.isSeed, '') + setFormValues('CLAIM', curve, poolDataCacheOrApi.pool.id, poolData, {}, null, seed.isSeed, '').catch(errorFallback) }, [curve, poolData, poolDataCacheOrApi.pool.id, seed.isSeed, setFormValues]) const handleClaimClick = useCallback( @@ -108,9 +109,10 @@ const FormClaim = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us : isClaimCrv ? getClaimText(formValues, formStatus, 'claimCrvButton', rewardsNeedNudging) : t`Claim Rewards`, - onClick: () => { - void handleClaimClick(activeKey, curve, poolData, formValues, formStatus, rewardsNeedNudging) - }, + onClick: () => + handleClaimClick(activeKey, curve, poolData, formValues, formStatus, rewardsNeedNudging).catch( + errorFallback, + ), }, } @@ -146,7 +148,7 @@ const FormClaim = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us // fetch claimable useEffect(() => { if (chainId && poolData && haveSigner) { - void fetchClaimable(activeKey, chainId, poolData.pool) + fetchClaimable(activeKey, chainId, poolData.pool).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, poolId, signerAddress]) @@ -171,7 +173,7 @@ const FormClaim = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, us cFormStatus.isClaimRewards = isClaimRewards setStateByKey('formStatus', cFormStatus) - void handleClaimClick(activeKey, curve, poolData, formValues, cFormStatus, rewardsNeedNudging) + handleClaimClick(activeKey, curve, poolData, formValues, cFormStatus, rewardsNeedNudging).catch(errorFallback) } } diff --git a/apps/main/src/dex/components/PagePool/Withdraw/components/FormUnstake.tsx b/apps/main/src/dex/components/PagePool/Withdraw/components/FormUnstake.tsx index 26c8b6ffec..5a0b4ab151 100644 --- a/apps/main/src/dex/components/PagePool/Withdraw/components/FormUnstake.tsx +++ b/apps/main/src/dex/components/PagePool/Withdraw/components/FormUnstake.tsx @@ -16,6 +16,7 @@ import TxInfoBar from '@ui/TxInfoBar' import { scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const FormUnstake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, userPoolBalances }: TransferProps) => { const isSubscribed = useRef(false) @@ -41,7 +42,7 @@ const FormUnstake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, const updateFormValues = useCallback( (updatedFormValues: Partial) => { setTxInfoBar(null) - void setFormValues( + setFormValues( 'UNSTAKE', curve, poolDataCacheOrApi.pool.id, @@ -50,7 +51,7 @@ const FormUnstake = ({ curve, poolData, poolDataCacheOrApi, routerParams, seed, null, seed.isSeed, '', - ) + ).catch(errorFallback) }, [curve, poolData, poolDataCacheOrApi.pool.id, seed.isSeed, setFormValues], ) diff --git a/apps/main/src/dex/components/PagePool/Withdraw/components/FormWithdraw.tsx b/apps/main/src/dex/components/PagePool/Withdraw/components/FormWithdraw.tsx index 645fbfba8c..b0c6d6f131 100644 --- a/apps/main/src/dex/components/PagePool/Withdraw/components/FormWithdraw.tsx +++ b/apps/main/src/dex/components/PagePool/Withdraw/components/FormWithdraw.tsx @@ -32,6 +32,7 @@ import { mediaQueries } from '@ui/utils/responsive' import { notify } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' import { useTokenUsdRates } from '@ui-kit/lib/model/entities/token-usd-rate' +import { errorFallback } from '@ui-kit/utils/error.util' const FormWithdraw = ({ chainIdPoolId, @@ -73,7 +74,7 @@ const FormWithdraw = ({ (updatedFormValues: Partial, updatedMaxSlippage: string | null) => { setTxInfoBar(null) setSlippageConfirmed(false) - void setFormValues( + setFormValues( 'WITHDRAW', curve, poolDataCacheOrApi.pool.id, @@ -82,7 +83,7 @@ const FormWithdraw = ({ null, seed.isSeed, updatedMaxSlippage || maxSlippage, - ) + ).catch(errorFallback) }, [setFormValues, curve, poolDataCacheOrApi.pool.id, poolData, seed.isSeed, maxSlippage], ) diff --git a/apps/main/src/dex/components/PagePool/components/AlertSeedAmounts.tsx b/apps/main/src/dex/components/PagePool/components/AlertSeedAmounts.tsx index 4800d999c4..ae528bd7bb 100644 --- a/apps/main/src/dex/components/PagePool/components/AlertSeedAmounts.tsx +++ b/apps/main/src/dex/components/PagePool/components/AlertSeedAmounts.tsx @@ -5,6 +5,7 @@ import { PoolData } from '@/dex/types/main.types' import AlertBox from '@ui/AlertBox' import { formatNumber } from '@ui/utils' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' type Props = { seed: Seed @@ -32,7 +33,7 @@ const AlertSeedAmounts = ({ seed, poolData }: Props) => { }, []) useEffect(() => { - if (!!poolData && loaded && isSeed) void getSeedRatio(poolData) + if (!!poolData && loaded && isSeed) getSeedRatio(poolData).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [poolData?.pool?.id, loaded, isSeed]) diff --git a/apps/main/src/dex/components/PagePool/index.tsx b/apps/main/src/dex/components/PagePool/index.tsx index c2663062fd..3cf05f895d 100644 --- a/apps/main/src/dex/components/PagePool/index.tsx +++ b/apps/main/src/dex/components/PagePool/index.tsx @@ -45,6 +45,7 @@ import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { type TabOption, TabsSwitcher } from '@ui-kit/shared/ui/TabsSwitcher' +import { errorFallback } from '@ui-kit/utils/error.util' const DEFAULT_SEED: Seed = { isSeed: null, loaded: false } @@ -119,11 +120,7 @@ const Transfer = (pageTransferProps: PageTransferProps) => { return pool.isCrypto ? '0.1' : '0.03' }, [storeMaxSlippage, pool]) - usePageVisibleInterval(() => { - if (curve && poolData) { - void fetchPoolStats(curve, poolData) - } - }, REFRESH_INTERVAL['5m']) + usePageVisibleInterval(() => curve && poolData && fetchPoolStats(curve, poolData), REFRESH_INTERVAL['5m']) useEffect(() => { if ( @@ -133,7 +130,7 @@ const Transfer = (pageTransferProps: PageTransferProps) => { pricesApiPoolsMapper[poolAddress] !== undefined && !snapshotsMapper[poolAddress] ) { - void fetchPricesPoolSnapshots(rChainId, poolAddress) + fetchPricesPoolSnapshots(rChainId, poolAddress).catch(errorFallback) } }, [curve, fetchPricesPoolSnapshots, poolAddress, pricesApi, pricesApiPoolsMapper, rChainId, snapshotsMapper]) @@ -151,7 +148,7 @@ const Transfer = (pageTransferProps: PageTransferProps) => { // fetch user pool info useEffect(() => { if (curve && poolId && signerAddress) { - void fetchUserPoolInfo(curve, poolId) + fetchUserPoolInfo(curve, poolId).catch(errorFallback) } }, [rChainId, poolId, signerAddress, curve, fetchUserPoolInfo]) diff --git a/apps/main/src/dex/components/PagePoolList/index.tsx b/apps/main/src/dex/components/PagePoolList/index.tsx index f5f0eec58c..8808cce7cc 100644 --- a/apps/main/src/dex/components/PagePoolList/index.tsx +++ b/apps/main/src/dex/components/PagePoolList/index.tsx @@ -1,3 +1,4 @@ +import { isEmpty } from 'lodash' import { useCallback, useEffect, useMemo, useState } from 'react' import { PoolRow } from '@/dex/components/PagePoolList/components/PoolRow' import TableHead from '@/dex/components/PagePoolList/components/TableHead' @@ -132,11 +133,10 @@ const PoolList = ({ ], ) - usePageVisibleInterval(() => { - if (curve && rewardsApyMapper && Object.keys(rewardsApyMapper).length > 0) { - void fetchPoolsRewardsApy(rChainId, poolDatas) - } - }, REFRESH_INTERVAL['11m']) + usePageVisibleInterval( + () => curve && !isEmpty(rewardsApyMapper) && fetchPoolsRewardsApy(rChainId, poolDatas), + REFRESH_INTERVAL['11m'], + ) // init useEffect(() => { diff --git a/apps/main/src/dex/components/PageRouterSwap/components/RouterSwapAlerts.tsx b/apps/main/src/dex/components/PageRouterSwap/components/RouterSwapAlerts.tsx index 27fa8d01c4..c7421c5b07 100644 --- a/apps/main/src/dex/components/PageRouterSwap/components/RouterSwapAlerts.tsx +++ b/apps/main/src/dex/components/PageRouterSwap/components/RouterSwapAlerts.tsx @@ -7,6 +7,7 @@ import type { FormStatus, FormValues, SearchedParams } from '@/dex/components/Pa import AlertBox from '@ui/AlertBox' import { t } from '@ui-kit/lib/i18n' import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' +import { errorFallback } from '@ui-kit/utils/error.util' const { isUndefined, isNaN } = lodash @@ -34,7 +35,7 @@ const RouterSwapAlerts = ({ isGetMaxFrom?: boolean, maxSlippage?: string, isFullReset?: boolean, - ) => void + ) => Promise }) => { const { error, swapError } = formStatus const { toAddress } = searchedParams @@ -58,7 +59,7 @@ const RouterSwapAlerts = ({ - updateFormValues({})} /> + updateFormValues({}).catch(errorFallback)} /> ) } diff --git a/apps/main/src/dex/components/PageRouterSwap/index.tsx b/apps/main/src/dex/components/PageRouterSwap/index.tsx index dd20c927e2..067e8ab506 100644 --- a/apps/main/src/dex/components/PageRouterSwap/index.tsx +++ b/apps/main/src/dex/components/PageRouterSwap/index.tsx @@ -46,6 +46,7 @@ import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { useTokenUsdRate, useTokenUsdRates } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const QuickSwap = ({ pageLoaded, @@ -132,7 +133,7 @@ const QuickSwap = ({ const toToken = tokens.find((x) => x.address.toLocaleLowerCase() == toAddress) const updateFormValues = useCallback( - ( + async ( updatedFormValues: Partial, isGetMaxFrom?: boolean, maxSlippage?: string, @@ -142,7 +143,7 @@ const QuickSwap = ({ setTxInfoBar(null) setConfirmedLoss(false) - void setFormValues( + await setFormValues( pageLoaded ? curve : null, updatedFormValues, searchedParams, @@ -183,7 +184,7 @@ const QuickSwap = ({ updateFormValues({}, false, '', true)} + onClose={() => updateFormValues({}, false, '', true).catch(errorFallback)} />, ) } @@ -250,42 +251,38 @@ const QuickSwap = ({ onClick: () => setConfirmedLoss(false), }, primaryBtnProps: { - onClick: () => { - if (typeof routesAndOutput !== 'undefined') { - void handleBtnClickSwap( - activeKey, - curve, - formValues, - storeMaxSlippage, - !!slippageImpact?.isExpectedToAmount, - routesAndOutput.toAmountOutput, - searchedParams, - toSymbol, - fromSymbol, - ) - } - }, + onClick: () => + routesAndOutput && + handleBtnClickSwap( + activeKey, + curve, + formValues, + storeMaxSlippage, + !!slippageImpact?.isExpectedToAmount, + routesAndOutput.toAmountOutput, + searchedParams, + toSymbol, + fromSymbol, + ).catch(errorFallback), disabled: !confirmedLoss, }, primaryBtnLabel: 'Swap anyway', }, } : { - onClick: () => { - if (typeof routesAndOutput !== 'undefined') { - void handleBtnClickSwap( - activeKey, - curve, - formValues, - storeMaxSlippage, - !!slippageImpact?.isExpectedToAmount, - routesAndOutput.toAmountOutput, - searchedParams, - toSymbol, - fromSymbol, - ) - } - }, + onClick: () => + routesAndOutput && + handleBtnClickSwap( + activeKey, + curve, + formValues, + storeMaxSlippage, + !!slippageImpact?.isExpectedToAmount, + routesAndOutput.toAmountOutput, + searchedParams, + toSymbol, + fromSymbol, + ).catch(errorFallback), }), }, } @@ -303,11 +300,14 @@ const QuickSwap = ({ [confirmedLoss, fetchStepApprove, storeMaxSlippage, handleBtnClickSwap, slippageImpact?.isExpectedToAmount, steps], ) - const fetchData = useCallback(() => { - if (isReady && !formStatus.formProcessing && formStatus.formTypeCompleted !== 'SWAP') { - updateFormValues({}, false, '', false, true) - } - }, [formStatus.formProcessing, formStatus.formTypeCompleted, isReady, updateFormValues]) + const fetchData = useCallback( + async () => + isReady && + !formStatus.formProcessing && + formStatus.formTypeCompleted !== 'SWAP' && + (await updateFormValues({}, false, '', false, true)), + [formStatus.formProcessing, formStatus.formTypeCompleted, isReady, updateFormValues], + ) // onMount useEffect(() => { @@ -315,35 +315,37 @@ const QuickSwap = ({ return () => { isSubscribed.current = false - updateFormValues({}, false, '', true) + updateFormValues({}, false, '', true).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, []) // maxSlippage useEffect(() => { - if (isReady) updateFormValues({}, false, cryptoMaxSlippage) + if (isReady) updateFormValues({}, false, cryptoMaxSlippage).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [cryptoMaxSlippage]) // pageVisible re-fetch data useEffect(() => { - if (isReady) fetchData() + if (isReady) fetchData().catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isPageVisible]) // network switched useEffect(() => { - updateFormValues({ isFrom: true, fromAmount: '', toAmount: '' }) + updateFormValues({ isFrom: true, fromAmount: '', toAmount: '' }).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [curve?.chainId]) // updateForm - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(() => fetchData(), [tokensMapperStr, searchedParams.fromAddress, searchedParams.toAddress]) + useEffect(() => { + fetchData().catch(errorFallback) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tokensMapperStr, searchedParams.fromAddress, searchedParams.toAddress]) useEffect(() => { - void updateTokenList(isReady ? curve : null, tokensMapper) + updateTokenList(isReady ? curve : null, tokensMapper).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isReady, tokensMapperStr, curve?.signerAddress]) @@ -375,11 +377,13 @@ const QuickSwap = ({ const shouldUseLegacyTokenInput = useLegacyTokenInput() const setFromAmount = useCallback( - (fromAmount?: Decimal) => updateFormValues({ isFrom: true, fromAmount: fromAmount ?? '', toAmount: '' }), + (fromAmount?: Decimal) => + updateFormValues({ isFrom: true, fromAmount: fromAmount ?? '', toAmount: '' }).catch(errorFallback), [updateFormValues], ) const setToAmount = useCallback( - (toAmount?: Decimal) => updateFormValues({ isFrom: false, toAmount: toAmount ?? '', fromAmount: '' }), + (toAmount?: Decimal) => + updateFormValues({ isFrom: false, toAmount: toAmount ?? '', fromAmount: '' }).catch(errorFallback), [updateFormValues], ) @@ -409,14 +413,16 @@ const QuickSwap = ({ } testId="from-amount" value={isMaxLoading ? '' : formValues.fromAmount} - onChange={(fromAmount) => updateFormValues({ isFrom: true, fromAmount, toAmount: '' })} + onChange={(fromAmount) => + updateFormValues({ isFrom: true, fromAmount, toAmount: '' }).catch(errorFallback) + } /> updateFormValues({ isFrom: true, toAmount: '' }, true)} + onClick={() => updateFormValues({ isFrom: true, toAmount: '' }, true).catch(errorFallback)} /> updateFormValues({ isFrom: false, toAmount, fromAmount: '' })} + onChange={(toAmount) => + updateFormValues({ isFrom: false, toAmount, fromAmount: '' }).catch(errorFallback) + } /> { @@ -28,24 +29,21 @@ export const useAutoRefresh = (networkDef: NetworkDef) => { const { chainId } = curve const poolsData = Object.values(poolDataMapper) await Promise.all([fetchPoolsVolume(chainId, poolsData), fetchPoolsTvl(curve, poolsData)]) - void setTokensMapper(curve, poolsData) + setTokensMapper(curve, poolsData).catch(errorFallback) }, [fetchPoolsTvl, fetchPoolsVolume, poolDataMapper, setTokensMapper], ) - usePageVisibleInterval(() => { - if (curveApi) { - void fetchPoolsVolumeTvl(curveApi) - - if (curveApi.signerAddress) { - void fetchAllStoredBalances(curveApi) - } - } - }, REFRESH_INTERVAL['5m']) + usePageVisibleInterval( + () => + curveApi && + Promise.all([fetchPoolsVolumeTvl(curveApi), curveApi.signerAddress && fetchAllStoredBalances(curveApi)]), + REFRESH_INTERVAL['5m'], + ) usePageVisibleInterval(async () => { if (!curveApi || !network) return console.warn('Curve API or network is not defined, cannot refetch pools') const poolIds = await curvejsApi.network.fetchAllPoolsList(curveApi, network) - void fetchPools(curveApi, poolIds, null) + await fetchPools(curveApi, poolIds, null) }, REFRESH_INTERVAL['11m']) } diff --git a/apps/main/src/dex/hooks/usePoolTotalStaked.tsx b/apps/main/src/dex/hooks/usePoolTotalStaked.tsx index b7a2d338d6..651060aa5e 100644 --- a/apps/main/src/dex/hooks/usePoolTotalStaked.tsx +++ b/apps/main/src/dex/hooks/usePoolTotalStaked.tsx @@ -5,6 +5,7 @@ import { PoolDataCacheOrApi, Provider } from '@/dex/types/main.types' import { isValidAddress } from '@/dex/utils' import { useConnection, useWallet } from '@ui-kit/features/connect-wallet' import dayjs from '@ui-kit/lib/dayjs' +import { errorFallback } from '@ui-kit/utils/error.util' import { useNetworks } from '../entities/networks' const usePoolTotalStaked = (poolDataCacheOrApi: PoolDataCacheOrApi) => { @@ -60,7 +61,7 @@ const usePoolTotalStaked = (poolDataCacheOrApi: PoolDataCacheOrApi) => { const shouldCallApi = staked?.timestamp ? dayjs().diff(staked.timestamp, 'seconds') > 30 : true if (address && rpcUrl && shouldCallApi) { - void (async () => { + ;(async () => { const provider = walletProvider || new JsonRpcProvider(rpcUrl) const gaugeContract = isValidAddress(gauge.address) ? await getContract('gaugeTotalSupply', gauge.address, provider) @@ -72,11 +73,11 @@ const usePoolTotalStaked = (poolDataCacheOrApi: PoolDataCacheOrApi) => { ? await getContract('poolTotalSupply', address, provider) : await getContract('lpTokenTotalSupply', lpToken, provider) - if (poolContract) void getTotalSupply(poolContract, gaugeContract) + if (poolContract) getTotalSupply(poolContract, gaugeContract).catch(errorFallback) } else { updateTotalStakeValue({ totalStakedPercent: 'N/A', gaugeTotalSupply: 'N/A' }) } - })() + })().catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [curveApi?.signerAddress, curveApi?.chainId, address, rpcUrl, walletProvider]) diff --git a/apps/main/src/dex/lib/curvejs.ts b/apps/main/src/dex/lib/curvejs.ts index 39fe11d27d..367ea0afce 100644 --- a/apps/main/src/dex/lib/curvejs.ts +++ b/apps/main/src/dex/lib/curvejs.ts @@ -42,6 +42,7 @@ import dayjs from '@ui-kit/lib/dayjs' import { waitForTransaction, waitForTransactions } from '@ui-kit/lib/ethers' import { t } from '@ui-kit/lib/i18n' import { log } from '@ui-kit/lib/logging' +import { errorFallback } from '@ui-kit/utils/error.util' import { fetchNetworks } from '../entities/networks' const { chunk, flatten, isUndefined } = lodash @@ -358,7 +359,7 @@ const router = { ? await curve.router.estimateGas.swap(fromAddress, toAddress, fromAmount) : await curve.router.estimateGas.approve(fromAddress, fromAmount) } - void warnIncorrectEstGas(curve.chainId, resp.estimatedGas) + warnIncorrectEstGas(curve.chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) @@ -472,7 +473,7 @@ const poolDeposit = { ? await p.estimateGas.depositWrappedApprove(amounts) : await p.estimateGas.depositApprove(amounts) } - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { resp.error = getErrorMessage(error, 'error-est-gas-approval') @@ -565,7 +566,7 @@ const poolDeposit = { ? await p.estimateGas.depositAndStakeWrappedApprove(amounts) : await p.estimateGas.depositAndStakeApprove(amounts) } - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) @@ -624,7 +625,7 @@ const poolDeposit = { resp.estimatedGas = resp.isApproved ? await p.estimateGas.stake(lpTokenAmount) : await p.estimateGas.stakeApprove(lpTokenAmount) - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { resp.error = getErrorMessage(error, 'error-est-gas-approval') @@ -772,7 +773,7 @@ const poolSwap = { ? await p.estimateGas.swapWrappedApprove(fromAddress, fromAmount) : await p.estimateGas.swapApprove(fromAddress, fromAmount) } - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) @@ -863,7 +864,7 @@ const poolWithdraw = { } else { resp.estimatedGas = await p.estimateGas.withdrawApprove(lpTokenAmount) } - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) @@ -944,7 +945,7 @@ const poolWithdraw = { } else { resp.estimatedGas = await p.estimateGas.withdrawImbalanceApprove(amounts) } - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) @@ -1035,7 +1036,7 @@ const poolWithdraw = { } else { resp.estimatedGas = await p.estimateGas.withdrawOneCoinApprove(lpTokenAmount) } - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) @@ -1086,7 +1087,7 @@ const poolWithdraw = { const resp = { activeKey, estimatedGas: null as EstimatedGas, isApproved: true, error: '' } try { resp.estimatedGas = await p.estimateGas.unstake(lpTokenAmount) - void warnIncorrectEstGas(chainId, resp.estimatedGas) + warnIncorrectEstGas(chainId, resp.estimatedGas).catch(errorFallback) return resp } catch (error) { console.error(error) diff --git a/apps/main/src/dex/store/createCacheSlice.ts b/apps/main/src/dex/store/createCacheSlice.ts index 218558cc42..795bcafa9a 100644 --- a/apps/main/src/dex/store/createCacheSlice.ts +++ b/apps/main/src/dex/store/createCacheSlice.ts @@ -2,6 +2,7 @@ import { StoreApi } from 'zustand' import type { State } from '@/dex/store/useStore' import { ChainId, PoolDataCacheMapper, type ValueMapperCached } from '@/dex/types/main.types' import { sleep } from '@/dex/utils' +import { errorFallback } from '@ui-kit/utils/error.util' export type SwapFormValuesCache = { fromAddress: string @@ -56,7 +57,7 @@ const createCacheSlice = (_: StoreApi['setState'], get: StoreApi[' parsedMapper[k] = { value } }) - void sliceState.setStateByActiveKey(key, chainId.toString(), parsedMapper) + sliceState.setStateByActiveKey(key, chainId.toString(), parsedMapper).catch(errorFallback) }, // slice helpers diff --git a/apps/main/src/dex/store/createDashboardSlice.ts b/apps/main/src/dex/store/createDashboardSlice.ts index 5e30f6c08d..487b4922b0 100644 --- a/apps/main/src/dex/store/createDashboardSlice.ts +++ b/apps/main/src/dex/store/createDashboardSlice.ts @@ -21,6 +21,7 @@ import type { IProfit } from '@curvefi/api/lib/interfaces' import { PromisePool } from '@supercharge/promise-pool' import { shortenAccount } from '@ui/utils' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -95,13 +96,11 @@ const createDashboardSlice = (_: StoreApi['setState'], get: StoreApi { const { @@ -287,7 +286,7 @@ const createDashboardSlice = (_: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi r.item.pool.id).map((r) => r.item) }, filterSmallTvl: (poolDatas, tvlMapper, chainId) => { - const networks = getNetworks() - const { hideSmallPoolsTvl } = networks[chainId] - - const result = takeTopWithMin(poolDatas, (pd) => +(tvlMapper?.[pd.pool.id]?.value || '0'), hideSmallPoolsTvl, 10) - - return result + const { hideSmallPoolsTvl } = getNetworks()[chainId] + return takeTopWithMin(poolDatas, (pd) => +(tvlMapper?.[pd.pool.id]?.value || '0'), hideSmallPoolsTvl, 10) }, sortFn: (sortKey, order, poolDatas, rewardsApyMapper, tvlMapper, volumeMapper, isCrvRewardsEnabled, chainId) => { const networks = getNetworks() @@ -281,7 +277,7 @@ const createPoolListSlice = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi { @@ -192,7 +193,7 @@ const createPoolWithdrawSlice = ( // get gas if (signerAddress) { - void get()[sliceKey].fetchEstGasApproval(activeKey, curve, formType, pool, cFormValues) + get()[sliceKey].fetchEstGasApproval(activeKey, curve, formType, pool, cFormValues).catch(errorFallback) } } }, @@ -283,7 +284,7 @@ const createPoolWithdrawSlice = ( // get gas if (signerAddress) { - void get()[sliceKey].fetchEstGasApproval(activeKey, curve, formType, pool, cFormValues) + get()[sliceKey].fetchEstGasApproval(activeKey, curve, formType, pool, cFormValues).catch(errorFallback) } }, fetchClaimable: async (activeKey, chainId, pool) => { @@ -350,16 +351,16 @@ const createPoolWithdrawSlice = ( maxSlippage, } if (cFormValues.selected === 'token') { - void get()[sliceKey].fetchWithdrawToken(props) + await get()[sliceKey].fetchWithdrawToken(props) } else if (cFormValues.selected === 'lpToken') { - void get()[sliceKey].fetchWithdrawLpToken(props) + await get()[sliceKey].fetchWithdrawLpToken(props) } else if (cFormValues.selected === 'imbalance') { - void get()[sliceKey].fetchWithdrawCustom(props) + await get()[sliceKey].fetchWithdrawCustom(props) } } else if (formType === 'UNSTAKE' && !!signerAddress && +cFormValues.stakedLpToken > 0) { - void get()[sliceKey].fetchEstGasApproval(activeKey, curve, formType, pool, cFormValues) + await get()[sliceKey].fetchEstGasApproval(activeKey, curve, formType, pool, cFormValues) } else if (formType === 'CLAIM') { - void get()[sliceKey].fetchClaimable(activeKey, chainId, pool) + await get()[sliceKey].fetchClaimable(activeKey, chainId, pool) } }, diff --git a/apps/main/src/dex/store/createPoolsSlice.ts b/apps/main/src/dex/store/createPoolsSlice.ts index 2f88b2c0bd..3a620f2168 100644 --- a/apps/main/src/dex/store/createPoolsSlice.ts +++ b/apps/main/src/dex/store/createPoolsSlice.ts @@ -43,6 +43,7 @@ import { convertToLocaleTimestamp } from '@ui/Chart/utils' import { requireLib } from '@ui-kit/features/connect-wallet' import { log } from '@ui-kit/lib/logging' import { fetchTokenUsdRate, getTokenUsdRateQueryData } from '@ui-kit/lib/model/entities/token-usd-rate' +import { errorFallback } from '@ui-kit/utils/error.util' import { fetchNetworks } from '../entities/networks' import { getPools } from '../lib/pools' @@ -269,7 +270,7 @@ const createPoolsSlice = (set: StoreApi['setState'], get: StoreApi ) // update cache - void storeCache.setStateByActiveKey('poolsMapper', chainId.toString(), poolsMapperCache) + storeCache.setStateByActiveKey('poolsMapper', chainId.toString(), poolsMapperCache).catch(errorFallback) const partialPoolDatas = poolIds.map((poolId) => poolsMapper[poolId]) @@ -286,7 +287,7 @@ const createPoolsSlice = (set: StoreApi['setState'], get: StoreApi const partialTokens = await tokens.setTokensMapper(curve, partialPoolDatas) if (curve.signerAddress) { - void userBalances.fetchUserBalancesByTokens(curve, partialTokens) + await userBalances.fetchUserBalancesByTokens(curve, partialTokens) } return { poolsMapper, poolDatas: partialPoolDatas } @@ -427,7 +428,7 @@ const createPoolsSlice = (set: StoreApi['setState'], get: StoreApi if (missingRewardsPoolIds.length > 0) { log('fetchMissingPoolsRewardsApy', chainId, missingRewardsPoolIds.length) - void fetchPoolsRewardsApy(chainId, missingRewardsPoolIds) + await fetchPoolsRewardsApy(chainId, missingRewardsPoolIds) } // const missingRewardsPoolIds = [] @@ -495,7 +496,7 @@ const createPoolsSlice = (set: StoreApi['setState'], get: StoreApi state.pools.poolsMapper[chainId][poolData.pool.id] = cPoolData }), ) - void get().pools.fetchPoolCurrenciesReserves(curve, cPoolData) + get().pools.fetchPoolCurrenciesReserves(curve, cPoolData).catch(errorFallback) return { tokens, tokenAddresses } }, updatePool: (chainId, poolId, updatedPoolData) => { diff --git a/apps/main/src/dex/store/createQuickSwapSlice.ts b/apps/main/src/dex/store/createQuickSwapSlice.ts index 50dbcd4e88..1db3f45c57 100644 --- a/apps/main/src/dex/store/createQuickSwapSlice.ts +++ b/apps/main/src/dex/store/createQuickSwapSlice.ts @@ -18,6 +18,7 @@ import { getMaxAmountMinusGas } from '@/dex/utils/utilsGasPrices' import { getSlippageImpact, getSwapActionModalType } from '@/dex/utils/utilsSwap' import { useWallet } from '@ui-kit/features/connect-wallet' import { fetchGasInfoAndUpdateLib } from '@ui-kit/lib/model/entities/gas-info' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' import { fetchNetworks } from '../entities/networks' @@ -326,16 +327,16 @@ const createQuickSwapSlice = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi { @@ -23,7 +24,7 @@ const PoolActivity = ({ chainId, poolAddress, coins }: PoolActivityProps) => { const minHeight = chartExpanded ? 548 : 330 useEffect(() => { - void fetchPoolActivity(chainId, poolAddress) + fetchPoolActivity(chainId, poolAddress).catch(errorFallback) }, [chainId, fetchPoolActivity, poolAddress]) return ( diff --git a/apps/main/src/lend/components/ChartOhlcWrapper/index.tsx b/apps/main/src/lend/components/ChartOhlcWrapper/index.tsx index e82b145cb0..273a68095e 100644 --- a/apps/main/src/lend/components/ChartOhlcWrapper/index.tsx +++ b/apps/main/src/lend/components/ChartOhlcWrapper/index.tsx @@ -15,6 +15,7 @@ import TextCaption from '@ui/TextCaption' import { useLayoutStore } from '@ui-kit/features/layout' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import { ChartOhlcWrapperProps, LendingMarketTokens } from './types' const ChartOhlcWrapper = ({ rChainId, userActiveKey, rOwmId, betaBackgroundColor }: ChartOhlcWrapperProps) => { @@ -266,27 +267,27 @@ const ChartOhlcWrapper = ({ rChainId, userActiveKey, rOwmId, betaBackgroundColor }, [timeOption]) const refetchPricesData = useCallback(() => { - if (market?.addresses.controller) { - void fetchOraclePoolOhlcData( - rChainId, - market.addresses.controller, - chartInterval, - timeUnit, - chartTimeSettings.start, - chartTimeSettings.end, - ) - } - if (market?.addresses.amm) { - void fetchLlammaOhlcData( - rChainId, - rOwmId, - market.addresses.amm, - chartInterval, - timeUnit, - chartTimeSettings.start, - chartTimeSettings.end, - ) - } + Promise.all([ + market?.addresses.controller && + fetchOraclePoolOhlcData( + rChainId, + market.addresses.controller, + chartInterval, + timeUnit, + chartTimeSettings.start, + chartTimeSettings.end, + ), + market?.addresses.amm && + fetchLlammaOhlcData( + rChainId, + rOwmId, + market.addresses.amm, + chartInterval, + timeUnit, + chartTimeSettings.start, + chartTimeSettings.end, + ), + ]).catch(errorFallback) }, [ chartInterval, chartTimeSettings.end, @@ -316,7 +317,7 @@ const ChartOhlcWrapper = ({ rChainId, userActiveKey, rOwmId, betaBackgroundColor const startTime = getThreeHundredResultsAgo(timeOption, endTime) if (market?.addresses.controller && market?.addresses.amm) { - void fetchMoreData( + fetchMoreData( rChainId, market?.addresses.controller, market?.addresses.amm, @@ -324,7 +325,7 @@ const ChartOhlcWrapper = ({ rChainId, userActiveKey, rOwmId, betaBackgroundColor timeUnit, startTime, endTime, - ) + ).catch(errorFallback) } }, [timeOption, fetchMoreData, rChainId, market?.addresses.amm, market?.addresses.controller, chartInterval, timeUnit], diff --git a/apps/main/src/lend/components/DetailsMarket/components/MarketParameters.tsx b/apps/main/src/lend/components/DetailsMarket/components/MarketParameters.tsx index 2c63762164..0548b84f34 100644 --- a/apps/main/src/lend/components/DetailsMarket/components/MarketParameters.tsx +++ b/apps/main/src/lend/components/DetailsMarket/components/MarketParameters.tsx @@ -10,6 +10,7 @@ import Chip from '@ui/Typography/Chip' import { FORMAT_OPTIONS, formatNumber, NumberFormatOptions } from '@ui/utils' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const MarketParameters = ({ rChainId, @@ -54,7 +55,7 @@ const MarketParameters = ({ ] useEffect(() => { - if (type === 'supply' && owm) void fetchVaultPricePerShare(rChainId, owm) + if (type === 'supply' && owm) fetchVaultPricePerShare(rChainId, owm).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [type, owm]) diff --git a/apps/main/src/lend/components/PageIntegrations/Page.tsx b/apps/main/src/lend/components/PageIntegrations/Page.tsx index 7f58150190..95cf9e5fd4 100644 --- a/apps/main/src/lend/components/PageIntegrations/Page.tsx +++ b/apps/main/src/lend/components/PageIntegrations/Page.tsx @@ -9,6 +9,7 @@ import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { breakpoints } from '@ui/utils/responsive' import { useSearchParams, useParams } from '@ui-kit/hooks/router' import { Trans } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const Page = () => { const params = useParams() @@ -19,7 +20,7 @@ const Page = () => { const integrationsTags = useStore((state) => state.integrations.integrationsTags) useEffect(() => { - void init(rChainId) + init(rChainId).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) diff --git a/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx b/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx index df124c19b5..a06760f5bc 100644 --- a/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx +++ b/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx @@ -6,6 +6,7 @@ import type { LiqRangeSliderIdx } from '@/lend/store/types' import useStore from '@/lend/store/useStore' import { PageContentProps } from '@/lend/types/lend.types' import { getActiveStep } from '@ui/Stepper/helpers' +import { errorFallback } from '@ui-kit/utils/error.util' const DetailInfoComp = ({ isLeverage, ...props }: PageContentProps & DetailInfoCompProps & { isLeverage: boolean }) => { const { api, market, steps, updateFormValues } = props @@ -32,11 +33,11 @@ const DetailInfoComp = ({ isLeverage, ...props }: PageContentProps & DetailInfoC const handleLiqRangesEdit = () => { const showEditLiqRange = !isEditLiqRange setStateByKey('isEditLiqRange', showEditLiqRange) - updateFormValues(formValues) + updateFormValues(formValues).catch(errorFallback) } const handleSelLiqRange = (n: number) => { - updateFormValues({ ...formValues, n }) + updateFormValues({ ...formValues, n }).catch(errorFallback) } const additionalProps: DetailInfoCompAdditionalProps = { diff --git a/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/index.tsx b/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/index.tsx index e7367ac0b4..e9b10939fd 100644 --- a/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/index.tsx +++ b/apps/main/src/lend/components/PageLoanCreate/LoanFormCreate/index.tsx @@ -36,6 +36,8 @@ import { useNavigate } from '@ui-kit/hooks/router' import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const LoanCreate = ({ isLeverage = false, @@ -60,7 +62,7 @@ const LoanCreate = ({ const fetchStepApprove = useStore((state) => state.loanCreate.fetchStepApprove) const fetchStepCreate = useStore((state) => state.loanCreate.fetchStepCreate) const setStateByKeyMarkets = useStore((state) => state.markets.setStateByKey) - const setFormValues = useStore((state) => state.loanCreate.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.loanCreate.setFormValues)) const resetState = useStore((state) => state.loanCreate.resetState) const isAdvancedMode = useUserProfileStore((state) => state.isAdvancedMode) @@ -82,18 +84,19 @@ const LoanCreate = ({ }) const updateFormValues = useCallback( - (updatedFormValues: Partial, isFullReset?: boolean, shouldRefetch?: boolean) => { + async (updatedFormValues: Partial, isFullReset?: boolean, shouldRefetch?: boolean) => { setConfirmWarning(DEFAULT_CONFIRM_WARNING) - void setFormValues( - isLoaded ? api : null, - market, - isFullReset ? DEFAULT_FORM_VALUES : updatedFormValues, - maxSlippage, - isLeverage, - shouldRefetch, - ) - - if (isFullReset) setHealthMode(DEFAULT_HEALTH_MODE) + await Promise.all([ + setFormValues( + isLoaded ? api : null, + market, + isFullReset ? DEFAULT_FORM_VALUES : updatedFormValues, + maxSlippage, + isLeverage, + shouldRefetch, + ), + isFullReset && setHealthMode(DEFAULT_HEALTH_MODE), + ]) }, [setFormValues, isLoaded, api, market, maxSlippage, isLeverage], ) @@ -253,11 +256,17 @@ const LoanCreate = ({ } }, []) - usePageVisibleInterval(() => { - if (isLoaded && isLeverage && !formStatus.isComplete && !formStatus.step && !formStatus.error && !isConfirming) { - updateFormValues({}) - } - }, REFRESH_INTERVAL['10s']) + usePageVisibleInterval( + () => + isLoaded && + isLeverage && + !formStatus.isComplete && + !formStatus.step && + !formStatus.error && + !isConfirming && + updateFormValues({}).catch(errorFallback), + REFRESH_INTERVAL['10s'], + ) // steps useEffect(() => { @@ -299,21 +308,24 @@ const LoanCreate = ({ // signerAddress, maxSlippage state change useEffect(() => { - if (isLoaded) updateFormValues({}) + if (isLoaded) updateFormValues({}).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage, isAdvancedMode]) useEffect(() => { if (isLoaded) { resetState() - updateFormValues({}) + updateFormValues({}).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) const disabled = !!formStatus.step - const setUserBorrowed = useCallback((userBorrowed: string) => updateFormValues({ userBorrowed }), [updateFormValues]) + const setUserBorrowed = useCallback( + (userBorrowed: string) => updateFormValues({ userBorrowed }).catch(errorFallback), + [updateFormValues], + ) return ( <> @@ -330,10 +342,12 @@ const LoanCreate = ({ tokenSymbol={collateral_token?.symbol} tokenBalance={userBalances?.collateral} handleInpChange={useCallback( - (userCollateral: string) => updateFormValues({ userCollateral }), + (userCollateral: string) => updateFormValues({ userCollateral }).catch(errorFallback), [updateFormValues], )} - handleMaxClick={() => updateFormValues({ userCollateral: userBalances?.collateral ?? '' })} + handleMaxClick={() => + updateFormValues({ userCollateral: userBalances?.collateral ?? '' }).catch(errorFallback) + } /> {isLeverage && ( @@ -349,7 +363,7 @@ const LoanCreate = ({ tokenSymbol={borrowed_token?.symbol} tokenBalance={userBalances?.borrowed} handleInpChange={setUserBorrowed} - handleMaxClick={() => updateFormValues({ userBorrowed: userBalances?.borrowed ?? '' })} + handleMaxClick={() => updateFormValues({ userBorrowed: userBalances?.borrowed ?? '' }).catch(errorFallback)} /> )} @@ -365,10 +379,10 @@ const LoanCreate = ({ tokenSymbol={borrowed_token?.symbol} tokenBalance={userBalances?.borrowed} maxRecv={maxRecv} - handleInpChange={useCallback((debt) => updateFormValues({ debt }), [updateFormValues])} + handleInpChange={useCallback((debt) => updateFormValues({ debt }).catch(errorFallback), [updateFormValues])} handleMaxClick={async () => { const debt = await refetchMaxRecv(market, isLeverage) - updateFormValues({ debt }) + updateFormValues({ debt }).catch(errorFallback) }} /> diff --git a/apps/main/src/lend/components/PageLoanCreate/types.ts b/apps/main/src/lend/components/PageLoanCreate/types.ts index 9623108db0..503c722976 100644 --- a/apps/main/src/lend/components/PageLoanCreate/types.ts +++ b/apps/main/src/lend/components/PageLoanCreate/types.ts @@ -40,7 +40,7 @@ export type DetailInfoCompProps = { market: OneWayMarketTemplate | null steps: Step[] setHealthMode: Dispatch> - updateFormValues: (updatedFormValues: FormValues) => void + updateFormValues: (updatedFormValues: FormValues) => Promise } export type DetailInfoCompAdditionalProps = { diff --git a/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx index 5fbe18c539..f64515f4cb 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx @@ -35,6 +35,8 @@ import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const { Spacing } = SizesAndSpaces @@ -61,7 +63,7 @@ const LoanBorrowMore = ({ const fetchStepApprove = useStore((state) => state.loanBorrowMore.fetchStepApprove) const fetchStepIncrease = useStore((state) => state.loanBorrowMore.fetchStepIncrease) const refetchMaxRecv = useStore((state) => state.loanBorrowMore.refetchMaxRecv) - const setFormValues = useStore((state) => state.loanBorrowMore.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.loanBorrowMore.setFormValues)) const resetState = useStore((state) => state.loanBorrowMore.resetState) const maxSlippage = useUserProfileStore((state) => state.maxSlippage.crypto) @@ -81,14 +83,15 @@ const LoanBorrowMore = ({ }) const updateFormValues = useCallback( - ( + async ( updatedFormValues: Partial, updatedMaxSlippage?: string, isFullReset?: boolean, shouldRefetch?: boolean, ) => { setConfirmWarning(DEFAULT_CONFIRM_WARNING) - void setFormValues( + if (isFullReset) setHealthMode(DEFAULT_HEALTH_MODE) + await setFormValues( isLoaded ? api : null, market, isFullReset ? DEFAULT_FORM_VALUES : updatedFormValues, @@ -96,8 +99,6 @@ const LoanBorrowMore = ({ isLeverage, shouldRefetch, ) - - if (isFullReset) setHealthMode(DEFAULT_HEALTH_MODE) }, [api, isLeverage, isLoaded, maxSlippage, market, setFormValues], ) @@ -122,7 +123,7 @@ const LoanBorrowMore = ({ updateFormValues({}, '', true, true)} + onClose={() => updateFormValues({}, '', true, true).catch(errorFallback)} />, ) } @@ -267,23 +268,29 @@ const LoanBorrowMore = ({ } }, []) - usePageVisibleInterval(() => { - if (isLoaded && isLeverage && !formStatus.isComplete && !formStatus.step && !formStatus.error && !isConfirming) { - updateFormValues({}) - } - }, REFRESH_INTERVAL['10s']) + usePageVisibleInterval( + () => + isLoaded && + isLeverage && + !formStatus.isComplete && + !formStatus.step && + !formStatus.error && + !isConfirming && + updateFormValues({}).catch(errorFallback), + REFRESH_INTERVAL['10s'], + ) useEffect(() => { if (isLoaded) { resetState() - updateFormValues({}) + updateFormValues({}).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) // form changed to leverage, reset form useEffect(() => { - if (isLoaded) updateFormValues(DEFAULT_FORM_VALUES, '', true) + if (isLoaded) updateFormValues(DEFAULT_FORM_VALUES, '', true).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLeverage]) @@ -323,7 +330,7 @@ const LoanBorrowMore = ({ ]) useEffect(() => { - if (isLoaded) updateFormValues({}, maxSlippage) + if (isLoaded) updateFormValues({}, maxSlippage).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -344,7 +351,10 @@ const LoanBorrowMore = ({ setHealthMode, } - const setUserBorrowed = useCallback((userBorrowed: string) => updateFormValues({ userBorrowed }), [updateFormValues]) + const setUserBorrowed = useCallback( + (userBorrowed: string) => updateFormValues({ userBorrowed }).catch(errorFallback), + [updateFormValues], + ) const network = networks[rChainId] return ( @@ -364,8 +374,13 @@ const LoanBorrowMore = ({ tokenAddress={market?.collateral_token?.address} tokenSymbol={market?.collateral_token?.symbol} tokenBalance={userBalances?.collateral} - handleInpChange={useCallback((userCollateral) => updateFormValues({ userCollateral }), [updateFormValues])} - handleMaxClick={() => updateFormValues({ userCollateral: userBalances?.collateral ?? '' })} + handleInpChange={useCallback( + (userCollateral) => updateFormValues({ userCollateral }).catch(errorFallback), + [updateFormValues], + )} + handleMaxClick={() => + updateFormValues({ userCollateral: userBalances?.collateral ?? '' }).catch(errorFallback) + } /> {isLeverage && ( @@ -381,7 +396,9 @@ const LoanBorrowMore = ({ tokenSymbol={market?.borrowed_token?.symbol} tokenBalance={userBalances?.borrowed} handleInpChange={setUserBorrowed} - handleMaxClick={() => updateFormValues({ userBorrowed: userBalances?.borrowed ?? '' })} + handleMaxClick={() => + updateFormValues({ userBorrowed: userBalances?.borrowed ?? '' }).catch(errorFallback) + } /> )} @@ -399,10 +416,10 @@ const LoanBorrowMore = ({ tokenSymbol={market?.borrowed_token?.symbol} tokenBalance={userBalances?.borrowed} maxRecv={maxRecv} - handleInpChange={useCallback((debt) => updateFormValues({ debt }), [updateFormValues])} + handleInpChange={useCallback((debt) => updateFormValues({ debt }).catch(errorFallback), [updateFormValues])} handleMaxClick={async () => { const debt = await refetchMaxRecv(market, isLeverage) - updateFormValues({ debt }) + updateFormValues({ debt }).catch(errorFallback) }} /> @@ -423,7 +440,7 @@ const LoanBorrowMore = ({ updateFormValues({})} + handleBtnClose={() => updateFormValues({}).catch(errorFallback)} /> )} {steps && } diff --git a/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx index 881f8ae4ca..e7559aa33b 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx @@ -29,6 +29,7 @@ import { formatNumber, scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const LoanCollateralAdd = ({ rChainId, rOwmId, api, isLoaded, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) @@ -61,7 +62,9 @@ const LoanCollateralAdd = ({ rChainId, rOwmId, api, isLoaded, market, userActive const updateFormValues = useCallback( (updatedFormValues: Partial, isFullReset?: boolean) => { - void setFormValues(isLoaded ? api : null, market, isFullReset ? DEFAULT_FORM_VALUES : updatedFormValues) + setFormValues(isLoaded ? api : null, market, isFullReset ? DEFAULT_FORM_VALUES : updatedFormValues).catch( + errorFallback, + ) }, [api, isLoaded, market, setFormValues], ) diff --git a/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx index 2e9bf7479d..23b8fc1d70 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx @@ -30,6 +30,7 @@ import { formatNumber, scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const LoanCollateralRemove = ({ rChainId, rOwmId, isLoaded, api, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) @@ -66,7 +67,7 @@ const LoanCollateralRemove = ({ rChainId, rOwmId, isLoaded, api, market, userAct const updateFormValues = useCallback( (updatedFormValues: Partial, isFullReset?: boolean) => { setConfirmWarning(DEFAULT_CONFIRM_WARNING) - void setFormValues(isLoaded ? api : null, market, updatedFormValues) + setFormValues(isLoaded ? api : null, market, updatedFormValues).catch(errorFallback) if (isFullReset) setHealthMode(DEFAULT_HEALTH_MODE) }, diff --git a/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx index 825f1169a8..c72cf9abce 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx @@ -44,6 +44,8 @@ import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' import { getPercentage, isGreaterThan, isGreaterThanOrEqualTo, sum } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' const { Spacing } = SizesAndSpaces @@ -68,7 +70,7 @@ const LoanRepay = ({ const fetchStepApprove = useStore((state) => state.loanRepay.fetchStepApprove) const fetchStepRepay = useStore((state) => state.loanRepay.fetchStepRepay) const fetchAllUserDetails = useStore((state) => state.user.fetchAll) - const setFormValues = useStore((state) => state.loanRepay.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.loanRepay.setFormValues)) const resetState = useStore((state) => state.loanRepay.resetState) const maxSlippage = useUserProfileStore((state) => state.maxSlippage.crypto) @@ -91,22 +93,21 @@ const LoanRepay = ({ }) const updateFormValues = useCallback( - ( + async ( updatedFormValues: Partial, updatedMaxSlippage?: string, isFullReset?: boolean, shouldRefetch?: boolean, ) => { setConfirmWarning(DEFAULT_CONFIRM_WARNING) - void setFormValues( + if (isFullReset) setHealthMode(DEFAULT_HEALTH_MODE) + await setFormValues( isLoaded ? api : null, market, updatedFormValues, updatedMaxSlippage || maxSlippage, shouldRefetch, ) - - if (isFullReset) setHealthMode(DEFAULT_HEALTH_MODE) }, [api, isLoaded, maxSlippage, market, setFormValues], ) @@ -130,9 +131,8 @@ const LoanRepay = ({ description={txMessage} txHash={scanTxPath(networks[rChainId], resp.hash)} onClose={() => { - if (resp.loanExists) { - updateFormValues(DEFAULT_FORM_VALUES, '', true) - } else { + updateFormValues(DEFAULT_FORM_VALUES, '', true).catch(errorFallback) + if (!resp.loanExists) { push(getCollateralListPathname(params)) } }} @@ -286,21 +286,27 @@ const LoanRepay = ({ usePageVisibleInterval(() => { const { swapRequired } = _parseValues(formValues) - if (isLoaded && swapRequired && !formStatus.isComplete && !formStatus.step && !formStatus.error && !isConfirming) { - updateFormValues({}) - } + return ( + isLoaded && + swapRequired && + !formStatus.isComplete && + !formStatus.step && + !formStatus.error && + !isConfirming && + updateFormValues({}).catch(errorFallback) + ) }, REFRESH_INTERVAL['10s']) useEffect(() => { if (isLoaded) { resetState() - updateFormValues({}) + updateFormValues({}).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) useEffect(() => { - if (isLoaded) updateFormValues({}, maxSlippage) + if (isLoaded) updateFormValues({}, maxSlippage).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -361,11 +367,11 @@ const LoanRepay = ({ const network = networks[rChainId] const setUserCollateral = useCallback( - (userCollateral: string) => updateFormValues({ userCollateral, isFullRepay: false }), + (userCollateral: string) => updateFormValues({ userCollateral, isFullRepay: false }).catch(errorFallback), [updateFormValues], ) const setStateCollateral = useCallback( - (stateCollateral: string) => updateFormValues({ stateCollateral, isFullRepay: false }), + (stateCollateral: string) => updateFormValues({ stateCollateral, isFullRepay: false }).catch(errorFallback), [updateFormValues], ) @@ -388,7 +394,9 @@ const LoanRepay = ({ tokenBalance={userState?.collateral} handleInpChange={setStateCollateral} handleMaxClick={() => - updateFormValues({ stateCollateral: userState?.collateral ?? '', isFullRepay: false }) + updateFormValues({ stateCollateral: userState?.collateral ?? '', isFullRepay: false }).catch( + errorFallback, + ) } /> @@ -412,7 +420,9 @@ const LoanRepay = ({ tokenBalance={userBalances?.collateral} handleInpChange={setUserCollateral} handleMaxClick={() => - updateFormValues({ userCollateral: userBalances?.collateral ?? '', isFullRepay: false }) + updateFormValues({ userCollateral: userBalances?.collateral ?? '', isFullRepay: false }).catch( + errorFallback, + ) } /> )} @@ -432,29 +442,29 @@ const LoanRepay = ({ handleInpChange={useCallback( (userBorrowed) => { if (hasExpectedBorrowed) { - updateFormValues({ userBorrowed, isFullRepay: false }) + updateFormValues({ userBorrowed, isFullRepay: false }).catch(errorFallback) return } if (!hasExpectedBorrowed && userState?.borrowed != null && borrowedTokenDecimals) { const totalRepay = sum([userState.borrowed, userBorrowed], borrowedTokenDecimals) const isFullRepay = isGreaterThanOrEqualTo(totalRepay, userState.debt, borrowedTokenDecimals) - updateFormValues({ userBorrowed, isFullRepay }) + updateFormValues({ userBorrowed, isFullRepay }).catch(errorFallback) return } - updateFormValues({ userBorrowed, isFullRepay: false }) + updateFormValues({ userBorrowed, isFullRepay: false }).catch(errorFallback) }, [borrowedTokenDecimals, hasExpectedBorrowed, updateFormValues, userState?.borrowed, userState?.debt], )} handleMaxClick={async () => { if (+userBalances.borrowed === 0) { - updateFormValues({ userBorrowed: '', isFullRepay: false }) + updateFormValues({ userBorrowed: '', isFullRepay: false }).catch(errorFallback) return } if (expectedBorrowed) { - updateFormValues({ userBorrowed: userBalances.borrowed, isFullRepay: false }) + updateFormValues({ userBorrowed: userBalances.borrowed, isFullRepay: false }).catch(errorFallback) return } @@ -467,14 +477,11 @@ const LoanRepay = ({ const amountNeededWithInterestRate = amountNeeded + getPercentage(amountNeeded, 1n) if (isGreaterThan(amountNeededWithInterestRate, userBalances.borrowed, borrowedTokenDecimals)) { - updateFormValues({ userBorrowed: userBalances.borrowed, isFullRepay: false }) + updateFormValues({ userBorrowed: userBalances.borrowed, isFullRepay: false }).catch(errorFallback) return } - - updateFormValues({ userBorrowed: '', isFullRepay: true }) - return } - updateFormValues({ userBorrowed: '', isFullRepay: false }) + updateFormValues({ userBorrowed: '', isFullRepay: false }).catch(errorFallback) }} /> @@ -489,9 +496,9 @@ const LoanRepay = ({ isSelected={detailInfoLeverage?.repayIsFull || formValues.isFullRepay} onChange={(isFullRepay) => { if (isFullRepay) { - updateFormValues({ ...DEFAULT_FORM_VALUES, isFullRepay }) + updateFormValues({ ...DEFAULT_FORM_VALUES, isFullRepay }).catch(errorFallback) } else { - updateFormValues({ ...DEFAULT_FORM_VALUES }) + updateFormValues({ ...DEFAULT_FORM_VALUES }).catch(errorFallback) } }} > @@ -531,7 +538,7 @@ const LoanRepay = ({ updateFormValues({})} + handleBtnClose={() => updateFormValues({}).catch(errorFallback)} /> ) : null} {steps && } diff --git a/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx index b1647b2693..fb43f5c6b1 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx @@ -36,6 +36,7 @@ import { formatNumber, scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t, Trans } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const LoanSelfLiquidation = ({ rChainId, @@ -75,7 +76,7 @@ const LoanSelfLiquidation = ({ setTxInfoBar(null) if (isLoaded && api && market) { - void fetchDetails(api, market, maxSlippage) + fetchDetails(api, market, maxSlippage).catch(errorFallback) } }, [isLoaded, api, market, fetchDetails, maxSlippage]) @@ -184,7 +185,7 @@ const LoanSelfLiquidation = ({ // max slippage useEffect(() => { - if (isLoaded && api && market && maxSlippage) void fetchDetails(api, market, maxSlippage) + if (isLoaded && api && market && maxSlippage) fetchDetails(api, market, maxSlippage).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -192,7 +193,7 @@ const LoanSelfLiquidation = ({ useEffect(() => { if (isLoaded && api && market && maxSlippage) { resetState() - void fetchDetails(api, market, maxSlippage) + fetchDetails(api, market, maxSlippage).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) diff --git a/apps/main/src/lend/components/PageLoanManage/Page.tsx b/apps/main/src/lend/components/PageLoanManage/Page.tsx index 92eb08a6c7..4975467cf1 100644 --- a/apps/main/src/lend/components/PageLoanManage/Page.tsx +++ b/apps/main/src/lend/components/PageLoanManage/Page.tsx @@ -38,6 +38,7 @@ import { useParams } from '@ui-kit/hooks/router' import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' +import { errorFallback } from '@ui-kit/utils/error.util' const { Spacing } = SizesAndSpaces @@ -108,13 +109,18 @@ const Page = () => { useEffect(() => { // delay fetch rest after form details are fetched first - const timer = setTimeout(async () => { - if (!api || !market || !isPageVisible || !isLoaded) return - void fetchAllMarketDetails(api, market, true) - if (api.signerAddress && loanExists) { - void fetchAllUserMarketDetails(api, market, true) - } - }, REFRESH_INTERVAL['3s']) + const timer = setTimeout( + () => + api && + market && + isPageVisible && + isLoaded && + Promise.all([ + fetchAllMarketDetails(api, market, true), + api.signerAddress && loanExists && fetchAllUserMarketDetails(api, market, true), + ]).catch(errorFallback), + REFRESH_INTERVAL['3s'], + ) return () => clearTimeout(timer) }, [api, fetchAllMarketDetails, fetchAllUserMarketDetails, isLoaded, isPageVisible, loanExists, market]) diff --git a/apps/main/src/lend/components/PageVault/VaultClaim/index.tsx b/apps/main/src/lend/components/PageVault/VaultClaim/index.tsx index 79ee59401f..8c7218ee1c 100644 --- a/apps/main/src/lend/components/PageVault/VaultClaim/index.tsx +++ b/apps/main/src/lend/components/PageVault/VaultClaim/index.tsx @@ -19,6 +19,7 @@ import TxInfoBar from '@ui/TxInfoBar' import { formatNumber, scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const VaultClaim = ({ isLoaded, api, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) @@ -38,13 +39,14 @@ const VaultClaim = ({ isLoaded, api, market, userActiveKey }: PageContentProps) const haveClaimableCrv = +crv > 0 const haveClaimableRewards = rewards.some((r) => +r.amount > 0) - const updateFormValues = useCallback(() => { - void setFormValues(userActiveKey, isLoaded ? api : null, market) - }, [api, isLoaded, market, setFormValues, userActiveKey]) + const updateFormValues = useCallback( + () => setFormValues(userActiveKey, isLoaded ? api : null, market), + [api, isLoaded, market, setFormValues, userActiveKey], + ) - const reset = useCallback(() => { + const reset = useCallback(async () => { setTxInfoBar(null) - updateFormValues() + await updateFormValues() }, [updateFormValues]) const handleBtnClickClaim = useCallback( @@ -71,7 +73,7 @@ const VaultClaim = ({ isLoaded, api, market, userActiveKey }: PageContentProps) reset()} + onClose={() => reset().catch(errorFallback)} />, ) } @@ -134,7 +136,7 @@ const VaultClaim = ({ isLoaded, api, market, userActiveKey }: PageContentProps) }, [resetState]) useEffect(() => { - if (isLoaded) updateFormValues() + if (isLoaded) updateFormValues().catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) @@ -182,7 +184,9 @@ const VaultClaim = ({ isLoaded, api, market, userActiveKey }: PageContentProps) {/* actions */} - {formStatus.error ? reset()} /> : null} + {formStatus.error && ( + reset().catch(errorFallback)} /> + )} {txInfoBar} {api && market && ( diff --git a/apps/main/src/lend/components/PageVault/VaultDepositMint/index.tsx b/apps/main/src/lend/components/PageVault/VaultDepositMint/index.tsx index 1d8ec1b20b..a367385630 100644 --- a/apps/main/src/lend/components/PageVault/VaultDepositMint/index.tsx +++ b/apps/main/src/lend/components/PageVault/VaultDepositMint/index.tsx @@ -28,6 +28,7 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const VaultDepositMint = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) @@ -53,16 +54,15 @@ const VaultDepositMint = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, const { signerAddress } = api ?? {} const updateFormValues = useCallback( - (updatedFormValues: Partial) => { - void setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues) - }, + (updatedFormValues: Partial) => + setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues), [api, isLoaded, market, rChainId, rFormType, setFormValues], ) const reset = useCallback( - (updatedFormValues: Partial) => { + async (updatedFormValues: Partial) => { setTxInfoBar(null) - updateFormValues(updatedFormValues) + await updateFormValues(updatedFormValues) }, [updateFormValues], ) @@ -71,7 +71,7 @@ const VaultDepositMint = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, const onBalance = useCallback((amount?: Decimal) => reset({ amount: amount ?? '' }), [reset]) const handleInpAmountChange = (amount: string) => { - reset({ amount }) + reset({ amount }).catch(errorFallback) } const handleBtnClickDeposit = useCallback( @@ -97,7 +97,7 @@ const VaultDepositMint = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, reset({})} + onClose={() => reset({}).catch(errorFallback)} />, ) } @@ -170,7 +170,7 @@ const VaultDepositMint = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, }, [resetState]) useEffect(() => { - if (isLoaded) updateFormValues({}) + if (isLoaded) updateFormValues({}).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) diff --git a/apps/main/src/lend/components/PageVault/VaultStake/index.tsx b/apps/main/src/lend/components/PageVault/VaultStake/index.tsx index 7a20024fdd..f437ae54d8 100644 --- a/apps/main/src/lend/components/PageVault/VaultStake/index.tsx +++ b/apps/main/src/lend/components/PageVault/VaultStake/index.tsx @@ -23,6 +23,7 @@ import { useLegacyTokenInput } from '@ui-kit/hooks/useFeatureFlags' import { t } from '@ui-kit/lib/i18n' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const VaultStake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) @@ -43,22 +44,21 @@ const VaultStake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, userAc const { signerAddress } = api ?? {} const updateFormValues = useCallback( - (updatedFormValues: Partial) => { - void setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues) - }, + (updatedFormValues: Partial) => + setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues), [api, isLoaded, market, rChainId, rFormType, setFormValues], ) const reset = useCallback( - (updatedFormValues: Partial) => { + async (updatedFormValues: Partial) => { setTxInfoBar(null) - updateFormValues(updatedFormValues) + await updateFormValues(updatedFormValues) }, [updateFormValues], ) const handleInpAmountChange = (amount: string) => { - reset({ amount }) + reset({ amount }).catch(errorFallback) } const handleBtnClickStake = useCallback( @@ -152,7 +152,7 @@ const VaultStake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, userAc }, [resetState]) useEffect(() => { - if (isLoaded) updateFormValues({}) + if (isLoaded) updateFormValues({}).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) @@ -167,7 +167,7 @@ const VaultStake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, userAc const activeStep = signerAddress ? getActiveStep(steps) : null const disabled = !!formStatus.step - const onBalance = useCallback((amount?: Decimal) => reset({ amount: amount ?? '' }), [reset]) + const onBalance = useCallback((amount?: Decimal) => reset({ amount: amount ?? '' }).catch(errorFallback), [reset]) const detailInfoCrvIncentivesComp = DetailInfoCrvIncentives({ rChainId, rOwmId, lpTokenAmount: formValues.amount }) return ( diff --git a/apps/main/src/lend/components/PageVault/VaultUnstake/index.tsx b/apps/main/src/lend/components/PageVault/VaultUnstake/index.tsx index 94278d61f5..89b16f1d1d 100644 --- a/apps/main/src/lend/components/PageVault/VaultUnstake/index.tsx +++ b/apps/main/src/lend/components/PageVault/VaultUnstake/index.tsx @@ -22,6 +22,7 @@ import { useLegacyTokenInput } from '@ui-kit/hooks/useFeatureFlags' import { t } from '@ui-kit/lib/i18n' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const VaultUnstake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) @@ -41,22 +42,21 @@ const VaultUnstake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, user const { signerAddress } = api ?? {} const updateFormValues = useCallback( - (updatedFormValues: Partial) => { - void setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues) - }, + (updatedFormValues: Partial) => + setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues), [api, isLoaded, market, rChainId, rFormType, setFormValues], ) const reset = useCallback( - (updatedFormValues: Partial) => { + async (updatedFormValues: Partial) => { setTxInfoBar(null) - updateFormValues(updatedFormValues) + await updateFormValues(updatedFormValues) }, [updateFormValues], ) const handleInpAmountChange = (amount: string) => { - reset({ amount }) + reset({ amount }).catch(errorFallback) } const handleBtnClickUnstake = useCallback( @@ -79,7 +79,9 @@ const VaultUnstake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, user if (isSubscribed.current && resp && resp.hash && resp.activeKey === activeKey && !resp.error) { const txMessage = t`Transaction completed.` const txHash = scanTxPath(networks[chainId], resp.hash) - setTxInfoBar( reset({})} />) + setTxInfoBar( + reset({}).catch(errorFallback)} />, + ) } if (resp?.error) setTxInfoBar(null) notification?.dismiss() @@ -137,7 +139,7 @@ const VaultUnstake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, user }, [resetState]) useEffect(() => { - if (isLoaded) updateFormValues({}) + if (isLoaded) updateFormValues({}).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) @@ -152,7 +154,7 @@ const VaultUnstake = ({ rChainId, rOwmId, rFormType, isLoaded, api, market, user const activeStep = signerAddress ? getActiveStep(steps) : null const disabled = !!formStatus.step - const onBalance = useCallback((amount?: Decimal) => reset({ amount: amount ?? '' }), [reset]) + const onBalance = useCallback((amount?: Decimal) => reset({ amount: amount ?? '' }).catch(errorFallback), [reset]) return ( <> diff --git a/apps/main/src/lend/components/PageVault/VaultWithdrawRedeem/index.tsx b/apps/main/src/lend/components/PageVault/VaultWithdrawRedeem/index.tsx index b44ea416ba..14d637abb6 100644 --- a/apps/main/src/lend/components/PageVault/VaultWithdrawRedeem/index.tsx +++ b/apps/main/src/lend/components/PageVault/VaultWithdrawRedeem/index.tsx @@ -26,6 +26,7 @@ import { useLegacyTokenInput } from '@ui-kit/hooks/useFeatureFlags' import { t } from '@ui-kit/lib/i18n' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const VaultWithdrawRedeem = ({ rChainId, @@ -61,24 +62,21 @@ const VaultWithdrawRedeem = ({ const disableWithdrawInFull = isNotReady || max !== userBalances?.vaultSharesConverted const updateFormValues = useCallback( - (updatedFormValues: Partial) => { - void setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues) - }, + (updatedFormValues: Partial) => + setFormValues(rChainId, rFormType, isLoaded ? api : null, market, updatedFormValues), [api, isLoaded, market, rChainId, rFormType, setFormValues], ) const reset = useCallback( - (updatedFormValues: Partial) => { + async (updatedFormValues: Partial) => { setTxInfoBar(null) - updateFormValues(updatedFormValues) + await updateFormValues(updatedFormValues) }, [updateFormValues], ) const handleFormChange = useCallback( - (updatedFormValues: Partial) => { - reset({ ...updatedFormValues, amountError: '' }) - }, + (updatedFormValues: Partial) => reset({ ...updatedFormValues, amountError: '' }), [reset], ) @@ -111,7 +109,7 @@ const VaultWithdrawRedeem = ({ reset({})} + onClose={() => reset({}).catch(errorFallback)} />, ) } @@ -173,7 +171,7 @@ const VaultWithdrawRedeem = ({ }, [resetState]) useEffect(() => { - if (isLoaded) updateFormValues({}) + if (isLoaded) updateFormValues({}).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoaded]) @@ -214,7 +212,7 @@ const VaultWithdrawRedeem = ({ }} value={formValues.amount} onChange={(amount) => { - handleFormChange({ amount, isFullWithdraw: false }) + handleFormChange({ amount, isFullWithdraw: false }).catch(errorFallback) }} /> @@ -276,7 +274,7 @@ const VaultWithdrawRedeem = ({ handleFormChange({ isFullWithdraw, amount: '' })} + onChange={(isFullWithdraw) => handleFormChange({ isFullWithdraw, amount: '' }).catch(errorFallback)} > {t`Withdraw in full`} diff --git a/apps/main/src/lend/components/TokenLabel.tsx b/apps/main/src/lend/components/TokenLabel.tsx index 5c14627846..d14ffdc912 100644 --- a/apps/main/src/lend/components/TokenLabel.tsx +++ b/apps/main/src/lend/components/TokenLabel.tsx @@ -10,6 +10,7 @@ import TextEllipsis from '@ui/TextEllipsis' import { scanTokenPath } from '@ui/utils' import { TokenIcon } from '@ui-kit/shared/ui/TokenIcon' import { copyToClipboard } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const TokenLabel = ({ rChainId, @@ -50,7 +51,7 @@ const TokenLabel = ({ size="medium" onClick={(evt) => { evt.stopPropagation() - void copyToClipboard(address) + copyToClipboard(address).catch(errorFallback) }} > diff --git a/apps/main/src/lend/hooks/useAbiTotalSupply.tsx b/apps/main/src/lend/hooks/useAbiTotalSupply.tsx index fea9a111b2..443fe09b32 100644 --- a/apps/main/src/lend/hooks/useAbiTotalSupply.tsx +++ b/apps/main/src/lend/hooks/useAbiTotalSupply.tsx @@ -6,6 +6,7 @@ import { ChainId } from '@/lend/types/lend.types' import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { weiToEther } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const useAbiTotalSupply = (rChainId: ChainId, contractAddress: string | undefined) => { const contract = useContract(rChainId, false, 'totalSupply', contractAddress) @@ -23,12 +24,10 @@ const useAbiTotalSupply = (rChainId: ChainId, contractAddress: string | undefine }, []) useEffect(() => { - if (contract && isValidAddress) void getTotalSupply(contract) + if (contract && isValidAddress) getTotalSupply(contract).catch(errorFallback) }, [contract, isValidAddress, getTotalSupply]) - usePageVisibleInterval(() => { - if (contract && isValidAddress) void getTotalSupply(contract) - }, REFRESH_INTERVAL['1m']) + usePageVisibleInterval(() => contract && isValidAddress && getTotalSupply(contract), REFRESH_INTERVAL['1m']) return totalSupply } diff --git a/apps/main/src/lend/hooks/useContract.ts b/apps/main/src/lend/hooks/useContract.ts index a15cb070f5..2744181783 100644 --- a/apps/main/src/lend/hooks/useContract.ts +++ b/apps/main/src/lend/hooks/useContract.ts @@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from 'react' import networks from '@/lend/networks' import { ChainId, Provider } from '@/lend/types/lend.types' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' const useAbiGaugeTotalSupply = ( rChainId: ChainId, @@ -41,7 +42,7 @@ const useAbiGaugeTotalSupply = ( : walletProvider || new JsonRpcProvider(networks[rChainId].rpcUrl) if (jsonModuleName && contractAddress && provider) { - void (async () => setContract(await getContract(jsonModuleName, contractAddress, provider)))() + ;(async () => setContract(await getContract(jsonModuleName, contractAddress, provider)))().catch(errorFallback) } } }, [contractAddress, getContract, walletProvider, jsonModuleName, rChainId, signerRequired]) diff --git a/apps/main/src/lend/hooks/useVaultShares.ts b/apps/main/src/lend/hooks/useVaultShares.ts index 177ae84c46..370c5ea9a7 100644 --- a/apps/main/src/lend/hooks/useVaultShares.ts +++ b/apps/main/src/lend/hooks/useVaultShares.ts @@ -4,6 +4,7 @@ import useStore from '@/lend/store/useStore' import { ChainId } from '@/lend/types/lend.types' import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { formatNumber } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' function formatNumberWithPrecision(value: number, precisionDigits: number) { const valueDigits = Math.max(0, Math.floor(Math.log10(value))) @@ -39,7 +40,7 @@ function useVaultShares(rChainId: ChainId, rOwmId: string, vaultShares: string | }, [pricePerShareResp, usdRate, symbol, vaultShares]) useEffect(() => { - if (market && +vaultShares > 0) void fetchVaultPricePerShare(rChainId, market) + if (market && +vaultShares > 0) fetchVaultPricePerShare(rChainId, market).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [market?.id, vaultShares]) diff --git a/apps/main/src/lend/store/createLoanBorrowMoreSlice.ts b/apps/main/src/lend/store/createLoanBorrowMoreSlice.ts index 9b43d69a03..f6b9d339e7 100644 --- a/apps/main/src/lend/store/createLoanBorrowMoreSlice.ts +++ b/apps/main/src/lend/store/createLoanBorrowMoreSlice.ts @@ -23,6 +23,7 @@ import { refetchLoanExists } from '@/llamalend/queries/loan-exists' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { getLib, useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -240,7 +241,7 @@ const createLoanBorrowMore = ( // api calls await sliceState.fetchMaxRecv(activeKey.activeKeyMax, api, market, isLeverage) await sliceState.fetchDetailInfo(activeKey.activeKey, api, market, maxSlippage, isLeverage) - void sliceState.fetchEstGasApproval(activeKey.activeKey, api, market, maxSlippage, isLeverage) + sliceState.fetchEstGasApproval(activeKey.activeKey, api, market, maxSlippage, isLeverage).catch(errorFallback) }, // steps @@ -271,7 +272,7 @@ const createLoanBorrowMore = ( isApprovedCompleted: !error, stepError: error, }) - if (!error) void sliceState.fetchEstGasApproval(activeKey, api, market, maxSlippage, isLeverage) + if (!error) sliceState.fetchEstGasApproval(activeKey, api, market, maxSlippage, isLeverage).catch(errorFallback) return { ...resp, error } } }, @@ -306,12 +307,12 @@ const createLoanBorrowMore = ( ) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { if (error) { @@ -330,18 +331,18 @@ const createLoanBorrowMore = ( userAddress: wallet?.account?.address, }) if (loanExists) { - void user.fetchAll(api, market, true) + user.fetchAll(api, market, true).catch(errorFallback) invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) } invalidateMarketDetails({ chainId: api.chainId, marketId: market.id }) - void markets.fetchAll(api, market, true) + markets.fetchAll(api, market, true).catch(errorFallback) // update formStatus sliceState.setStateByKeys({ ...DEFAULT_STATE, formStatus: { ...DEFAULT_FORM_STATUS, isApproved: true, isComplete: true }, }) - void sliceState.setFormValues(api, market, DEFAULT_FORM_VALUES, maxSlippage, isLeverage) + sliceState.setFormValues(api, market, DEFAULT_FORM_VALUES, maxSlippage, isLeverage).catch(errorFallback) return { ...resp, error } } } diff --git a/apps/main/src/lend/store/createLoanCollateralAddSlice.ts b/apps/main/src/lend/store/createLoanCollateralAddSlice.ts index a0b6fe3ccd..ff5afaa141 100644 --- a/apps/main/src/lend/store/createLoanCollateralAddSlice.ts +++ b/apps/main/src/lend/store/createLoanCollateralAddSlice.ts @@ -14,6 +14,7 @@ import { refetchLoanExists } from '@/llamalend/queries/loan-exists' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -126,8 +127,10 @@ const createLoanCollateralAdd = ( } // api calls - void sliceState.fetchDetailInfo(activeKey, api, market) - void sliceState.fetchEstGasApproval(activeKey, api, market) + await Promise.all([ + sliceState.fetchDetailInfo(activeKey, api, market), + sliceState.fetchEstGasApproval(activeKey, api, market), + ]) }, // step @@ -151,7 +154,7 @@ const createLoanCollateralAdd = ( isApproved: !error, isInProgress: !error, }) - if (!error) void sliceState.fetchEstGasApproval(activeKey, api, market) + if (!error) sliceState.fetchEstGasApproval(activeKey, api, market).catch(errorFallback) return { ...resp, error } } }, @@ -179,12 +182,12 @@ const createLoanCollateralAdd = ( ) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { if (error) { @@ -198,11 +201,11 @@ const createLoanCollateralAdd = ( userAddress: wallet?.account?.address, }) if (loanExists) { - void user.fetchAll(api, market, true) + user.fetchAll(api, market, true).catch(errorFallback) invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) } invalidateMarketDetails({ chainId: api.chainId, marketId: market.id }) - void markets.fetchAll(api, market, true) + markets.fetchAll(api, market, true).catch(errorFallback) // update formStatus sliceState.setStateByKeys({ diff --git a/apps/main/src/lend/store/createLoanCollateralRemoveSlice.ts b/apps/main/src/lend/store/createLoanCollateralRemoveSlice.ts index 3ae72c6f3a..7780b5a389 100644 --- a/apps/main/src/lend/store/createLoanCollateralRemoveSlice.ts +++ b/apps/main/src/lend/store/createLoanCollateralRemoveSlice.ts @@ -14,6 +14,7 @@ import { refetchLoanExists } from '@/llamalend/queries/loan-exists' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' const { cloneDeep } = lodash @@ -140,8 +141,10 @@ const createLoanCollateralRemove = ( // api calls await sliceState.fetchMaxRemovable(api, market) - void sliceState.fetchDetailInfo(activeKey, api, market) - void sliceState.fetchEstGas(activeKey, api, market) + Promise.all([ + sliceState.fetchDetailInfo(activeKey, api, market), + sliceState.fetchEstGas(activeKey, api, market), + ]).catch(errorFallback) }, // steps @@ -168,12 +171,12 @@ const createLoanCollateralRemove = ( formValues.collateral, ) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { if (error) { @@ -187,18 +190,18 @@ const createLoanCollateralRemove = ( userAddress: wallet?.account?.address, }) if (loanExists) { - void user.fetchAll(api, market, true) + user.fetchAll(api, market, true).catch(errorFallback) invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) } invalidateMarketDetails({ chainId: api.chainId, marketId: market.id }) - void markets.fetchAll(api, market, true) + markets.fetchAll(api, market, true).catch(errorFallback) // update formStatus sliceState.setStateByKeys({ ...DEFAULT_STATE, formStatus: { ...DEFAULT_FORM_STATUS, isComplete: true }, }) - void sliceState.setFormValues(api, market, DEFAULT_FORM_VALUES) + sliceState.setFormValues(api, market, DEFAULT_FORM_VALUES).catch(errorFallback) return { ...resp, error } } } diff --git a/apps/main/src/lend/store/createLoanCreateSlice.ts b/apps/main/src/lend/store/createLoanCreateSlice.ts index 445a2bf8e1..510163f746 100644 --- a/apps/main/src/lend/store/createLoanCreateSlice.ts +++ b/apps/main/src/lend/store/createLoanCreateSlice.ts @@ -21,6 +21,7 @@ import { refetchLoanExists } from '@/llamalend/queries/loan-exists' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -252,11 +253,16 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi } // api calls - if (isLeverage) void sliceState.fetchMaxLeverage(market) - await sliceState.fetchMaxRecv(activeKeys.activeKeyMax, api, market, isLeverage) - await sliceState.fetchDetailInfo(activeKeys.activeKey, api, market, maxSlippage, isLeverage) - void sliceState.fetchEstGasApproval(activeKeys.activeKey, api, market, maxSlippage, isLeverage) - void sliceState.fetchLiqRanges(activeKeys.activeKeyLiqRange, api, market, isLeverage) + if (isLeverage) sliceState.fetchMaxLeverage(market).catch(errorFallback) + + await Promise.all([ + sliceState.fetchMaxRecv(activeKeys.activeKeyMax, api, market, isLeverage), + sliceState.fetchDetailInfo(activeKeys.activeKey, api, market, maxSlippage, isLeverage), + ]) + Promise.all([ + sliceState.fetchEstGasApproval(activeKeys.activeKey, api, market, maxSlippage, isLeverage), + sliceState.fetchLiqRanges(activeKeys.activeKeyLiqRange, api, market, isLeverage), + ]).catch(errorFallback) }, // steps @@ -288,7 +294,7 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi isApprovedCompleted: !error, stepError: error, }) - if (!error) void sliceState.fetchEstGasApproval(activeKey, api, market, maxSlippage, isLeverage) + if (!error) sliceState.fetchEstGasApproval(activeKey, api, market, maxSlippage, isLeverage).catch(errorFallback) return { ...resp, error } } }, @@ -323,12 +329,12 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi isLeverage, ) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { if (error) { @@ -343,7 +349,7 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi if (loanExists) { // api calls await user.fetchAll(api, market, true) - void markets.fetchAll(api, market, true) + markets.fetchAll(api, market, true).catch(errorFallback) markets.setStateByKey('marketDetailsView', 'user') invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) // update formStatus diff --git a/apps/main/src/lend/store/createLoanRepaySlice.ts b/apps/main/src/lend/store/createLoanRepaySlice.ts index 229b660358..2977cd7657 100644 --- a/apps/main/src/lend/store/createLoanRepaySlice.ts +++ b/apps/main/src/lend/store/createLoanRepaySlice.ts @@ -19,6 +19,7 @@ import { refetchLoanExists } from '@/llamalend/queries/loan-exists' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -193,7 +194,7 @@ const createLoanRepaySlice = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi { const { formStatus, ...sliceState } = get()[sliceKey] @@ -153,7 +154,7 @@ const createLoanSelfLiquidationSlice = ( isInProgress: !error, stepError: error, }) - if (!error) void sliceState.fetchEstGasApproval(api, market, maxSlippage) + if (!error) sliceState.fetchEstGasApproval(api, market, maxSlippage).catch(errorFallback) return { ...resp, error } } }, @@ -175,12 +176,12 @@ const createLoanSelfLiquidationSlice = ( // api calls const { error, ...resp } = await loanSelfLiquidation.selfLiquidate(provider, market, maxSlippage) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp) { const loanExists = await refetchLoanExists({ @@ -199,11 +200,11 @@ const createLoanSelfLiquidationSlice = ( } else { // api calls if (loanExists) { - void user.fetchAll(api, market, true) + user.fetchAll(api, market, true).catch(errorFallback) invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) } invalidateMarketDetails({ chainId: api.chainId, marketId: market.id }) - void markets.fetchAll(api, market, true) + markets.fetchAll(api, market, true).catch(errorFallback) // update state sliceState.setStateByKey('formStatus', { ...DEFAULT_FORM_STATUS, isApproved: true, isComplete: true }) diff --git a/apps/main/src/lend/store/createVaultClaimSlice.ts b/apps/main/src/lend/store/createVaultClaimSlice.ts index f8c1082384..fae675526b 100644 --- a/apps/main/src/lend/store/createVaultClaimSlice.ts +++ b/apps/main/src/lend/store/createVaultClaimSlice.ts @@ -7,6 +7,7 @@ import apiLending from '@/lend/lib/apiLending' import type { State } from '@/lend/store/useStore' import { Api, MarketClaimable, OneWayMarketTemplate } from '@/lend/types/lend.types' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -63,10 +64,9 @@ const createVaultClaim = (set: StoreApi['setState'], get: StoreApi if (!userActiveKey || !api || !market) return const { signerAddress } = api - // api calls if (signerAddress) { - void get()[sliceKey].fetchClaimable(userActiveKey, api, market) + get()[sliceKey].fetchClaimable(userActiveKey, api, market).catch(errorFallback) } }, @@ -86,9 +86,11 @@ const createVaultClaim = (set: StoreApi['setState'], get: StoreApi if (resp.userActiveKey === userActiveKey) { // re-fetch api - void get()[sliceKey].fetchClaimable(resp.userActiveKey, api, market) - void get().user.fetchUserMarketBalances(api, market, true) - void get().markets.fetchAll(api, market, true) + Promise.all([ + get()[sliceKey].fetchClaimable(resp.userActiveKey, api, market), + get().user.fetchUserMarketBalances(api, market, true), + get().markets.fetchAll(api, market, true), + ]).catch(errorFallback) // update state const partialFormStatus: Partial = { diff --git a/apps/main/src/lend/store/createVaultDepositMintSlice.ts b/apps/main/src/lend/store/createVaultDepositMintSlice.ts index 6dfd9e7047..7bad81685b 100644 --- a/apps/main/src/lend/store/createVaultDepositMintSlice.ts +++ b/apps/main/src/lend/store/createVaultDepositMintSlice.ts @@ -13,6 +13,7 @@ import { Api, ChainId, FutureRates, OneWayMarketTemplate } from '@/lend/types/le import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -132,11 +133,11 @@ const createVaultMint = ( } // api calls - void get()[sliceKey].fetchDetails(activeKey, formType, market) + get()[sliceKey].fetchDetails(activeKey, formType, market).catch(errorFallback) if (signerAddress) { await get()[sliceKey].fetchMax(rChainId, formType, market) - void get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market) + get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market).catch(errorFallback) } }, @@ -161,7 +162,7 @@ const createVaultMint = ( isInProgress: true, } get()[sliceKey].setStateByKey('formStatus', merge(cloneDeep(FORM_STATUS), partialFormStatus)) - if (!resp.error) void get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market) + if (!resp.error) get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market).catch(errorFallback) return resp } }, @@ -179,17 +180,19 @@ const createVaultMint = ( const { amount } = formValues const resp = await fn(activeKey, provider, market, amount) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { // re-fetch api - void get().user.fetchUserMarketBalances(api, market, true) - void get().markets.fetchAll(api, market, true) + Promise.all([ + get().user.fetchUserMarketBalances(api, market, true), + get().markets.fetchAll(api, market, true), + ]).catch(errorFallback) invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) invalidateMarketDetails({ chainId: api.chainId, marketId: market.id }) // update state diff --git a/apps/main/src/lend/store/createVaultStakeSlice.ts b/apps/main/src/lend/store/createVaultStakeSlice.ts index da21f4d54e..d585b9f029 100644 --- a/apps/main/src/lend/store/createVaultStakeSlice.ts +++ b/apps/main/src/lend/store/createVaultStakeSlice.ts @@ -13,6 +13,7 @@ import { Api, ChainId, OneWayMarketTemplate } from '@/lend/types/lend.types' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -98,7 +99,7 @@ const createVaultStake = (set: StoreApi['setState'], get: StoreApi // api calls if (signerAddress) { - void get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market) + get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market).catch(errorFallback) } }, @@ -122,7 +123,7 @@ const createVaultStake = (set: StoreApi['setState'], get: StoreApi isInProgress: true, } get()[sliceKey].setStateByKey('formStatus', merge(cloneDeep(FORM_STATUS), partialFormStatus)) - if (!resp.error) void get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market) + if (!resp.error) get()[sliceKey].fetchEstGasApproval(activeKey, formType, api, market).catch(errorFallback) return resp } }, @@ -139,17 +140,20 @@ const createVaultStake = (set: StoreApi['setState'], get: StoreApi const { amount } = formValues const resp = await apiLending.vaultStake.stake(activeKey, provider, market, amount) // update user events api - void getUserMarketCollateralEvents( + getUserMarketCollateralEvents( wallet?.account?.address, networks[chainId].name as Chain, market.addresses.controller, resp.hash, - ) + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { // re-fetch api - void get().user.fetchUserMarketBalances(api, market, true) - void get().markets.fetchAll(api, market, true) + Promise.all([ + get().user.fetchUserMarketBalances(api, market, true), + get().markets.fetchAll(api, market, true), + ]).catch(errorFallback) + invalidateAllUserBorrowDetails({ chainId: api.chainId, marketId: market.id }) invalidateMarketDetails({ chainId: api.chainId, marketId: market.id }) diff --git a/apps/main/src/lend/store/createVaultUnstakeSlice.ts b/apps/main/src/lend/store/createVaultUnstakeSlice.ts index 1bf3d4da88..02a5a43888 100644 --- a/apps/main/src/lend/store/createVaultUnstakeSlice.ts +++ b/apps/main/src/lend/store/createVaultUnstakeSlice.ts @@ -13,6 +13,7 @@ import { Api, ChainId, OneWayMarketTemplate } from '@/lend/types/lend.types' import { Chain } from '@curvefi/prices-api' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/lending' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -96,7 +97,7 @@ const createVaultUnstake = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi { - void onUpdate({ userCollateral, debt, range, userBorrowed, slippage, leverageEnabled }) + onUpdate({ userCollateral, debt, range, userBorrowed, slippage, leverageEnabled }).catch(errorFallback) }, [onUpdate, userCollateral, debt, range, userBorrowed, slippage, leverageEnabled]) } diff --git a/apps/main/src/loan/components/ChartOhlcWrapper/index.tsx b/apps/main/src/loan/components/ChartOhlcWrapper/index.tsx index abeca0e11a..638dca00d4 100644 --- a/apps/main/src/loan/components/ChartOhlcWrapper/index.tsx +++ b/apps/main/src/loan/components/ChartOhlcWrapper/index.tsx @@ -14,6 +14,7 @@ import TextCaption from '@ui/TextCaption' import { useLayoutStore } from '@ui-kit/features/layout' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' import { ChartOhlcWrapperProps, LlammaLiquidityCoins } from './types' const ChartOhlcWrapper = ({ rChainId, llamma, llammaId, betaBackgroundColor }: ChartOhlcWrapperProps) => { @@ -232,23 +233,25 @@ const ChartOhlcWrapper = ({ rChainId, llamma, llammaId, betaBackgroundColor }: C * the oracle pools based ohlc chart. */ const refetchPricesData = useCallback(() => { - void fetchOracleOhlcData( - rChainId, - controller, - chartInterval, - timeUnit, - chartTimeSettings.start, - chartTimeSettings.end, - ) - void fetchLlammaOhlcData( - rChainId, - llammaId, - address, - chartInterval, - timeUnit, - chartTimeSettings.start, - chartTimeSettings.end, - ) + Promise.all([ + fetchOracleOhlcData( + rChainId, + controller, + chartInterval, + timeUnit, + chartTimeSettings.start, + chartTimeSettings.end, + ), + fetchLlammaOhlcData( + rChainId, + llammaId, + address, + chartInterval, + timeUnit, + chartTimeSettings.start, + chartTimeSettings.end, + ), + ]).catch(errorFallback) }, [ fetchOracleOhlcData, rChainId, @@ -274,7 +277,7 @@ const ChartOhlcWrapper = ({ rChainId, llamma, llammaId, betaBackgroundColor }: C const endTime = subtractTimeUnit(timeOption, lastFetchEndTime) const startTime = getThreeHundredResultsAgo(timeOption, endTime) - void fetchMoreData(rChainId, controller, address, chartInterval, timeUnit, +startTime, endTime) + fetchMoreData(rChainId, controller, address, chartInterval, timeUnit, +startTime, endTime).catch(errorFallback) }, [timeOption, fetchMoreData, rChainId, controller, address, chartInterval, timeUnit], ) diff --git a/apps/main/src/loan/components/PageCrvUsdStaking/DepositWithdraw/DeployButton.tsx b/apps/main/src/loan/components/PageCrvUsdStaking/DepositWithdraw/DeployButton.tsx index e82f6adbd5..30b68c65e5 100644 --- a/apps/main/src/loan/components/PageCrvUsdStaking/DepositWithdraw/DeployButton.tsx +++ b/apps/main/src/loan/components/PageCrvUsdStaking/DepositWithdraw/DeployButton.tsx @@ -6,6 +6,7 @@ import { useScrvUsdUserBalances } from '@/loan/entities/scrvusd-userBalances' import useStore from '@/loan/store/useStore' import Button from '@ui/Button' import { t } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' type DeployButtonProps = { className?: string } @@ -49,24 +50,19 @@ const DeployButton = ({ className }: DeployButtonProps) => { const handleClick = useCallback(async () => { if (stakingModule === 'deposit') { if (isInputAmountApproved) { - void deposit(inputAmount) + deposit(inputAmount).catch(errorFallback) } if (!isInputAmountApproved) { - const approved = await depositApprove(inputAmount) - if (approved) { - void deposit(inputAmount) + if (await depositApprove(inputAmount)) { + deposit(inputAmount).catch(errorFallback) } } } if (stakingModule === 'withdraw') { - if (inputAmount === userBalance.scrvUSD) { - void redeem(inputAmount) - } else { - void redeem(inputAmount) - } + redeem(inputAmount).catch(errorFallback) } - }, [stakingModule, isInputAmountApproved, deposit, inputAmount, depositApprove, redeem, userBalance]) + }, [stakingModule, isInputAmountApproved, deposit, inputAmount, depositApprove, redeem]) return ( { if (curve && inputAmount !== '0') { if (stakingModule === 'deposit') { if (isDepositApprovalReady) { - void estimateGasDeposit(inputAmount) + estimateGasDeposit(inputAmount).catch(errorFallback) } else { - void estimateGasDepositApprove(inputAmount) + estimateGasDepositApprove(inputAmount).catch(errorFallback) } previewAction('deposit', inputAmount) } else { - void estimateGasWithdraw(inputAmount) + estimateGasWithdraw(inputAmount).catch(errorFallback) previewAction('withdraw', inputAmount) } } diff --git a/apps/main/src/loan/components/PageCrvUsdStaking/index.tsx b/apps/main/src/loan/components/PageCrvUsdStaking/index.tsx index 5457d26839..12c7780e67 100644 --- a/apps/main/src/loan/components/PageCrvUsdStaking/index.tsx +++ b/apps/main/src/loan/components/PageCrvUsdStaking/index.tsx @@ -6,7 +6,7 @@ import Statistics from '@/loan/components/PageCrvUsdStaking/Statistics' import StatsBanner from '@/loan/components/PageCrvUsdStaking/StatsBanner' import UserInformation from '@/loan/components/PageCrvUsdStaking/UserInformation' import UserPosition from '@/loan/components/PageCrvUsdStaking/UserPosition' -import { useScrvUsdUserBalances } from '@/loan/entities/scrvusd-userBalances' +import { invalidateScrvUsdUserBalances, useScrvUsdUserBalances } from '@/loan/entities/scrvusd-userBalances' import useStore from '@/loan/store/useStore' import type { NetworkUrlParams } from '@/loan/types/loan.types' import { Stack, useMediaQuery } from '@mui/material' @@ -15,6 +15,7 @@ import { useConnection } from '@ui-kit/features/connect-wallet' import { useSwitch } from '@ui-kit/hooks/useSwitch' import { Sizing } from '@ui-kit/themes/design/0_primitives' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' +import { errorFallback } from '@ui-kit/utils/error.util' const { MaxWidth } = SizesAndSpaces @@ -33,7 +34,6 @@ const CrvUsdStaking = ({ params }: { params: NetworkUrlParams }) => { data: userScrvUsdBalance, isFetching: isUserScrvUsdBalanceFetching, isFetched: isUserScrvUsdBalanceFetched, - refetch: refetchUserScrvUsdBalance, } = useScrvUsdUserBalances({ userAddress: address }) const isUserScrvUsdBalanceZero = !address || !userScrvUsdBalance || BigNumber(userScrvUsdBalance.scrvUSD).isZero() @@ -49,22 +49,16 @@ const CrvUsdStaking = ({ params }: { params: NetworkUrlParams }) => { const columnView = useMediaQuery(`(max-width: ${columnViewBreakPoint})`) useEffect(() => { - const fetchData = async () => { - if (!lendApi || !address) return - // ensure user balances are up to date on load - void refetchUserScrvUsdBalance() - fetchExchangeRate() - fetchCrvUsdSupplies() - } - - void fetchData() - }, [lendApi, fetchExchangeRate, fetchCrvUsdSupplies, refetchUserScrvUsdBalance, address]) + if (!lendApi || !address) return + // ensure user balances are up to date on load + invalidateScrvUsdUserBalances({ userAddress: address }) + fetchExchangeRate() + fetchCrvUsdSupplies() + }, [lendApi, fetchExchangeRate, fetchCrvUsdSupplies, address]) useEffect(() => { - if (!lendApi || !chainId || !address || inputAmount === '0') return - - if (stakingModule === 'deposit') { - void checkApproval.depositApprove(inputAmount) + if (lendApi && chainId && address && inputAmount !== '0' && stakingModule === 'deposit') { + checkApproval.depositApprove(inputAmount).catch(errorFallback) } }, [checkApproval, lendApi, chainId, inputAmount, stakingModule, address]) diff --git a/apps/main/src/loan/components/PageIntegrations/Page.tsx b/apps/main/src/loan/components/PageIntegrations/Page.tsx index 58025741e2..59e612377d 100644 --- a/apps/main/src/loan/components/PageIntegrations/Page.tsx +++ b/apps/main/src/loan/components/PageIntegrations/Page.tsx @@ -9,6 +9,7 @@ import Spinner, { SpinnerWrapper } from '@ui/Spinner' import { breakpoints } from '@ui/utils/responsive' import { useParams } from '@ui-kit/hooks/router' import { Trans } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' const Page = () => { const params = useParams() @@ -17,7 +18,7 @@ const Page = () => { const integrationsTags = useStore((state) => state.integrations.integrationsTags) useEffect(() => { - void init(rChainId) + init(rChainId).catch(errorFallback) }, [init, rChainId]) return ( diff --git a/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx b/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx index e91db6f69c..1dbf680c09 100644 --- a/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/components/DetailInfo.tsx @@ -9,6 +9,7 @@ import { getActiveStep } from '@ui/Stepper/helpers' import { FORMAT_OPTIONS, formatNumber } from '@ui/utils' import { t } from '@ui-kit/lib/i18n' import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' +import { errorFallback } from '@ui-kit/utils/error.util' const DetailInfoComp = (props: FormDetailInfo) => { const { activeKeyLiqRange, formValues, isLeverage, isReady, llamma, haveSigner, steps, updateFormValues } = props @@ -31,11 +32,11 @@ const DetailInfoComp = (props: FormDetailInfo) => { const handleLiqRangesEdit = () => { const showEditLiqRange = !isEditLiqRange setStateByKey('isEditLiqRange', showEditLiqRange) - updateFormValues(formValues) + updateFormValues(formValues).catch(errorFallback) } const handleSelLiqRange = (n: number) => { - updateFormValues({ ...formValues, n }) + updateFormValues({ ...formValues, n }).catch(errorFallback) } const loanToValueRatio = useMemo(() => { diff --git a/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx b/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx index 144b1032bc..8c0d973dba 100644 --- a/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx @@ -35,6 +35,7 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' const LoanCreate = ({ collateralAlert, @@ -86,9 +87,9 @@ const LoanCreate = ({ const { data: stablecoinUsdRate } = useTokenUsdRate({ chainId: network.chainId, tokenAddress: stablecoinAddress }) const updateFormValues = useCallback( - (updatedFormValues: FormValues) => { + async (updatedFormValues: FormValues) => { if (curve && llamma) { - void setFormValues(curve, isLeverage, llamma, updatedFormValues, maxSlippage) + await setFormValues(curve, isLeverage, llamma, updatedFormValues, maxSlippage) } }, [curve, isLeverage, llamma, maxSlippage, setFormValues], @@ -117,7 +118,7 @@ const LoanCreate = ({ [name]: value, collateralError: '', debtError: '', - }) + }).catch(errorFallback) }, [formStatus, reset, updateFormValues], ) @@ -283,7 +284,7 @@ const LoanCreate = ({ const disabled = !isReady || (formStatus.isInProgress && !formStatus.error) useEffect(() => { - updateFormValues(formValues) + updateFormValues(formValues).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [haveSigner]) @@ -452,9 +453,9 @@ const LoanCreate = ({ {t`Transaction complete`} ) : healthMode.message ? ( {healthMode.message} - ) : formStatus.error ? ( - reset(true, false)} /> - ) : null} + ) : ( + formStatus.error && reset(true, false)} /> + )} {txInfoBar} {steps && } diff --git a/apps/main/src/loan/components/PageLoanCreate/Page.tsx b/apps/main/src/loan/components/PageLoanCreate/Page.tsx index 42c0e1aff0..3502faef75 100644 --- a/apps/main/src/loan/components/PageLoanCreate/Page.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/Page.tsx @@ -42,6 +42,7 @@ import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' import { CRVUSD } from '@ui-kit/utils/address' +import { errorFallback } from '@ui-kit/utils/error.util' const { Spacing } = SizesAndSpaces @@ -96,7 +97,7 @@ const Page = () => { }) const fetchInitial = useCallback( - (curve: LlamaApi, isLeverage: boolean, llamma: Llamma) => { + async (curve: LlamaApi, isLeverage: boolean, llamma: Llamma) => { // reset createLoan estGas, detailInfo state setStateByKeys({ formEstGas: {}, @@ -107,13 +108,11 @@ const Page = () => { maxRecv: {}, maxRecvLeverage: {}, }) - const updatedFormValues = { ...formValues, n: formValues.n || llamma.defaultBands } - void setFormValues(curve, isLeverage, llamma, updatedFormValues, maxSlippage) - - if (curve.signerAddress) { - void fetchUserLoanWalletBalances(curve, llamma) - } + await Promise.all([ + setFormValues(curve, isLeverage, llamma, updatedFormValues, maxSlippage).catch(errorFallback), + curve.signerAddress && fetchUserLoanWalletBalances(curve, llamma).catch(errorFallback), + ]) }, [fetchUserLoanWalletBalances, formValues, maxSlippage, setFormValues, setStateByKeys], ) @@ -122,8 +121,7 @@ const Page = () => { if (isHydrated && curve) { if (market) { resetUserDetailsState(market) - fetchInitial(curve, isLeverage, market) - void fetchLoanDetails(curve, market) + Promise.all([fetchInitial(curve, isLeverage, market), fetchLoanDetails(curve, market)]).catch(errorFallback) setLoaded(true) } else { console.warn(`Collateral ${rCollateralId} not found for chain ${rChainId}. Redirecting to market list.`) @@ -150,16 +148,12 @@ const Page = () => { // max slippage updated useEffect(() => { if (loaded && !!curve && market) { - void setFormValues(curve, isLeverage, market, formValues, maxSlippage) + setFormValues(curve, isLeverage, market, formValues, maxSlippage).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) - usePageVisibleInterval(() => { - if (curve && market) { - void fetchLoanDetails(curve, market) - } - }, REFRESH_INTERVAL['1m']) + usePageVisibleInterval(() => curve && market && fetchLoanDetails(curve, market), REFRESH_INTERVAL['1m']) useEffect(() => { if (!isMdUp && chartExpanded) { diff --git a/apps/main/src/loan/components/PageLoanCreate/index.tsx b/apps/main/src/loan/components/PageLoanCreate/index.tsx index 719ab51bf2..a267504b5a 100644 --- a/apps/main/src/loan/components/PageLoanCreate/index.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/index.tsx @@ -15,6 +15,7 @@ import { useNavigate } from '@ui-kit/hooks/router' import { useBorrowUnifiedForm } from '@ui-kit/hooks/useFeatureFlags' import { t } from '@ui-kit/lib/i18n' import { type TabOption, TabsSwitcher } from '@ui-kit/shared/ui/TabsSwitcher' +import { errorFallback } from '@ui-kit/utils/error.util' /** * Callback that synchronizes the `ChartOhlc` component with the `RangeSlider` component in the new `BorrowTabContents`. @@ -41,7 +42,7 @@ const LoanCreate = ({ ...props }: PageLoanCreateProps & { loanExists: boolean | undefined - fetchInitial: (curve: LlamaApi, isLeverage: boolean, llamma: Llamma) => void + fetchInitial: (curve: LlamaApi, isLeverage: boolean, llamma: Llamma) => Promise }) => { const { curve, llamma, loanExists, params, rCollateralId, rFormType, rChainId } = props const push = useNavigate() @@ -68,7 +69,7 @@ const LoanCreate = ({ push(getLoanManagePathname(params, rCollateralId, 'loan')) } else { if (curve && llamma) { - fetchInitial(curve, formType === 'leverage', llamma) + fetchInitial(curve, formType === 'leverage', llamma).catch(errorFallback) } push(getLoanCreatePathname(params, rCollateralId, formType)) } diff --git a/apps/main/src/loan/components/PageLoanCreate/types.ts b/apps/main/src/loan/components/PageLoanCreate/types.ts index 1649efab88..9a69a665f3 100644 --- a/apps/main/src/loan/components/PageLoanCreate/types.ts +++ b/apps/main/src/loan/components/PageLoanCreate/types.ts @@ -50,7 +50,7 @@ export type FormDetailInfo = { llammaId: string steps: Step[] setHealthMode: Dispatch> - updateFormValues: (updatedFormValues: FormValues) => void + updateFormValues: (updatedFormValues: FormValues) => Promise } export type FormDetailInfoLeverage = { diff --git a/apps/main/src/loan/components/PageLoanManage/CollateralDecrease/index.tsx b/apps/main/src/loan/components/PageLoanManage/CollateralDecrease/index.tsx index 0eec65cf2e..146da9290f 100644 --- a/apps/main/src/loan/components/PageLoanManage/CollateralDecrease/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/CollateralDecrease/index.tsx @@ -34,6 +34,7 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' interface Props extends Pick {} @@ -72,9 +73,9 @@ const CollateralDecrease = ({ curve, llamma, llammaId, rChainId }: Props) => { const { data: collateralUsdRate } = useTokenUsdRate({ chainId: network.chainId, tokenAddress: collateralAddress }) const updateFormValues = useCallback( - (updatedFormValues: FormValues) => { + async (updatedFormValues: FormValues) => { if (chainId && llamma) { - void setFormValues(chainId, llamma, updatedFormValues, maxRemovable) + await setFormValues(chainId, llamma, updatedFormValues, maxRemovable) } }, [chainId, llamma, maxRemovable, setFormValues], @@ -101,7 +102,7 @@ const CollateralDecrease = ({ curve, llamma, llammaId, rChainId }: Props) => { const updatedFormValues = { ...formValues } updatedFormValues.collateral = collateral updatedFormValues.collateralError = '' - updateFormValues(updatedFormValues) + updateFormValues(updatedFormValues).catch(errorFallback) } const onCollateralChanged = useCallback( @@ -109,7 +110,7 @@ const CollateralDecrease = ({ curve, llamma, llammaId, rChainId }: Props) => { const { formValues, formStatus } = useStore.getState().loanCollateralDecrease if ((val ?? '') === formValues.collateral) return reset(!!formStatus.error, formStatus.isComplete) - updateFormValues({ ...formValues, collateral: val ?? '', collateralError: '' }) + updateFormValues({ ...formValues, collateral: val ?? '', collateralError: '' }).catch(errorFallback) }, [reset, updateFormValues], ) @@ -331,9 +332,9 @@ const CollateralDecrease = ({ curve, llamma, llammaId, rChainId }: Props) => { {formStatus.error ? ( reset(true, false)} /> - ) : healthMode.message ? ( - {healthMode.message} - ) : null} + ) : ( + healthMode.message && {healthMode.message} + )} {txInfoBar} {steps && } diff --git a/apps/main/src/loan/components/PageLoanManage/CollateralIncrease/index.tsx b/apps/main/src/loan/components/PageLoanManage/CollateralIncrease/index.tsx index 5999f82673..5fc3c94a97 100644 --- a/apps/main/src/loan/components/PageLoanManage/CollateralIncrease/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/CollateralIncrease/index.tsx @@ -35,6 +35,7 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' interface Props extends Pick {} @@ -73,9 +74,9 @@ const CollateralIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { const { data: collateralUsdRate } = useTokenUsdRate({ chainId: network?.chainId, tokenAddress: collateralAddress }) const updateFormValues = useCallback( - (updatedFormValues: FormValues) => { + async (updatedFormValues: FormValues) => { if (chainId && llamma) { - void setFormValues(chainId, llamma, updatedFormValues) + await setFormValues(chainId, llamma, updatedFormValues) } }, [chainId, llamma, setFormValues], @@ -102,7 +103,7 @@ const CollateralIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { const updatedFormValues = { ...formValues } updatedFormValues.collateral = collateral updatedFormValues.collateralError = '' - updateFormValues(updatedFormValues) + updateFormValues(updatedFormValues).catch(errorFallback) } const onCollateralChanged = useCallback( @@ -110,7 +111,7 @@ const CollateralIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { const { formStatus, formValues } = useStore.getState().loanCollateralIncrease if (formValues.collateral === (val ?? '')) return reset(!!formStatus.error, formStatus.isComplete) - updateFormValues({ ...formValues, collateral: val ?? '', collateralError: '' }) + updateFormValues({ ...formValues, collateral: val ?? '', collateralError: '' }).catch(errorFallback) }, [reset, updateFormValues], ) @@ -345,9 +346,10 @@ const CollateralIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { {formStatus.error ? ( reset(true, false)} /> - ) : detailInfo.healthNotFull !== healthMode.percent && healthMode.message ? ( - {healthMode.message} - ) : null} + ) : ( + detailInfo.healthNotFull !== healthMode.percent && + healthMode.message && {healthMode.message} + )} {txInfoBar} {steps && } diff --git a/apps/main/src/loan/components/PageLoanManage/LoanDecrease/index.tsx b/apps/main/src/loan/components/PageLoanManage/LoanDecrease/index.tsx index 6b63fdbdde..404e08b598 100644 --- a/apps/main/src/loan/components/PageLoanManage/LoanDecrease/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/LoanDecrease/index.tsx @@ -36,6 +36,7 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' interface Props extends Pick {} @@ -76,9 +77,9 @@ const LoanDecrease = ({ curve, llamma, llammaId, params, rChainId }: Props) => { const { userState } = userLoanDetails ?? {} const updateFormValues = useCallback( - (updatedFormValues: FormValues) => { + async (updatedFormValues: FormValues) => { if (chainId && llamma) { - void setFormValues(chainId, llamma, updatedFormValues) + await setFormValues(chainId, llamma, updatedFormValues) } }, [chainId, llamma, setFormValues], @@ -104,7 +105,7 @@ const LoanDecrease = ({ curve, llamma, llammaId, params, rChainId }: Props) => { const updatedFormValues = { ...formValues } updatedFormValues.debt = debt updatedFormValues.debtError = '' - updateFormValues(updatedFormValues) + updateFormValues(updatedFormValues).catch(errorFallback) } const onDebtChanged = useCallback( @@ -116,7 +117,7 @@ const LoanDecrease = ({ curve, llamma, llammaId, params, rChainId }: Props) => { debt, debtError: '', isFullRepay: decimal(userWalletBalances.stablecoin) == value, - }) + }).catch(errorFallback) }, [formStatus.error, formStatus.isComplete, reset, updateFormValues, userWalletBalances.stablecoin], ) @@ -127,7 +128,7 @@ const LoanDecrease = ({ curve, llamma, llammaId, params, rChainId }: Props) => { updatedFormValues.debt = '' updatedFormValues.debtError = '' updatedFormValues.isFullRepay = isFullRepay - updateFormValues(updatedFormValues) + updateFormValues(updatedFormValues).catch(errorFallback) } const handleBtnClickPay = useCallback( @@ -371,9 +372,9 @@ const LoanDecrease = ({ curve, llamma, llammaId, params, rChainId }: Props) => { <> {formStatus.error ? ( reset(true, false)} /> - ) : formStatus.warning ? ( - - ) : null} + ) : ( + formStatus.warning && + )} )} {txInfoBar} diff --git a/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx b/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx index 04a09a02fe..fab349d189 100644 --- a/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx @@ -50,6 +50,8 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' +import { useThrottle } from '@ui-kit/utils/timers' // Loan Deleverage const LoanDeleverage = ({ @@ -73,7 +75,7 @@ const LoanDeleverage = ({ const userWalletBalances = useStore((state) => state.loans.userWalletBalancesMapper[llammaId]) const userWalletBalancesLoading = useStore((state) => state.loans.userWalletBalancesLoading) const fetchStepRepay = useStore((state) => state.loanDeleverage.fetchStepRepay) - const setFormValues = useStore((state) => state.loanDeleverage.setFormValues) + const setFormValues = useThrottle(useStore((state) => state.loanDeleverage.setFormValues)) const isAdvancedMode = useUserProfileStore((state) => state.isAdvancedMode) const maxSlippage = useUserProfileStore((state) => state.maxSlippage.crypto) @@ -92,7 +94,7 @@ const LoanDeleverage = ({ const { data: collateralUsdRate } = useTokenUsdRate({ chainId: network.chainId, tokenAddress: collateralAddress }) const updateFormValues = useCallback( - (updatedFormValues: Partial, updatedMaxSlippage: string | null, isFullReset: boolean) => { + async (updatedFormValues: Partial, updatedMaxSlippage: string | null, isFullReset: boolean) => { setTxInfoBar(null) setConfirmHighPriceImpact(false) @@ -100,7 +102,7 @@ const LoanDeleverage = ({ setHealthMode(DEFAULT_HEALTH_MODE) } - void setFormValues( + await setFormValues( llammaId, curve, llamma, @@ -135,13 +137,11 @@ const LoanDeleverage = ({ { - if (resp.loanExists) { - updateFormValues({}, '', true) - } else { - push(getCollateralListPathname(params)) - } - }} + onClose={() => + resp.loanExists + ? updateFormValues({}, '', true).catch(errorFallback) + : push(getCollateralListPathname(params)) + } />, ) } @@ -207,7 +207,7 @@ const LoanDeleverage = ({ // onMount useEffect(() => { isSubscribed.current = true - updateFormValues(DEFAULT_FORM_VALUES, '', true) + updateFormValues(DEFAULT_FORM_VALUES, '', true).catch(errorFallback) return () => { isSubscribed.current = false @@ -217,15 +217,14 @@ const LoanDeleverage = ({ // signer changed useEffect(() => { - updateFormValues(DEFAULT_FORM_VALUES, '', true) - + updateFormValues(DEFAULT_FORM_VALUES, '', true).catch(errorFallback) // eslint-disable-next-line react-hooks/exhaustive-deps }, [curve?.signerAddress]) // update formValues useEffect(() => { if (chainId && llamma) { - updateFormValues({}, '', false) + updateFormValues({}, '', false).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [chainId, llamma, userState?.collateral, userLoanDetails?.userIsCloseToLiquidation]) @@ -233,7 +232,7 @@ const LoanDeleverage = ({ // maxSlippage useEffect(() => { if (maxSlippage) { - updateFormValues({}, maxSlippage, false) + updateFormValues({}, maxSlippage, false).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [maxSlippage]) @@ -241,17 +240,13 @@ const LoanDeleverage = ({ // pageVisible useEffect(() => { if (!formStatus.isInProgress) { - updateFormValues({}, '', false) + updateFormValues({}, '', false).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isPageVisible]) // interval - usePageVisibleInterval(() => { - if (!formStatus.isInProgress) { - updateFormValues({}, '', false) - } - }, REFRESH_INTERVAL['1m']) + usePageVisibleInterval(() => !formStatus.isInProgress && updateFormValues({}, '', false), REFRESH_INTERVAL['1m']) // steps useEffect(() => { @@ -431,30 +426,34 @@ const LoanDeleverage = ({ updateFormValues({}, '', true)} /> ) : formStatus.warning ? ( - ) : !!llamma && + ) : ( + !!llamma && userState && !detailInfo.loading && !formValues.collateralError && +formValues.collateral > 0 && - +detailInfo.receiveStablecoin > 0 ? ( - - {formValues.isFullRepay ? ( - - ) : formStatus.warning !== 'warning-full-repayment-only' ? ( - - ) : null} - - ) : null} + +detailInfo.receiveStablecoin > 0 && ( + + {formValues.isFullRepay ? ( + + ) : ( + formStatus.warning !== 'warning-full-repayment-only' && ( + + ) + )} + + ) + )} )} {txInfoBar} diff --git a/apps/main/src/loan/components/PageLoanManage/LoanIncrease/index.tsx b/apps/main/src/loan/components/PageLoanManage/LoanIncrease/index.tsx index 6dfefd68bd..31f0b909a8 100644 --- a/apps/main/src/loan/components/PageLoanManage/LoanIncrease/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/LoanIncrease/index.tsx @@ -38,6 +38,7 @@ import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate' import { LargeTokenInput } from '@ui-kit/shared/ui/LargeTokenInput' import { TokenLabel } from '@ui-kit/shared/ui/TokenLabel' import { decimal, type Decimal } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' interface Props extends Pick {} @@ -84,7 +85,7 @@ const LoanIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { const updateFormValues = useCallback( (updatedFormValues: FormValues) => { if (chainId && llamma) { - void setFormValues(chainId, llamma, updatedFormValues) + setFormValues(chainId, llamma, updatedFormValues).catch(errorFallback) } }, [chainId, llamma, setFormValues], @@ -245,7 +246,7 @@ const LoanIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { // init useEffect(() => { if (isReady && chainId && llamma) { - void init(chainId, llamma) + init(chainId, llamma).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isReady, chainId, llamma]) @@ -443,9 +444,9 @@ const LoanIncrease = ({ curve, isReady, llamma, llammaId }: Props) => { {formStatus.error ? ( reset(true, false)} /> - ) : healthMode.message ? ( - {healthMode.message} - ) : null} + ) : ( + healthMode.message && {healthMode.message} + )} {txInfoBar} {steps && } diff --git a/apps/main/src/loan/components/PageLoanManage/LoanLiquidate/index.tsx b/apps/main/src/loan/components/PageLoanManage/LoanLiquidate/index.tsx index 85950e562e..f530d3bb46 100644 --- a/apps/main/src/loan/components/PageLoanManage/LoanLiquidate/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/LoanLiquidate/index.tsx @@ -27,6 +27,7 @@ import { formatNumber, scanTxPath } from '@ui/utils' import { notify } from '@ui-kit/features/connect-wallet' import { useUserProfileStore } from '@ui-kit/features/user-profile' import { t, Trans } from '@ui-kit/lib/i18n' +import { errorFallback } from '@ui-kit/utils/error.util' interface Props extends Pick {} @@ -59,7 +60,7 @@ const LoanLiquidate = ({ curve, llamma, llammaId, params, rChainId }: Props) => if (chainId && llamma && (isErrorReset || isFullReset)) { setStateByKey('formStatus', { ...DEFAULT_FORM_STATUS, isApproved: formStatus.isApproved }) - void fetchTokensToLiquidate(rChainId, llamma, llammaId, maxSlippage, userWalletBalances) + fetchTokensToLiquidate(rChainId, llamma, llammaId, maxSlippage, userWalletBalances).catch(errorFallback) } }, [ @@ -170,7 +171,7 @@ const LoanLiquidate = ({ curve, llamma, llammaId, params, rChainId }: Props) => // init useEffect(() => { if (chainId && llamma && llammaId && typeof userWalletBalances?.stablecoin !== 'undefined') { - void fetchTokensToLiquidate(chainId, llamma, llammaId, maxSlippage, userWalletBalances) + fetchTokensToLiquidate(chainId, llamma, llammaId, maxSlippage, userWalletBalances).catch(errorFallback) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [curve?.signerAddress, chainId, llamma, llammaId, maxSlippage, userWalletBalances?.stablecoin]) diff --git a/apps/main/src/loan/components/PageLoanManage/Page.tsx b/apps/main/src/loan/components/PageLoanManage/Page.tsx index b99e1f7a3c..2e388a1ebf 100644 --- a/apps/main/src/loan/components/PageLoanManage/Page.tsx +++ b/apps/main/src/loan/components/PageLoanManage/Page.tsx @@ -35,6 +35,7 @@ import { t } from '@ui-kit/lib/i18n' import { REFRESH_INTERVAL } from '@ui-kit/lib/model' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' import { CRVUSD } from '@ui-kit/utils/address' +import { errorFallback } from '@ui-kit/utils/error.util' const { Spacing } = SizesAndSpaces @@ -92,14 +93,15 @@ const Page = () => { useEffect(() => { if (isHydrated && curve && rCollateralId && market) { - void (async () => { - const fetchedLoanDetails = await fetchLoanDetails(curve, market) - if (!fetchedLoanDetails.loanExists) { - resetUserDetailsState(market) - push(getLoanCreatePathname(params, rCollateralId)) - } - setLoaded(true) - })() + ;(async () => { + const fetchedLoanDetails = await fetchLoanDetails(curve, market) + if (fetchedLoanDetails.loanExists) { + setLoaded(true) + } else { + resetUserDetailsState(market) + push(getLoanCreatePathname(params, rCollateralId)) + } + })().catch(errorFallback) } }, [ isReady, @@ -122,12 +124,14 @@ const Page = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [loaded, rFormType, market]) - usePageVisibleInterval(() => { - if (curve?.signerAddress && market && loanExists) { - void fetchLoanDetails(curve, market) - void fetchUserLoanDetails(curve, market) - } - }, REFRESH_INTERVAL['1m']) + usePageVisibleInterval( + () => + curve?.signerAddress && + market && + loanExists && + Promise.all([fetchLoanDetails(curve, market), fetchUserLoanDetails(curve, market)]), + REFRESH_INTERVAL['1m'], + ) useEffect(() => { if (!isMdUp && chartExpanded) { diff --git a/apps/main/src/loan/store/createLoanCollateralDecreaseSlice.ts b/apps/main/src/loan/store/createLoanCollateralDecreaseSlice.ts index 1f30d97502..1c5d4742cc 100644 --- a/apps/main/src/loan/store/createLoanCollateralDecreaseSlice.ts +++ b/apps/main/src/loan/store/createLoanCollateralDecreaseSlice.ts @@ -14,6 +14,7 @@ import { loadingLRPrices } from '@/loan/utils/utilsCurvejs' import { getTokenName } from '@/loan/utils/utilsLoan' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/crvusd' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -78,7 +79,7 @@ const createLoanCollateralDecrease = (set: StoreApi['setState'], get: Sto ...DEFAULT_STATE, init: (chainId: ChainId, llamma: Llamma) => { - void get()[sliceKey].fetchMaxRemovable(chainId, llamma) + get()[sliceKey].fetchMaxRemovable(chainId, llamma).catch(errorFallback) }, fetchEstGas: async (activeKey: string, chainId: ChainId, llamma: Llamma, formValues: FormValues) => { const { collateral } = formValues @@ -142,8 +143,10 @@ const createLoanCollateralDecrease = (set: StoreApi['setState'], get: Sto // fetch detail, approval, est gas, set loading if (haveCollateral) { - void get()[sliceKey].fetchDetailInfo(activeKey, chainId, llamma, cFormValues) - void get()[sliceKey].fetchEstGas(activeKey, chainId, llamma, cFormValues) + Promise.all([ + get()[sliceKey].fetchDetailInfo(activeKey, chainId, llamma, cFormValues), + get()[sliceKey].fetchEstGas(activeKey, chainId, llamma, cFormValues), + ]).catch(errorFallback) } else { get()[sliceKey].setStateByActiveKey('detailInfo', activeKey, DEFAULT_DETAIL_INFO) get()[sliceKey].setStateByActiveKey('formEstGas', activeKey, DEFAULT_FORM_EST_GAS) @@ -165,8 +168,10 @@ const createLoanCollateralDecrease = (set: StoreApi['setState'], get: Sto const removeCollateralFn = networks[chainId].api.collateralDecrease.removeCollateral const resp = await removeCollateralFn(activeKey, provider, llamma, formValues.collateral) // update user events api - void getUserMarketCollateralEvents(wallet?.account?.address, networks[chainId].id, llamma.controller, resp.hash) - void get()[sliceKey].fetchMaxRemovable(chainId, llamma) + Promise.all([ + getUserMarketCollateralEvents(wallet?.account?.address, networks[chainId].id, llamma.controller, resp.hash), + get()[sliceKey].fetchMaxRemovable(chainId, llamma), + ]).catch(errorFallback) const { loanExists } = await get().loans.fetchLoanDetails(curve, llamma) if (!loanExists) { get().loans.resetUserDetailsState(llamma) diff --git a/apps/main/src/loan/store/createLoanCollateralIncreaseSlice.ts b/apps/main/src/loan/store/createLoanCollateralIncreaseSlice.ts index 26f0dc0704..6bccfbd756 100644 --- a/apps/main/src/loan/store/createLoanCollateralIncreaseSlice.ts +++ b/apps/main/src/loan/store/createLoanCollateralIncreaseSlice.ts @@ -13,6 +13,7 @@ import { ChainId, LlamaApi, Llamma } from '@/loan/types/loan.types' import { loadingLRPrices } from '@/loan/utils/utilsCurvejs' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/crvusd' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -133,8 +134,10 @@ const createLoanCollateralIncrease = (set: StoreApi['setState'], get: Sto // fetch detail, approval, est gas, set loading if (haveCollateral) { - void get()[sliceKey].fetchDetailInfo(activeKey, chainId, llamma, cFormValues) - void get()[sliceKey].fetchEstGasApproval(activeKey, chainId, llamma, cFormValues) + Promise.all([ + get()[sliceKey].fetchDetailInfo(activeKey, chainId, llamma, cFormValues), + get()[sliceKey].fetchEstGasApproval(activeKey, chainId, llamma, cFormValues), + ]).catch(errorFallback) } else { get()[sliceKey].setStateByActiveKey('detailInfo', activeKey, DEFAULT_DETAIL_INFO) get()[sliceKey].setStateByActiveKey('formEstGas', activeKey, DEFAULT_FORM_EST_GAS) @@ -165,7 +168,7 @@ const createLoanCollateralIncrease = (set: StoreApi['setState'], get: Sto }) if (!resp.error) { - void get()[sliceKey].fetchEstGasApproval(activeKey, chainId, llamma, formValues) + get()[sliceKey].fetchEstGasApproval(activeKey, chainId, llamma, formValues).catch(errorFallback) } return resp } @@ -183,7 +186,9 @@ const createLoanCollateralIncrease = (set: StoreApi['setState'], get: Sto const addCollateralFn = networks[chainId].api.collateralIncrease.addCollateral const resp = await addCollateralFn(activeKey, provider, llamma, formValues.collateral) // update user events api - void getUserMarketCollateralEvents(wallet?.account?.address, networks[chainId].id, llamma.controller, resp.hash) + getUserMarketCollateralEvents(wallet?.account?.address, networks[chainId].id, llamma.controller, resp.hash).catch( + errorFallback, + ) if (activeKey === get()[sliceKey].activeKey) { // re-fetch loan info const { loanExists } = await get().loans.fetchLoanDetails(curve, llamma) diff --git a/apps/main/src/loan/store/createLoanCreateSlice.ts b/apps/main/src/loan/store/createLoanCreateSlice.ts index 27bd4527d1..f12e187b4d 100644 --- a/apps/main/src/loan/store/createLoanCreateSlice.ts +++ b/apps/main/src/loan/store/createLoanCreateSlice.ts @@ -21,6 +21,7 @@ import { ChainId, LlamaApi, Llamma } from '@/loan/types/loan.types' import { loadingLRPrices } from '@/loan/utils/utilsCurvejs' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/crvusd' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -308,7 +309,9 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi storedFormValues.debt !== formValues.debt || !get()[sliceKey].liqRangesMapper[activeKeyLiqRange] ) { - void get()[sliceKey].fetchLiqRanges(activeKeyLiqRange, chainId, isLeverage, llamma, clonedFormValues) + get() + [sliceKey].fetchLiqRanges(activeKeyLiqRange, chainId, isLeverage, llamma, clonedFormValues) + .catch(errorFallback) } // fetch approval and estimate gas, detail @@ -322,25 +325,16 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi } // fetch detail info - void get()[sliceKey].fetchDetailInfo( - activeKey, - chainId, - isLeverage, - llamma, - clonedFormValues, - signerAddress, - maxSlippage, - ) + get() + [ + sliceKey + ].fetchDetailInfo(activeKey, chainId, isLeverage, llamma, clonedFormValues, signerAddress, maxSlippage) + .catch(errorFallback) if (signerAddress && !collateralError) { - void get()[sliceKey].fetchEstGasApproval( - activeKey, - chainId, - isLeverage, - llamma, - clonedFormValues, - maxSlippage, - ) + get() + [sliceKey].fetchEstGasApproval(activeKey, chainId, isLeverage, llamma, clonedFormValues, maxSlippage) + .catch(errorFallback) } } else { if (isLeverage) { @@ -395,7 +389,9 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi error: resp.error, }) - void get()[sliceKey].fetchEstGasApproval(activeKey, chainId, isLeverage, llamma, formValues, maxSlippage) + get() + [sliceKey].fetchEstGasApproval(activeKey, chainId, isLeverage, llamma, formValues, maxSlippage) + .catch(errorFallback) return resp } @@ -422,7 +418,12 @@ const createLoanCreate = (set: StoreApi['setState'], get: StoreApi const createFn = networks[chainId].api.loanCreate.create const resp = await createFn(activeKey, provider, llamma, isLeverage, collateral, debt, n, maxSlippage) // update user events api - void getUserMarketCollateralEvents(wallet?.account?.address, networks[chainId].id, llamma.controller, resp.hash) + getUserMarketCollateralEvents( + wallet?.account?.address, + networks[chainId].id, + llamma.controller, + resp.hash, + ).catch(errorFallback) if (resp.activeKey === get()[sliceKey].activeKey) { get()[sliceKey].setStateByKeys({ diff --git a/apps/main/src/loan/store/createLoanDecreaseSlice.ts b/apps/main/src/loan/store/createLoanDecreaseSlice.ts index 3b814c2e68..06caa4dd82 100644 --- a/apps/main/src/loan/store/createLoanDecreaseSlice.ts +++ b/apps/main/src/loan/store/createLoanDecreaseSlice.ts @@ -13,6 +13,7 @@ import { ChainId, LlamaApi, Llamma } from '@/loan/types/loan.types' import { loadingLRPrices } from '@/loan/utils/utilsCurvejs' import { getUserMarketCollateralEvents } from '@curvefi/prices-api/crvusd' import { useWallet } from '@ui-kit/features/connect-wallet' +import { errorFallback } from '@ui-kit/utils/error.util' import { setMissingProvider } from '@ui-kit/utils/store.util' type StateKey = keyof typeof DEFAULT_STATE @@ -119,7 +120,7 @@ const createLoanDecrease = (set: StoreApi['setState'], get: StoreApi 0 @@ -155,12 +156,11 @@ const createLoanDecrease = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi { - void get()[sliceKey].fetchMaxRecv(chainId, llamma, DEFAULT_FORM_VALUES) + get()[sliceKey].fetchMaxRecv(chainId, llamma, DEFAULT_FORM_VALUES).catch(errorFallback) }, fetchEstGasApproval: async (activeKey: string, chainId: ChainId, llamma: Llamma, formValues: FormValues) => { const { collateral, debt } = formValues @@ -162,10 +163,10 @@ const createLoanIncrease = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi { @@ -139,7 +140,9 @@ const createLoanLiquidate = (set: StoreApi['setState'], get: StoreApi['setState'], get: StoreApi[' get()[sliceKey].setStateByActiveKey('detailsMapper', collateralId, fetchedLoanDetails) if (curve.signerAddress) { - void get()[sliceKey].fetchUserLoanWalletBalances(curve, llamma) - + get()[sliceKey].fetchUserLoanWalletBalances(curve, llamma).catch(errorFallback) if (loanExists) { - void get()[sliceKey].fetchUserLoanDetails(curve, llamma) + get()[sliceKey].fetchUserLoanDetails(curve, llamma).catch(errorFallback) } } diff --git a/apps/main/src/loan/store/createScrvUsdSlice.ts b/apps/main/src/loan/store/createScrvUsdSlice.ts index 2c95f8cf9d..4a7d66864b 100644 --- a/apps/main/src/loan/store/createScrvUsdSlice.ts +++ b/apps/main/src/loan/store/createScrvUsdSlice.ts @@ -13,6 +13,7 @@ import { getLib, notify, useWallet } from '@ui-kit/features/connect-wallet' import { queryClient } from '@ui-kit/lib/api/query-client' import { t } from '@ui-kit/lib/i18n' import type { TimeOption } from '@ui-kit/lib/types/scrvusd' +import { errorFallback } from '@ui-kit/utils/error.util' type StateKey = keyof typeof DEFAULT_STATE @@ -227,7 +228,7 @@ const createScrvUsdSlice = (set: StoreApi['setState'], get: StoreApi({ setConnectState(FAILURE) } } - void initLib() + initLib().catch(errorFallback) return () => abort.abort() }, [app, hydrate, isReconnecting, libKey, network, wallet, walletChainId]) diff --git a/packages/curve-ui-kit/src/hooks/useDebounce.ts b/packages/curve-ui-kit/src/hooks/useDebounce.ts index 1e7fa509d6..262c8e76e2 100644 --- a/packages/curve-ui-kit/src/hooks/useDebounce.ts +++ b/packages/curve-ui-kit/src/hooks/useDebounce.ts @@ -79,7 +79,7 @@ export function useDebounce(initialValue: T, debounceMs: number, callback: (v */ export function useDebouncedValue( givenValue: T, - { defaultValue = givenValue, debounceMs = Duration.FormDebounce }: { defaultValue?: T; debounceMs?: number } = {}, + { defaultValue = givenValue, debounceMs = Duration.FormThrottle }: { defaultValue?: T; debounceMs?: number } = {}, ) { const [value, setValue] = useState(defaultValue) useEffect(() => { diff --git a/packages/curve-ui-kit/src/hooks/useLocalStorage.ts b/packages/curve-ui-kit/src/hooks/useLocalStorage.ts index 62a79bc12e..bcc5ee583e 100644 --- a/packages/curve-ui-kit/src/hooks/useLocalStorage.ts +++ b/packages/curve-ui-kit/src/hooks/useLocalStorage.ts @@ -43,6 +43,10 @@ const useLocalStorage = (key: string, initialValue: T, migration?: MigrationO /* -- Export specific hooks so that we can keep an overview of all the local storage keys used in the app -- */ export const useShowTestNets = () => useLocalStorage('showTestnets', false) +const getReleaseChannel = (): ReleaseChannel => + getFromLocalStorage('release-channel') ?? defaultReleaseChannel +export const shouldShowErrors = () => + getReleaseChannel() === ReleaseChannel.Beta && defaultReleaseChannel === ReleaseChannel.Beta export const useReleaseChannel = () => useLocalStorage('release-channel', defaultReleaseChannel, { version: 1, diff --git a/packages/curve-ui-kit/src/hooks/usePageVisibleInterval.ts b/packages/curve-ui-kit/src/hooks/usePageVisibleInterval.ts index 45c0baf972..23ab1a611b 100644 --- a/packages/curve-ui-kit/src/hooks/usePageVisibleInterval.ts +++ b/packages/curve-ui-kit/src/hooks/usePageVisibleInterval.ts @@ -2,7 +2,7 @@ import { useEffect, useEffectEvent } from 'react' import { useLayoutStore } from '@ui-kit/features/layout' import { setTimeoutInterval } from '@ui-kit/utils/timers' -type CallbackFunction = () => unknown +type CallbackFunction = () => unknown | Promise /** * A hook that runs a callback function at specified intervals, but only when the page is visible. diff --git a/packages/curve-ui-kit/src/shared/ui/ActionInfo.tsx b/packages/curve-ui-kit/src/shared/ui/ActionInfo.tsx index 8e9e48741b..e880f26af4 100644 --- a/packages/curve-ui-kit/src/shared/ui/ActionInfo.tsx +++ b/packages/curve-ui-kit/src/shared/ui/ActionInfo.tsx @@ -17,6 +17,7 @@ import { Duration } from '@ui-kit/themes/design/0_primitives' import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' import type { TypographyVariantKey } from '@ui-kit/themes/typography' import { copyToClipboard } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' import { Tooltip } from './Tooltip' import { WithSkeleton } from './WithSkeleton' @@ -109,7 +110,7 @@ const ActionInfo = ({ const [isSnackbarOpen, openSnackbar, closeSnackbar] = useSwitch(false) const copyAndShowSnackbar = useCallback(() => { - void copyToClipboard(copyValue!.trim()) + copyToClipboard(copyValue!.trim()).catch(errorFallback) openSnackbar() }, [copyValue, openSnackbar]) diff --git a/packages/curve-ui-kit/src/shared/ui/LargeTokenInput.tsx b/packages/curve-ui-kit/src/shared/ui/LargeTokenInput.tsx index 0bf466b550..877eaf1399 100644 --- a/packages/curve-ui-kit/src/shared/ui/LargeTokenInput.tsx +++ b/packages/curve-ui-kit/src/shared/ui/LargeTokenInput.tsx @@ -250,7 +250,7 @@ export const LargeTokenInput = ({ const [balance, setBalance, cancelSetBalance] = useUniqueDebounce({ defaultValue: externalBalance, callback: onBalance, - debounceMs: Duration.FormDebounce, + debounceMs: Duration.FormThrottle, // We don't want to trigger onBalance if the value is effectively the same, e.g. "0.0" and "0.00" equals: bigNumEquals, }) diff --git a/packages/curve-ui-kit/src/shared/ui/Metric.tsx b/packages/curve-ui-kit/src/shared/ui/Metric.tsx index 9d861f47c9..07ee3661d8 100644 --- a/packages/curve-ui-kit/src/shared/ui/Metric.tsx +++ b/packages/curve-ui-kit/src/shared/ui/Metric.tsx @@ -18,6 +18,7 @@ import { type NumberFormatOptions, type SxProps, } from '@ui-kit/utils' +import { errorFallback } from '@ui-kit/utils/error.util' import { Duration } from '../../themes/design/0_primitives' import { WithSkeleton } from './WithSkeleton' @@ -203,7 +204,7 @@ export const Metric = ({ const notionals = useMemo(() => notionalsToString(notional), [notional]) const [isCopyAlertOpen, openCopyAlert, closeCopyAlert] = useSwitch(false) const copyValue = useCallback(() => { - void copyToClipboard(value!.toString()) + copyToClipboard(value!.toString()).catch(errorFallback) openCopyAlert() }, [value, openCopyAlert]) diff --git a/packages/curve-ui-kit/src/themes/design/0_primitives.ts b/packages/curve-ui-kit/src/themes/design/0_primitives.ts index 9b5f1a956f..3ba18f3a4a 100644 --- a/packages/curve-ui-kit/src/themes/design/0_primitives.ts +++ b/packages/curve-ui-kit/src/themes/design/0_primitives.ts @@ -103,10 +103,10 @@ export const Duration = { Snackbar: 6000, Tooltip: { Enter: 500, Exit: 500 }, Flicker: 1000, - FormDebounce: 500, Transition: 256, Focus: 50, Delay: 100, + FormThrottle: 166, // ~10fps at 60Hz } export const TransitionFunction = `ease-out ${Duration.Transition}ms` diff --git a/packages/curve-ui-kit/src/types/window.d.ts b/packages/curve-ui-kit/src/types/window.d.ts index bff3accecb..1cef4536be 100644 --- a/packages/curve-ui-kit/src/types/window.d.ts +++ b/packages/curve-ui-kit/src/types/window.d.ts @@ -15,8 +15,6 @@ declare global { interface Window { clipboardData: any ethereum: EIP1193Provider & { eip6963ProviderDetails: Eip6963Provider[] } - exodus?: EIP1193Provider - enkrypt?: { providers: { ethereum: EIP1193Provider } } binancew3w?: { ethereum?: EIP1193Provider } } } diff --git a/packages/curve-ui-kit/src/utils/error.util.ts b/packages/curve-ui-kit/src/utils/error.util.ts new file mode 100644 index 0000000000..59352db51a --- /dev/null +++ b/packages/curve-ui-kit/src/utils/error.util.ts @@ -0,0 +1,19 @@ +import { notify } from '@ui-kit/features/connect-wallet' +import { shouldShowErrors } from '@ui-kit/hooks/useLocalStorage' + +const IGNORED_ERROR_MESSAGES = [ + 'network error', + 'Error in input stream', + 'NetworkError', + 'AbortError', + 'ChunkLoadError', +] + +export const errorFallback = (error: unknown) => { + console.error(error) + if (!shouldShowErrors()) return + const { message = 'An unknown error occurred' } = error as Error + const { name } = error as DOMException + if (IGNORED_ERROR_MESSAGES.find((ignored) => message.startsWith(ignored) || name === ignored)) return + notify(message, 'error') +} diff --git a/packages/curve-ui-kit/src/utils/timers.ts b/packages/curve-ui-kit/src/utils/timers.ts index f9ebc44990..e0fc3c35fc 100644 --- a/packages/curve-ui-kit/src/utils/timers.ts +++ b/packages/curve-ui-kit/src/utils/timers.ts @@ -1,3 +1,7 @@ +import { throttle } from 'lodash' +import { useMemo } from 'react' +import { Duration } from '@ui-kit/themes/design/0_primitives' + /** * Replaces setInterval using recursive setTimeout. * Returns a cancel function to stop future executions. @@ -27,3 +31,10 @@ export function setTimeoutInterval(callback: () => unknown, delay: number): () = clearTimeout(timeoutId) } } + +/** + * Throttles a function using lodash throttle and memoizes it with useMemo. + * Important: the passed function should be stable between renders (e.g., static or wrapped in useCallback). + */ +export const useThrottle = any>(f: T, duration = Duration.FormThrottle) => + useMemo(() => throttle(f, duration), [f, duration]) diff --git a/packages/curve-ui-kit/src/widgets/ErrorBoundary.tsx b/packages/curve-ui-kit/src/widgets/ErrorBoundary.tsx index 383992cdda..eaa1303491 100644 --- a/packages/curve-ui-kit/src/widgets/ErrorBoundary.tsx +++ b/packages/curve-ui-kit/src/widgets/ErrorBoundary.tsx @@ -2,6 +2,7 @@ import { ReactNode } from 'react' import { CatchBoundary } from '@tanstack/react-router' import type { ErrorComponentProps } from '@tanstack/router-core' import { ErrorPage } from '@ui-kit/pages/ErrorPage' +import { errorFallback } from '@ui-kit/utils/error.util' export const ErrorBoundary = ({ children, title }: { children: ReactNode; title: string }) => ( ( )} + onCatch={errorFallback} > {children} diff --git a/packages/ui/src/Chart/CandleChart.tsx b/packages/ui/src/Chart/CandleChart.tsx index c2e8645899..d590b07472 100644 --- a/packages/ui/src/Chart/CandleChart.tsx +++ b/packages/ui/src/Chart/CandleChart.tsx @@ -153,7 +153,7 @@ const CandleChart = ({ const barsInfo = candlestickSeriesRef.current.barsInLogicalRange(logicalRange) if (barsInfo && barsInfo.barsBefore < 50) { - void debouncedFetchMoreChartData.current() + debouncedFetchMoreChartData.current() setLastTimescale(timeScale.getVisibleRange()) } }, [refetchingCapped]) diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 5bbb8f055d..92c1beb57b 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -11,5 +11,5 @@ "@ui-kit/*": ["../../curve-ui-kit/src/*"] } }, - "include": ["src"] + "include": ["src", "../curve-ui-kit/src/types/*.d.ts"] } diff --git a/tests/cypress/support/helpers/ComponentTestWrapper.tsx b/tests/cypress/support/helpers/ComponentTestWrapper.tsx index 59ac548476..78899470e1 100644 --- a/tests/cypress/support/helpers/ComponentTestWrapper.tsx +++ b/tests/cypress/support/helpers/ComponentTestWrapper.tsx @@ -1,4 +1,4 @@ -import { type ReactElement } from 'react' +import { type ReactNode } from 'react' import { WagmiProvider, type ResolvedRegister } from 'wagmi' import { createMemoryHistory, createRootRoute, createRouter, RouterProvider } from '@tanstack/react-router' import { persister, queryClient, QueryProvider } from '@ui-kit/lib/api' @@ -9,7 +9,7 @@ export type Config = ResolvedRegister['config'] type Props = { config?: Config - children: ReactElement + children: ReactNode autoConnect?: boolean } @@ -25,7 +25,7 @@ export function ComponentTestWrapper({ config, children, autoConnect }: Props) { // Create a minimal router for testing environment const router = createRouter({ routeTree: createRootRoute({ - component: () => children, + component: () => <>{children}, }), history: createMemoryHistory({ initialEntries: ['/'],