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
167 changes: 167 additions & 0 deletions frontend/docs/ERROR_HANDLING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Error Handling for Token Transfers

## Overview

This document describes the improved error handling system for token transfers and approvals in the application. The system provides user-friendly, actionable error messages that help users understand what went wrong and how to fix it.

## Error Types

### Token Transfer Errors

The system recognizes and handles the following token transfer errors:

#### `INSUFFICIENT_TOKEN_BALANCE`
- **Message**: "Insufficient token balance. Please ensure you have enough cUSD in your wallet."
- **Cause**: User doesn't have enough tokens to complete the transfer
- **Solution**: User needs to add more cUSD tokens to their wallet

#### `INSUFFICIENT_ALLOWANCE`
- **Message**: "Token approval required. Please approve the transaction to allow the contract to spend your tokens."
- **Cause**: Contract doesn't have permission to spend user's tokens
- **Solution**: User needs to approve the contract (handled automatically in the flow)

#### `TOKEN_TRANSFER_FAILED`
- **Message**: "Token transfer failed. Please check your balance and try again."
- **Cause**: Generic transfer failure (could be network, gas, or contract issue)
- **Solution**: Check balance, network connection, and try again

#### `ZERO_AMOUNT_TRANSFER`
- **Message**: "Transfer amount must be greater than zero."
- **Cause**: Attempted to transfer zero tokens
- **Solution**: Ensure transfer amount is greater than zero

#### `TRANSFER_TO_ZERO_ADDRESS`
- **Message**: "Cannot transfer tokens to an invalid address."
- **Cause**: Attempted to transfer to zero address
- **Solution**: Use a valid recipient address

### Token Approval Errors

#### `TOKEN_APPROVAL_REJECTED`
- **Message**: "Token approval was cancelled. Please approve the transaction to continue."
- **Cause**: User rejected the approval transaction
- **Solution**: User needs to approve the transaction when prompted

#### `TOKEN_APPROVAL_FAILED`
- **Message**: "Token approval failed. Please try again or check your wallet connection."
- **Cause**: Approval transaction failed (network, gas, or other issue)
- **Solution**: Check wallet connection and try again

## Error Detection

The system uses several helper functions to detect specific error types:

### `isTokenTransferError(error)`
Detects if an error is related to token transfers by checking:
- Error message contains "transfer", "erc20", or "token"
- Error reason contains transfer-related keywords
- Error code indicates transfer failure

### `isInsufficientAllowanceError(error)`
Detects insufficient allowance errors by checking:
- Error message contains "allowance"
- Error message contains "insufficient allowance" or "allowance too low"
- Error code is `INSUFFICIENT_ALLOWANCE`

### `isTokenApprovalError(error)`
Detects token approval errors by checking:
- Error message contains "approve" or "approval"
- Error reason contains approval-related keywords
- Error code indicates approval failure

## Error Parsing

The `parseContractError` function automatically:
1. Detects the error type
2. Extracts relevant information
3. Returns a user-friendly message
4. Provides an error code for programmatic handling

### Example Usage

```typescript
import { parseContractError } from '@/utils/contractErrors';

try {
await transferTokens(amount);
} catch (error) {
const { message, code } = parseContractError(error);
// message: "Insufficient token balance. Please ensure you have enough cUSD in your wallet."
// code: ContractErrorType.INSUFFICIENT_TOKEN_BALANCE
toast.error(message);
}
```

## Integration Points

### useTokenApproval Hook

The hook automatically parses and enhances errors:

```typescript
const { approve, error } = useTokenApproval();

try {
await approve();
} catch (error) {
// Error is already parsed with user-friendly message
console.error(error.message); // "Token approval was cancelled..."
}
```

### Play Page

The play page provides specific error messages based on error type:

```typescript
if (error?.code === 'INSUFFICIENT_ALLOWANCE') {
toast.error('Token approval required. Please approve the transaction...');
} else if (error?.code === 'INSUFFICIENT_TOKEN_BALANCE') {
toast.error('Insufficient cUSD balance. Please add more tokens...');
}
```

### Rewards Page

The rewards page handles transfer errors for reward claims:

