Skip to main content
This example demonstrates a complete deposit flow using wagmi React hooks and the unified deposit API.
This example uses the unified deposit API which automatically detects the optimal authorization method (permit vs approval).

Prerequisites

  • Node.js 18+
  • wagmi v2+ configured in your app
  • Amplify API key from Paxos Labs

Installation

pnpm add @paxoslabs/amplify-sdk wagmi viem @tanstack/react-query

Complete Example

useDeposit Hook

// src/hooks/useDeposit.ts
import { useState, useCallback } from "react";
import { useAccount, useWriteContract, useSignTypedData } from "wagmi";
import {
  prepareDepositAuthorization,
  prepareDepositTxData,
  prepareDepositWithPermitTxData,
  DepositAuthMethod,
  YieldType,
} from "@paxoslabs/amplify-sdk";

interface DepositParams {
  amount: string;
  depositToken: `0x${string}`;
  yieldType: YieldType;
}

export function useDeposit() {
  const { address, chainId } = useAccount();
  const { writeContractAsync } = useWriteContract();
  const { signTypedDataAsync } = useSignTypedData();
  const [status, setStatus] = useState<string>("");
  const [isLoading, setIsLoading] = useState(false);

  const deposit = useCallback(
    async ({ amount, depositToken, yieldType }: DepositParams) => {
      if (!address || !chainId) {
        throw new Error("Connect a wallet first");
      }

      setIsLoading(true);

      try {
        const params = {
          yieldType,
          depositToken,
          depositAmount: amount,
          recipientAddress: address,
          chainId,
        };

        // Step 1: Get authorization method
        setStatus("Checking authorization...");
        const auth = await prepareDepositAuthorization(params);

        // Step 2: Handle based on method
        switch (auth.method) {
          case DepositAuthMethod.PERMIT: {
            setStatus("Please sign permit in your wallet...");
            const signature = await signTypedDataAsync(auth.permitData);

            setStatus("Submitting deposit...");
            const permitTx = await prepareDepositWithPermitTxData({
              ...params,
              signature,
              deadline: BigInt(auth.permitData.message.deadline),
            });

            await writeContractAsync({
              address: permitTx.address,
              abi: permitTx.data.abi,
              functionName: permitTx.data.functionName,
              args: permitTx.data.args,
              account: address,
            });
            break;
          }

          case DepositAuthMethod.APPROVAL: {
            setStatus("Approving token spend...");
            await writeContractAsync({
              ...auth.txData,
              account: address,
            });

            setStatus("Submitting deposit...");
            const depositTx = await prepareDepositTxData(params);
            await writeContractAsync({
              ...depositTx,
              account: address,
            });
            break;
          }

          case DepositAuthMethod.ALREADY_APPROVED: {
            setStatus("Submitting deposit...");
            const directTx = await prepareDepositTxData(params);
            await writeContractAsync({
              ...directTx,
              account: address,
            });
            break;
          }
        }

        setStatus("Deposit successful!");
      } catch (error) {
        setStatus(`Error: ${error instanceof Error ? error.message : "Unknown"}`);
        throw error;
      } finally {
        setIsLoading(false);
      }
    },
    [address, chainId, writeContractAsync, signTypedDataAsync]
  );

  return { deposit, status, isLoading };
}

Deposit Component

// src/components/DepositForm.tsx
import { useState } from "react";
import { useAccount } from "wagmi";
import { YieldType } from "@paxoslabs/amplify-sdk";
import { useDeposit } from "../hooks/useDeposit";

const USDC_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as const;

export function DepositForm() {
  const { isConnected } = useAccount();
  const [amount, setAmount] = useState("100");
  const { deposit, status, isLoading } = useDeposit();

  if (!isConnected) {
    return <p>Please connect your wallet</p>;
  }

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    await deposit({
      amount,
      depositToken: USDC_ADDRESS,
      yieldType: YieldType.PRIME,
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Amount (USDC):
        <input
          type="number"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          disabled={isLoading}
          min="0"
          step="0.01"
        />
      </label>
      <button type="submit" disabled={isLoading}>
        {isLoading ? "Processing..." : "Deposit"}
      </button>
      {status && <p>{status}</p>}
    </form>
  );
}

What This Code Does

  1. Uses wagmi hooks - useAccount, useWriteContract, useSignTypedData
  2. Checks authorization method - Determines optimal path automatically
  3. Signs permits with wagmi - Uses signTypedDataAsync for EIP-712
  4. Writes contracts with wagmi - Uses writeContractAsync for transactions
  5. Tracks loading state - Disables form during processing

Key Features

  • Native wagmi integration - Works with your existing wagmi setup
  • Automatic chain handling - Uses connected chain from useAccount
  • Type-safe hooks - Full TypeScript support
  • Composable architecture - Separate hook from UI component

Benefits of This Pattern

BenefitDescription
Separation of concernsBusiness logic in hook, UI in component
ReusabilityHook can be used across multiple components
TestabilityHook logic can be tested independently
MaintainabilityChanges to flow logic don’t affect UI

Troubleshooting

IssueSolution
”SDK not initialized”Call initAmplifySDK() at app startup
”Connect a wallet first”Check isConnected from useAccount
Transaction rejectedUser cancelled in wallet, show retry option
For more details, see Deposits.