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

# Wagmi Deposit Example

> Complete React component example for depositing into vaults using wagmi hooks

Complete deposit flow example using wagmi (React hooks) and the Earn SDK.

## Overview

This example demonstrates how to:

* Connect wallet with wagmi in React
* Check deposit approval status
* Approve deposit tokens when needed
* Execute deposit transactions with slippage protection
* Create custom React hooks for reusable deposit logic
* Handle loading states and transaction confirmation tracking
* Display error messages and transaction results

## Prerequisites

Before running this example, ensure you have:

* **Node.js >= 20** installed
* **wagmi >= 2.0.0** and **viem >= 2.0.0** installed
* **@paxoslabs/earn-sdk** installed
* **@tanstack/react-query** installed
* Modern web browser with Web3 wallet extension (MetaMask, Rainbow, etc.)
* ETH for gas fees
* Deposit tokens (e.g., USDC)

## Complete Code Example

### Custom Hook: `useVaultDeposit.ts`

First, create a custom hook that encapsulates all deposit logic:

```typescript theme={null}
/**
 * useVaultDeposit Hook
 *
 * Custom React hook that encapsulates the complete vault deposit flow:
 * - Check approval status
 * - Approve deposit tokens
 * - Execute deposit transaction
 */

import {
  isDepositSpendApproved,
  prepareApproveDepositToken,
  prepareDepositTransactionData,
} from "@paxoslabs/earn-sdk";
import { useCallback, useState } from "react";
import type { Address } from "viem";
import { useWaitForTransactionReceipt, useWriteContract } from "wagmi";

interface CheckApprovalParams {
  yieldType: string;
  depositToken: Address;
  depositAmount: string;
  recipientAddress: Address;
  chainId: number;
}

interface ApproveParams {
  yieldType: string;
  depositToken: Address;
  depositAmount: string;
  chainId: number;
}

interface DepositParams {
  yieldType: string;
  recipientAddress: Address;
  depositToken: Address;
  depositAmount: string;
  chainId: number;
  slippage: number;
}

interface UseVaultDepositReturn {
  // Actions
  checkApproval: (params: CheckApprovalParams) => Promise<void>;
  approve: (params: ApproveParams) => Promise<void>;
  deposit: (params: DepositParams) => Promise<void>;
  reset: () => void;

  // State
  isApproved: boolean | null;
  isCheckingApproval: boolean;
  isApprovingToken: boolean;
  isDepositing: boolean;
  error: Error | null;
  approvalHash: Address | null;
  depositHash: Address | null;
}

export function useDeposit(): UseVaultDepositReturn {
  // State management
  const [isApproved, setIsApproved] = useState<boolean | null>(null);
  const [isCheckingApproval, setIsCheckingApproval] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  // Wagmi hooks for writing contracts
  const {
    writeContractAsync: writeApproval,
    data: approvalHash,
    isPending: isApprovingToken,
  } = useWriteContract();

  const {
    writeContractAsync: writeDeposit,
    data: depositHash,
    isPending: isDepositing,
  } = useWriteContract();

  // Wait for transaction confirmations
  const { isLoading: isWaitingForApproval } = useWaitForTransactionReceipt({
    hash: approvalHash,
  });

  const { isLoading: isWaitingForDeposit } = useWaitForTransactionReceipt({
    hash: depositHash,
  });

  /**
   * Check if deposit tokens are approved
   */
  const checkApproval = useCallback(async (params: CheckApprovalParams) => {
    setIsCheckingApproval(true);
    setError(null);

    try {
      const approved = await isDepositSpendApproved({
        yieldType: params.yieldType,
        depositToken: params.depositToken,
        depositAmount: params.depositAmount,
        recipientAddress: params.recipientAddress,
        chainId: params.chainId,
      });

      setIsApproved(approved);
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      setError(error);
      setIsApproved(null);
    } finally {
      setIsCheckingApproval(false);
    }
  }, []);

  /**
   * Approve deposit tokens
   */
  const approve = useCallback(
    async (params: ApproveParams) => {
      setError(null);

      try {
        // Prepare approval transaction
        const approvalTx = await prepareApproveDepositTxData({
          yieldType: params.yieldType,
          depositToken: params.depositToken,
          depositAmount: params.depositAmount,
          chainId: params.chainId,
        });

        // Execute approval using wagmi
        await writeApproval(approvalTx);

        // Update approval state after successful transaction
        setIsApproved(true);
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [writeApproval]
  );

  /**
   * Execute deposit transaction
   */
  const deposit = useCallback(
    async (params: DepositParams) => {
      setError(null);

      try {
        // Prepare deposit transaction
        const depositTx = await prepareDepositTxData({
          yieldType: params.yieldType,
          recipientAddress: params.recipientAddress,
          depositToken: params.depositToken,
          depositAmount: params.depositAmount,
          chainId: params.chainId,
          slippage: params.slippage,
        });

        // Execute deposit using wagmi
        await writeDeposit(depositTx);
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [writeDeposit]
  );

  /**
   * Reset hook state
   */
  const reset = useCallback(() => {
    setIsApproved(null);
    setError(null);
  }, []);

  return {
    // Actions
    checkApproval,
    approve,
    deposit,
    reset,

    // State
    isApproved,
    isCheckingApproval,
    isApprovingToken:
      isApprovingToken || isWaitingForApproval || Boolean(approvalHash),
    isDepositing: isDepositing || isWaitingForDeposit || Boolean(depositHash),
    error,
    approvalHash: (approvalHash as Address) || null,
    depositHash: (depositHash as Address) || null,
  };
}
```

