> ## Documentation Index
> Fetch the complete documentation index at: https://docs.onebalance.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting Contract Calls

> Solutions to common issues in cross-chain contract calls with OneBalance, including debugging and error-handling best practices.

This guide covers the most common issues developers encounter when implementing OneBalance contract calls and their solutions.

<Tip>
  **Quick Debug Tip**: Most contract call failures happen during the prepare phase. Always validate your inputs before calling the API.
</Tip>

## Common Errors

### Including Manual Approval Calls

<Warning>
  **Most Common Error**: Adding `approve()` calls to your transaction array will cause failures.
</Warning>

OneBalance automatically handles all token approvals through the `allowanceRequirements` field. Including manual `approve()` calls in your transaction array conflicts with this system and will cause the request to fail.

```typescript wrong-approval-approach.ts theme={null}
// ❌ WRONG - This will fail
const badRequest = {
  calls: [
    {
      to: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
      data: encodeFunctionData({
        abi: parseAbi(['function approve(address spender, uint256 amount)']),
        functionName: 'approve',
        args: [spenderAddress, amount]
      }),
      value: '0'
    },
    {
      to: spenderAddress,
      data: actualCallData,
      value: '0'
    }
  ]
  // This causes "Invalid call data" errors
};
```

```typescript correct-approval-approach.ts theme={null}
// ✅ CORRECT - Use allowanceRequirements
const correctRequest = {
  calls: [{
    to: spenderAddress,
    data: actualCallData,
    value: '0'
  }],
  allowanceRequirements: [{
    assetType: 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
    amount: amount.toString(),
    spender: spenderAddress
  }]
};
```

### Invalid Tamper Proof Signature

This error occurs when the quote structure is modified after preparation. The tamper-proof signature validates the exact quote structure, so any changes will invalidate it.

**Common Causes:**

* JSON key ordering changed during serialization
* Extra fields added to the quote object
* Quote passed through JSON.stringify/parse incorrectly

```typescript preserve-quote-structure.ts theme={null}
// ❌ Wrong - modifies structure
const modifiedQuote = {
  ...preparedQuote,
  extraField: 'value'
};

// ❌ Wrong - changes key order
const reordered = JSON.parse(JSON.stringify(preparedQuote));

// ✅ Correct - preserve exact structure
preparedQuote.chainOperation.userOp.signature = signature;
```

### Account Configuration Errors

Account validation ensures all required addresses are present and properly formatted. Missing or invalid addresses will cause authentication failures during quote preparation.

```typescript account-validation.ts theme={null}
// ✅ Validate account before using
function validateAccount(account: Account) {
  if (!account.sessionAddress || !account.adminAddress || !account.accountAddress) {
    throw new Error('Missing required account addresses');
  }
  
  if (!isAddress(account.sessionAddress)) {
    throw new Error('Invalid session address format');
  }
  
  if (account.sessionAddress === account.adminAddress) {
    throw new Error('Session and admin addresses must be different');
  }
  
  return true;
}
```

## API Response Errors

<Tabs>
  <Tab title="4xx Client Errors">
    ### 400 Bad Request

    These errors occur when request data doesn't match expected formats. Always validate input data before sending API requests.

    **Asset ID format errors:**

    ```typescript asset-id-validation.ts theme={null}
    // ❌ Wrong formats
    const wrong = [
      'usdc',
      'USDC', 
      'erc20:0x...',
      'ob:USDC'
    ];

    // ✅ Correct format
    const correct = 'ob:usdc';
    ```

    **Chain ID format errors:**

    ```typescript chain-validation.ts theme={null}
    // ❌ Wrong formats
    const wrongChains = ['base', '8453', 'Base'];

    // ✅ Correct format
    const correctChain = 'eip155:8453';
    ```

    ### 401 Unauthorized

    This error indicates missing or invalid API key configuration. Verify your environment variables are set correctly.

    ```typescript api-key-check.ts theme={null}
    // Check your API key configuration
    const headers = {
      'x-api-key': process.env.ONEBALANCE_API_KEY
    };

    if (!headers['x-api-key']) {
      throw new Error('OneBalance API key not configured');
    }
    ```

    ### 422 Unprocessable Entity

    Usually indicates business logic errors:

    * Insufficient balance
    * Amount below minimum (\$0.50)
    * Unsupported token/chain combination
  </Tab>

  <Tab title="5xx Server Errors">
    ### 503 Service Unavailable

    Server errors are typically temporary. Implement retry logic with exponential backoff to handle these gracefully.

    ```typescript retry-logic.ts theme={null}
    async function retryableApiCall<T>(
      apiCall: () => Promise<T>,
      maxRetries = 3
    ): Promise<T> {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
        try {
          return await apiCall();
        } catch (error: any) {
          const isRetryable = error.response?.status >= 500 || 
                             error.response?.status === 503;
          
          if (!isRetryable || attempt === maxRetries - 1) {
            throw error;
          }
          
          // Exponential backoff: 1s, 2s, 4s
          const delay = Math.pow(2, attempt) * 1000;
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
      throw new Error('Max retries exceeded');
    }
    ```
  </Tab>
