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

# Feature Flags

> Feature flags allow you to enable or disable specific features in the Portal SDK. This provides flexibility in customizing the behavior of the SDK for your application.

### Overview

The `FeatureFlags` data class is used to configure feature flags when initializing the Portal SDK. Each flag corresponds to a specific feature or behavior that can be toggled on or off.

#### Example Usage:

```kotlin theme={null}
import io.portalhq.android.Portal
import io.portalhq.android.mpc.data.FeatureFlags

// Initialize Portal with custom feature flags
val portal = Portal(
    apiKey = "CLIENT_API_KEY_OR_CLIENT_SESSION_TOKEN",
    featureFlags = FeatureFlags(
        useEnclaveMpcApi = true
    )
)
```

***

### Available Feature Flags

Below is a list of available feature flags and their functionality.

#### 1. `useEnclaveMpcApi`

* **Type**: `Boolean?`
* **Default**: `null` (disabled)
* **Description**: Enables the use of the **Enclave MPC API** for signing transactions. When enabled, MPC operations are executed server-side in a secure AWS Nitro Enclave, ensuring consistent and faster signing times.

**How It Works**

Executing MPC operations on client devices can lead to inconsistent signing times due to variations in device CPU performance. By enabling the `useEnclaveMpcApi` flag, the client key share is transmitted to a **Trusted Execution Environment (TEE)** hosted in an AWS Nitro Enclave. This ensures:

1. **Encrypted Memory**: All data processed in the enclave is encrypted and inaccessible to anyone, including Portal employees.
2. **Verified Execution**: Users can cryptographically verify that their request was handled in a secure enclave using signed measurements.

**Example:**

```kotlin theme={null}
import io.portalhq.android.Portal
import io.portalhq.android.mpc.data.FeatureFlags

// Initialize Portal with the Enclave MPC API enabled
val portal = Portal(
    apiKey = "CLIENT_API_KEY_OR_CLIENT_SESSION_TOKEN",
    featureFlags = FeatureFlags(
        useEnclaveMpcApi = true
    )
)
```

By setting `useEnclaveMpcApi` to `true`, the Portal instance will use the Enclave MPC API for signing transactions, ensuring faster computation and consistent performance across client devices.

***

#### `usePreGeneratedWallet`

* **Type**: `Boolean?`
* **Default**: `null` (disabled)
* **Description**: When enabled, `portal.createWallet()` attempts to claim a pre-generated wallet share instead of running the standard interactive MPC generation. This can make wallet creation faster. You do not need to change how you call `createWallet`.

**How It Works**

Normally, `createWallet` runs the MPC key generation (DKG) protocol interactively between the device and the MPC servers at the moment it is called. With this flag enabled, the SDK asks the enclave for a share from a pre-computed pool instead.

Two separate fallbacks protect that path, and it helps to keep them apart:

* **Enclave-side fallback**—if the pool is empty, or the eligibility check can't be completed, the enclave generates the shares on demand and returns them in the same successful response. Your app sees an ordinary success, and the device still skips the DKG protocol.
* **SDK-side fallback**—if the request fails with an HTTP 5xx, the SDK falls back to running the standard DKG protocol on the device. This is transparent too: `createWallet` returns the same `Result` it would through the standard flow.

Failures that aren't a 5xx are not retried and propagate as a failed `Result`.

| Scenario                                        | Behavior                                                                                                                                                                                                                                                                                                                                                                  |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Flag disabled (default)**                     | `createWallet` runs the standard interactive DKG protocol, exactly as it does today.                                                                                                                                                                                                                                                                                      |
| **Flag enabled, share claimed**                 | `createWallet` claims a pre-generated share, and wallet creation completes faster than the standard flow.                                                                                                                                                                                                                                                                 |
| **Pool empty or eligibility check unavailable** | Handled inside the enclave, which generates the shares on demand and returns them in a successful response. The SDK sees a success rather than a 5xx, so this never reaches your error handling and never triggers the on-device DKG protocol.                                                                                                                            |
| **Enclave returns HTTP 5xx**                    | The SDK falls back to the standard interactive DKG protocol on the device.                                                                                                                                                                                                                                                                                                |
| **Enclave rejects the claim (HTTP 4xx)**        | Returned as a failed `Result` carrying `PortalException.Mpc.MpcResultError` with the enclave's message. The common case is a client that already has a wallet: `Not eligible to claim a pre-generated wallet` when the pre-check catches it, or `Wallet already exists` when the claim is rejected at finalization. These are expected hard failures, not fallback cases. |
| **Any other failure**                           | An auth failure (`PortalException.Api.HttpUnauthorized` on a 401), an `IOException` from the network, or a share that fails to decode are returned as a failed `Result`, since retrying with the standard flow wouldn't resolve them.                                                                                                                                     |

