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

# Examples

> End-to-end SDK examples for vault discovery, deposits, withdrawals, positions, and error handling.

## Initialize

```typescript theme={null}
import { GauntletClient } from '@gauntlet-xyz/sdk'
import { createPublicClient, createWalletClient, http, privateKeyToAccount } from 'viem'
import { base } from 'viem/chains'

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)

const publicClient = createPublicClient({
  chain: base,
  transport: http(process.env.RPC_URL_BASE!),
})

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(process.env.RPC_URL_BASE!),
})

const client = new GauntletClient({
  evmClients: { [base.id]: publicClient },
  wallet: walletClient,
  builderCode: 'your-builder-code', // issued by Gauntlet — request from the partnerships team
})
```

## Embedded Wallet (Privy)

The SDK reads only `wallet.account.address` — it never signs. Any viem-compatible wallet works, including embedded wallets from Privy, Dynamic, or similar providers.

```typescript theme={null}
import { GauntletClient } from '@gauntlet-xyz/sdk'
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { base } from 'viem/chains'
import { useWallets } from '@privy-io/react-auth'

const { wallets } = useWallets()
const embeddedWallet = wallets.find(w => w.walletClientType === 'privy')
const provider = await embeddedWallet.getEthereumProvider()

const publicClient = createPublicClient({ chain: base, transport: http(process.env.RPC_URL_BASE!) })

const walletClient = createWalletClient({
  account: embeddedWallet.address as `0x${string}`,
  chain: base,
  transport: custom(provider),
})

const client = new GauntletClient({
  evmClients: { [base.id]: publicClient },
  wallet: walletClient,
  builderCode: 'your-builder-code', // issued by Gauntlet — request from the partnerships team
})
```

## Deposit

```typescript theme={null}
import { getDepositTx, VaultId } from '@gauntlet-xyz/sdk/evm'

const steps = await getDepositTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  amount: 1_000_000n, // 1 USDC (6 decimals)
  receiver: '0xReceiver', // optional, defaults to wallet account
})
// returns:
// [
//   { payload: { type: 'approve', to: '0x...', data: '0x...', account: '0x...' }, tx: { ... } },
//   { payload: { type: 'requestDeposit', to: '0x...', data: '0x...', account: '0x...' }, tx: { ... } }
// ]

// steps must be executed in order — approve before requestDeposit
for (const step of steps) {
  // Estimate gas — simulates exact calldata before broadcast, catches reverts before spending gas
  const gas = await publicClient.estimateGas({
    to: step.payload.to,
    data: step.payload.data,
    account: step.payload.account,
  })

  const hash = await walletClient.sendTransaction({ ...step.payload, gas })

  // Wait for confirmation before the next step — deposit reverts if preceding approve is not mined
  const receipt = await publicClient.waitForTransactionReceipt({ hash, confirmations: 2 })

  if (receipt.status !== 'success') {
    throw new Error(`Transaction reverted: ${step.payload.type}`)
  }
}
```

## Withdraw

```typescript theme={null}
import { getWithdrawTx, VaultId } from '@gauntlet-xyz/sdk/evm'

// Withdraw entire position
const steps = await getWithdrawTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  entireAmount: true,
  receiver: '0xReceiver', // optional
})
// returns:
// [
//   { payload: { type: 'requestRedeem', to: '0x...', data: '0x...', account: '0x...' }, tx: { ... } }
// ]

for (const step of steps) {
  const gas = await publicClient.estimateGas({
    to: step.payload.to,
    data: step.payload.data,
    account: step.payload.account,
  })

  const hash = await walletClient.sendTransaction({ ...step.payload, gas })

  const receipt = await publicClient.waitForTransactionReceipt({ hash, confirmations: 2 })

  if (receipt.status !== 'success') {
    throw new Error(`Transaction reverted: ${step.payload.type}`)
  }
}
```

```typescript theme={null}
import { getWithdrawTx, VaultId } from '@gauntlet-xyz/sdk/evm'

// By shares
const steps = await getWithdrawTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  shares: 500_000000000000000000n,
})

// By asset amount
const steps = await getWithdrawTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  amount: 500_000n,
})
```