### Component: `DepositComponent.tsx`

Now create the React component that uses the custom hook:

```typescript theme={null}
/**
 * Deposit Component
 *
 * React component demonstrating vault deposit using wagmi hooks
 * and the custom useVaultDeposit hook.
 */

import { useState } from "react";
import type { Address } from "viem";
import { useAccount, useConnect, useDisconnect } from "wagmi";
import { injected } from "wagmi/connectors";
import { useVaultDeposit } from "./hooks/useVaultDeposit";

interface DepositConfig {
  yieldType: "PRIME" | "TBILL" | "LENDING";
  depositToken: Address;
  depositAmount: string;
  chainId: number;
  slippage: number;
}

const DEFAULT_CONFIG: DepositConfig = {
  yieldType: "PRIME",
  depositToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum
  depositAmount: "1000.0", // $1000 USDC
  chainId: 1, // Ethereum mainnet
  slippage: 100, // 1% (100 basis points)
};

export function DepositComponent() {
  // Wagmi wallet connection hooks
  const { address, isConnected } = useAccount();
  const { connect } = useConnect();
  const { disconnect } = useDisconnect();

  // Local state for deposit configuration
  const [config, setConfig] = useState<DepositConfig>(DEFAULT_CONFIG);

  // Custom deposit hook
  const {
    deposit,
    approve,
    checkApproval,
    isApproved,
    isCheckingApproval,
    isApprovingToken,
    isDepositing,
    error,
    approvalHash,
    depositHash,
    reset,
  } = useVaultDeposit();

  /**
   * Handle wallet connection
   */
  const handleConnect = () => {
    connect({ connector: injected() });
  };

  /**
   * Handle check approval
   */
  const handleCheckApproval = async () => {
    if (!address) return;

    await checkApproval({
      yieldType: config.yieldType,
      depositToken: config.depositToken,
      depositAmount: config.depositAmount,
      recipientAddress: address,
      chainId: config.chainId,
    });
  };

  /**
   * Handle approve tokens
   */
  const handleApprove = async () => {
    await approve({
      yieldType: config.yieldType,
      depositToken: config.depositToken,
      depositAmount: config.depositAmount,
      chainId: config.chainId,
    });
  };

  /**
   * Handle deposit
   */
  const handleDeposit = async () => {
    if (!address) return;

    await deposit({
      yieldType: config.yieldType,
      recipientAddress: address,
      depositToken: config.depositToken,
      depositAmount: config.depositAmount,
      chainId: config.chainId,
      slippage: config.slippage,
    });
  };

  // Render wallet connection UI if not connected
  if (!isConnected) {
    return (
      <div className="deposit-container">
        <div className="connect-section">
          <h2>Connect Wallet</h2>
          <p>Connect your wallet to deposit into Earn Vaults</p>
          <button onClick={handleConnect} className="btn btn-primary">
            Connect Wallet
          </button>
        </div>
      </div>
    );
  }

  // Render deposit form
  return (
    <div className="deposit-container">
      <div className="wallet-section">
        <p className="wallet-address">
          Connected: {address?.slice(0, 6)}...{address?.slice(-4)}
        </p>
        <button onClick={() => disconnect()} className="btn btn-secondary">
          Disconnect
        </button>
      </div>

      <div className="deposit-form">
        <h2>Deposit to Vault</h2>

        <div className="form-group">
          <label htmlFor="yieldType">Yield Type</label>
          <select
            id="yieldType"
            value={config.yieldType}
            onChange={(e) =>
              setConfig((prev) => ({
                ...prev,
                yieldType: e.target.value as "PRIME" | "TBILL" | "LENDING",
              }))
            }
            disabled={isApprovingToken || isDepositing}
          >
            <option value="PRIME">PRIME</option>
            <option value="TBILL">TBILL</option>
            <option value="LENDING">LENDING</option>
          </select>
        </div>

        <div className="form-group">
          <label htmlFor="amount">Deposit Amount (USDC)</label>
          <input
            id="amount"
            type="text"
            value={config.depositAmount}
            onChange={(e) =>
              setConfig((prev) => ({
                ...prev,
                depositAmount: e.target.value,
              }))
            }
            disabled={isApprovingToken || isDepositing}
            placeholder="1000.0"
          />
        </div>

        <div className="form-group">
          <label htmlFor="slippage">Slippage (basis points)</label>
          <input
            id="slippage"
            type="number"
            value={config.slippage}
            onChange={(e) =>
              setConfig((prev) => ({
                ...prev,
                slippage: Number(e.target.value),
              }))
            }
            disabled={isApprovingToken || isDepositing}
            placeholder="100"
          />
          <small>100 basis points = 1%</small>
        </div>

        <div className="button-group">
          <button
            onClick={handleCheckApproval}
            disabled={isCheckingApproval || isApprovingToken || isDepositing}
            className="btn btn-secondary"
          >
            {isCheckingApproval ? "Checking..." : "Check Approval"}
          </button>

          {isApproved !== null && (
            <div className="approval-status">
              {isApproved ? (
                <span className="status-approved">✓ Approved</span>
              ) : (
                <span className="status-not-approved">✗ Not Approved</span>
              )}
            </div>
          )}

          {isApproved === false && (
            <button
              onClick={handleApprove}
              disabled={isApprovingToken || isDepositing}
              className="btn btn-warning"
            >
              {isApprovingToken ? "Approving..." : "Approve Tokens"}
            </button>
          )}

          {isApproved === true && (
            <button
              onClick={handleDeposit}
              disabled={isDepositing}
              className="btn btn-primary"
            >
              {isDepositing ? "Depositing..." : "Deposit"}
            </button>
          )}

          {(approvalHash || depositHash) && (
            <button onClick={reset} className="btn btn-secondary">
              Reset
            </button>
          )}
        </div>

        {error && (
          <div className="error-message">
            <strong>Error:</strong> {error.message}
          </div>
        )}

        {approvalHash && (
          <div className="success-message">
            <strong>Approval Transaction:</strong>
            <br />
            <a
              href={`https://etherscan.io/tx/${approvalHash}`}
              target="_blank"
              rel="noopener noreferrer"
            >
              {approvalHash.slice(0, 10)}...{approvalHash.slice(-8)}
            </a>
          </div>
        )}

        {depositHash && (
          <div className="success-message">
            <strong>Deposit Transaction:</strong>
            <br />
            <a
              href={`https://etherscan.io/tx/${depositHash}`}
              target="_blank"
              rel="noopener noreferrer"
            >
              {depositHash.slice(0, 10)}...{depositHash.slice(-8)}
            </a>
            <br />
            <br />
            <strong>✓ Deposit completed successfully!</strong>
          </div>
        )}
      </div>
    </div>
  );
}
```

## What This Code Does

### Custom Hook (`useVaultDeposit`)

The custom hook encapsulates all deposit logic and provides a clean API:

1. **State Management**: Tracks approval status, loading states, errors, and transaction hashes
2. **Approval Checking**: `checkApproval()` verifies if tokens are already approved
3. **Token Approval**: `approve()` prepares and executes approval transaction
4. **Deposit Execution**: `deposit()` prepares and executes deposit transaction
5. **Transaction Tracking**: Uses `useWaitForTransactionReceipt` to track confirmations
6. **Reset Functionality**: `reset()` clears state for new deposits

### Component (`DepositComponent`)

The React component provides the UI and orchestrates the deposit flow:

1. **Wallet Connection**: Uses wagmi's `useConnect` and `useAccount` hooks
2. **Form State**: Manages deposit configuration (yield type, amount, slippage)
3. **Approval Workflow**: Check approval → Approve if needed → Deposit
4. **Loading States**: Disables buttons and shows loading indicators during transactions
5. **Error Handling**: Displays error messages from hook
6. **Transaction Results**: Shows Etherscan links for approval and deposit transactions

## Key Features

### Custom Hook Pattern

The `useVaultDeposit` hook provides a reusable, testable pattern for vault deposits:

```typescript theme={null}
const {
  deposit,
  approve,
  checkApproval,
  isApproved,
  isCheckingApproval,
  isApprovingToken,
  isDepositing,
  error,
  approvalHash,
  depositHash,
  reset,
} = useVaultDeposit();
```

**Benefits**:

* **Separation of Concerns**: Business logic separated from UI
* **Reusability**: Use the same hook in multiple components
* **Testability**: Test logic independently from UI
* **Type Safety**: Full TypeScript support with interfaces

### Approval-First Workflow

<Snippet file="v0.1.0/snippets/approval-workflow.mdx" />

### Loading States

The component shows appropriate loading states during:

* **Approval checking**: `isCheckingApproval`
* **Token approval**: `isApprovingToken` (includes waiting for confirmation)
* **Deposit execution**: `isDepositing` (includes waiting for confirmation)

Buttons are disabled during these operations to prevent duplicate transactions.

### Error Handling

Errors are caught at the hook level and exposed to components:

```typescript theme={null}
if (error) {
  // Display user-friendly error message
  console.error("Deposit failed:", error.message);
}
```

### Slippage Protection

<Snippet file="v0.1.0/snippets/slippage-explanation.mdx" />

## Configuration Options

### Change Deposit Amount

```typescript theme={null}
const DEFAULT_CONFIG: DepositConfig = {
  // ...
  depositAmount: "5000.0", // Change to $5000 USDC
};
```

### Change Yield Type

```typescript theme={null}
const DEFAULT_CONFIG: DepositConfig = {
  yieldType: "TBILL", // Switch to T-Bill vault
  // ...
};
```

### Change Slippage Tolerance

```typescript theme={null}
const DEFAULT_CONFIG: DepositConfig = {
  // ...
  slippage: 50, // 0.5% slippage (50 basis points)
};
```

### Use Different Token

```typescript theme={null}
const DEFAULT_CONFIG: DepositConfig = {
  depositToken: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI
  // ...
};
```

### Add More Chains

Update your wagmi config to support additional chains:

```typescript theme={null}
import { createConfig, http } from "wagmi";
import { mainnet, boba, sei } from "wagmi/chains";

