diff --git a/libs/oeth/redeem/src/hooks.tsx b/libs/oeth/redeem/src/hooks.tsx index 99081d424..cb125289d 100644 --- a/libs/oeth/redeem/src/hooks.tsx +++ b/libs/oeth/redeem/src/hooks.tsx @@ -8,7 +8,7 @@ import { } from '@origin/oeth/shared'; import { contracts, tokens } from '@origin/shared/contracts'; import { usePushNotification, useSlippage } from '@origin/shared/providers'; -import { isNilOrEmpty } from '@origin/shared/utils'; +import { isNilOrEmpty, isUserRejected } from '@origin/shared/utils'; import { prepareWriteContract, waitForTransaction, @@ -103,7 +103,7 @@ export const useHandleRedeem = () => { ), }); } catch (error) { - if (error.cause.name === 'UserRejectedRequestError') { + if (isUserRejected(error)) { deleteActivity(activity.id); pushNotification({ title: intl.formatMessage({ defaultMessage: 'Redeem Cancelled' }), @@ -116,14 +116,14 @@ export const useHandleRedeem = () => { updateActivity({ ...activity, status: 'error', - error: error.shortMessage, + error: error?.shortMessage ?? error.message, }); pushNotification({ content: ( ), }); diff --git a/libs/oeth/redeem/src/state.ts b/libs/oeth/redeem/src/state.ts index a15ae9d57..f428a44ee 100644 --- a/libs/oeth/redeem/src/state.ts +++ b/libs/oeth/redeem/src/state.ts @@ -77,7 +77,7 @@ export const { Provider: RedeemProvider, useTracked: useRedeemState } = try { splitEstimates = await queryClient.fetchQuery({ queryKey: ['splitEstimates', state.amountIn.toString()], - queryFn: () => + queryFn: async () => readContract({ address: contracts.mainnet.OETHVaultCore.address, abi: contracts.mainnet.OETHVaultCore.abi, @@ -85,8 +85,8 @@ export const { Provider: RedeemProvider, useTracked: useRedeemState } = args: [state.amountIn], }), }); - } catch (e) { - console.error(`redeem vault estimate amount error.\n${e.message}`); + } catch (error) { + console.error(`Fail to estimate redeem operation.\n${error.message}`); setState( produce((draft) => { draft.amountIn = 0n; @@ -99,7 +99,7 @@ export const { Provider: RedeemProvider, useTracked: useRedeemState } = title: intl.formatMessage({ defaultMessage: 'Error while estimating', }), - message: e.shortMessage, + message: error?.shortMessage ?? error.message, severity: 'error', }); @@ -145,10 +145,8 @@ export const { Provider: RedeemProvider, useTracked: useRedeemState } = account: whales.mainnet.OETH, }), }); - } catch (e) { - console.error( - `redeem vault estimate gas error. Using default!\n${e.message}`, - ); + } catch (error) { + console.log(`Redeem uses fix gas estimate: 1500000`); gasEstimate = 1500000n; } diff --git a/libs/oeth/shared/src/components/ActivityProvider/components/ActivityPopover.tsx b/libs/oeth/shared/src/components/ActivityProvider/components/ActivityPopover.tsx index 4ead2ec98..1f1a1e684 100644 --- a/libs/oeth/shared/src/components/ActivityProvider/components/ActivityPopover.tsx +++ b/libs/oeth/shared/src/components/ActivityProvider/components/ActivityPopover.tsx @@ -75,12 +75,22 @@ export const ActivityPopover = ({ (a) => ({ approval: ( - + ), redeem: ( - + + ), + swap: ( + ), - swap: , })[a.type], ) )} diff --git a/libs/oeth/shared/src/components/ActivityProvider/components/ApprovalNotification.tsx b/libs/oeth/shared/src/components/ActivityProvider/components/ApprovalNotification.tsx index 497f07610..95debba7d 100644 --- a/libs/oeth/shared/src/components/ActivityProvider/components/ApprovalNotification.tsx +++ b/libs/oeth/shared/src/components/ActivityProvider/components/ApprovalNotification.tsx @@ -18,7 +18,7 @@ type ApprovalNotificationProps = { amountIn?: bigint; txReceipt?: TransactionReceipt; error?: string; -} & StackProps; +} & Pick; const title: Record = { pending: defineMessage({ defaultMessage: 'Approving' }), @@ -34,12 +34,12 @@ export const ApprovalNotification = ({ amountIn, txReceipt, error, - ...rest + sx, }: ApprovalNotificationProps) => { const intl = useIntl(); return ( - + diff --git a/libs/oeth/shared/src/components/ActivityProvider/components/RedeemNotification.tsx b/libs/oeth/shared/src/components/ActivityProvider/components/RedeemNotification.tsx index 97bb89ae7..e0024930a 100644 --- a/libs/oeth/shared/src/components/ActivityProvider/components/RedeemNotification.tsx +++ b/libs/oeth/shared/src/components/ActivityProvider/components/RedeemNotification.tsx @@ -19,7 +19,7 @@ type RedeemNotificationProps = { amountOut?: bigint; txReceipt?: TransactionReceipt; error?: string; -} & StackProps; +} & Pick; const title: Record = { pending: defineMessage({ defaultMessage: 'Redeeming' }), @@ -36,12 +36,12 @@ export const RedeemNotification = ({ amountOut, txReceipt, error, - ...rest + sx, }: RedeemNotificationProps) => { const intl = useIntl(); return ( - + diff --git a/libs/oeth/shared/src/components/ActivityProvider/components/SwapNotification.tsx b/libs/oeth/shared/src/components/ActivityProvider/components/SwapNotification.tsx index c316b21ab..c22b97379 100644 --- a/libs/oeth/shared/src/components/ActivityProvider/components/SwapNotification.tsx +++ b/libs/oeth/shared/src/components/ActivityProvider/components/SwapNotification.tsx @@ -19,7 +19,7 @@ type SwapNotificationProps = { amountOut?: bigint; txReceipt?: TransactionReceipt; error?: string; -} & StackProps; +} & Pick; const title: Record = { pending: defineMessage({ defaultMessage: 'Swapping' }), @@ -36,12 +36,12 @@ export const SwapNotification = ({ amountOut, txReceipt, error, - ...rest + sx, }: SwapNotificationProps) => { const intl = useIntl(); return ( - + diff --git a/libs/oeth/swap/src/actions/index.ts b/libs/oeth/swap/src/actions/index.ts index 4890e10a5..016b2d6a4 100644 --- a/libs/oeth/swap/src/actions/index.ts +++ b/libs/oeth/swap/src/actions/index.ts @@ -43,9 +43,11 @@ const defaultApi: SwapApi = { }, approve: async () => { console.log('Approve operation not implemented'); + return null; }, swap: async () => { console.log('Route swap operation not implemented'); + return null; }, }; diff --git a/libs/oeth/swap/src/components/BestRoutes.tsx b/libs/oeth/swap/src/components/BestRoutes.tsx index 8de1bc56e..c449b6ed2 100644 --- a/libs/oeth/swap/src/components/BestRoutes.tsx +++ b/libs/oeth/swap/src/components/BestRoutes.tsx @@ -10,8 +10,7 @@ import type { Grid2Props } from '@mui/material'; export type BestRoutesProps = { isLoading: boolean } & Grid2Props; export function BestRoutes(props: Grid2Props) { - const [{ swapRoutes, selectedSwapRoute, isSwapRoutesLoading }] = - useSwapState(); + const [{ swapRoutes, selectedSwapRoute }] = useSwapState(); const handleSelectSwapRoute = useHandleSelectSwapRoute(); return ( @@ -24,7 +23,6 @@ export function BestRoutes(props: Grid2Props) { isBest={index === 0} onSelect={handleSelectSwapRoute} route={route} - isLoading={isSwapRoutesLoading} /> ))} diff --git a/libs/oeth/swap/src/components/SwapRouteCard.tsx b/libs/oeth/swap/src/components/SwapRouteCard.tsx index 2e0bf7f83..f84d8764e 100644 --- a/libs/oeth/swap/src/components/SwapRouteCard.tsx +++ b/libs/oeth/swap/src/components/SwapRouteCard.tsx @@ -21,7 +21,6 @@ import type { EstimatedSwapRoute } from '../types'; export type SwapRouteCardProps = { isSelected: boolean; isBest: boolean; - isLoading: boolean; onSelect: (route: EstimatedSwapRoute) => void; route: EstimatedSwapRoute; } & Omit; @@ -29,19 +28,29 @@ export type SwapRouteCardProps = { export function SwapRouteCard({ isSelected, isBest, - isLoading, onSelect, route, ...rest }: SwapRouteCardProps) { const intl = useIntl(); - const [{ amountIn }] = useSwapState(); + const [{ amountIn, isSwapRoutesLoading }] = useSwapState(); const { data: prices } = usePrices(); - const { data: swapGasPrice, isLoading: swapGasPriceLoading } = useGasPrice( - route.gas, - ); - const { data: approvalGasPrice, isLoading: approvalGasPriceLoading } = - useGasPrice(route.approvalGas, { refetchInterval: 30e3 }); + const { + data: swapGasPrice, + isLoading: swapGasPriceLoading, + isFetching: swapGasPriceFetching, + } = useGasPrice(route.gas, { + refetchInterval: 30e3, + enabled: route.gas > 0n, + }); + const { + data: approvalGasPrice, + isLoading: approvalGasPriceLoading, + isFetching: approvalGasPriceFetching, + } = useGasPrice(route.approvalGas, { + refetchInterval: 30e3, + enabled: route.approvalGas > 0n, + }); const { data: allowance } = useSwapRouteAllowance(route); const estimatedAmount = +formatUnits( @@ -51,7 +60,9 @@ export function SwapRouteCard({ const convertedAmount = (prices?.[route.tokenOut.symbol] ?? 1) * estimatedAmount; const isGasLoading = - isLoading || swapGasPriceLoading || approvalGasPriceLoading; + isSwapRoutesLoading || + (swapGasPriceLoading && swapGasPriceFetching) || + (approvalGasPriceLoading && approvalGasPriceFetching); const gasPrice = swapGasPrice?.gasCostUsd + (allowance < amountIn ? approvalGasPrice?.gasCostUsd : 0); @@ -114,7 +125,7 @@ export function SwapRouteCard({ - {isLoading ? ( + {isSwapRoutesLoading ? ( ) : ( - {isLoading ? ( + {isSwapRoutesLoading ? ( ) : ( formatAmount(route.estimatedAmount, route.tokenOut.decimals) @@ -139,7 +150,7 @@ export function SwapRouteCard({ - {isLoading ? ( + {isSwapRoutesLoading ? ( ) : ( `(${intl.formatNumber(convertedAmount, currencyFormat)})` @@ -152,7 +163,7 @@ export function SwapRouteCard({ fontWeight={500} sx={{ fontSize: 12, marginBlock: { xs: 1.5, md: 1 } }} > - {isLoading ? ( + {isSwapRoutesLoading ? ( ) : ( intl.formatMessage(routeActionLabel[route.action]) @@ -169,7 +180,7 @@ export function SwapRouteCard({ {intl.formatMessage({ defaultMessage: 'Rate:' })} - {isLoading ? ( + {isSwapRoutesLoading ? ( ) : ( `1:${intl.formatNumber(route.rate, quantityFormat)}` diff --git a/libs/oeth/swap/src/hooks.tsx b/libs/oeth/swap/src/hooks.tsx index 24985d31a..f88b608f2 100644 --- a/libs/oeth/swap/src/hooks.tsx +++ b/libs/oeth/swap/src/hooks.tsx @@ -12,7 +12,7 @@ import { usePushNotification, useSlippage, } from '@origin/shared/providers'; -import { isNilOrEmpty } from '@origin/shared/utils'; +import { isNilOrEmpty, isUserRejected } from '@origin/shared/utils'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { waitForTransaction } from '@wagmi/core'; import { produce } from 'immer'; @@ -256,7 +256,7 @@ export const useHandleApprove = () => { draft.isApprovalLoading = false; }), ); - if (error.cause.name === 'UserRejectedRequestError') { + if (isUserRejected(error)) { deleteActivity(activity.id); pushNotification({ title: intl.formatMessage({ defaultMessage: 'Approval Cancelled' }), @@ -269,14 +269,14 @@ export const useHandleApprove = () => { updateActivity({ ...activity, status: 'error', - error: error.shortMessage, + error: error?.shortMessage ?? error.message, }); pushNotification({ content: ( ), }); @@ -375,7 +375,7 @@ export const useHandleSwap = () => { draft.isSwapLoading = false; }), ); - if (error.cause.name === 'UserRejectedRequestError') { + if (isUserRejected(error)) { deleteActivity(activity.id); pushNotification({ title: intl.formatMessage({ defaultMessage: 'Operation Cancelled' }), diff --git a/libs/shared/utils/src/errors.ts b/libs/shared/utils/src/errors.ts new file mode 100644 index 000000000..f99046b61 --- /dev/null +++ b/libs/shared/utils/src/errors.ts @@ -0,0 +1,6 @@ +import { pathEq } from 'ramda'; + +export const isUserRejected = pathEq('UserRejectedRequestError', [ + 'cause', + 'name', +]); diff --git a/libs/shared/utils/src/index.ts b/libs/shared/utils/src/index.ts index aef480533..c571e023d 100644 --- a/libs/shared/utils/src/index.ts +++ b/libs/shared/utils/src/index.ts @@ -1,6 +1,7 @@ export * from './addresses'; export * from './BigInt'; export * from './composeContext'; +export * from './errors'; export * from './formatters'; export * from './isNilOrEmpty'; export * from './types';