</Tabs>

## Balance & Amount Issues

### Insufficient Balance

Always verify the account has sufficient balance before attempting operations. This prevents failed transactions and provides better user feedback.

```typescript balance-validation.ts theme={null}
// Always check balance before operations
async function validateSufficientBalance(
  accountAddress: string,
  assetId: string,
  requiredAmount: bigint
) {
  const response = await apiGet('/v2/balances/aggregated-balance', {
    address: accountAddress,
    assetId
  });
  
  const assetBalance = response.balanceByAggregatedAsset.find(
    asset => asset.aggregatedAssetId === assetId
  );
  
  if (!assetBalance) {
    throw new Error(`No balance found for asset ${assetId}`);
  }
  
  const availableBalance = BigInt(assetBalance.balance);
  
  if (availableBalance < requiredAmount) {
    throw new Error(
      `Insufficient balance. Required: ${requiredAmount}, Available: ${availableBalance}`
    );
  }
  
  return true;
}
```

### Decimal Calculation Errors

Token amounts must be calculated using the correct decimal places. Using wrong decimals is a common cause of "insufficient balance" or "amount too small" errors.

<CardGroup cols={2}>
  <Card title="Common Token Decimals" icon="calculator">
    * **USDC**: 6 decimals
    * **ETH/WETH**: 18 decimals
    * **WBTC**: 8 decimals
    * **DAI**: 18 decimals
  </Card>

  <Card title="Amount Validation" icon="circle-check">
    Always use `parseUnits()` and verify the token's actual decimals before calculations.
  </Card>
</CardGroup>

```typescript decimal-handling.ts theme={null}
import { parseUnits, formatUnits } from 'viem';

// ✅ Correct decimal handling
function formatTokenAmount(amount: string, decimals: number) {
  // Convert user input to smallest unit
  const parsedAmount = parseUnits(amount, decimals);
  
  // Validate minimum amount ($0.50 equivalent)
  const minimumUSD = parseUnits('0.50', 6); // $0.50 in USDC terms
  
  return {
    amount: parsedAmount.toString(),
    formatted: formatUnits(parsedAmount, decimals)
  };
}
```

## Signing & Execution Issues

### Signature Validation

Verify signatures locally before sending to prevent failed transactions. This helps debug signing issues early in the development process.

```typescript signature-validation.ts theme={null}
import { verifyTypedData } from 'viem';

async function validateSignature(
  account: Account,
  typedData: any,
  signature: string
) {
  const isValid = await verifyTypedData({
    address: account.sessionAddress as `0x${string}`,
    domain: typedData.domain,
    types: typedData.types,
    primaryType: typedData.primaryType,
    message: typedData.message,
    signature: signature as `0x${string}`
  });
  
  if (!isValid) {
    throw new Error('Invalid signature');
  }
  
  return true;
}
```

### Transaction Status Monitoring

Implement proper status polling to track transaction progress and handle different completion states. This provides users with real-time feedback on their transactions.

```typescript status-monitoring.ts theme={null}
async function waitForTransactionCompletion(
  quoteId: string,
  timeoutMs = 60000
): Promise<QuoteStatus> {
  const startTime = Date.now();
  
  while (Date.now() - startTime < timeoutMs) {
    const status = await apiGet('/status/get-execution-status', { quoteId });
    
    switch (status.status.status) {
      case 'COMPLETED':
        return status;
        
      case 'FAILED':
        throw new Error(`Transaction failed: ${status.quoteId}`);
        
      case 'REFUNDED':
        throw new Error(`Transaction refunded - likely amount too small or gas costs too high`);
        
      case 'PENDING':
        // Continue polling
        await new Promise(resolve => setTimeout(resolve, 2000));
        break;
        
      default:
        throw new Error(`Unknown status: ${status.status.status}`);
    }
  }
  
  throw new Error('Transaction timeout');
}
```

## Contract-Specific Issues

### DEX Integration Problems

DEX protocols have specific parameter requirements that must be validated before execution. Common issues include expired deadlines and invalid fee tiers.

```typescript dex-troubleshooting.ts theme={null}
// Common Uniswap V3 issues
function validateUniswapV3Call(params: any) {
  // Check deadline is in future
  const now = Math.floor(Date.now() / 1000);
  if (params.deadline <= now) {
    throw new Error('Deadline must be in the future');
  }
  
  // Validate fee tier
  const validFees = [100, 500, 3000, 10000];
  if (!validFees.includes(params.fee)) {
    throw new Error(`Invalid fee tier: ${params.fee}`);
  }
  
  // Check recipient matches account
  if (params.recipient !== account.accountAddress) {
    console.warn('Recipient does not match account address');
  }
}
```

