---
# System prepended metadata

title: SDK Embedded Wallet Deposit Mode

---

---
title: Embedded Wallet Deposit Mode
description: Route deposits from a user's external wallet to their in-app embedded wallet.
---

# Embedded Wallet Deposit Mode

Users fund an in-app embedded wallet or smart account. Funds are routed from the user's external wallet (MetaMask, Coinbase Wallet, etc.) to their embedded wallet hosted by your application.

## Overview

Embedded Wallet Deposit Mode solves a common onboarding challenge: users have funds in their external wallet, but your app uses embedded wallets (via Privy, Dynamic, Turnkey, or similar providers). This mode lets users deposit directly into their in-app wallet without manual bridging or transfers.

**When to use this mode:**
- Onboarding users with embedded wallet providers
- Funding in-app balances or smart accounts
- Top-ups for DEXs, social, gaming, or consumer applications
- Any flow where users pay from an external wallet but funds should land in an app-controlled wallet

## How It Works

```
┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│   User's EOA    │ ──▶  │    Trustware    │ ──▶  │ User's Embedded │
│(External Wallet)│      │  Routing Engine │      │     Wallet      │
└─────────────────┘      └─────────────────┘      └─────────────────┘
     USDT on                                         USDC on Base
     Arbitrum                                     (Privy/Dynamic/etc.)
```

The key difference from Swap/Bridge Mode: the destination is the user's **embedded wallet**, not their connected external wallet. This requires setting the destination address at runtime using `Trustware.setDestinationAddress()`.

---

## Core Concept: `setDestinationAddress()`

Since embedded wallet addresses aren't known until the user authenticates with your app, you can't hardcode the destination in your config. Instead, you set it at runtime:

```typescript
import { Trustware } from "@trustware/sdk";

// Call this once the embedded wallet address is available
Trustware.setDestinationAddress("0x1234...abcd");
```

This overrides any `toAddress` in your config and routes all subsequent transactions to the specified address.

:::warning
`setDestinationAddress()` must be called before the user initiates a deposit. If it's never called and `toAddress` is omitted from config, funds will route to the connected external wallet instead.
:::

---

## Basic Setup

### Step 1: Configure the Provider

Set `autoDetectProvider: true` so the widget can detect the user's external wallet for payment. Omit `toAddress` - you'll set it at runtime.

```typescript
import type { TrustwareConfigOptions } from "@trustware/sdk";

export const trustwareConfig: TrustwareConfigOptions = {
  apiKey: "your-api-key",
  routes: {
    toChain: "8453",  // Base
    toToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
    defaultSlippage: 1,
    // toAddress intentionally omitted, set it at runtime
  },
  autoDetectProvider: true, // Detect user's external wallet
  messages: {
    title: "Fund Your Account",
    description: "Deposit from any wallet to your in-app balance.",
  },
};
```

### Step 2: Set Destination When Embedded Wallet is Ready

You need to call `setDestinationAddress()` once your embedded wallet provider returns the user's address. There are two approaches:

---

## Approach A: Listener Component

Create a dedicated component that watches for the embedded wallet address and updates Trustware when it's available.

```typescript
// components/DestinationBridge.tsx
"use client";

import { useEffect } from "react";
import { Trustware } from "@trustware/sdk";

interface DestinationBridgeProps {
  address: string | undefined;
}

export function DestinationBridge({ address }: DestinationBridgeProps) {
  useEffect(() => {
    if (!address) return;
    Trustware.setDestinationAddress(address);
  }, [address]);

  return null; // This component renders nothing
}
```

Then use it in your provider tree:

```typescript
// app/providers.tsx
"use client";

import { TrustwareProvider, TrustwareWidget } from "@trustware/sdk";
import { usePrivy } from "@privy-io/react-auth";
import { DestinationBridge } from "@/components/DestinationBridge";
import { trustwareConfig } from "@/config/trustware";

export function DepositFlow() {
  const { user } = usePrivy();
  const embeddedWalletAddress = user?.wallet?.address;

  return (
    <TrustwareProvider config={trustwareConfig}>
      <DestinationBridge address={embeddedWalletAddress} />
      <TrustwareWidget />
    </TrustwareProvider>
  );
}
```

**Why this approach?**
- Clean separation of concerns
- Reusable across different pages
- Easy to test in isolation

---

## Approach B: Inline Effect

If you prefer fewer components, you can inline the effect directly in your deposit page:

```typescript
// app/deposit/page.tsx
"use client";

import { useEffect } from "react";
import { TrustwareProvider, TrustwareWidget, Trustware } from "@trustware/sdk";
import { usePrivy } from "@privy-io/react-auth";
import { trustwareConfig } from "@/config/trustware";

export default function DepositPage() {
  const { user } = usePrivy();
  const embeddedWalletAddress = user?.wallet?.address;

  useEffect(() => {
    if (!embeddedWalletAddress) return;
    Trustware.setDestinationAddress(embeddedWalletAddress);
  }, [embeddedWalletAddress]);

  return (
    <TrustwareProvider config={trustwareConfig}>
      <TrustwareWidget />
    </TrustwareProvider>
  );
}
```

**Why this approach?**
- Simpler for single-page implementations
- All logic in one place
- Fewer files to maintain

---

## Complete Example with Privy

Here's a full implementation showing the complete provider stack:

```typescript
// app/providers.tsx
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createConfig, http, WagmiProvider } from "wagmi";
import { base } from "wagmi/chains";
import { PrivyProvider } from "@privy-io/react-auth";
import { TrustwareProvider } from "@trustware/sdk";
import type { TrustwareConfigOptions } from "@trustware/sdk";
import { DestinationBridge } from "@/components/DestinationBridge";

const queryClient = new QueryClient();

const wagmiConfig = createConfig({
  chains: [base],
  transports: { [base.id]: http() },
});

const trustwareConfig: TrustwareConfigOptions = {
  apiKey: process.env.NEXT_PUBLIC_TRUSTWARE_API_KEY!,
  routes: {
    toChain: String(base.id),
    toToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
    defaultSlippage: 1,
  },
  autoDetectProvider: true,
  theme: {
    primaryColor: "#5555FF",
    backgroundColor: "#FFFFFF",
    borderColor: "#E5E5E5",
    secondaryColor: "#F5F5F5",
    textColor: "#333333",
    radius: 12,
  },
  messages: {
    title: "Fund Your Account",
    description: "Deposit into your smart account to get started!",
  },
};

export default function Providers({ children }: { children: React.ReactNode }) {
  return (
    <PrivyProvider
      appId={process.env.NEXT_PUBLIC_PRIVY_APP_ID!}
      config={{
        embeddedWallets: {
          ethereum: { createOnLogin: "users-without-wallets" },
        },
      }}
    >
      <WagmiProvider config={wagmiConfig}>
        <QueryClientProvider client={queryClient}>
          <TrustwareProvider config={trustwareConfig}>
            {children}
          </TrustwareProvider>
        </QueryClientProvider>
      </WagmiProvider>
    </PrivyProvider>
  );
}
```

```typescript
// app/deposit/page.tsx
"use client";

import { TrustwareWidget, Trustware } from "@trustware/sdk";
import { usePrivy } from "@privy-io/react-auth";
import { useEffect } from "react";

export default function DepositPage() {
  const { ready, authenticated, user } = usePrivy();
  const embeddedWalletAddress = user?.wallet?.address;

  useEffect(() => {
    if (!embeddedWalletAddress) return;
    Trustware.setDestinationAddress(embeddedWalletAddress);
  }, [embeddedWalletAddress]);

  if (!ready) {
    return <div>Loading...</div>;
  }

  if (!authenticated) {
    return <div>Please sign in to deposit.</div>;
  }

  if (!embeddedWalletAddress) {
    return <div>Creating your wallet...</div>;
  }

  return (
    <div>
      <p>Depositing to: {embeddedWalletAddress}</p>
      <TrustwareWidget />
    </div>
  );
}
```

