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

# Quickstart

> Build a React app with deposits and withdrawals in under 30 minutes

This walkthrough bootstraps a Vite + React project that authenticates users with Privy, initializes the Amplify SDK, and wires up deposit flows using the unified deposit API.

<Info>
  The snippets use the latest Privy React SDK (`@privy-io/react-auth`) APIs.
  Wait for `ready` from `usePrivy` and `useWallets` before inspecting user or
  wallet state to avoid race conditions.
</Info>

## 1. Scaffold the Project

```bash theme={null}
pnpm create vite amplify-starter --template react-ts
cd amplify-starter
pnpm install
```

Install the runtime dependencies:

```bash theme={null}
pnpm add @paxoslabs/amplify-sdk viem @privy-io/react-auth @tanstack/react-query
```

## 2. Configure Environment Variables

Create `.env.local`:

```bash theme={null}
VITE_PRIVY_APP_ID=your-privy-app-id
VITE_AMPLIFY_API_KEY=pxl_your_api_key
VITE_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-key
VITE_APP_ETHEREUM_MAINNET_RPC=https://eth-mainnet.g.alchemy.com/v2/your-key
```

<Warning>
  Never commit this file. Provide an `.env.example` without secrets for
  teammates.
</Warning>

## 3. Set Up Providers

Create `src/providers.tsx`:

```tsx theme={null}
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { PrivyProvider } from '@privy-io/react-auth'
import type { ReactNode } from 'react'

const queryClient = new QueryClient()

export function Providers({ children }: { children: ReactNode }) {
  if (!import.meta.env.VITE_PRIVY_APP_ID) {
    throw new Error('Missing VITE_PRIVY_APP_ID env variable')
  }

  return (
    <PrivyProvider appId={import.meta.env.VITE_PRIVY_APP_ID}>
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    </PrivyProvider>
  )
}
```

Wire the providers in `src/main.tsx`:

```tsx theme={null}
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import { Providers } from './providers.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <Providers>
      <App />
    </Providers>
  </StrictMode>
)
```

## 4. Initialize the SDK

Create `src/hooks/useAmplify.ts`:

```ts theme={null}
import { initAmplifySDK, LogLevel } from '@paxoslabs/amplify-sdk'
import { useEffect, useState } from 'react'
import { mainnet } from 'viem/chains'

let initialized = false

export function useAmplify() {
  const [isReady, setIsReady] = useState(initialized)
  const [error, setError] = useState<Error | null>(null)

  useEffect(() => {
    if (initialized) {
      setIsReady(true)
      return
    }

    const apiKey = import.meta.env.VITE_AMPLIFY_API_KEY
    if (!apiKey) {
      setError(new Error('Missing VITE_AMPLIFY_API_KEY env variable'))
      return
    }

    async function init() {
      try {
        await initAmplifySDK(apiKey, {
          rpcUrls: {
            [mainnet.id]: import.meta.env.VITE_APP_ETHEREUM_MAINNET_RPC,
          },
          logLevel: LogLevel.ERROR,
          telemetry: true,
        })
        initialized = true
        setIsReady(true)
      } catch (err) {
        setError(
          err instanceof Error ? err : new Error('SDK initialization failed')
        )
      }
    }

    init()
  }, [])

  return { isReady, error }
}
```

## 5. Create the App

Replace `src/App.tsx`:

