From 1ebab4eb8f8e76b19d05509e3b1029c2619db118 Mon Sep 17 00:00:00 2001 From: dofili Date: Fri, 24 Jul 2026 10:30:09 +0100 Subject: [PATCH] docs: add React Native integration guide --- docs.json | 3 +- guides/integrations/react-native.mdx | 282 +++++++++++++++++++++++++++ 2 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 guides/integrations/react-native.mdx 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 ? ( +