> ## 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.

# Allowances & Approvals

> Learn how OneBalance manages token allowances and approvals, ensuring secure and gas-efficient transactions automatically.

Learn how OneBalance automatically handles token approvals for DeFi operations while maintaining security best practices.

<Warning>
  **Important**: Never manually call `approve()` functions when using OneBalance. The platform automatically manages all required approvals as part of the contract call preparation process.
</Warning>

## How Approval Management Works

When you specify `allowanceRequirements`, OneBalance automatically:

1. **Checks existing allowances** - Verifies current approval amounts
2. **Adds approval transactions** - Only when needed, for exact amounts
3. **Executes your operations** - Runs your contract calls
4. **Removes excess approvals** - Cleans up remaining allowances for security

This prevents front-running attacks and ensures optimal gas usage.

<Tip>
  OneBalance bundles approvals, your calls, and approval cleanup into a single user operation for atomic execution.
</Tip>

## Basic Example

Here's how to properly handle approvals for a DEX swap:

```typescript swap-with-approval.ts theme={null}
import { encodeFunctionData, parseAbi, parseUnits } from 'viem';

const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const UNISWAP_ROUTER = '0x2626664c2603336E57B271c5C0b26F421741e481';

// ✅ Correct - Let OneBalance handle approvals
const prepareRequest = {
  account: {
    sessionAddress: '0x...',
    adminAddress: '0x...',
    accountAddress: '0x...'
  },
  targetChain: 'eip155:8453', // Base
  calls: [{
    to: UNISWAP_ROUTER,
    data: encodeFunctionData({
      abi: parseAbi(['function exactInputSingle((address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 deadline, uint256 amountIn, uint256 amountOutMinimum, uint160 sqrtPriceLimitX96))']),
      functionName: 'exactInputSingle',
      args: [{
        tokenIn: USDC_BASE,
        tokenOut: '0x...',
        fee: 3000,
        recipient: account.accountAddress,
        deadline: Math.floor(Date.now() / 1000) + 3600,
        amountIn: parseUnits('100', 6), // 100 USDC
        amountOutMinimum: 0,
        sqrtPriceLimitX96: 0
      }]
    }),
    value: '0'
  }],
  allowanceRequirements: [{
    assetType: `eip155:8453/erc20:${USDC_BASE}`,
    amount: parseUnits('100', 6).toString(), // Exact amount needed
    spender: UNISWAP_ROUTER
  }],
  tokensRequired: [{
    assetType: `eip155:8453/erc20:${USDC_BASE}`,
    amount: parseUnits('100', 6).toString()
  }]
};
```

## What NOT to Do

<Warning>
  **Common Mistake**: Including approval calls manually will cause transaction failures.
</Warning>

```typescript wrong-approach.ts theme={null}
// ❌ WRONG - Don't do this!
const badRequest = {
  calls: [
    {
      // This will cause the transaction to fail
      to: USDC_BASE,
      data: encodeFunctionData({
        abi: parseAbi(['function approve(address spender, uint256 amount)']),
        functionName: 'approve',
        args: [UNISWAP_ROUTER, parseUnits('100', 6)]
      }),
      value: '0'
    },
    {
      to: UNISWAP_ROUTER,
      data: swapCallData,
      value: '0'
    }
  ]
  // No allowanceRequirements - this is the problem!
};
```

## Common Patterns

### DEX Swaps

```typescript dex-swap.ts theme={null}
// Uniswap V3 swap requiring token approval
allowanceRequirements: [{
  assetType: `eip155:8453/erc20:${inputToken}`,
  amount: inputAmount.toString(),
  spender: UNISWAP_V3_ROUTER
}]
```

### Lending Protocols

```typescript aave-deposit.ts theme={null}
// Aave deposit requiring pool approval
allowanceRequirements: [{
  assetType: `eip155:1/erc20:${asset}`,
  amount: depositAmount.toString(),
  spender: AAVE_POOL_ADDRESS
}]
```

### Multiple Token Operations

```typescript multi-token-defi.ts theme={null}
// Complex DeFi operation requiring multiple approvals
allowanceRequirements: [
  {
    assetType: `eip155:1/erc20:${tokenA}`,
    amount: amountA.toString(),
    spender: DEX_ROUTER
  },
  {
    assetType: `eip155:1/erc20:${tokenB}`,
    amount: amountB.toString(),
    spender: LENDING_POOL
  }
]
```

### NFT Purchases

```typescript nft-purchase.ts theme={null}
// NFT marketplace purchase with USDC
allowanceRequirements: [{
  assetType: 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
  amount: nftPrice.toString(),
  spender: NFT_MARKETPLACE_ADDRESS
}]
```

## Special Cases

### Native Tokens (ETH, MATIC, etc.)

Native tokens don't require approvals - they're sent directly:

```typescript native-token.ts theme={null}
// No allowanceRequirements needed for ETH
calls: [{
  to: CONTRACT_ADDRESS,
  data: contractCallData,
  value: ethAmount.toString() // Send ETH directly
}],
tokensRequired: [{
  assetType: 'eip155:1/slip44:60', // ETH
  amount: ethAmount.toString()
}]
// No allowanceRequirements array needed
```

### Existing Allowances

OneBalance optimizes gas by checking existing allowances:

<CardGroup cols={2}>
  <Card title="Sufficient Allowance" icon="check">
    If `current allowance ≥ required amount`, no approval transaction is added
  </Card>

  <Card title="Insufficient Allowance" icon="plus">
    Only approves the exact amount needed, not unlimited approvals
  </Card>
</CardGroup>

## Security Features

OneBalance's approval management includes several security measures:

* **Exact Amount Approvals** - Never approves more than needed
* **Automatic Cleanup** - Removes remaining allowances after execution
* **Front-running Protection** - Atomic bundling prevents manipulation
* **Approval Validation** - Verifies spender addresses match your calls

## Best Practices

<Steps>
  <Step title="Use allowanceRequirements">
    Always specify token approvals in the `allowanceRequirements` array, never in `calls`
  </Step>

  <Step title="Specify Exact Amounts">
    Use precise amounts to minimize approval exposure
  </Step>

  <Step title="Verify Spender Addresses">
    Double-check that spender addresses match your contract calls
  </Step>

  <Step title="Test with Small Amounts">
    Start with small transactions to verify your integration
  </Step>
</Steps>

## TypeScript Interface

```typescript interfaces.ts theme={null}
interface AllowanceRequirement {
  assetType: string;  // Format: "eip155:chainId/erc20:tokenAddress"
  amount: string;     // Amount in smallest unit (e.g., wei)
  spender: string;    // Contract address that needs approval
}

interface PrepareCallRequest {
  account: Account;
  targetChain: string;
  calls: CallData[];
  allowanceRequirements: AllowanceRequirement[];
  tokensRequired: TokenRequirement[];
}
```

## Troubleshooting

* **Transaction fails with 'Approval not found'** - Make sure you're using `allowanceRequirements` instead of manual approval calls.
* **Gas costs seem high** - OneBalance only adds approvals when needed. High gas might indicate multiple tokens or complex operations.
* **Spender address mismatch** - Verify that the spender in `allowanceRequirements` matches the contract address in your `calls`.
* **Amount calculation errors** - Ensure you're using the correct decimals for the token (e.g., 6 for USDC, 18 for most ERC20s).

<Tip>
  Need help? Check the [troubleshooting guide](/guides/contract-calls/troubleshooting) for common issues and solutions.
</Tip>
