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

# useApprove

> Grants permission to a smart contract to spend tokens from the user wallet. Required before staking or other delegated actions.

## Usage

```typescript theme={null}
const { 
  approve, 
  approveAsync, 
  data, 
  isLoading, 
  isError, 
  error, 
  isSuccess, 
  reset 
} = useApprove();
```

### Parameters

The hook accepts an object with:

* `params` (`ApproveHookInput`):
  * `encryptKey` (string): User's decryption PIN
  * `wallet` (`WalletData`): Wallet public/private key pair
  * `contractAddress` (string): Token contract to approve
  * `spender` (string): Contract address to authorize
  * `amount` (number): Maximum spend allowance (will be converted to string internally)
  * `decimals` (number, optional): Token decimals (default: 18)
  * `usePasskey` (boolean, optional): Set `true` when `encryptKey` was derived from a passkey
* `bearerToken` (string): Bearer token for authentication

### Return Value

Returns an object containing:

* `approve`: Function to trigger token approval (fire-and-forget)
* `approveAsync`: Promise-based function that resolves with the transaction hash
* `data`: Transaction hash of the approval (string | undefined)
* `isLoading`: Boolean indicating if the operation is in progress
* `isError`: Boolean indicating if an error occurred
* `error`: Error instance when `isError` is true, otherwise `null`
* `isSuccess`: Boolean indicating if the approval completed successfully
* `reset`: Function to reset the mutation state

## Example Implementation for Approving VESU

```typescript theme={null}
const VESU_CONTRACT = "0x037ae3f583c8d644b7556c93a04b83b52fa96159b2b0cbd83c14d3122aef80a2";

// Sample wallet data - replace with your wallet in production.
// Keep walletType + signerKind from createWallet / useGetWallet: the SDK
// routes by walletType, and omitting it defaults to "READY" (a SHHH wallet
// would revert).
const sampleWallet: {
  publicKey: string;
  encryptedPrivateKey: string;
  walletType: "SHHH" | "CHIPI" | "READY";
  signerKind?: "STARK" | "WEBAUTHN_P256" | "EIP191_SECP256K1" | "ED25519";
} = {
  publicKey: "0x123...yourPublicKeyHere",
  encryptedPrivateKey: "encrypted:key:data", // This would be encrypted data in production
  walletType: "SHHH",
  signerKind: "STARK",
};

export function ApproveForm() {
  
  const { approveAsync, data, isLoading, isError, error } = useApprove();
  const [wallet] = useState(sampleWallet);
  const [form, setForm] = useState({
    pin: '',
    amount: ''
  });

  const handleApprove = async (e: React.FormEvent) => {
    e.preventDefault();

    const bearerToken = await getToken();
    if (!bearerToken) {
      console.error('No bearer token available');
      return;
    }

    try {
      await approveAsync({
        params: {
          encryptKey: form.pin,
          wallet: {
            publicKey: wallet.publicKey,
            encryptedPrivateKey: wallet.encryptedPrivateKey,
            walletType: wallet.walletType, // routing-critical (SHHH/CHIPI/READY)
            signerKind: wallet.signerKind,
          },
          contractAddress: VESU_CONTRACT,
          spender: VESU_CONTRACT, // Authorizing VESU contract
          amount: Number(form.amount),
          decimals: 18
        },
        bearerToken,
      });
    } catch (err) {
      console.error('Approval failed:', err);
    }
  };

  return (
    <div className="bg-white rounded-xl shadow-lg p-6">
      <h2 className="text-2xl font-bold mb-4">Approve Token Access</h2>
      
      <form onSubmit={handleApprove} className="space-y-4">
        <div>
          <label className="block text-sm font-medium mb-1">Security PIN</label>
          <input
            type="password"
            value={form.pin}
            onChange={(e) => setForm({...form, pin: e.target.value})}
            className="w-full p-2 border rounded-md"
            required
          />
        </div>

        <div>
          <label className="block text-sm font-medium mb-1">Amount to Approve</label>
          <input
            type="number"
            value={form.amount}
            onChange={(e) => setForm({...form, amount: e.target.value})}
            className="w-full p-2 border rounded-md"
            required
          />
        </div>

        <button 
          type="submit" 
          disabled={isLoading}
          className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:bg-gray-400"
        >
          {isLoading ? 'Approving...' : 'Authorize Contract'}
        </button>
      </form>

      {data && (
        <div className="mt-4 p-3 bg-gray-50 rounded-md">
          <p className="text-sm font-mono break-all">
            Approval TX: {data}
          </p>
        </div>
      )}

      {isError && error && (
        <div className="mt-4 p-3 bg-red-50 text-red-700 rounded-md">
          Error: {error.message}
        </div>
      )}
    </div>
  );
}
```

## Security Considerations

* Always use encrypted private keys
* Never store or transmit raw private keys
* Implement proper PIN validation
* Use secure storage for wallet data
* Consider implementing approval limits

## Error Handling

* Handle insufficient token balance
* Validate contract addresses
* Check for existing approvals
* Monitor gas fees
* Implement retry logic for failed transactions

<Warning>
  Approvals are specific to each token-contract pair. You'll need to re-approve when interacting with new contracts.
</Warning>

## Related Hooks

* **useTransfer** - For moving tokens
* **useCallAnyContract** - For custom contract interactions that need prior approval