```typescript
if (error?.code === 'TOKEN_TRANSFER_FAILED') {
toast.error('Token transfer failed. The contract may not have enough funds...');
}
```

## Best Practices

1. **Always use parseContractError**: Don't display raw error messages to users
2. **Provide actionable messages**: Tell users what they can do to fix the issue
3. **Handle specific error codes**: Use error codes for conditional logic
4. **Log original errors**: Keep original errors for debugging while showing friendly messages
5. **Test error scenarios**: Ensure all error paths are tested

## Testing

Error handling is tested in `src/utils/__tests__/contractErrors.test.ts`:

- Token transfer error detection
- Insufficient allowance detection
- Token approval error detection
- Error message parsing
- User-friendly message generation

## Error Message Guidelines

1. **Be specific**: Tell users exactly what went wrong
2. **Be actionable**: Provide guidance on how to fix the issue
3. **Be friendly**: Use conversational, non-technical language
4. **Be concise**: Keep messages short and to the point
5. **Include context**: Mention relevant details (e.g., "cUSD" instead of just "tokens")

## Future Improvements

- [ ] Add error recovery suggestions
- [ ] Implement retry mechanisms for transient errors
- [ ] Add error analytics to track common issues
- [ ] Create error code reference documentation
- [ ] Add i18n support for error messages

42 changes: 36 additions & 6 deletions frontend/docs/TOKEN_APPROVAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,29 @@ The hook provides granular loading states for better UX:

## Error Handling

The hook handles various error scenarios:
The hook handles various error scenarios with improved, user-friendly messages:

- **Wallet not connected**: Throws error when trying to approve without wallet
- **User rejection**: Detects when user rejects transaction in wallet
- **Transaction failure**: Handles failed transactions gracefully
- **Network errors**: Catches and reports network-related errors
### Token Transfer Errors

- **Insufficient Token Balance**: "Insufficient token balance. Please ensure you have enough cUSD in your wallet."
- **Insufficient Allowance**: "Token approval required. Please approve the transaction to allow the contract to spend your tokens."
- **Transfer Failed**: "Token transfer failed. Please check your balance and try again."
- **Zero Amount**: "Transfer amount must be greater than zero."
- **Invalid Address**: "Cannot transfer tokens to an invalid address."

### Token Approval Errors

- **Approval Rejected**: "Token approval was cancelled. Please approve the transaction to continue."
- **Approval Failed**: "Token approval failed. Please try again or check your wallet connection."

### General Errors

- **Wallet not connected**: "Wallet not connected. Please connect your wallet to approve tokens."
- **User rejection**: Detects when user rejects transaction in wallet with clear messaging
- **Transaction failure**: Handles failed transactions gracefully with specific error messages
- **Network errors**: "Network error. Please check your connection and try again."

All errors are parsed using the `parseContractError` utility which provides consistent, user-friendly error messages across the application.

## UI Integration

Expand Down Expand Up @@ -235,8 +252,11 @@ The test suite covers:
- Detection of approval needs
- Loading states (allowance check, approving, waiting)
- Approval function calls with correct parameters
- Error handling
- Error handling with improved error messages
- Success states
- Token transfer error detection
- Token approval error detection
- User-friendly error message parsing

## Best Practices

Expand Down Expand Up @@ -270,6 +290,16 @@ The test suite covers:
- Verify ABI includes the `approve` function
- Check that contract addresses are correct

### Common Error Messages

If you encounter specific error messages, here's what they mean:

- **"Insufficient token balance"**: The user doesn't have enough cUSD tokens. They need to add more tokens to their wallet.
- **"Token approval required"**: The user needs to approve the contract to spend their tokens. This happens automatically in the flow.
- **"Token transfer failed"**: The transfer transaction failed. This could be due to network issues, insufficient gas, or contract issues.
- **"Transaction was cancelled"**: The user rejected the transaction in their wallet. They can try again.
- **"Network error"**: There's a problem with the network connection. Check internet connectivity.

## Security Considerations

