> ## 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.

# Set Up a Wallet

> Build the Rain Client SDK with a wallet provider, resolve a wallet-bound client, and read the wallet address.

Create a user's non-custodial wallet with the provider your app ships. Do this first: set up the wallet and read its address before you create the user in the Rain API, since creating the user's application requires the address. To start, [install the SDK](/sdks/embedded-wallets-overview#installation) and [authenticate the wallet with your provider](/sdks/embedded-wallets-authentication); no Client Session Token needed for this step.

The SDK uses a **builder**: register your RPC endpoints and one or more providers, then `build()` the SDK. There's no singleton and no `initialize` call.

Once built, resolve a wallet-bound `RainClient` for each provider you registered. A `RainClient` is bound to one provider for its lifetime, but multiple providers can coexist on the same built SDK.

<Steps>
  <Step title="Build the SDK with a provider">
    Register the provider adapter(s) your app ships: the examples use the managed Turnkey provider with the authenticated `TurnkeyContext` from the [authentication](/sdks/embedded-wallets-authentication) step. `build()` validates the configuration and throws `RainSDKError.invalidConfig` / `RainError.InvalidConfig` if the configuration is incomplete.

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

      let rain = try RainSdk.builder()
          .rpcEndpoints([RainChain.avalancheMainnet: "https://avalanche-c-chain-rpc.publicnode.com"])
          .register(TurnkeyProvider(TurnkeyConfig(turnkey: turnkeyContext)))
          .build()
      ```

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

      val rain = RainSdk.builder()
          .rpcEndpoints(mapOf(RainChain.AVALANCHE_MAINNET to "https://avalanche-c-chain-rpc.publicnode.com"))
          .register(TurnkeyProvider(TurnkeyConfig(turnkeyContext)))
          .build()
      ```
    </CodeGroup>

    Optional builder calls:

    | Method                               | Purpose                                                                                                                        |
    | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
    | `registerTokens(...)`                | Pre-register token metadata so balance calls skip on-chain lookups.                                                            |
    | `rainApiEnvironment(...)`            | Select the Rain API host (see [the built-in Rain API client](/sdks/embedded-wallets-authentication#built-in-rain-api-client)). |
    | `rainApiCredentials(apiKey, userId)` | Configure the built-in Rain API client at build time.                                                                          |

    On iOS, providers are optional: build with endpoints alone for a wallet-agnostic instance that only does transaction building and Rain API calls. `rpcEndpoints` also accepts `[NetworkConfig]` when you want to name networks or use CAIP-2 ids. On Android, `build()` requires at least one registered provider.
  </Step>

  <Step title="Resolve the wallet client">
    Resolve the `RainClient` for a registered provider. This suspends on first access: it materializes the vendor wallet. The Turnkey and Privy adapters fail fast here if the provider has no usable account (Portal validates lazily on first use). Resolution runs once per id and is cached; a failed resolution is evicted so you can retry.

    <CodeGroup>
      ```swift iOS theme={null}
      let client = try await rain.provider(.turnkey)
      ```

      ```kotlin Android theme={null}
      import com.rain.sdk.provider.ProviderId

      val client = rain.provider(ProviderId.TURNKEY)
      ```
    </CodeGroup>

    You can also resolve by capability instead of id:

    <CodeGroup>
      ```swift iOS theme={null}
      let exporter = try await rain.first { $0.capabilities.contains(.export) }
      ```

      ```kotlin Android theme={null}
      import com.rain.sdk.provider.Capability

      val exporter = rain.first { Capability.EXPORT in it.capabilities }
      ```
    </CodeGroup>

    Resolving an unregistered id throws `RAIN_102` (`RainSDKError.providerNotRegistered` / `RainError.InvalidConfig`). Use `client` for every wallet operation: [balances and transfers](/sdks/embedded-wallets-balances-and-transactions), [withdrawals](/sdks/embedded-wallets-withdraw-collateral), and the calls below.
  </Step>

  <Step title="Get the wallet address">
    Read the resolved wallet's address:

    <CodeGroup>
      ```swift iOS theme={null}
      let address = try await client.getWalletAddress()
      // "0x1234...abcd"
      ```

      ```kotlin Android theme={null}
      val address = client.getWalletAddress()
      // "0x1234...abcd"
      ```
    </CodeGroup>

    Rain records the wallet address against the user, so you never handle key material. Turnkey wallets also hold a Solana account. Pass a Solana chain id to read the base58 address:

    <CodeGroup>
      ```swift iOS theme={null}
      let solAddress = try await client.getWalletAddress(chainId: RainChain.solanaDevnet)
      ```

      ```kotlin Android theme={null}
      val solAddress = client.getWalletAddress(RainChain.SOLANA_DEVNET)
      ```
    </CodeGroup>
  </Step>

  <Step title="Generate a QR code">
    Create a QR code image for the wallet address so users can receive funds:

    <CodeGroup>
      ```swift iOS theme={null}
      let png = try await client.generateWalletAddressQRCode(dimension: 500, backgroundColor: nil, foregroundColor: nil)
      let image = UIImage(data: png)
      // Returns PNG image data
      ```

      ```kotlin Android theme={null}
      val bitmap = client.generateAddressQRCode(width = 500, height = 500)
      // Returns an android.graphics.Bitmap of the resolved wallet address
      ```
    </CodeGroup>

    On Android, pass an explicit `address` to encode a different one.
  </Step>
</Steps>

<Check>
  Your user now has a non-custodial embedded wallet. [Query balances](/sdks/embedded-wallets-balances-and-transactions), [withdraw collateral](/sdks/embedded-wallets-withdraw-collateral), or fund a card against it.
</Check>

## Test your integration

Use a testnet chain ID to validate before production:

<Steps>
  <Step title="Build for testnet">
    Point `rpcEndpoints` at a testnet, for example Avalanche Fuji (`RainChain.avalancheTestnet` / `RainChain.AVALANCHE_TESTNET`, chain id `43113`) at `https://api.avax-test.network/ext/bc/C/rpc`, and resolve the client as above.
  </Step>

  <Step title="Fund your test wallet">
    Mint rUSD test tokens and deposit them to your user's collateral contract. See [Mint Test Tokens](/docs/sandbox-mint-test-tokens-for-collateral).
  </Step>

  <Step title="Verify each operation">
    Confirm you get a `0x...` address, read a testnet balance, send a small amount, and build a test withdrawal.
  </Step>
</Steps>

## What's next

<Columns cols={4}>
  <Card title="Create the user & KYC" icon="user-check" href="/sdks/embedded-wallets-onboarding">
    Onboard the user with the wallet address.
  </Card>

  <Card title="Balances & Transactions" icon="coins" href="/sdks/embedded-wallets-balances-and-transactions">
    Query balances, fetch history, and send tokens.
  </Card>

  <Card title="Fund the Wallet" icon="circle-dollar-to-slot" href="/sdks/embedded-wallets-funding">
    Give the card spending power with on-chain collateral.
  </Card>

  <Card title="Withdraw Collateral" icon="arrow-right-from-bracket" href="/sdks/embedded-wallets-withdraw-collateral">
    Execute collateral withdrawals from your app.
  </Card>
</Columns>
