Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
37 changes: 33 additions & 4 deletions src/features/leverage-tokens/utils/errorDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down Expand Up @@ -87,14 +88,42 @@ export function getErrorDisplay(
case 'SLIPPAGE_EXCEEDED':
return {
icon: <AlertTriangle className="h-8 w-8 text-[var(--state-error-text)]" />,
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: <AlertTriangle className="h-8 w-8 text-[var(--state-error-text)]" />,
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: <AlertTriangle className="h-8 w-8 text-[var(--state-error-text)]" />,
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: <AlertTriangle className="h-8 w-8 text-[var(--state-error-text)]" />,
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 (
Expand Down
56 changes: 43 additions & 13 deletions src/features/leverage-tokens/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 }
Expand Down Expand Up @@ -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') ||
Expand Down
105 changes: 105 additions & 0 deletions tests/unit/features/leverage-tokens/utils/errors.test.ts
Original file line number Diff line number Diff line change
@@ -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,
})
})
})
})