> ## Documentation Index
> Fetch the complete documentation index at: https://rain-sandbox-trial.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Third-Party Wallet Providers

> Use an existing wallet from Portal, Privy, or your own Turnkey with the Rain SDK.

Rain embedded wallets are the default integration. If your application already uses another wallet provider, you can integrate that provider with Rain without creating new wallets for your users.

Rain's provider adapters expose a consistent `RainClient` interface for wallet operations, including balances, transfers, and card funding. Authentication, wallet creation, session management, and key export remain with your existing provider.

<Info>
  **Choosing a provider:** Use Rain's embedded wallet unless your application already has an existing wallet integration. When using an external provider, authentication, session management, and key export are handled through that provider's SDK rather than Rain.
</Info>

## Available wallet providers

Each provider has a dedicated adapter that connects its wallet infrastructure to the Rain SDK. Install the adapter for your chosen provider and register it when initializing the SDK.

| Provider | iOS package and import | Android artifact and package | Provider ID |
| :- | :- | :- | :- |
| Portal | `rain-portal-ios`<br />`import RainPortal` | `rain-portal-android`<br />`com.rain.sdk.portal` | `.portal` / `ProviderId.PORTAL` |
| Privy | `rain-privy-ios`<br />`import RainPrivy` | `rain-privy-android`<br />`com.rain.sdk.privy` | `.privy` / `ProviderId.PRIVY` |
| Turnkey | `rain-turnkey-ios`<br />`import RainTurnkey` | `rain-turnkey-android`<br />`com.rain.sdk.turnkey` | `.turnkey` / `ProviderId.TURNKEY` |

You can register multiple wallet providers in a single Rain SDK instance and resolve the appropriate client using its provider ID.

**Important:** Rain embedded wallets and your own Turnkey integration share the same wallet backend. Register only one of these providers in your application. Registering both returns `RAIN_102` (`invalidConfig`).

## Portal

Portal provides MPC wallets with support for EVM networks. Authenticate users through Portal's SDK, then configure the Rain adapter with the user's Portal session token. The adapter can refresh expired sessions through `onSessionTokenNeeded`. If the session expires and cannot be refreshed, the SDK returns `RAIN_201` (`tokenExpired`).

<CodeGroup>
  ```swift iOS theme={null}
  import RainPortal

  let portal = PortalProvider(PortalConfig(
      sessionToken: clientSessionToken,
      onSessionTokenNeeded: { try await fetchFreshPortalToken() },   // optional
      onSessionExpired: { /* re-authenticate with Portal */ }
  ))

  let rain = try RainSdk.builder()
      .rpcEndpoints([RainChain.baseMainnet: "https://mainnet.base.org"])
      .register(portal)
      .build()
  let client = try await rain.provider(.portal)
  ```

  ```kotlin Android theme={null}
  import com.rain.sdk.portal.PortalConfig
  import com.rain.sdk.portal.PortalProvider

  val portal = PortalProvider(
      PortalConfig(
          sessionToken = clientSessionToken,
          onSessionTokenNeeded = { fetchFreshPortalToken() },   // optional
          onSessionExpired = { /* re-authenticate with Portal */ },
      )
  )

  val rain = RainSdk.builder()
      .rpcEndpoints(mapOf(RainChain.BASE_MAINNET to "https://mainnet.base.org"))
      .register(portal)
      .build()
  val client = rain.provider(ProviderId.PORTAL)
  ```
</CodeGroup>

### Limitations

Portal's Rain adapter supports EVM networks only. Attempting to use a Solana network returns `RAIN_104` (`chainNotSupported`).

Rain does not sponsor gas for Portal wallets. Users must have sufficient native tokens to cover applicable transaction fees.

## Privy

Privy supports embedded wallets with EVM and Solana accounts. Authenticate users through Privy's SDK, then register the authenticated Privy instance with Rain. If a user has multiple embedded EVM wallets, specify `walletAddress` to select the wallet you want to use. Otherwise, the adapter selects the first available wallet.