## Check User Current Balance

`getUserCurrentBalance` returns a unified view of all three balance states for a vault position. Call it on load and after any deposit or withdrawal transaction to keep your UI in sync.

```typescript theme={null}
import { getUserCurrentBalance } from '@gauntlet-xyz/sdk'
import { VaultId } from '@gauntlet-xyz/sdk/evm'

const balances = await getUserCurrentBalance(client, {
  vaultId: VaultId.AeraUsdAlpha,
  address: '0xUser',
})

console.log(balances)
// [
//   {
//     chain: 'base',
//     token: '0xUSDCADDRESS123',
//     decimals: 6
//     pendingDeposit: 0n,
//     balance: 1_000_000n,
//     pendingWithdraw: 0n,
//   },
// ]
```

### After an async deposit

When a user deposits with `depositMode: 'async'`, the amount appears in `pendingDeposit` while the vault solver queues it. During this time the funds are locked in the provisioner contract and are not yet earning yield. They move to `balance` once the solver settles the request — usually within 2 hours.

```typescript theme={null}
import { getDepositTx, VaultId } from '@gauntlet-xyz/sdk/evm'
import { getUserCurrentBalance } from '@gauntlet-xyz/sdk'

// Submit the async deposit
const steps = await getDepositTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  amount: 500_000n,
  depositMode: 'async',
})

for (const step of steps) {
  const gas = await publicClient.estimateGas({
    to: step.payload.to,
    data: step.payload.data,
    account: step.payload.account,
  })
  const hash = await walletClient.sendTransaction({ ...step.payload, gas })
  const receipt = await publicClient.waitForTransactionReceipt({ hash, confirmations: 2 })
  if (receipt.status !== 'success') {
    throw new Error(`Transaction reverted: ${step.payload.type}`)
  }
}

// funds are locked in pendingDeposit — not yet earning — until solver settles (~2 hours)
const balances = await getUserCurrentBalance(client, {
  vaultId: VaultId.AeraUsdAlpha,
  address: '0xUser',
})
```

### After an async withdrawal

When a user withdraws with `depositMode: 'async'`, the amount moves from `balance` to `pendingWithdraw`. During this time the vault shares have been redeemed and the assets are no longer earning yield, but they have not yet been transferred. Once the solver settles the request (usually within 2 hours), the assets become claimable as ERC-20 tokens in the receiver wallet.

```typescript theme={null}
import { getWithdrawTx, VaultId } from '@gauntlet-xyz/sdk/evm'
import { getUserCurrentBalance } from '@gauntlet-xyz/sdk'

// Submit the async withdraw
const steps = await getWithdrawTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  entireAmount: true,
  depositMode: 'async',
})

for (const step of steps) {
  const gas = await publicClient.estimateGas({
    to: step.payload.to,
    data: step.payload.data,
    account: step.payload.account,
  })
  const hash = await walletClient.sendTransaction({ ...step.payload, gas })
  const receipt = await publicClient.waitForTransactionReceipt({ hash, confirmations: 2 })
  if (receipt.status !== 'success') {
    throw new Error(`Transaction reverted: ${step.payload.type}`)
  }
}

// assets are in pendingWithdraw — no longer earning — until solver settles (~2 hours)
const balances = await getUserCurrentBalance(client, {
  vaultId: VaultId.AeraUsdAlpha,
  address: '0xUser',
})
```

### Sync deposit and withdrawal

Sync transactions skip the queue. The balance moves immediately — no `pendingDeposit` or `pendingWithdraw`. Morpho vaults operate in sync mode; Aera vaults operate in async mode.