---

## Using Other Embedded Wallet Providers

The pattern is the same regardless of provider: get the embedded wallet address and pass it to `setDestinationAddress()`.

### Dynamic

```typescript
import { useDynamicContext } from "@dynamic-labs/sdk-react-core";
import { Trustware } from "@trustware/sdk";
import { useEffect } from "react";

export function DynamicDepositFlow() {
  const { primaryWallet } = useDynamicContext();
  const embeddedWalletAddress = primaryWallet?.address;

  useEffect(() => {
    if (!embeddedWalletAddress) return;
    Trustware.setDestinationAddress(embeddedWalletAddress);
  }, [embeddedWalletAddress]);

  return <TrustwareWidget />;
}
```

### Turnkey

```typescript
import { useTurnkey } from "@turnkey/sdk-react";
import { Trustware } from "@trustware/sdk";
import { useEffect } from "react";

export function TurnkeyDepositFlow() {
  const { wallets } = useTurnkey();
  const embeddedWalletAddress = wallets?.[0]?.address;

  useEffect(() => {
    if (!embeddedWalletAddress) return;
    Trustware.setDestinationAddress(embeddedWalletAddress);
  }, [embeddedWalletAddress]);

  return <TrustwareWidget />;
}
```

---

## Edge Cases

### Embedded Wallet Not Yet Created

If the user hasn't completed onboarding and doesn't have an embedded wallet yet, `setDestinationAddress()` won't be called. Handle this by showing a loading state or prompting the user to complete signup:

```typescript
if (!embeddedWalletAddress) {
  return (
    <div>
      <p>Complete signup to get your wallet.</p>
      <SignupButton />
    </div>
  );
}
```

### `setDestinationAddress()` Never Called

If `setDestinationAddress()` is never called and `toAddress` is omitted from config, the SDK falls back to the connected external wallet as the destination. This means:

- User pays from EOA
- User receives funds in EOA (not the embedded wallet)

:::danger
This fallback behavior can be confusing for users who expect funds in their in-app balance. Always ensure `setDestinationAddress()` is called before rendering the widget.
:::

### Address Changes Mid-Session

If the embedded wallet address could change (e.g., user switches accounts), the `useEffect` pattern handles this automatically; it re-runs whenever the address changes and updates the destination.

---

## Configuration Reference

| Parameter | Value for Embedded Wallet Mode |
|-----------|-------------------------------|
| `toAddress` | **Omit** from config - set via `setDestinationAddress()` |
| `autoDetectProvider` | `true` - detect user's external wallet for payment |
| `setDestinationAddress()` | **Required** - call when embedded wallet address is available |

### Full Config Options

```typescript
const config: TrustwareConfigOptions = {
  apiKey: "your-api-key",
  routes: {
    toChain: "8453",
    toToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    defaultSlippage: 1,
    // toAddress: DO NOT SET - use setDestinationAddress() instead
  },
  autoDetectProvider: true,
  theme: { /* ... */ },
  messages: {
    title: "Fund Your Account",
    description: "Deposit from any wallet.",
  },
};
```

---

## Summary

| Step | Action |
|------|--------|
| 1 | Configure `TrustwareProvider` with `autoDetectProvider: true` |
| 2 | Omit `toAddress` from config |
| 3 | Get embedded wallet address from your provider (Privy, Dynamic, Turnkey) |
| 4 | Call `Trustware.setDestinationAddress(address)` when address is available |
| 5 | Render `TrustwareWidget` |

→ [Back to configuration modes / SDK OVERVIEW](https://hackmd.io/@trustware/B1zaIVkSbe)



