# Funding with `OFFunding`

For concepts (sessions, payment methods, statuses) see [Funding](/docs/configuration/funding). This page covers `OFFunding` — the SwiftUI counterpart of `@openfort/react`'s `useFunding` hook — for a bespoke Deposit screen.

`OFFunding` is an `ObservableObject`: hold one per deposit flow with `@StateObject`, call `fund` / `createSession` / `track` / `payLink`, and observe `session` / `status` / `loading` / `error` to drive the UI. Funding authenticates with the project publishable key, so it works for guest and authenticated users alike.

## Custom deposit flow

`fund` creates a session, sets a payment method, and polls until the session reaches a terminal status — publishing each update along the way.

```swift
import SwiftUI
import OpenfortSwift

struct DepositView: View {
    @StateObject private var funding = OFFunding()
    let walletAddress: String

    var body: some View {
        if let method = funding.session?.paymentMethod {
            VStack(alignment: .leading) {
                Text("Status: \(funding.status?.rawValue ?? "idle")")
                Text("Send to: \(method.receiverAddress)")
                // render method.addressUri as a QR, or method.deeplinks as buttons
            }
        } else {
            Button("Deposit") { Task { try? await deposit() } }
                .disabled(funding.loading)
        }
    }

    func deposit() async throws {
        try await funding.fund(
            // target — where funds land (USDC on Base)
            OFFundingTarget(
                chain: "eip155:8453",
                currency: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                address: walletAddress
            ),
            // source — what the user sends (USDC on Polygon)
            .evm(source: OFFundingSource(
                chain: "eip155:137",
                currency: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
                amount: "10000000"
            ))
        )
    }
}
```

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

### What `OFFunding` exposes

| Member | Type | Description |
| --- | --- | --- |
| `session` | `OFFundingSession?` | The current or last session, incl. `paymentMethod` once set. |
| `status` | `OFFundingSessionStatus?` | Lifecycle status; `nil` is the idle state (no session yet). |
| `loading` | `Bool` | `true` while creating the session and minting the address. |
| `error` | `Error?` | The last error, cleared at the start of the next call. |
| `isAvailable` | `Bool` | `true` once the SDK bridge is ready. |
| `fund(_:_:)` | `async throws -> OFFundingSession` | Create a session and set a payment method in one call, then poll to terminal. |
| `createSession(_:)` | `async throws -> OFFundingSession` | Create a session for a destination, to set the payment method later. |
| `track(id:clientSecret:)` | `async throws -> OFFundingSession` | Attach to a session created elsewhere and poll it to a terminal status. |
| `payLink(_:)` | `async throws -> String` | Resolve a prefilled Coinbase on-ramp URL for the session. |
| `reset()` | `Void` | Clear session state and stop any in-flight poll loop. |

Once `session.paymentMethod` is set, it carries everything a custom UI needs: `receiverAddress`, `addressUri` (a BIP-21 / EIP-681 / Solana Pay URI for a QR), `deeplinks` (prefilled wallet links), `fees`, and — for a `cex` route — `cex` withdrawal guidance (network, minimum, memo flag).

## Centralized exchange (pay-link)

For an exchange route, create a session, mint a Coinbase pay-link, open it, then watch the bound session settle:

```swift
let session = try await funding.createSession(target)
let url = try await funding.payLink(OFPayLinkParams(sessionId: session.id, amount: "25"))
// open `url` (e.g. in SFSafariViewController), then:
try await funding.track(id: session.id, clientSecret: session.clientSecret)
```

Or commit to a guided exchange withdrawal directly with `.cex` — `session.paymentMethod?.cex` then carries the withdrawal network, minimum, and memo flag:

```swift
try await funding.fund(
    target,
    .cex(cex: "binance", source: OFFundingSource(
        chain: "eip155:137", currency: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", amount: "5000000"
    ))
)
```

## Headless (without SwiftUI)

The same namespace is available directly on `OFSDK.shared` (each with `async` and completion-handler variants) for non-SwiftUI or backend-style flows:

```swift
let session = try await OFSDK.shared.fundingCreateSession(target: target)
let funded = try await OFSDK.shared.fundingSetPaymentMethod(
    sessionId: session.id,
    paymentMethod: .evm(source: source)
)
let latest = try await OFSDK.shared.fundingGetSession(sessionId: session.id)
let chains = try await OFSDK.shared.fundingChains() // source chains + currencies for a picker
```

:::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 client: use [webhooks](/docs/configuration/webhooks#funding-events).
:::

:::tip
Same-chain deposits (source chain == destination chain) skip bridging entirely — a plain transfer to the wallet address with no fees.
:::

## Related

* [Balances, history & receipts](/docs/products/embedded-wallet/swift/wallet/token-helpers) — refresh the balance after a deposit settles.
* [Send a transaction](/docs/products/embedded-wallet/swift/wallet/send)
* Drive funding from a backend or agent with the [REST reference](/docs/configuration/funding/headless).
* React to settlement with [Webhooks](/docs/configuration/webhooks#funding-events).
