---
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)