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

# Privy Withdraw Example

> Redeem Amplify vault shares with Privy wallets

Redeem shares in one transaction by pairing `prepareWithdrawTxData` with Privy’s wallet connection hooks. This pattern keeps signer UX inside Privy while letting the Amplify SDK handle calldata.

## Overview

* Fetch the target vault (for example with `fetchVaults` and React Query).
* Prepare withdrawal calldata with slippage protection.
* Submit the transaction via Privy’s `sendTransaction`.
* Track optimistic state and surface any `APIError` details.

## Prerequisites

* **React 18+**
* **@privy-io/react-auth >= 3**
* **@paxoslabs/amplify-sdk**
* Vault metadata available in your component (e.g., from `fetchVaults`)

## Withdraw Hook

```tsx theme={null}
import { useCallback, useMemo, useState } from "react";
import { encodeFunctionData } from "viem";
import {
  isWithdrawalSpendApproved,
  prepareApproveWithdrawTxData,
  prepareWithdrawTxData,
  type YieldType,
} from "@paxoslabs/amplify-sdk";
import { usePrivy, useWallets } from "@privy-io/react-auth";

interface WithdrawParams {
  yieldType: YieldType;
  shareAmount: string;
  wantAssetAddress: `0x${string}`;
  chainId: number;
  userAddress: `0x${string}`;
  slippage?: number;
}

export function usePrivyWithdraw() {
  const { sendTransaction } = usePrivy();
  const { wallets } = useWallets();
  const wallet = useMemo(() => wallets.find(Boolean), [wallets]);

  const [txHash, setTxHash] = useState<`0x${string}` | null>(null);
  const [status, setStatus] = useState<
    "idle" | "checking" | "approving" | "withdrawing" | "success"
  >("idle");
  const [error, setError] = useState<Error | null>(null);

  const run = useCallback(
    async ({
      yieldType,
      shareAmount,
      wantAssetAddress,
      chainId,
      userAddress,
      slippage = 75,
    }: WithdrawParams) => {
      if (!wallet) {
        throw new Error("Connect a Privy wallet before withdrawing.");
      }

      setStatus("checking");
      setError(null);
      setTxHash(null);

      try {
        const approval = await isWithdrawalSpendApproved({
          yieldType,
          wantAssetAddress,
          userAddress,
          chainId,
        });

        if (!approval.isApproved) {
          setStatus("approving");
          const approvalTx = await prepareApproveWithdrawTxData({
            yieldType,
            wantAssetAddress,
            shareAmount,
            chainId,
          });

          await sendTransaction({
            chainId: approvalTx.chainId,
            to: approvalTx.address,
            data: encodeFunctionData({
              abi: approvalTx.abi,
              functionName: approvalTx.functionName,
              args: approvalTx.args,
            }),
          });
        }

        const tx = await prepareWithdrawTxData({
          yieldType,
          shareAmount,
          wantAssetAddress,
          chainId,
          userAddress,
          slippage,
        });

        setStatus("withdrawing");
        const hash = await sendTransaction({
          chainId: tx.chainId,
          to: tx.address,
          data: encodeFunctionData({
            abi: tx.abi,
            functionName: tx.functionName,
            args: tx.args,
          }),
        });

        setTxHash(hash as `0x${string}`);
        setStatus("success");
      } catch (err) {
        const message = err instanceof Error ? err : new Error(String(err));
        setError(message);
        setStatus("idle");
        throw err;
      }
    },
    [wallet, sendTransaction]
  );

  return { run, status, error, txHash };
}
```

## Component Usage

```tsx theme={null}
import { useMemo } from "react";
import { useWallets } from "@privy-io/react-auth";
import { useQuery } from "@tanstack/react-query";
import { fetchVaults, YieldType } from "@paxoslabs/amplify-sdk";
import { mainnet } from "viem/chains";
import { usePrivyWithdraw } from "./usePrivyWithdraw";

export function PrivyWithdrawButton() {
  const { wallets } = useWallets();
  const wallet = useMemo(() => wallets.find(Boolean), [wallets]);
  const { run, status, error, txHash } = usePrivyWithdraw();

  const { data: vaults } = useQuery({
    queryKey: ["core-vaults", mainnet.id],
    queryFn: () =>
      fetchVaults({
        chainId: mainnet.id,
        yieldType: YieldType.CORE,
      }),
    enabled: Boolean(wallet),
  });

  const vault = vaults?.[0];

  if (!wallet) {
    return <p>Connect with Privy to withdraw.</p>;
  }

  if (!vault) {
    return <p>Loading vault metadata…</p>;
  }

  async function handleClick() {
    await run({
      yieldType: vault.yieldType,
      shareAmount: "5.0",
      wantAssetAddress: vault.depositTokenAddressId as `0x${string}`,
      chainId: vault.chainId,
      userAddress: wallet.address as `0x${string}`,
      slippage: 75,
    });
  }

  return (
    <section>
      <button onClick={handleClick} disabled={status !== "idle" && status !== "success"}>
        {status === "checking" && "Checking allowance…"}
        {status === "approving" && "Approving…"}
        {status === "withdrawing" && "Withdrawing…"}
        {status === "success" && "Withdraw Again"}
        {(status === "idle" || status === "success") && "Withdraw"}
      </button>

      {txHash && (
        <p>
          Withdrawal sent:{" "}
          <a
            href={`https://etherscan.io/tx/${txHash}`}
            target="_blank"
            rel="noreferrer"
          >
            {txHash}
          </a>
        </p>
      )}

      {error && <p role="alert">Withdraw failed: {error.message}</p>}
    </section>
  );
}
```

<Callout type="info">
  `prepareWithdrawTxData` throws `APIError` when the vault or asset is
  unsupported. Log the `endpoint` and `statusCode` to help users fall back to
  alternate flows.
</Callout>