const config = createConfig({
  chains: [mainnet, boba, sei],
  transports: {
    [mainnet.id]: http(),
    [boba.id]: http(),
    [sei.id]: http(),
  },
});
```

## Troubleshooting

### "Connect Wallet" button not working

**Possible causes**:

* No Web3 wallet extension installed
* Wallet extension disabled or locked

**Solutions**:

1. Install MetaMask, Rainbow, or another Web3 wallet
2. Unlock your wallet extension
3. Refresh the page and try again

### "Approval transaction failed"

**Possible causes**:

* Insufficient ETH for gas fees
* Incorrect deposit token address
* Wrong network selected in wallet

**Solutions**:

1. Check ETH balance for gas fees
2. Verify deposit token address is correct
3. Ensure wallet is connected to Ethereum mainnet

### "Deposit transaction failed"

**Possible causes**:

* Approval not successful
* Insufficient deposit tokens
* Slippage exceeded

**Solutions**:

1. Wait for approval confirmation before depositing
2. Check token balance in wallet
3. Increase slippage tolerance if needed

### Wagmi hook errors

**Possible causes**:

* Wagmi or React Query providers not configured
* Incompatible wagmi version
* Missing chains in wagmi config

**Solutions**:

1. Ensure `WagmiProvider` and `QueryClientProvider` wrap your app
2. Use wagmi >= 2.0.0
3. Add chains to wagmi config that you're using

## Next Steps

* **Viem Example**: See the [viem deposit example](/v0.1.0/intro/products/earn/developers/examples/viem-deposit) for vanilla TypeScript integration
* **Withdrawal Flow**: See the [wagmi withdrawal example](/v0.1.0/intro/products/earn/developers/examples/wagmi-withdraw) for withdrawal patterns
* **API Documentation**: Read the [deposits API documentation](/v0.1.0/intro/products/earn/developers/functions/deposit) for detailed parameter descriptions
