# WebView

The modal's **Transfer from wallet** method sends users to a standalone **deposit send page** instead of embedding a flow. On mobile the modal builds a one-tap deeplink that opens this page inside the user's wallet app, where the in-app browser injects a wallet provider — `window.ethereum` for EVM wallets, or the Solana provider (`window.solana` / the Solana Wallet Standard) when the embedded wallet is on Solana. The page reads the transfer from its URL and submits it through that provider. No backend, no session, and no Openfort SDK run on the page.

Openfort hosts it at **`https://deposit.openfort.io`** — the default. You can self-host the single static file and point the modal at your copy with `uiConfig.funding.depositPageUrl`.

:::info
On **desktop**, "Transfer from wallet" doesn't use this page — it sends directly through the user's connected browser-extension wallet (MetaMask, Rabby, …). The hosted page is the mobile path, reached by deeplink.
:::

## How the modal uses it

For each supported wallet the modal builds an open-dApp universal link that wraps the page URL, so the user lands on it with the transfer prefilled. The list is scoped to the deposit chain's VM: an **EVM** deposit surfaces MetaMask, Coinbase Wallet, Trust, Rainbow, and Rabby; a **Solana** deposit surfaces the Solana-capable wallets — MetaMask, Phantom, and Trust. When no deeplink fits, the modal falls back to a copyable deposit address and QR.

Without `depositPageUrl` set, the default `https://deposit.openfort.io` is used, so one-tap deeplinks work out of the box.

## URL params

The page reads the transfer entirely from the query string:

| param | required | meaning |
| --- | --- | --- |
| `to` | yes | deposit address (the funds receiver) |
| `chainId` | yes | numeric source chain id (e.g. `42161`) |
| `token` | no | ERC-20 contract or SPL-token mint; omit for the chain's native token |
| `decimals` | no | token decimals (default `18`) |
| `symbol` | no | display symbol |
| `chain` | no | display chain name |
| `amount` | no | preset amount in base units; user-editable |

```
https://deposit.openfort.io?to=0xReceiver…&chainId=42161&token=0xaf88…5831&decimals=6&symbol=USDC&chain=Arbitrum&amount=10000000
```

:::info
**Solana deposits** reuse the same page and params: `token` carries the SPL-token mint (omit for native SOL) and `decimals` its precision. The page detects the Solana chain from the URL and submits through the injected Solana provider instead of `window.ethereum`.
:::

## What the page does

:::steps

### Show the transfer

Render the asset, network, recipient, and (when supplied) amount so the user can review before confirming.

### Connect and switch chain

* **EVM** — request accounts from `window.ethereum` (`eth_requestAccounts`) and switch to the source chain (`wallet_switchEthereumChain`).
* **Solana** — connect the injected Solana provider (`window.solana.connect()`, or a wallet from the Solana Wallet Standard). There's no chain switch; the cluster is fixed.

### Send

* **EVM** — check the wallet balance to avoid a reverting transfer, then submit with `eth_sendTransaction` — native value, or an ERC-20 `transfer`.
* **Solana** — build a transfer to the deposit address (`SystemProgram.transfer` for native SOL, or an SPL-token transfer when `token` is set), then sign and send it through the provider (`signAndSendTransaction`).

:::

On success the page shows the transaction hash and the user returns to your app. The page does **not** call back into a host app — track settlement with [Webhooks](/docs/configuration/funding/webhooks) or by polling the session through the [Headless API](/docs/configuration/funding/headless).

## Self-hosting

The page is a single static `index.html` — no build step, no third-party scripts. Host it at a domain root (Vercel, Cloudflare Pages, S3, …) and point the modal at it:

```tsx
<OpenfortProvider
  publishableKey="pk_…"
  uiConfig={{ funding: { depositPageUrl: 'https://deposit.yourapp.com' } }}
>
```

:::warning
This page triggers token transfers from the user's wallet, so the origin must be trusted. Serve it over HTTPS from a domain you control, keep it self-contained (no trackers or analytics), and review changes like any code that moves funds. The user still confirms the destination and amount in their wallet.
:::

## Next steps

* For the underlying session API and server-side polling, see the [Headless API](/docs/configuration/funding/headless).
* Get notified of settlement without polling with [Webhooks](/docs/configuration/funding/webhooks).