```tsx theme={null}
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { usePrivy, useWallets } from '@privy-io/react-auth'
import { encodeFunctionData } from 'viem'
import { mainnet } from 'viem/chains'
import {
  getVaultsByConfig,
  prepareDepositAuthorization,
  prepareDeposit,
  isPermitAuth,
  isApprovalAuth,
  isAlreadyApprovedAuth,
  toEthSignTypedDataV4,
  YieldType,
} from '@paxoslabs/amplify-sdk'
import { useAmplify } from './hooks/useAmplify'

export default function App() {
  const { isReady, error: sdkError } = useAmplify()
  const { ready, authenticated, login, logout, sendTransaction } = usePrivy()
  const { wallets } = useWallets()
  const wallet = wallets[0]

  const [status, setStatus] = useState<string>('')
  const [amount, setAmount] = useState('100')

  // Discover the vault first — vault.name is used in all deposit calls
  const { data: vaults } = useQuery({
    queryKey: ['vaults', mainnet.id],
    queryFn: () =>
      getVaultsByConfig({ yieldType: YieldType.CORE, chainId: mainnet.id }),
    enabled: isReady && authenticated,
  })

  // Loading states
  if (!ready || !isReady) return <p>Loading...</p>
  if (sdkError) return <p>SDK Error: {sdkError.message}</p>
  if (!authenticated) return <button onClick={login}>Connect with Privy</button>
  if (!wallet) return <p>Connecting wallet...</p>

  const vault = vaults?.[0]
  const owner = wallet.address as `0x${string}`
  const depositAsset = vault?.vault.baseTokenAddress as
    | `0x${string}`
    | undefined

  async function handleDeposit() {
    if (!vault || !depositAsset) return

    const params = {
      vaultName: vault.name,
      depositAsset,
      depositAmount: amount,
      to: owner,
      chainId: mainnet.id,
    }

    try {
      setStatus('Checking authorization...')
      const auth = await prepareDepositAuthorization(params)

      if (isPermitAuth(auth)) {
        setStatus('Please sign permit...')
        const provider = await wallet.getEthereumProvider()
        const signature = (await provider.request({
          method: 'eth_signTypedData_v4',
          params: [owner, toEthSignTypedDataV4(auth.permitData)],
        })) as `0x${string}`

        setStatus('Submitting deposit...')
        const prepared = await prepareDeposit({
          ...params,
          signature,
          deadline: auth.permitData.message.deadline,
        })

        await sendTransaction({
          chainId: prepared.txData.chainId,
          to: prepared.txData.address,
          data: encodeFunctionData({
            abi: prepared.txData.abi,
            functionName: prepared.txData.functionName,
            args: prepared.txData.args,
          }),
        })
      } else if (isApprovalAuth(auth)) {
        setStatus('Approving token...')
        await sendTransaction({
          chainId: mainnet.id,
          to: auth.txData.address,
          data: encodeFunctionData({
            abi: auth.txData.abi,
            functionName: auth.txData.functionName,
            args: auth.txData.args,
          }),
        })

        setStatus('Submitting deposit...')
        const prepared = await prepareDeposit(params)
        await sendTransaction({
          chainId: prepared.txData.chainId,
          to: prepared.txData.address,
          data: encodeFunctionData({
            abi: prepared.txData.abi,
            functionName: prepared.txData.functionName,
            args: prepared.txData.args,
          }),
        })
      } else if (isAlreadyApprovedAuth(auth)) {
        setStatus('Submitting deposit...')
        const prepared = await prepareDeposit(params)
        await sendTransaction({
          chainId: prepared.txData.chainId,
          to: prepared.txData.address,
          data: encodeFunctionData({
            abi: prepared.txData.abi,
            functionName: prepared.txData.functionName,
            args: prepared.txData.args,
          }),
        })
      }

      setStatus('Deposit complete!')
    } catch (err) {
      setStatus(`Error: ${err instanceof Error ? err.message : 'Unknown'}`)
    }
  }

  return (
    <main style={{ padding: '2rem' }}>
      <h1>Amplify Starter</h1>
      <p>Connected: {wallet.address}</p>
      {vault && <p>Vault: {vault.name}</p>}

      <div style={{ marginTop: '1rem' }}>
        <label>
          Amount:
          <input
            type="number"
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            style={{ marginLeft: '0.5rem' }}
          />
        </label>
      </div>

      <div style={{ marginTop: '1rem' }}>
        <button onClick={handleDeposit} disabled={!vault}>
          Deposit
        </button>
        <button onClick={logout} style={{ marginLeft: '1rem' }}>
          Disconnect
        </button>
      </div>

      {status && <p style={{ marginTop: '1rem' }}>{status}</p>}
    </main>
  )
}
```

## 6. Run the App

```bash theme={null}
pnpm dev
```

Open [http://localhost:5173](http://localhost:5173) and test the deposit flow.

## Next Steps

<CardGroup cols={2}>
  <Card title="Deposits Guide" icon="arrow-down-to-bracket" href="/v0.5.2/intro/products/earn/developers/guides/deposits">
    Complete deposit examples with hooks and components.
  </Card>

  <Card title="Withdrawals Guide" icon="arrow-up-from-bracket" href="/v0.5.2/intro/products/earn/developers/guides/withdrawals">
    Add withdrawal functionality to your app.
  </Card>

  <Card title="Smart Wallets" icon="wallet" href="/v0.5.2/intro/products/earn/developers/guides/smart-wallets">
    Enable gas sponsorship and transaction batching.
  </Card>

  <Card title="API Reference" icon="code" href="/v0.5.2/intro/products/earn/developers/api/index">
    Explore all SDK functions and types.
  </Card>
</CardGroup>
