diff --git a/modules/blockChain/hooks/useTransactionSender.ts b/modules/blockChain/hooks/useTransactionSender.ts
index 9465ec8a..16c38cad 100644
--- a/modules/blockChain/hooks/useTransactionSender.ts
+++ b/modules/blockChain/hooks/useTransactionSender.ts
@@ -7,6 +7,7 @@ import { PopulatedTransaction } from '@ethersproject/contracts'
import { openWindow } from 'modules/shared/utils/openWindow'
import { getGnosisSafeLink } from '../utils/getGnosisSafeLink'
import { getEtherscanLink } from '@lido-sdk/helpers'
+import { getErrorMessage } from 'modules/shared/utils/getErrorMessage'
import { ToastError } from '@lidofinance/lido-ui'
type PopulateFn =
@@ -53,7 +54,7 @@ export function useTransactionSender(
onError?.()
setStatus('empty')
console.error(error)
- ToastError(error.message || (error as any).toString(), {})
+ ToastError(getErrorMessage(error), {})
}
},
[finish, populateTx, sendTransactionGnosisWorkaround, onError],
diff --git a/modules/network/hooks/useSwr.ts b/modules/network/hooks/useSwr.ts
index 9e30dd37..65aaec60 100644
--- a/modules/network/hooks/useSwr.ts
+++ b/modules/network/hooks/useSwr.ts
@@ -11,6 +11,7 @@ import {
SWRInfiniteConfiguration,
SWRInfiniteKeyLoader,
} from 'swr/infinite'
+import { getErrorMessage } from 'modules/shared/utils/getErrorMessage'
export type SWRResponse = SWRResponseSource & {
initialLoading: boolean
@@ -19,7 +20,7 @@ export type SWRResponse = SWRResponseSource & {
const defaultConfig = {
onError: (error: any) => {
console.error(error)
- ToastError(error, {})
+ ToastError(getErrorMessage(error), {})
},
errorRetryInterval: 100_000,
focusThrottleInterval: 10_000,
diff --git a/modules/shared/utils/getErrorMessage.ts b/modules/shared/utils/getErrorMessage.ts
new file mode 100644
index 00000000..019bead3
--- /dev/null
+++ b/modules/shared/utils/getErrorMessage.ts
@@ -0,0 +1,90 @@
+export const ErrorMessageDisplayText = {
+ NOT_ENOUGH_ETHER: 'Not enough ether for gas.',
+ DENIED_SIG: 'User denied the transaction signature.',
+ SOMETHING_WRONG: 'Something went wrong.',
+ ENABLE_BLIND_SIGNING:
+ 'Please enable blind signing on your Ledger hardware wallet.',
+ LIMIT_REACHED:
+ 'Transaction could not be completed because stake limit is exhausted. Please wait until the stake limit restores and try again. Otherwise, you can swap your Ethereum on 1inch platform instantly.',
+} as const
+
+// type safe error code extractor
+const extractCodeFromError = (
+ error: unknown,
+ shouldDig = true,
+): number | string => {
+ // early exit on non object error
+ if (!error || typeof error != 'object') return 0
+
+ if ('reason' in error) {
+ if (typeof error.reason == 'string' && error.reason.includes('STAKE_LIMIT'))
+ return 'LIMIT_REACHED'
+ // TODO: error.reason more cases
+ }
+
+ // sometimes we have error message but bad error code
+ if ('message' in error && typeof error.message == 'string') {
+ const normalizedMessage = error.message.toLowerCase()
+ if (
+ normalizedMessage.includes('denied message signature') ||
+ normalizedMessage.includes('transaction was rejected') ||
+ normalizedMessage.includes('rejected the transaction') ||
+ normalizedMessage.includes('rejected the request')
+ )
+ return 'ACTION_REJECTED'
+ }
+
+ // Ledger live errors
+ if (
+ 'data' in error &&
+ typeof error.data === 'object' &&
+ Array.isArray(error.data) &&
+ typeof error.data['0'] === 'object' &&
+ typeof error.data['0'].message === 'string'
+ ) {
+ if (error.data['0'].message.toLowerCase().includes('rejected'))
+ return 'ACTION_REJECTED'
+ }
+
+ if ('name' in error && typeof error.name == 'string') {
+ if (error.name.toLocaleLowerCase() === 'ethapppleaseenablecontractdata')
+ return 'ENABLE_BLIND_SIGNING'
+ }
+ if ('code' in error) {
+ if (typeof error.code === 'string') return error.code.toUpperCase()
+ if (typeof error.code == 'number') return error.code
+ }
+
+ // errors are sometimes nested :(
+ if ('error' in error && shouldDig && error.error) {
+ return extractCodeFromError(error.error, false)
+ }
+
+ return 0
+}
+
+export const getErrorMessage = (error: unknown) => {
+ try {
+ console.error('TX_ERROR:', { error, error_string: JSON.stringify(error) })
+ } catch (e) {
+ console.error('TX_ERROR:', e)
+ }
+
+ const code = extractCodeFromError(error)
+ switch (code) {
+ case -32000:
+ case 3:
+ case 'UNPREDICTABLE_GAS_LIMIT':
+ case 'INSUFFICIENT_FUNDS':
+ return ErrorMessageDisplayText.NOT_ENOUGH_ETHER
+ case 'ACTION_REJECTED':
+ case 4001:
+ return ErrorMessageDisplayText.DENIED_SIG
+ case 'LIMIT_REACHED':
+ return ErrorMessageDisplayText.LIMIT_REACHED
+ case 'ENABLE_BLIND_SIGNING':
+ return ErrorMessageDisplayText.ENABLE_BLIND_SIGNING
+ default:
+ return ErrorMessageDisplayText.SOMETHING_WRONG
+ }
+}