> ## 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 {
  prepareApproveWithdrawTxData,
  prepareWithdrawTxData,
  type YieldType,
} from "@paxoslabs/amplify-sdk";
import { usePrivy, useWallets } from "@privy-io/react-auth";

interface WithdrawParams {
  yieldType: YieldType;
  offerAmount: string;
  wantAssetAddress: `0x${string}`;
  chainId: number;
  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" | "approving" | "withdrawing" | "success"
  >("idle");
  const [error, setError] = useState<Error | null>(null);

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

      setError(null);
      setTxHash(null);

      try {
        // Step 1: Approve withdrawal
        setStatus("approving");
        const approval = await prepareApproveWithdrawTxData({
          chainId,
          wantAssetAddress,
          yieldType,
        });

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

        // Step 2: Execute withdrawal
        setStatus("withdrawing");
        const tx = await prepareWithdrawTxData({
          yieldType,
          wantAssetAddress,
          offerAmount,
          chainId,
        });

        const { abi, functionName, args } = tx;
        const hash = await sendTransaction({
          chainId: tx.chainId,
          to: tx.address,
          data: encodeFunctionData({ abi, functionName, 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 { fetchSupportedAssets, 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: supportedAssets } = useQuery({
    queryKey: ["amplify-assets", mainnet.id],
    queryFn: () =>
      fetchSupportedAssets({
        yieldType: YieldType.PRIME,
      }),
    enabled: Boolean(wallet),
  });

  const asset = supportedAssets?.[0];

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

  if (!asset) {
    return <p>Loading supported assets…</p>;
  }

  async function handleClick() {
    await run({
      yieldType: YieldType.PRIME,
      offerAmount: "5.0",
      wantAssetAddress: asset.address as `0x${string}`,
      chainId: mainnet.id,
      slippage: 75,
    });
  }

  return (
    <section>
      <button onClick={handleClick} disabled={status !== "idle" && status !== "success"}>
        {status === "approving" && "Approving…"}
        {status === "withdrawing" && "Withdrawing…"}
        {status === "success" && "Withdraw Again"}
        {status === "idle" && "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>
