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

# React Native - @buckspay/react-native

> The same BuckspayProvider and hooks on iOS and Android, with nativePasskey (device secure enclave) and secure-storage adapters.

`@buckspay/react-native` brings the SDK to iOS and Android. The core pipeline (auth-entry build,
fee-bump, prepare -> sign -> send) is platform-agnostic. This package adds three things on top:

* **`nativePasskey`** - a `WebAuthnLike` backed by `react-native-passkey` that drives the
  device secure enclave instead of `navigator.credentials`. The private key never leaves the
  device.
* **Secure-storage adapters** - `memorySecureStore`, `expoSecureStore`, `keychainSecureStore`
  for persisting session blobs and credential IDs.
* **Hermes polyfills** - installed as a side-effect on import, before `@stellar/stellar-sdk` is
  used.

`BuckspayProvider`, `useWallet`, and `useStellarPay` are re-exported **by reference** from
`@buckspay/react` - the same store, same status machine, zero fork. Your screen logic is
identical to a web component; only the host primitives (`<View>` / `<Text>` / `<Pressable>`)
and the signer differ.

<Steps>
  ### Install the package and peer dependencies

  Install `@buckspay/react-native` plus the native peers your app requires:

  ```bash theme={null}
  pnpm add @buckspay/react-native @buckspay/react @buckspay/core @buckspay/accounts @buckspay/relayer

  # Native peers - install in the app, not in the SDK
  pnpm add react-native react-native-passkey react-native-get-random-values
  ```

  The peer modules (`react-native-passkey`, `react-native-get-random-values`) are optional: each
  is lazily loaded only if you use the feature that depends on it, so apps that skip `nativePasskey`
  never pull in the native module.

  ### Build the config with `nativePasskey`

  The config shape is identical to web. The only mobile-specific change is the signer:

  ```tsx theme={null}
  import { nativePasskey } from "@buckspay/react-native";
  import { ozContractAccount } from "@buckspay/accounts/oz-contract";
  import { buckspayFacilitator } from "@buckspay/relayer/buckspay-facilitator";
  import type { BuckspayConfig } from "@buckspay/core";

  const config: BuckspayConfig = {
    network: "testnet",
    account: ozContractAccount({ network: "testnet", sponsorAddress: "GA...SPONSOR" }),
    signer: nativePasskey({ rpId: "app.example.com", rpName: "My App" }),
    relayer: buckspayFacilitator({ url: "/api/gasless", network: "testnet" }),
    gas: { mode: "sponsored" }
  };
  ```

  `nativePasskey` accepts:

  | Option   | Type     | Required | Description                                           |
  | -------- | -------- | -------- | ----------------------------------------------------- |
  | `rpId`   | `string` | Yes      | Relying-party domain, bound at registration           |
  | `rpName` | `string` | No       | Human-readable name shown in the authenticator prompt |

  ### Wrap the tree with `BuckspayProvider`

  Exactly the same as web - pass `sim` so `pay()` can simulate:

  ```tsx theme={null}
  import { BuckspayProvider } from "@buckspay/react-native";
  import { createRpcSimContext } from "@buckspay/core";

  export function App() {
    return (
      <BuckspayProvider config={config} sim={createRpcSimContext("https://soroban-testnet.stellar.org")}>
        {/* your screens */}
      </BuckspayProvider>
    );
  }
  ```

  ### Connect and pay - identical to web

  `useWallet` and `useStellarPay` work exactly as on web. Replace DOM elements with React
  Native primitives:

  ```tsx theme={null}
  import { useWallet, useStellarPay } from "@buckspay/react-native";
  import { View, Text, Pressable } from "react-native";

  function PayScreen() {
    const { wallet, connect, status } = useWallet();
    const { pay, status: payStatus, receipt } = useStellarPay();

    if (!wallet) {
      return <Pressable onPress={() => void connect()} disabled={status === "connecting"}>
        <Text>{status === "connecting" ? "Connecting..." : "Connect"}</Text>
      </Pressable>;
    }
    return (
      <View>
        <Pressable onPress={() => void pay([/* calls */])} disabled={payStatus === "relaying"}>
          <Text>Pay 1.50 USDC (free)</Text>
        </Pressable>
        {receipt && <Text>Settled: {receipt.transferTx}</Text>}
      </View>
    );
  }
  ```
