diff --git a/packages/checkout/src/views/Checkout/PaymentMethodSelect/PayWithCrypto/index.tsx b/packages/checkout/src/views/Checkout/PaymentMethodSelect/PayWithCrypto/index.tsx index d0468db6b..a590ba254 100644 --- a/packages/checkout/src/views/Checkout/PaymentMethodSelect/PayWithCrypto/index.tsx +++ b/packages/checkout/src/views/Checkout/PaymentMethodSelect/PayWithCrypto/index.tsx @@ -2,6 +2,7 @@ import { compareAddress, ContractVerificationStatus, formatDisplay, + isTxRejected, sendTransactions, TRANSACTION_CONFIRMATIONS_DEFAULT, useAnalyticsContext @@ -37,6 +38,8 @@ interface PayWithCryptoTabProps { isSwitchingChainRef: RefObject } +type ErrorCause = 'generic' | 'user-rejection' + export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: PayWithCryptoTabProps) => { const connectedChainId = useChainId() const { switchChain } = useSwitchChain() @@ -46,7 +49,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P const { openTransactionStatusModal } = useTransactionStatusModal() const { selectPaymentSettings = {} as SelectPaymentSettings, closeSelectPaymentModal } = useSelectPaymentModal() const { analytics } = useAnalyticsContext() - const [isError, setIsError] = useState(false) + const [error, setError] = useState(null) const { navigation, setNavigation } = useNavigationCheckout() const { initializeTransactionCounter, @@ -246,7 +249,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P } setIsPurchasing(true) - setIsError(false) + setError(null) try { if (connectedChainId != chainId) { @@ -368,7 +371,8 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P } catch (e) { console.error('Failed to purchase...', e) onError(e as Error) - setIsError(true) + const isRejected = isTxRejected(e as Error) + setError(isRejected ? 'user-rejection' : 'generic') } resetTransactionCounter() @@ -393,7 +397,7 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P } setIsPurchasing(true) - setIsError(false) + setError(null) try { if (connectedChainId != chainId) { @@ -540,7 +544,8 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P } catch (e) { console.error('Failed to purchase...', e) onError(e as Error) - setIsError(true) + const isRejected = isTxRejected(e as Error) + setError(isRejected ? 'user-rejection' : 'generic') } setIsPurchasing(false) @@ -772,15 +777,22 @@ export const PayWithCryptoTab = ({ skipOnCloseCallback, isSwitchingChainRef }: P return 'Confirm payment' } + const getErrorText = () => { + if (error == 'user-rejection') { + return 'The transaction was rejected.' + } + return 'An error occurred. Please try again.' + } + return (
- {isError && ( + {!!error && (
- An error occurred. Please try again. + {getErrorText()}
)} diff --git a/packages/connect/src/index.ts b/packages/connect/src/index.ts index 66d8263f4..e26c162c8 100644 --- a/packages/connect/src/index.ts +++ b/packages/connect/src/index.ts @@ -63,7 +63,7 @@ export { getModalPositionCss } from './utils/styling.js' export { getNetwork, getNetworkBackgroundColor, getNetworkColor } from './utils/networks.js' export { publicClientToProvider, walletClientToSigner } from './utils/adapters.js' export { signEthAuthProof, validateEthProof } from './utils/ethAuth.js' -export { sendTransactions, waitForTransactionReceipt } from './utils/transactions.js' +export { isTxRejected, sendTransactions, waitForTransactionReceipt } from './utils/transactions.js' // Contexts export { ConnectConfigContextProvider, useConnectConfigContext } from './contexts/ConnectConfig.js' diff --git a/packages/connect/src/utils/transactions.ts b/packages/connect/src/utils/transactions.ts index 7ae4caed8..b15ddd048 100644 --- a/packages/connect/src/utils/transactions.ts +++ b/packages/connect/src/utils/transactions.ts @@ -265,3 +265,19 @@ export const waitForTransactionReceipt = async ({ return receipt } + +interface ErrorWithCode extends Error { + code?: number +} + +export const isTxRejected = (error: Error): boolean => { + const errorWithCode = error as ErrorWithCode + + // error 4001 is documented in EIP-1193 + // https://eips.ethereum.org/EIPS/eip-1193#provider-errors + if (errorWithCode?.code == 4001) { + return true + } + + return false +}