### NFT Marketplace Issues

NFT purchases require additional validation for contract addresses and reasonable price limits. This helps prevent accidental overpayments or invalid transactions.

```typescript nft-troubleshooting.ts theme={null}
// Common NFT purchase validation
function validateNFTPurchase(contractAddress: string, tokenId: string, price: bigint) {
  if (!isAddress(contractAddress)) {
    throw new Error('Invalid NFT contract address');
  }
  
  // Check if price seems reasonable (basic sanity check)
  const maxReasonablePrice = parseUnits('1000', 6); // $1000 USDC
  if (price > maxReasonablePrice) {
    console.warn('Price seems unusually high - please verify');
  }
  
  return true;
}
```

## Debugging Tools

### Enhanced Logging

The logging helps identify issues quickly during development. This debug function provides structured output for all request parameters.

```typescript debug-helpers.ts theme={null}
// Request logging
function debugPrepareRequest(request: PrepareCallRequest) {
  console.group('🔍 OneBalance Prepare Request Debug');
  
  console.log('📋 Account:', {
    session: request.account.sessionAddress,
    admin: request.account.adminAddress,
    smart: request.account.accountAddress
  });
  
  console.log('🌐 Target Chain:', request.targetChain);
  
  console.log(`📞 Calls (${request.calls.length}):`);
  request.calls.forEach((call, i) => {
    console.log(`  Call ${i + 1}:`, {
      to: call.to,
      value: call.value,
      dataLength: call.data.length,
      dataPreview: call.data.slice(0, 10) + '...'
    });
  });
  
  console.log(`💰 Tokens Required (${request.tokensRequired.length}):`);
  request.tokensRequired.forEach((token, i) => {
    console.log(`  Token ${i + 1}:`, token);
  });
  
  console.log(`🔐 Allowances Required (${request.allowanceRequirements.length}):`);
  request.allowanceRequirements.forEach((allowance, i) => {
    console.log(`  Allowance ${i + 1}:`, allowance);
  });
  
  console.groupEnd();
}
```

### Health Check Function

Run this function before implementing your main logic to verify all components are working correctly. It tests API connectivity, account prediction, and balance retrieval.

```typescript health-check.ts theme={null}
async function performHealthCheck(account: Account) {
  const checks = [];
  
  try {
    // 1. Check API connectivity
    await apiGet('/chains/supported-list', {});
    checks.push('✅ API connectivity');
  } catch {
    checks.push('❌ API connectivity failed');
  }
  
  try {
    // 2. Check account prediction
    const prediction = await apiPost('/account/predict-address', {
      sessionAddress: account.sessionAddress,
      adminAddress: account.adminAddress
    });
    checks.push(`✅ Account prediction: ${prediction.predictedAddress}`);
  } catch {
    checks.push('❌ Account prediction failed');
  }
  
  try {
    // 3. Check balance retrieval
    const balance = await apiGet('/v2/balances/aggregated-balance', {
      address: account.accountAddress
    });
    checks.push(`✅ Balance check: ${balance.balanceByAggregatedAsset.length} assets`);
  } catch {
    checks.push('❌ Balance check failed');
  }
  
  console.log('🏥 OneBalance Health Check Results:');
  checks.forEach(check => console.log(check));
  
  return checks.every(check => check.startsWith('✅'));
}
```

## Common Pitfalls

<Warning>
  **Top 5 Mistakes to Avoid:**

  1. **Manual Approvals** - Never include `approve()` in your calls array
  2. **Wrong Decimals** - Always verify token decimals (USDC = 6, not 18)
  3. **Invalid Chain Format** - Use `eip155:chainId`, not just the chain ID
  4. **Modifying Quotes** - Never alter the quote structure after preparation
  5. **Insufficient Balance** - Always check balance before attempting operations
</Warning>

## Error Code Reference

| Error Code | Meaning              | Solution                                |
| ---------- | -------------------- | --------------------------------------- |
| `400`      | Bad Request          | Check input format and validation       |
| `401`      | Unauthorized         | Verify API key configuration            |
| `422`      | Unprocessable Entity | Check business logic (balance, amounts) |
| `503`      | Service Unavailable  | Implement retry logic                   |

## Getting Help

<Steps>
  <Step title="Check This Guide">
    Review the specific error section above for your issue
  </Step>

  <Step title="Use Debug Tools">
    Run the health check and debug logging functions
  </Step>

  <Step title="Review Examples">
    Check [working examples](/guides/contract-calls/examples) for reference implementations
  </Step>

  <Step title="Contact Support">
    Use the **Intercom chat widget** in the bottom right corner for instant help, or email [support@onebalance.io](mailto:support@onebalance.io). Provide your quote ID, error message, and debug logs for faster resolution.
  </Step>
</Steps>

<Tip>
  **Pro Tip**: Most issues can be prevented by running the health check function before implementing your main logic.
</Tip>