</Steps>

## Secure storage

Session blobs and credential IDs are persisted via a `SecureStore` port. Three adapters are
exported from `@buckspay/react-native`:

| Adapter                            | Use                                         |
| ---------------------------------- | ------------------------------------------- |
| `memorySecureStore()`              | Tests and ephemeral in-memory sessions      |
| `expoSecureStore()`                | Expo managed workflow (`expo-secure-store`) |
| `keychainSecureStore({ service })` | Bare React Native (`react-native-keychain`) |

Each adapter lazily imports its peer, so apps that do not use a given adapter never pull the
native module into their bundle.

## Full example

```tsx theme={null}
// Recipe 13 - REACT NATIVE. The mobile binding re-exports the SAME @buckspay/react hooks and only
// swaps the signer (native passkey / secure enclave), storage, and Hermes polyfills. The screen
// logic is identical to web (recipe 05); only the host components (<View>/<Text>) and the signer
// differ. This example pins the @buckspay/react-native surface; the View/Text layer is the app's,
// so it is omitted here (it would pull react-native intrinsics) - fragments stand in for it.
import {
  BuckspayProvider,
  useWallet,
  useStellarPay,
  nativePasskey,
  memorySecureStore,
  type SecureStore
} from "@buckspay/react-native";
import { ozContractAccount } from "@buckspay/accounts/oz-contract";
import { buckspayFacilitator } from "@buckspay/relayer/buckspay-facilitator";
import { createRpcSimContext, type BuckspayConfig, type Call } from "@buckspay/core";

const SPONSOR_G = "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN";
const USDC_SAC = "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA";
const MERCHANT = "GA6HCMBLTZS5VYYBCATRBR5VBZJEH5C2OON6XQGB3RNYDDAQ7JZ65YQH";

// Same config shape as web - the ONLY mobile-specific line is the native passkey signer.
export const mobileConfig: BuckspayConfig = {
  network: "testnet",
  account: ozContractAccount({ network: "testnet", sponsorAddress: SPONSOR_G }),
  signer: nativePasskey({ rpId: "app.buckspay.dev", rpName: "buckspay" }),
  relayer: buckspayFacilitator({ url: "/api/gasless", network: "testnet" }),
  gas: { mode: "sponsored" }
};

// Session blobs / credential ids persist via a SecureStore port (keychain/expo on device).
export const store: SecureStore = memorySecureStore();

// The hooks are byte-identical to @buckspay/react - no fork (recipe 05).
export function PayScreen() {
  const { wallet, address, connect } = useWallet();
  const { pay, status, receipt } = useStellarPay();

  if (!wallet) {
    // On device this is a <Pressable onPress={connect}> inside a <View>.
    return <>{"Connect"}</>;
  }
  const call: Call = {
    contract: USDC_SAC,
    fn: "transfer",
    args: [] // built from address -> MERCHANT in the real screen; see recipe 05
  };
  void address;
  void (() => pay([call]));
  return <>{status === "success" && receipt ? `settled: ${receipt.transferTx}` : "Pay 1.50 USDC (free)"}</>;
}

// Wrap the tree once, exactly like web - pass `sim` so useStellarPay().pay() can simulate.
export function App() {
  return (
    <BuckspayProvider config={mobileConfig} sim={createRpcSimContext("https://soroban-testnet.stellar.org")}>
      <PayScreen />
    </BuckspayProvider>
  );
}
```

## Next

<CardGroup cols={2}>
  <Card title="Native passkey signer" href="/signers/native-passkey">
    How `nativePasskey` delegates to the shared passkey crypto pipeline.
  </Card>

  <Card title="Web - @buckspay/react" href="/platforms/web-react">
    The web counterpart - same hooks, browser authenticator transport.
  </Card>
</CardGroup>
