diff --git a/src/features/leverage-tokens/components/leverage-token-mint-modal/ErrorStep.tsx b/src/features/leverage-tokens/components/leverage-token-mint-modal/ErrorStep.tsx
index ca579374..3d14a690 100644
--- a/src/features/leverage-tokens/components/leverage-token-mint-modal/ErrorStep.tsx
+++ b/src/features/leverage-tokens/components/leverage-token-mint-modal/ErrorStep.tsx
@@ -12,6 +12,7 @@ export function ErrorStep({ error, onRetry, onClose }: ErrorStepProps) {
const { icon, title, message, showRetry, severity, technicalDetails } = getErrorDisplay(
error || '',
'Transaction Failed',
+ 'mintLt',
)
const bgClass =
severity === 'warning'
diff --git a/src/features/leverage-tokens/components/leverage-token-redeem-modal/ErrorStep.tsx b/src/features/leverage-tokens/components/leverage-token-redeem-modal/ErrorStep.tsx
index 4606ffac..aff59631 100644
--- a/src/features/leverage-tokens/components/leverage-token-redeem-modal/ErrorStep.tsx
+++ b/src/features/leverage-tokens/components/leverage-token-redeem-modal/ErrorStep.tsx
@@ -12,6 +12,7 @@ export function ErrorStep({ error, onRetry, onClose }: ErrorStepProps) {
const { icon, title, message, showRetry, severity, technicalDetails } = getErrorDisplay(
error || '',
'Redemption Failed',
+ 'redeemLt',
)
const bgClass =
severity === 'warning'
diff --git a/src/features/leverage-tokens/utils/errorDisplay.tsx b/src/features/leverage-tokens/utils/errorDisplay.tsx
index 8708f43d..10da490b 100644
--- a/src/features/leverage-tokens/utils/errorDisplay.tsx
+++ b/src/features/leverage-tokens/utils/errorDisplay.tsx
@@ -19,11 +19,12 @@ export interface ErrorDisplayConfig {
export function getErrorDisplay(
error: string,
defaultTitle: string = 'Transaction Failed',
+ txType?: 'mintLt' | 'redeemLt',
): ErrorDisplayConfig {
// Try to classify the error first
let classifiedError: LeverageTokenError
try {
- classifiedError = classifyError(error)
+ classifiedError = classifyError(error, txType)
} catch {
classifiedError = { type: 'UNKNOWN', message: error }
}
@@ -87,14 +88,42 @@ export function getErrorDisplay(
case 'SLIPPAGE_EXCEEDED':
return {
icon: ,
- title: 'Slippage Tolerance Exceeded',
- message:
- 'The price moved beyond your slippage tolerance. Try increasing your slippage tolerance or retry the transaction.',
+ title: 'Swap Slippage Tolerance Exceeded',
+ message: `The spot price moved beyond your slippage tolerance. Try decreasing your swap slippage tolerance, increasing the ${txType === 'mintLt' ? 'leverage token' : 'collateral'} adjustment parameter, or retry the transaction.`,
showRetry: true,
severity: 'warning',
technicalDetails: error,
}
+ case 'LT_SHARE_SLIPPAGE_EXCEEDED':
+ return {
+ icon: ,
+ title: 'Leverage Token Slippage Exceeded',
+ message:
+ 'The Leverage Token share price moved beyond your slippage tolerance. Try decreasing your swap slippage tolerance, increasing the Leverage Token slippage tolerance, or retry the transaction.',
+ showRetry: true,
+ severity: 'warning',
+ }
+
+ case 'LT_COLLATERAL_SLIPPAGE_EXCEEDED':
+ return {
+ icon: ,
+ title: 'Leverage Token Collateral Slippage Exceeded',
+ message:
+ 'The Leverage Token collateral price moved beyond your slippage tolerance. Try decreasing your swap slippage tolerance, increasing the collateral slippage tolerance, or retry the transaction.',
+ showRetry: true,
+ severity: 'warning',
+ }
+
+ case 'INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT':
+ return {
+ icon: ,
+ title: 'Insufficient Assets for Flash Loan Repayment',
+ message: `Unable to repay flash loan. Try decreasing your swap slippage tolerance, increasing the ${txType === 'mintLt' ? 'flash loan adjustment' : 'collateral swap adjustment'} parameter, or retry the transaction.`,
+ showRetry: true,
+ severity: 'error',
+ }
+
default:
// For unknown errors, check if it's a user rejection by looking for common patterns
if (
diff --git a/src/features/leverage-tokens/utils/errors.ts b/src/features/leverage-tokens/utils/errors.ts
index 42720806..19af78c4 100644
--- a/src/features/leverage-tokens/utils/errors.ts
+++ b/src/features/leverage-tokens/utils/errors.ts
@@ -10,16 +10,19 @@ export type LeverageTokenError =
| { type: 'USER_REJECTED'; code: 4001 }
| { type: 'CHAIN_MISMATCH'; expected: number; actual: number }
| { type: 'UNKNOWN'; message: string; originalError?: unknown }
+ | { type: 'LT_SHARE_SLIPPAGE_EXCEEDED' }
+ | { type: 'LT_COLLATERAL_SLIPPAGE_EXCEEDED' }
+ | { type: 'INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT' }
/**
* Classify errors into actionable types
* User errors (4001, 4902) should not be sent to Sentry
*/
-export function classifyError(e: unknown): LeverageTokenError {
+export function classifyError(e: unknown, txType?: 'mintLt' | 'redeemLt'): LeverageTokenError {
// Handle string input directly
if (typeof e === 'string') {
const error = { message: e }
- return classifyErrorFromObject(error)
+ return classifyErrorFromObject(error, txType)
}
const error = e as {
@@ -32,18 +35,21 @@ export function classifyError(e: unknown): LeverageTokenError {
message?: string
}
- return classifyErrorFromObject(error)
+ return classifyErrorFromObject(error, txType)
}
-function classifyErrorFromObject(error: {
- code?: number
- cause?: { code?: number }
- expectedChainId?: number
- actualChainId?: number
- reason?: string
- data?: { message?: string }
- message?: string
-}): LeverageTokenError {
+function classifyErrorFromObject(
+ error: {
+ code?: number
+ cause?: { code?: number }
+ expectedChainId?: number
+ actualChainId?: number
+ reason?: string
+ data?: { message?: string }
+ message?: string
+ },
+ txType?: 'mintLt' | 'redeemLt',
+): LeverageTokenError {
// User rejected transaction
if (error?.code === 4001 || error?.cause?.code === 4001) {
return { type: 'USER_REJECTED', code: 4001 }
@@ -113,9 +119,33 @@ function classifyErrorFromObject(error: {
// Check for slippage-related error signatures in the raw message
const rawMessage = error?.message || ''
+
+ if (txType === 'mintLt' && rawMessage.includes('0x76baadda')) {
+ return {
+ type: 'LT_SHARE_SLIPPAGE_EXCEEDED',
+ }
+ }
+
+ if (
+ txType === 'redeemLt' &&
+ (rawMessage.includes('0x76baadda') || rawMessage.includes('CollateralSlippageTooHigh'))
+ ) {
+ return {
+ type: 'LT_COLLATERAL_SLIPPAGE_EXCEEDED',
+ }
+ }
+
+ if (
+ (txType === 'mintLt' || txType === 'redeemLt') &&
+ rawMessage.includes('transferFrom reverted')
+ ) {
+ return {
+ type: 'INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT',
+ }
+ }
+
if (
rawMessage.includes('0x5a046737') || // Common slippage signature
- rawMessage.includes('0x76baadda') || // Another slippage signature
rawMessage.includes('SlippageExceeded') ||
rawMessage.includes('SlippageToleranceExceeded') ||
rawMessage.includes('PriceImpactTooHigh') ||
diff --git a/tests/unit/features/leverage-tokens/utils/errors.test.ts b/tests/unit/features/leverage-tokens/utils/errors.test.ts
new file mode 100644
index 00000000..4c20dd81
--- /dev/null
+++ b/tests/unit/features/leverage-tokens/utils/errors.test.ts
@@ -0,0 +1,105 @@
+import { describe, expect, it } from 'vitest'
+import { classifyError } from '@/features/leverage-tokens/utils/errors'
+
+describe('classifyError', () => {
+ describe('LT_SHARE_SLIPPAGE_EXCEEDED (mint)', () => {
+ it('returns LT_SHARE_SLIPPAGE_EXCEEDED when txType is mintLt and message contains 0x76baadda', () => {
+ const error = {
+ message:
+ 'The contract function "deposit" reverted. Error signature 0x76baadda. Some other text.',
+ }
+ expect(classifyError(error, 'mintLt')).toEqual({
+ type: 'LT_SHARE_SLIPPAGE_EXCEEDED',
+ })
+ })
+
+ it('does not return LT_SHARE_SLIPPAGE_EXCEEDED when txType is mintLt but message lacks 0x76baadda', () => {
+ const error = { message: 'transferFrom reverted' }
+ expect(classifyError(error, 'mintLt')).not.toEqual({
+ type: 'LT_SHARE_SLIPPAGE_EXCEEDED',
+ })
+ })
+
+ it('does not return LT_SHARE_SLIPPAGE_EXCEEDED when message contains 0x76baadda but txType is not mintLt', () => {
+ const error = { message: 'Revert 0x76baadda' }
+ expect(classifyError(error, 'redeemLt')).toEqual({
+ type: 'LT_COLLATERAL_SLIPPAGE_EXCEEDED',
+ })
+ expect(classifyError(error)).not.toEqual({
+ type: 'LT_SHARE_SLIPPAGE_EXCEEDED',
+ })
+ })
+ })
+
+ describe('LT_COLLATERAL_SLIPPAGE_EXCEEDED (redeem)', () => {
+ it('returns LT_COLLATERAL_SLIPPAGE_EXCEEDED when txType is redeemLt and message contains 0x76baadda', () => {
+ const error = { message: 'Reverted with 0x76baadda' }
+ expect(classifyError(error, 'redeemLt')).toEqual({
+ type: 'LT_COLLATERAL_SLIPPAGE_EXCEEDED',
+ })
+ })
+
+ it('returns LT_COLLATERAL_SLIPPAGE_EXCEEDED when txType is redeemLt and message contains CollateralSlippageTooHigh', () => {
+ const error = { message: 'CollateralSlippageTooHigh' }
+ expect(classifyError(error, 'redeemLt')).toEqual({
+ type: 'LT_COLLATERAL_SLIPPAGE_EXCEEDED',
+ })
+ })
+
+ it('does not return LT_COLLATERAL_SLIPPAGE_EXCEEDED when txType is redeemLt but message is not CollateralSlippageTooHigh or 0x76baadda', () => {
+ const error = { message: 'Some other revert' }
+ expect(classifyError(error, 'redeemLt')).toEqual({
+ type: 'UNKNOWN',
+ message: 'Some other revert',
+ originalError: error,
+ })
+ })
+
+ it('does not return LT_COLLATERAL_SLIPPAGE_EXCEEDED when txType is not redeemLt', () => {
+ const error = { message: '0x76baadda' }
+ expect(classifyError(error, 'mintLt')).toEqual({
+ type: 'LT_SHARE_SLIPPAGE_EXCEEDED',
+ })
+ expect(classifyError(error)).toEqual({
+ type: 'UNKNOWN',
+ message: '0x76baadda',
+ originalError: error,
+ })
+ })
+ })
+
+ describe('INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT', () => {
+ it('returns INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT when txType is mintLt and message contains transferFrom reverted', () => {
+ const error = {
+ message:
+ 'The contract function "deposit" reverted with the following reason:\ntransferFrom reverted\n\nContract Call:',
+ }
+ expect(classifyError(error, 'mintLt')).toEqual({
+ type: 'INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT',
+ })
+ })
+
+ it('returns INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT when txType is redeemLt and message contains transferFrom reverted', () => {
+ const error = { message: 'transferFrom reverted' }
+ expect(classifyError(error, 'redeemLt')).toEqual({
+ type: 'INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT',
+ })
+ })
+
+ it('does not return INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT when message does not contain transferFrom reverted', () => {
+ const error = { message: 'Some other error' }
+ expect(classifyError(error, 'mintLt')).not.toEqual({
+ type: 'INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT',
+ })
+ })
+
+ it('does not return INSUFFICIENT_ASSETS_FOR_FLASH_LOAN_REPAYMENT when txType is omitted', () => {
+ const error = { message: 'transferFrom reverted' }
+ expect(classifyError(error)).toEqual({
+ type: 'UNKNOWN',
+ message: 'transferFrom reverted',
+ originalError: error,
+ })
+ })
+ })
+})