<CodeGroup>
  ```swift iOS theme={null}
  import RainPrivy

  let privyProvider = PrivyProvider(PrivyConfig(
      privy: privy,                       // authenticated Privy instance
      walletAddress: nil,                 // optional: pick one of several embedded wallets
      onSessionExpired: { /* re-authenticate with Privy */ }
  ))

  let rain = try RainSdk.builder()
      .rpcEndpoints([RainChain.baseMainnet: "https://mainnet.base.org"])
      .register(privyProvider)
      .build()
  let client = try await rain.provider(.privy)
  ```

  ```kotlin Android theme={null}
  import com.rain.sdk.privy.PrivyConfig
  import com.rain.sdk.privy.PrivyProvider

  val privyProvider = PrivyProvider(
      PrivyConfig(
          privy = privy,                  // authenticated Privy instance
          walletAddress = null,           // optional: pick one of several embedded wallets
          onSessionExpired = { /* re-authenticate with Privy */ },
      )
  )

  val rain = RainSdk.builder()
      .rpcEndpoints(mapOf(RainChain.BASE_MAINNET to "https://mainnet.base.org"))
      .register(privyProvider)
      .build()
  val client = rain.provider(ProviderId.PRIVY)
  ```
</CodeGroup>

### Transaction handling

Transactions are signed by the user's Privy embedded wallet and broadcast through the configured RPC endpoint. Rain does not provide gas sponsorship for Privy wallets. Gas fees are handled by Privy's wallet infrastructure and configuration. Transaction history is retrieved from Privy's indexer. Solana transaction history is currently supported on mainnet only.

## Turnkey

If you manage your own Turnkey organization, you can connect its wallets to Rain without creating new wallets for your users. Authenticate users through Turnkey's SDK, then pass the authenticated context to the Rain adapter. Transactions are submitted through Turnkey's infrastructure, with the same blockchain coverage and gas sponsorship capabilities as Rain embedded wallets. Gas sponsorship is enabled by default. If your Turnkey organization does not support gas sponsorship, set `sponsorGas` to `false` to prevent transactions from being rejected.

<CodeGroup>
  ```swift iOS theme={null}
  import RainTurnkey

  let turnkey = TurnkeyProvider(TurnkeyConfig(
      turnkey: TurnkeyContext.shared,     // authenticated by your own Turnkey integration
      sponsorGas: false,
      onSessionExpired: { /* re-authenticate with Turnkey */ }
  ))

  let rain = try RainSdk.builder()
      .rpcEndpoints([RainChain.baseMainnet: "https://mainnet.base.org"])
      .register(turnkey)
      .build()
  let client = try await rain.provider(.turnkey)
  ```

  ```kotlin Android theme={null}
  import com.rain.sdk.turnkey.TurnkeyConfig
  import com.rain.sdk.turnkey.TurnkeyProvider
  import com.turnkey.sdk.TurnkeyContext

  val turnkey = TurnkeyProvider(
      TurnkeyConfig(
          turnkey = TurnkeyContext,       // authenticated by your own Turnkey integration
          sponsorGas = false,
          onSessionExpired = { /* re-authenticate with Turnkey */ },
      )
  )

  val rain = RainSdk.builder()
      .rpcEndpoints(mapOf(RainChain.BASE_MAINNET to "https://mainnet.base.org"))
      .register(turnkey)
      .build()
  val client = rain.provider(ProviderId.TURNKEY)
  ```
</CodeGroup>

### Key export

Key export support differs by platform:

* **Android:** `TurnkeyProvider` supports `exportRecoveryPhrase()` and `exportPrivateKey(TurnkeyKeyFamily)` for wallets in your Turnkey organization.
* **iOS:** Use Turnkey's native SDK to export keys from wallets in your organization. Key export through the Rain SDK is only available for Rain embedded wallets.

## Shared wallet functionality

Regardless of provider, `RainClient` provides a consistent interface for retrieving wallet addresses, checking balances, viewing transaction history, sending assets, estimating fees, and withdrawing collateral.

For Rain managed programs, register your existing wallet's address when creating the user's Rain application. The registered wallet becomes the owner of the user's collateral contract and can authorize subsequent collateral withdrawals. See [Card funding and settlement](/docs/embedded-wallets/card-funding-and-settlement).

## What's next

<Columns cols={2}>
  <Card title="Feature matrix" icon="table" href="/sdks/embedded-wallets/features#third-party-providers-compared">
    How the adapters compare with the Rain wallet.
  </Card>

  <Card title="Error reference" icon="circle-exclamation" href="/sdks/embedded-wallets/error-reference">
    Vendor errors are mapped to the same `RAIN_*` codes.
  </Card>
</Columns>