1. **Unlimited approval**: The default approval uses `maxUint256` for convenience. For production, consider using specific amounts.
Expand Down
41 changes: 32 additions & 9 deletions frontend/src/app/play/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,20 @@ export default function PlayPage() {
toast.dismiss('approval-waiting');
console.error('Approval error:', approvalError);

if (approvalError?.message?.includes('User rejected') || approvalError?.message?.includes('rejected')) {
toast.error('Approval cancelled');
// Use the enhanced error message from the hook
const errorMessage = approvalError?.message || 'Failed to approve tokens. Please try again.';

// Provide specific guidance based on error type
if (approvalError?.code === 'TOKEN_APPROVAL_REJECTED' ||
approvalError?.message?.includes('cancelled') ||
approvalError?.message?.includes('rejected')) {
toast.error('Token approval was cancelled. Please approve the transaction to start the game.');
} else if (approvalError?.code === 'WALLET_NOT_CONNECTED') {
toast.error('Wallet not connected. Please connect your wallet and try again.');
} else if (approvalError?.code === 'NETWORK_ERROR') {
toast.error('Network error. Please check your connection and try again.');
} else {
toast.error(approvalError?.message || 'Failed to approve tokens');
toast.error(errorMessage);
}
setIsStarting(false);
return;
Expand All @@ -134,13 +144,26 @@ export default function PlayPage() {
toast.dismiss('approval-loading');
toast.dismiss('approval-waiting');

if (error?.message?.includes('approval required')) {
// Approval is still needed, but we already tried
toast.error('Please wait for approval to complete before starting the game');
} else if (error?.message?.includes('User rejected') || error?.message?.includes('rejected')) {
toast.error('Transaction cancelled');
const errorMessage = error?.message || 'Failed to start game. Please try again.';

// Provide specific guidance based on error type
if (error?.code === 'INSUFFICIENT_ALLOWANCE' || error?.message?.includes('approval required')) {
toast.error('Token approval required. Please approve the transaction to allow the game to use your tokens.');
} else if (error?.code === 'INSUFFICIENT_TOKEN_BALANCE' || error?.message?.includes('insufficient balance')) {
toast.error('Insufficient cUSD balance. Please add more tokens to your wallet.');
} else if (error?.code === 'TOKEN_TRANSFER_FAILED' || error?.message?.includes('transfer failed')) {
toast.error('Token transfer failed. Please check your balance and try again.');
} else if (error?.code === 'TRANSACTION_REJECTED' ||
error?.message?.includes('User rejected') ||
error?.message?.includes('rejected') ||
error?.message?.includes('cancelled')) {
toast.error('Transaction was cancelled. Please try again when ready.');
} else if (error?.code === 'WALLET_NOT_CONNECTED') {
toast.error('Wallet not connected. Please connect your wallet and try again.');
} else if (error?.code === 'NETWORK_ERROR') {
toast.error('Network error. Please check your connection and try again.');
} else {
toast.error(error?.message || 'Failed to start game');
toast.error(errorMessage);
}
setIsStarting(false);
}
Expand Down
21 changes: 20 additions & 1 deletion frontend/src/app/rewards/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,26 @@ export default function RewardsPage() {
} catch (error: any) {
console.error('Error claiming rewards:', error);
toast.dismiss();
toast.error(error?.message || 'Failed to claim rewards');

const errorMessage = error?.message || 'Failed to claim rewards. Please try again.';

// Provide specific guidance based on error type
if (error?.code === 'TOKEN_TRANSFER_FAILED' || error?.message?.includes('transfer failed')) {
toast.error('Token transfer failed. The contract may not have enough funds. Please contact support.');
} else if (error?.code === 'INSUFFICIENT_TOKEN_BALANCE' || error?.message?.includes('insufficient balance')) {
toast.error('Insufficient contract balance. Please contact support.');
} else if (error?.code === 'TRANSACTION_REJECTED' ||
error?.message?.includes('User rejected') ||
error?.message?.includes('rejected') ||
error?.message?.includes('cancelled')) {
toast.error('Transaction was cancelled. Please try again when ready.');
} else if (error?.code === 'WALLET_NOT_CONNECTED') {
toast.error('Wallet not connected. Please connect your wallet and try again.');
} else if (error?.code === 'NETWORK_ERROR') {
toast.error('Network error. Please check your connection and try again.');
} else {
toast.error(errorMessage);
}
setIsClaimingRewards(false);
}
};
Expand Down
Loading