# Embedded wallet state

The embedded wallet moves through a small set of states as the SDK boots, the user authenticates, and the signer is configured. Wait until the wallet reaches `.ready` before signing messages or sending transactions — calling those APIs earlier throws.

On iOS the state is **event-driven**: `OFSDK.shared.embeddedStatePublisher` is a [Combine](https://developer.apple.com/documentation/combine) publisher that emits a new value on every transition, so your UI can react instead of polling.

:::info
For a chain-agnostic overview of every state and how a wallet flows between them, see [Wallet lifecycle](/docs/products/embedded-wallet/wallet-lifecycle).
:::

## States

`OFEmbeddedState` is an `Int`-backed enum:

```swift
public enum OFEmbeddedState: Int, OFCodableSendable {
    case none = 0                          // SDK loaded, bridge not yet ready
    case unauthenticated = 1               // No authenticated user
    case embeddedSignerNotConfigured = 2   // Authenticated, wallet not configured
    case creatingAccount = 3               // configure()/recover() in progress
    case ready = 4                         // Wallet ready to sign and send
}
```

| State                          | Value | What it means                                                                                                         |
| ------------------------------ | ----- | --------------------------------------------------------------------------------------------------------------------- |
| `.none`                        | 0     | The SDK is loaded but the WebView bridge hasn't finished loading.                                                      |
| `.unauthenticated`             | 1     | The bridge is ready but no user is signed in. Run [authentication](/docs/products/embedded-wallet/swift/auth/email).   |
| `.embeddedSignerNotConfigured` | 2     | The user is authenticated but the wallet signer isn't set up. Call [`configure`](/docs/products/embedded-wallet/swift/wallet/recovery). |
| `.creatingAccount`             | 3     | `configure()` or `recover()` is provisioning the account.                                                             |
| `.ready`                       | 4     | The wallet can sign messages and send transactions.                                                                   |

## Observe state with Combine

Subscribe to `embeddedStatePublisher` and keep the returned `AnyCancellable` alive — store it on your view model or controller, otherwise the subscription is torn down immediately:

```swift
import Combine
import OpenfortSwift

final class WalletViewModel: ObservableObject {
    @Published var isReady = false
    private var cancellables = Set<AnyCancellable>()

    func startObserving() {
        OFSDK.shared.embeddedStatePublisher
            .receive(on: DispatchQueue.main)
            .sink { [weak self] state in
                switch state {
                case .ready:
                    self?.isReady = true
                case .embeddedSignerNotConfigured:
                    // Prompt the user to set up / recover their wallet.
                    self?.isReady = false
                case .unauthenticated:
                    // Send the user to your login screen.
                    self?.isReady = false
                case .creatingAccount, .none, nil:
                    self?.isReady = false
                }
            }
            .store(in: &cancellables)
    }
}
```

:::tip
The publisher's element type is `OFEmbeddedState?`. A `nil` value is the state before the bridge has reported anything — treat it the same as `.none`.
:::

## Gate UI on readiness

A common pattern is to enable wallet actions only once the wallet is `.ready`:

```swift
struct WalletButton: View {
    @StateObject private var model = WalletViewModel()

    var body: some View {
        Button("Send transaction") { /* ... */ }
            .disabled(!model.isReady)
            .onAppear { model.startObserving() }
    }
}
```

## One-off reads

If you only need the current value once (not a subscription), call `getEmbeddedState()`. It returns the raw `Int`, which you can map back to the enum:

```swift
let raw = try await OFSDK.shared.getEmbeddedState() // OFGetEmbeddedStateResponse? (Int?)
let state = raw.flatMap(OFEmbeddedState.init(rawValue:))
print("Current state: \(String(describing: state))")
```

:::note
Prefer the publisher for anything that drives UI — `getEmbeddedState()` is a snapshot and won't notify you when the state changes.
:::

## Next steps

* [Set up a wallet](/docs/products/embedded-wallet/swift/wallet/recovery) — configure recovery and reach `.ready`.
* [Send a transaction](/docs/products/embedded-wallet/swift/wallet/send) — once the wallet is ready.