```typescript theme={null}
import { getDepositTx, getWithdrawTx, VaultId } from '@gauntlet-xyz/sdk/evm'

// Sync deposit with a Morpho vault: balance goes straight to `balance`
const depositSteps = await getDepositTx(client, {
  vaultId: VaultId.BaseUsdcPrime, // Morpho vault — sync mode
  amount: 500_000n,
})

for (const step of depositSteps) {
  const gas = await publicClient.estimateGas({
    to: step.payload.to,
    data: step.payload.data,
    account: step.payload.account,
  })
  const hash = await walletClient.sendTransaction({ ...step.payload, gas })
  const receipt = await publicClient.waitForTransactionReceipt({ hash, confirmations: 2 })
  if (receipt.status !== 'success') {
    throw new Error(`Transaction reverted: ${step.payload.type}`)
  }
}

// Sync withdraw: balance drops from `balance` immediately;
// tokens appear in the receiver wallet right away
const withdrawSteps = await getWithdrawTx(client, {
  vaultId: VaultId.BaseUsdcPrime, // Morpho vault — sync mode
  entireAmount: true,
})

for (const step of withdrawSteps) {
  const gas = await publicClient.estimateGas({
    to: step.payload.to,
    data: step.payload.data,
    account: step.payload.account,
  })
  const hash = await walletClient.sendTransaction({ ...step.payload, gas })
  const receipt = await publicClient.waitForTransactionReceipt({ hash, confirmations: 2 })
  if (receipt.status !== 'success') {
    throw new Error(`Transaction reverted: ${step.payload.type}`)
  }
}
```

## Wagmi / writeContract

When integrating with wagmi, use `step.tx` fields with `writeContractAsync`. Pass `step.tx.attribution` as `dataSuffix` — wagmi appends it to the calldata before sending. **Omitting `dataSuffix` silently drops attribution: the transaction succeeds but volume is not tracked.**

```typescript theme={null}
import { getDepositTx, VaultId } from '@gauntlet-xyz/sdk/evm'
import { useWriteContract } from 'wagmi'

const { writeContractAsync } = useWriteContract()

const steps = await getDepositTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  amount: 1_000_000n,
})

for (const step of steps) {
  await writeContractAsync({
    address: step.tx.address,
    abi: step.tx.abi,
    functionName: step.tx.functionName,
    args: step.tx.args,
    account: step.tx.account,
    dataSuffix: step.tx.attribution, // required — omitting silently drops attribution
  })
}
```

## Slippage

Both `getDepositTx` and `getWithdrawTx` accept a `slippageBps` parameter (integer basis points, e.g. `50` = 0.5%). Defaults to `100` (1%).

```typescript theme={null}
import { getDepositTx, VaultId } from '@gauntlet-xyz/sdk/evm'

const steps = await getDepositTx(client, {
  vaultId: VaultId.AeraUsdAlpha,
  amount: 1_000_000n,
  slippageBps: 50, // 0.5% slippage tolerance
})
```

## Error Handling

```typescript theme={null}
import { getDepositTx, VaultId } from '@gauntlet-xyz/sdk/evm'
import {
  VaultNotFoundError,
  AccountRequiredError,
  RpcNotConfiguredError,
  UnsupportedDepositModeError,
  InvalidSlippageBPSError,
  UnimplementedFeatureError,
  UnitConversionError,
} from '@gauntlet-xyz/sdk'

try {
  await getDepositTx(client, {
    vaultId: VaultId.AeraUsdAlpha,
    amount: 1_000_000n,
  })
} catch (e) {
  if (e instanceof VaultNotFoundError)          { /* e.vaultId, e.chainId */ }
  if (e instanceof AccountRequiredError)        { /* add wallet to GauntletClient config */ }
  if (e instanceof RpcNotConfiguredError)       { /* e.chainId — add RPC URL for this chain */ }
  if (e instanceof UnsupportedDepositModeError) { /* e.vaultId, e.requested, e.available */ }
  if (e instanceof InvalidSlippageBPSError)     { /* e.slippage — must be integer 0–10000 */ }
  if (e instanceof UnimplementedFeatureError)   { /* e.feature */ }
  if (e instanceof UnitConversionError)         { /* e.vaultAddress */ }
}
```

## Go Deeper

<CardGroup cols={2}>
  <Card title="SDK Reference" icon="code" href="/sdk/reference">
    Full constructor, methods, result shapes, and errors.
  </Card>

  <Card title="Deposit Your First Dollar" icon="arrow-right-arrow-left" href="/guides/developer/earn/deposits-and-withdrawals">
    The full integration guide with confirmation and fallback guidance.
  </Card>
</CardGroup>
