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

# Asset migrations

> Fund a deposit from balances the user already holds in another app.

The modal can pull balances a user already holds in a supported third-party app
and fund the deposit from there — no manual transfer first. Each provider is
**off by default**; opt in per provider via `assetMigrations`.

```tsx theme={null}
<DepositModal
  // ...required props
  assetMigrations={{ polymarket: true }}
/>
```

When at least one provider is enabled, a **Migrate assets** row appears on the
deposit entry screen and opens a picker over that provider's positions. The user
picks one, and the modal pulls the funds into their smart account and bridges
them to `targetChain` / `targetToken` like any other source.

| Key           | Status      |
| ------------- | ----------- |
| `polymarket`  | Live        |
| `aave`        | Live        |
| `hyperliquid` | Coming soon |
| `morpho`      | Coming soon |

Only the providers you enable are listed. Enabling one that isn't live yet shows it
as a disabled "Coming soon" row rather than hiding it.

## Polymarket

Set `assetMigrations={{ polymarket: true }}`. The modal looks up the connected
EOA's Polymarket proxy wallet on Polygon and surfaces any pUSD or USDC.e
balance. pUSD is unwrapped to USDC.e on the way out; USDC.e is what lands in the
smart account and what the orchestrator bridges from.

Polymarket exposes two wallet types and the modal handles both: some transfer
on-chain directly from the user's signed transaction, while others are relayed
through your [backend proxy](/deposits/widget/backend), which must forward
`POST /polymarket/withdraw`.

### Open directly into Polymarket

To skip the deposit-method home screen and land the user straight on the
Polymarket transfer, pass `initialAssetMigration="polymarket"` alongside
`assetMigrations={{ polymarket: true }}`. While balances load the modal shows a
skeleton; if there's no account, no balance, or no connected wallet it falls
back to the home screen.

```tsx theme={null}
<DepositModal
  // ...required props
  assetMigrations={{ polymarket: true }}
  initialAssetMigration="polymarket"
/>
```

### Headless account lookup

If you build your own UI and only need the data, the
`@rhinestone/deposit-modal/polymarket` subpath exports a headless
`getPolymarketAccount` — no React, modal, or wallet-connect code pulled into
your bundle. Give it the connected EOA and it returns the user's Polymarket
proxy wallet address and on-chain pUSD / USDC.e balances on Polygon.

```ts theme={null}
import { getPolymarketAccount } from "@rhinestone/deposit-modal/polymarket";

const account = await getPolymarketAccount({ eoa: connectedAddress });

if (account) {
  account.proxyWallet; // the user's Polymarket address on Polygon
  account.pusd.formatted; // pUSD balance, e.g. "12.5"
  account.usdce.formatted; // USDC.e balance
  account.totalUsd; // combined USD value
}
```

Returns `null` only when the EOA has no Polymarket account. A transient failure
(network, 5xx, abort) rejects instead, so an outage is never mistaken for "no
account". Pass `rpcUrl` to override the default public Polygon RPC, or a
`signal` (`AbortSignal`) to cancel the lookup.

## Aave

Set `assetMigrations={{ aave: true }}`. The modal lists the connected EOA's Aave
v3 supply positions across every chain you can take deposits from, and picking
one produces a single `Pool.withdraw` that sends the proceeds **straight to the
user's deposit address** — the funds never pass through their wallet, and the
normal deposit pipeline ingests them like any other incoming transfer.

Requires your [backend proxy](/deposits/widget/backend) to forward
`GET /positions/:address` and `POST /positions/:address/unwind`. A read-scoped
API key is enough for both.

Three behaviours worth knowing, because they are deliberate:

* **The amount offered is what can actually be withdrawn right now**, not the
  full supplied balance. Aave caps a withdrawal against the user's health factor,
  E-Mode thresholds, paused reserves and pool liquidity, so a position worth $100
  may only permit $40 out. The modal offers the \$40 — the user is never shown a
  figure the pool would reject.
* **The user's wallet signs; Rhinestone never holds a key on this path.** The
  aTokens sit in the user's own EOA, so only they can authorise the withdraw. The
  transaction we build is unsigned and inert until they sign it.
* **A position whose proceeds your config would refuse is not offered at all** —
  under your `minDepositUsd`, or outside your source-token allowlist. Offering it
  and failing afterwards would leave the user having irreversibly exited a
  position for funds we then reject.

Positions are keyed by **market**, not chain: Ethereum alone hosts four Aave v3
markets with distinct pools and risk parameters, so the same token supplied to two
of them appears as two rows, each naming its market.

If a market can't be read, the positions that did load are still listed and the
screen says the list may be incomplete — an outage never silently reports a
smaller balance than the user holds.

### Open directly into Aave

As with Polymarket, `initialAssetMigration="aave"` skips the home screen:

```tsx theme={null}
<DepositModal
  // ...required props
  assetMigrations={{ aave: true }}
  initialAssetMigration="aave"
/>
```
