# Funding with `useFunding`

For concepts (sessions, payment methods, statuses) see [Funding](/docs/configuration/funding). For the drop-in Deposit flow in the wallet modal, see [UI configuration](/docs/products/embedded-wallet/react/ui/configuration#funding). This page covers the `useFunding` hook for a bespoke UI.

## Custom UI with `useFunding`

For a bespoke flow, drive a session yourself with the `useFunding` hook. It exposes the session state plus `fund` (create a session and set a payment method in one call), `createSession` (create a session for a destination, to set the payment method later), `payLink`, and `reset`.

```tsx
import { useFunding } from '@openfort/react'

function Deposit({ walletAddress }: { walletAddress: string }) {
  const { fund, createSession, session, status, loading, error, isAvailable, payLink, reset } = useFunding()

  async function depositFromPolygon() {
    await fund(
      // target — where funds land (USDC on Base)
      { chain: 'eip155:8453', currency: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', address: walletAddress },
      // source — what the user sends (USDC on Polygon)
      { type: 'evm', source: { chain: 'eip155:137', currency: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', amount: '10000000' } }
    )
  }

  if (session?.paymentMethod) {
    return (
      <div>
        <p>Status: {status}</p>
        <p>Send to: {session.paymentMethod.receiverAddress}</p>
        {/* render session.paymentMethod.addressUri as a QR, or session.paymentMethod.deeplinks */}
      </div>
    )
  }

  return (
    <button type="button" onClick={depositFromPolygon} disabled={loading}>
      {loading ? 'Preparing…' : 'Deposit'}
    </button>
  )
}
```

The hook returns once a deposit address is available and keeps polling until the session reaches a terminal status (`succeeded`, `bounced`, or `expired`). `fund`'s payment method can source from an EVM wallet (`{ type: 'evm', source }`), a Solana wallet (`{ type: 'solana', source }`), or a centralized exchange (`{ type: 'cex', cex, source }`).

### What `useFunding` returns

| Field | Type | Description |
| --- | --- | --- |
| `session` | `FundingSession \| null` | The current or last session, incl. `paymentMethod` once set. |
| `status` | `SessionStatus \| 'idle'` | Lifecycle status; `'idle'` before the first call. |
| `loading` | `boolean` | True while creating the session and minting the address. |
| `error` | `Error \| null` | The last error, if any. |
| `isAvailable` | `boolean` | True when a funding backend is configured (`fundingBaseUrl` set). |
| `fund(target, paymentMethod)` | `=> Promise<FundingSession>` | Create a session and set a payment method in one call. |
| `createSession(target)` | `=> Promise<FundingSession>` | Create a session for a destination, to set the payment method later. |
| `track(session)` | `=> Promise<FundingSession>` | Attach to a session created elsewhere (its `id` + `clientSecret`) and poll it to a terminal status. |
| `payLink(params)` | `=> Promise<string>` | Resolve a prefilled exchange on-ramp URL (Coinbase / Binance). |
| `reset()` | `=> void` | Clear session state and start over. |

:::tip\[Reacting to settlement]
There's no completion callback — drive UI off `status`. It reaches `succeeded` when funds land (or `bounced` / `expired`). For server-side fulfilment, don't rely on the browser: use [webhooks](/docs/configuration/webhooks#funding-events).
:::

:::tip
Same‑chain deposits (source chain == destination chain) skip bridging entirely — the hook returns the wallet address directly, so a plain transfer works with no fees.
:::

## Next steps

* Drive funding from a backend or agent with the [JavaScript SDK](/docs/products/embedded-wallet/javascript/signer/funding) or the [REST reference](/docs/configuration/funding/headless).
* Render the mobile deposit page with the [hosted deposit page](/docs/configuration/funding#hosted-deposit-page).
* React to settlement with [Webhooks](/docs/configuration/webhooks#funding-events).