Claiming a share does not change the security model: shares are still split between the user's device and Portal, and the pre-generated shares are produced in the same Trusted Execution Environment described in the `useEnclaveMpcApi` section above.

**Checking the fallback rule yourself**

The policy is driven by a public helper, `Mpc.isRetryableServerError(error: Throwable)`, which returns `true` only for a `PortalException.Api.HttpRequestFailed` carrying a 5xx status. Every other throwable—including other `PortalException.Api` types and `IOException`—returns `false`. It is useful for asserting the classification in your own tests:

```kotlin theme={null}
import io.portalhq.android.exceptions.PortalException
import io.portalhq.android.mpc.Mpc

val serverError = PortalException.Api.HttpRequestFailed("503", statusCode = 503)
assert(Mpc.isRetryableServerError(serverError)) // true — the SDK falls back on this
```

Note that by the time an error reaches your `Result`, the SDK has already made the fallback decision, so this helper predicts nothing about an error you receive from `onFailure`. See [Error handling](./error-handling) for the full `PortalException` hierarchy.

**When to enable**

Enable `usePreGeneratedWallet` when you want faster wallet creation without changing your integration. It helps most on lower-end devices, where running the DKG protocol on the handset is slowest and least consistent. The resulting wallet is identical to one created through the standard flow.

**Limitations**

* This is a performance optimization only; it doesn't change the API surface, the resulting wallet, or how backup and recovery work.
* An empty pool isn't something your app has to handle: the enclave covers it by generating on demand, so it never reaches the SDK as an error.
* SDK-side fallback to the on-device protocol occurs on an HTTP 5xx response from the enclave only. A 4xx rejection (such as `Wallet already exists`), an unauthorized API key, and network failures propagate normally—so a misconfigured API key produces a failed wallet creation rather than a slow one. Keep your existing error handling around `createWallet`.

**Example:**

```kotlin theme={null}
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import io.portalhq.android.Portal
import io.portalhq.android.mpc.data.FeatureFlags
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    private lateinit var portal: Portal

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Initialize Portal with pre-generated wallets enabled
        portal = Portal(
            apiKey = "CLIENT_API_KEY_OR_CLIENT_SESSION_TOKEN",
            featureFlags = FeatureFlags(
                usePreGeneratedWallet = true
            )
        )

        lifecycleScope.launch {
            portal.createWallet()
                .onSuccess { walletAddresses ->
                    Log.d("[PortalEx]", "✅ Generated address successfully! $walletAddresses")
                }
                .onFailure { error ->
                    // A 5xx from the enclave would have fallen back to the standard flow, so
                    // reaching this point means the failure was not retryable — for example the
                    // client already has a wallet, which the enclave rejects with a 4xx.
                    Log.d("[PortalEx]", "Error generating share: ${error.stackTraceToString()}")
                }
        }
    }
}
```

Every parameter on `FeatureFlags` is optional and defaults to `null`, so you can enable `usePreGeneratedWallet` on its own as shown above, or alongside any other flag.

**Types**

Claiming a share calls the Enclave MPC API at `POST https://{enclaveApiHost}/v1/generate`, where `enclaveApiHost` is a `Portal` constructor parameter that defaults to `mpc-client.portalhq.io`. The request and response types are public so you can build mocks and tests against them—most integrations never reference them directly, since `createWallet` handles the response for you.

```kotlin theme={null}
data class GenerateWithEnclaveApiRequest(
    @SerializedName("usePreGenerated") val usePreGenerated: Boolean,
    @SerializedName("metadataStr") val metadataStr: String,
)

data class GenerateWithEnclaveApiResponse(
    @SerializedName("SECP256K1") val secp256k1: ShareData?,
    @SerializedName("ED25519") val ed25519: ShareData?,
    @SerializedName("error") val error: PortalError? = null,
)

// ShareData.share is the base64-encoded serialized MPC share.
data class ShareData(
    val id: String,
    val share: String,
)
```

Both curve fields are nullable, so a response that decodes successfully can still be missing a share.
