diff --git a/docs.json b/docs.json
index 9761769..5b1d6fc 100644
--- a/docs.json
+++ b/docs.json
@@ -119,7 +119,8 @@
"guides/privacy-best-practices",
"guides/stellar-fees",
"guides/stellar-troubleshooting",
- "guides/spectre-stellar-cookbook"
+ "guides/spectre-stellar-cookbook",
+ "guides/integrations/react-native"
]
},
{
diff --git a/guides/integrations/react-native.mdx b/guides/integrations/react-native.mdx
new file mode 100644
index 0000000..9dc7523
--- /dev/null
+++ b/guides/integrations/react-native.mdx
@@ -0,0 +1,282 @@
+---
+title: "React Native Integration"
+description: "Configure the Wraith SDK in Expo and bare React Native applications"
+---
+
+The `@wraith-protocol/sdk-react` package allows you to integrate managed AI agents and stealth payments directly into mobile applications.
+
+Because React Native and Expo environments do not support Node.js built-ins or standard browser web-cryptography APIs out of the box, you must configure a secure cryptographic shim and a persistent storage adapter.
+
+---
+
+## Installation
+
+Install the required packages. Depending on whether you are using **Expo** or **Bare React Native**, install the corresponding dependencies:
+
+
+```bash Expo
+npm install @wraith-protocol/sdk @wraith-protocol/sdk-react @react-native-async-storage/async-storage expo-crypto
+```
+
+```bash Bare React Native
+npm install @wraith-protocol/sdk @wraith-protocol/sdk-react @react-native-async-storage/async-storage react-native-get-random-values buffer
+```
+
+
+---
+
+## 1. Cryptographic Shimming
+
+The Wraith SDK relies on secure random bytes for elliptic curve operations (such as deriving ephemeral stealth keys). Since `crypto.getRandomValues` is not standard in React Native, you must register a shim at the **absolute entry point** of your application (usually `index.js` or `App.js`).
+
+### Expo Setup
+
+For Expo projects, use `expo-crypto` to supply the random byte generator.
+
+Add the following shim to your entry file before any other imports:
+
+```typescript
+// App.js (or index.js) - Place this at the very top
+import * as Crypto from "expo-crypto";
+
+if (typeof global.crypto !== "object") {
+ global.crypto = {} as any;
+}
+
+if (typeof global.crypto.getRandomValues !== "function") {
+ global.crypto.getRandomValues = (array: T): T => {
+ if (!array) {
+ throw new Error("crypto.getRandomValues: array cannot be null");
+ }
+ const bytes = Crypto.getRandomBytes(array.byteLength);
+ const view = new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
+ view.set(bytes);
+ return array;
+ };
+}
+```
+
+### Bare React Native Setup
+
+For bare React Native projects, use `react-native-get-random-values` and polyfill Node's `Buffer` global.
+
+Add these imports to the very top of your entry file:
+
+```typescript
+// index.js - Place this at the very top
+import "react-native-get-random-values";
+import { Buffer } from "buffer";
+
+global.Buffer = global.Buffer || Buffer;
+```
+
+---
+
+## 2. AsyncStorage Adapter
+
+By default, the React SDK uses the browser's `localStorage` to persist active agent sessions and cached state. In a mobile environment, you must wire up `@react-native-async-storage/async-storage` as a custom storage adapter.
+
+Define the storage adapter following the SDK's storage interface:
+
+```typescript
+import AsyncStorage from "@react-native-async-storage/async-storage";
+
+export const asyncStorageAdapter = {
+ getItem: async (key: string): Promise => {
+ try {
+ return await AsyncStorage.getItem(key);
+ } catch (error) {
+ console.error("Wraith storage error (getItem):", error);
+ return null;
+ }
+ },
+ setItem: async (key: string, value: string): Promise => {
+ try {
+ await AsyncStorage.setItem(key, value);
+ } catch (error) {
+ console.error("Wraith storage error (setItem):", error);
+ }
+ },
+ removeItem: async (key: string): Promise => {
+ try {
+ await AsyncStorage.removeItem(key);
+ } catch (error) {
+ console.error("Wraith storage error (removeItem):", error);
+ }
+ },
+};
+```
+
+---
+
+## 3. Wiring up the Provider
+
+Wrap your application root inside `WraithProvider`, passing your API key and the `asyncStorageAdapter`:
+
+```tsx
+import React from "react";
+import { WraithProvider } from "@wraith-protocol/sdk-react";
+import { asyncStorageAdapter } from "./storage";
+import { MainScreen } from "./MainScreen";
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+---
+
+## Full Send + Receive Example
+
+Here is a complete screen component demonstrating how to connect to an agent, fund it, send a stealth payment, and scan for incoming payments.
+
+```tsx
+import React, { useState } from "react";
+import { StyleSheet, Text, View, Button, ActivityIndicator, Alert } from "react-native";
+import { useWraith, useAgent } from "@wraith-protocol/sdk-react";
+import { Chain } from "@wraith-protocol/sdk";
+
+export function MainScreen() {
+ const { client } = useWraith();
+ const [agentId, setAgentId] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ // Hook to interact with the active agent once connected
+ const { agent, chat, getBalance } = useAgent(agentId);
+ const [balance, setBalance] = useState("0");
+
+ // Step 1: Create or connect to an agent
+ const handleConnectAgent = async () => {
+ setLoading(true);
+ try {
+ // Sign the registration message using your app's wallet adapter
+ const message = "Sign to initialize Wraith Agent";
+ const signature = "0x..."; // Obtain from wallet signature (e.g. WalletConnect/Expo)
+
+ const newAgent = await client.createAgent({
+ name: "mobile_user",
+ chain: Chain.Ethereum,
+ wallet: "0xYourWalletAddress",
+ signature: signature,
+ message: message,
+ });
+
+ setAgentId(newAgent.info.id);
+ Alert.alert("Success", `Connected to ${newAgent.info.name}.wraith`);
+ } catch (error: any) {
+ Alert.alert("Connection Error", error.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Step 2: Send a stealth payment
+ const handleSendPayment = async () => {
+ if (!agent) return;
+ setLoading(true);
+ try {
+ const res = await chat("send 0.05 ETH to bob.wraith");
+ Alert.alert("Payment Sent", res.response);
+
+ // Update balance
+ const newBalance = await getBalance();
+ setBalance(newBalance.native);
+ } catch (error: any) {
+ Alert.alert("Payment Error", error.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Step 3: Scan for incoming payments
+ const handleScanPayments = async () => {
+ if (!agent) return;
+ setLoading(true);
+ try {
+ const res = await chat("scan for payments");
+ Alert.alert("Scan Completed", res.response);
+
+ // Update balance
+ const newBalance = await getBalance();
+ setBalance(newBalance.native);
+ } catch (error: any) {
+ Alert.alert("Scan Error", error.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+ Wraith Mobile Agent
+
+ {loading && }
+
+ {!agentId ? (
+
+ ) : (
+
+ Agent: mobile_user.wraith
+ Balance: {balance} ETH
+
+
+
+
+
+
+
+ )}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ padding: 20,
+ backgroundColor: "#f5f5f5",
+ },
+ title: {
+ fontSize: 24,
+ fontWeight: "bold",
+ marginBottom: 20,
+ },
+ loader: {
+ marginBottom: 20,
+ },
+ agentBox: {
+ padding: 20,
+ backgroundColor: "#ffffff",
+ borderRadius: 8,
+ width: "100%",
+ shadowColor: "#000",
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 4,
+ elevation: 3,
+ },
+ agentText: {
+ fontSize: 18,
+ marginBottom: 10,
+ },
+ balanceText: {
+ fontSize: 16,
+ color: "#666",
+ marginBottom: 20,
+ },
+ buttonRow: {
+ marginTop: 10,
+ },
+ spacer: {
+ height: 10,
+ },
+});