npm package: @human.tech/waap-sdk-react-native
Description: React Native implementation of WaaP SDK
Author: WaaP
Latest version: 1.0.8

# WaaP SDK for React Native

React Native wallet integration that brings WaaP's security and ease of use to mobile apps.

[📦 npm](https://www.npmjs.com/package/@human.tech/waap-sdk-react-native) • [📘 Docs](https://docs.wallet.human.tech/) • [💬 Support](https://t.me/+YjZwY_a6EqU2NzNh)

## Quick Start

### Installation

```bash
npm install @human.tech/waap-sdk-react-native
# or
yarn add @human.tech/waap-sdk-react-native
# or
pnpm add @human.tech/waap-sdk-react-native
```

### Required Dependencies

```bash
npm install @react-native-async-storage/async-storage \
  @react-native-community/netinfo \
  react-native-css-interop \
  react-native-get-random-values \
  react-native-keychain \
  react-native-safe-area-context \
  react-native-svg \
  react-native-webview
```

**Plus ONE of these browser libraries:**

**For Expo apps:**
```bash
npx expo install expo-web-browser
```

**For bare React Native apps:**
```bash
npm install react-native-inappbrowser-reborn
```

> **Important Notes:**
>
> - **`react-native-keychain`**: Required for secure storage of sensitive data like authentication tokens and private keys. Provides hardware-backed encryption via iOS Keychain and Android Keystore.
> - **Browser library** (choose one):
>   - **Expo**: Use `expo-web-browser` with the `createExpoNativeBrowser()` factory function
>   - **Bare React Native**: Use `react-native-inappbrowser-reborn` with the `createInAppNativeBrowser()` factory function
>   - You must pass the created browser function to `initWaapNative()` for social authentication to work
> - **`react-native-safe-area-context`**: Your app **MUST** wrap its root component with `<SafeAreaProvider>` for the wallet UI to render correctly
>
> The SDK will behave unexpectedly if these critical dependencies are missing.

Most React Native apps already have several of these installed. Make sure to check your package.json.

### Basic Usage

<details open>
<summary>📦 <b>Expo</b></summary>

<br/>

```typescript
import { useEffect, useState } from 'react'
import { View, Button, Text } from 'react-native'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import * as WebBrowser from 'expo-web-browser'
import {
  initWaapNative,
  WalletComponent,
  createExpoNativeBrowser
} from '@human.tech/waap-sdk-react-native'

function App() {
  const [provider, setProvider] = useState(null)
  const [account, setAccount] = useState(null)

  useEffect(() => {
    // Initialize with Expo browser
    const provider = initWaapNative({
      project: {
        name: 'My App',
        logo: 'data:image/png;base64,...'
      },
      nativeBrowser: createExpoNativeBrowser(WebBrowser)
    })

    setProvider(provider)

    // Listen to events
    provider.on('accountsChanged', (accounts) => {
      setAccount(accounts[0] || null)
    })

    // Auto-connect
    provider
      .request({ method: 'eth_requestAccounts' })
      .then((accounts) => setAccount(accounts[0]))
      .catch(() => console.log('Not connected'))
  }, [])

  const connectWallet = async () => {
    try {
      await provider.login()
      const accounts = await provider.request({
        method: 'eth_requestAccounts'
      })
      setAccount(accounts[0])
    } catch (error) {
      console.error('Login failed:', error)
    }
  }

  if (!provider) return <Text>Loading...</Text>

  return (
    <SafeAreaProvider>
      <View>
        {account ? (
          <>
            <Text>Connected: {account.slice(0, 6)}...{account.slice(-4)}</Text>
            <Button title='Disconnect' onPress={() => provider.logout()} />
          </>
        ) : (
          <Button title='Connect Wallet' onPress={connectWallet} />
        )}
        <WalletComponent />
      </View>
    </SafeAreaProvider>
  )
}
```

</details>

<details>
<summary>⚛️ <b>Bare React Native</b></summary>

<br/>

```typescript
import { useEffect, useState } from 'react'
import { View, Button, Text } from 'react-native'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import InAppBrowser from 'react-native-inappbrowser-reborn'
import {
  initWaapNative,
  WalletComponent,
  createInAppNativeBrowser
} from '@human.tech/waap-sdk-react-native'

function App() {
  const [provider, setProvider] = useState(null)
  const [account, setAccount] = useState(null)

  useEffect(() => {
    // Initialize with InAppBrowser
    const provider = initWaapNative({
      project: {
        name: 'My App',
        logo: 'data:image/png;base64,...'
      },
      nativeBrowser: createInAppNativeBrowser(InAppBrowser)
    })

    setProvider(provider)

    // Listen to events
    provider.on('accountsChanged', (accounts) => {
      setAccount(accounts[0] || null)
    })

    // Auto-connect
    provider
      .request({ method: 'eth_requestAccounts' })
      .then((accounts) => setAccount(accounts[0]))
      .catch(() => console.log('Not connected'))
  }, [])

  const connectWallet = async () => {
    try {
      await provider.login()
      const accounts = await provider.request({
        method: 'eth_requestAccounts'
      })
      setAccount(accounts[0])
    } catch (error) {
      console.error('Login failed:', error)
    }
  }

  if (!provider) return <Text>Loading...</Text>

  return (
    <SafeAreaProvider>
      <View>
        {account ? (
          <>
            <Text>Connected: {account.slice(0, 6)}...{account.slice(-4)}</Text>
            <Button title='Disconnect' onPress={() => provider.logout()} />
          </>
        ) : (
          <Button title='Connect Wallet' onPress={connectWallet} />
        )}
        <WalletComponent />
      </View>
    </SafeAreaProvider>
  )
}
```

</details>

<br/>

**Key points:**

- **MUST** wrap your app with `<SafeAreaProvider>` from `react-native-safe-area-context`
- Use `createExpoNativeBrowser(WebBrowser)` for Expo or `createInAppNativeBrowser(InAppBrowser)` for bare React Native
- Pass the created browser function to `initWaapNative()` via the `nativeBrowser` option
- `initWaapNative()` returns only the `provider`
- `WalletComponent` handles its own visibility - calling `provider.login()` shows it automatically

[→ See complete example](#complete-example)

## API Reference

### Configuration

<details open>
<summary>📦 <b>Expo Configuration</b></summary>

<br/>

```typescript
import * as WebBrowser from 'expo-web-browser'
import { createExpoNativeBrowser } from '@human.tech/waap-sdk-react-native'

initWaapNative({
  // REQUIRED: Native browser for authentication flows
  nativeBrowser: createExpoNativeBrowser(WebBrowser),

  // Project details (required for native auth)
  project: {
    name: 'My App', // Display name
    logo: 'data:image/png;base64,...', // Base64 logo
    appId: 'com.myapp.mobile', // Bundle ID (iOS) or package name (Android)
    entryTitle: 'Log in to My App', // Custom login screen title
    projectId: 'YOUR_PROJECT_ID', // For gastank integration
    termsOfServiceUrl: 'https://...', // Optional
    privacyPolicyUrl: 'https://...' // Optional
  },

  // Optional: UI customization
  customConfig: {
    authenticationMethods: ['email', 'phone', 'social', 'wallet'],
    allowedSocials: ['google', 'apple', 'twitter', 'bluesky', 'discord'],
    styles: {
      darkMode: true
    },
    showSecured: true
  },

  // Optional: WalletConnect (required if 'wallet' in authenticationMethods)
  walletConnectProjectId: 'YOUR_PROJECT_ID', // Get from https://cloud.reown.com

  // Optional: Human Wallet points referral
  referralCode: 'YOUR_REFERRAL_CODE',

  // Optional: Use staging environment
  useStaging: false
})
```

</details>

<details>
<summary>⚛️ <b>Bare React Native Configuration</b></summary>

<br/>

```typescript
import InAppBrowser from 'react-native-inappbrowser-reborn'
import { createInAppNativeBrowser } from '@human.tech/waap-sdk-react-native'

initWaapNative({
  // REQUIRED: Native browser for authentication flows
  nativeBrowser: createInAppNativeBrowser(InAppBrowser),

  // Project details (required for native auth)
  project: {
    name: 'My App', // Display name
    logo: 'data:image/png;base64,...', // Base64 logo
    appId: 'com.myapp.mobile', // Bundle ID (iOS) or package name (Android)
    entryTitle: 'Log in to My App', // Custom login screen title
    projectId: 'YOUR_PROJECT_ID', // For gastank integration
    termsOfServiceUrl: 'https://...', // Optional
    privacyPolicyUrl: 'https://...' // Optional
  },

  // Optional: UI customization
  customConfig: {
    authenticationMethods: ['email', 'phone', 'social', 'wallet'],
    allowedSocials: ['google', 'apple', 'twitter', 'bluesky', 'discord'],
    styles: {
      darkMode: true
    },
    showSecured: true
  },

  // Optional: WalletConnect (required if 'wallet' in authenticationMethods)
  walletConnectProjectId: 'YOUR_PROJECT_ID', // Get from https://cloud.reown.com

  // Optional: Human Wallet points referral
  referralCode: 'YOUR_REFERRAL_CODE',

  // Optional: Use staging environment
  useStaging: false
})
```

</details>

<br/>

[→ Full configuration reference](https://docs.wallet.human.tech/guides/methods#initwaap-configuration)

### Provider Methods

The provider implements [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) with additional methods:

```typescript
// Get accounts (auto-connects if previously logged in)
const accounts = await provider.request({
  method: 'eth_requestAccounts'
})

// Get balance
const balance = await provider.request({
  method: 'eth_getBalance',
  params: [address, 'latest']
})

// Send transaction
const txHash = await provider.request({
  method: 'eth_sendTransaction',
  params: [{ from, to, value, data }]
})

// Sign message
const signature = await provider.request({
  method: 'personal_sign',
  params: [message, account]
})

// Sign typed data (EIP-712)
const signature = await provider.request({
  method: 'eth_signTypedData_v4',
  params: [account, typedData]
})

// Logout
await provider.logout()
```

[→ All available methods](https://docs.wallet.human.tech/guides/methods)

### Events

Listen to standard EIP-1193 events:

```typescript
provider.on('connect', (connectInfo: { chainId: string }) => {
  console.log('Connected to chain:', connectInfo.chainId)
})

provider.on('accountsChanged', (accounts: string[]) => {
  console.log('Account changed:', accounts[0])
})

provider.on('chainChanged', (chainId: string) => {
  console.log('Chain changed:', chainId)
})

provider.on('disconnect', (error) => {
  console.log('Disconnected:', error)
})
```

[→ Event handling guide](https://docs.wallet.human.tech/guides/methods#event-listeners)

## Platform Setup

### Native App Authentication

WaaP uses Universal Links (iOS) and App Links (Android) to redirect users back to your app after authentication. You need to configure your app to handle these redirects.

#### iOS - Universal Links

<details open>
<summary>📦 <b>Expo</b></summary>

<br/>

Add to `app.json`:

```json
{
  "expo": {
    "ios": {
      "associatedDomains": ["applinks:waap.xyz"],
      "bundleIdentifier": "com.company.myapp"
    }
  }
}
```

</details>

<details>
<summary>⚛️ <b>Bare React Native</b></summary>

<br/>

Add to `Info.plist`:

```xml
<key>com.apple.developer.associated-domains</key>
<array>
  <string>applinks:waap.xyz</string>
</array>
```

</details>

#### Android - App Links

<details open>
<summary>📦 <b>Expo</b></summary>

<br/>

Add to `app.json`:

```json
{
  "expo": {
    "android": {
      "package": "com.company.myapp"
    },
    "plugins": [
      [
        "expo-build-properties",
        {
          "android": {
            "manifestQueries": {
              "intent": [
                {
                  "action": "android.intent.action.VIEW",
                  "data": {
                    "scheme": "https",
                    "host": "waap.xyz"
                  }
                }
              ]
            }
          }
        }
      ]
    ]
  }
}
```

</details>

<details>
<summary>⚛️ <b>Bare React Native</b></summary>

<br/>

Add to `AndroidManifest.xml`:

```xml
<activity android:name=".MainActivity" android:exported="true">
  <intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
      android:scheme="https"
      android:host="waap.xyz"
      android:pathPrefix="/auth" />
  </intent-filter>
</activity>
```

</details>
<br/>

**Important:** The `appId` you pass to `initWaapNative()` must exactly match your bundle ID (iOS) or package name (Android).

[→ Learn more about WaaP's security architecture](https://docs.wallet.human.tech/architecture-security-model/architecture)

### External Wallets (Optional)

To let users connect external mobile wallets like MetaMask or Rainbow via WalletConnect:

#### 1. **Enable in config:**

```typescript
initWaapNative({
  walletConnectProjectId: 'YOUR_PROJECT_ID', // Get from https://cloud.reown.com
  customConfig: {
    authenticationMethods: ['email', 'phone', 'social', 'wallet'] // Include 'wallet'
  }
})
```

#### 2. **Configure wallet detection:**

#### iOS

<details open>
<summary>📦 <b>Expo</b></summary>

<br/>

Add to `app.json`:

```json
{
  "expo": {
    "ios": {
      "infoPlist": {
        "LSApplicationQueriesSchemes": [
          "metamask",
          "trust",
          "rainbow",
          "uniswap",
          "zerion"
        ]
      }
    }
  }
}
```

</details>

<details>
<summary>⚛️ <b>Bare React Native</b></summary>

<br/>

Add to `Info.plist`:

```xml
<key>LSApplicationQueriesSchemes</key>
<array>
  <string>metamask</string>
  <string>trust</string>
  <string>rainbow</string>
  <string>uniswap</string>
  <string>zerion</string>
</array>
```

</details>

#### Android

<details open>
<summary>📦 <b>Expo</b></summary>

<br/>

Create `android-wallet-queries.js`:

```javascript
const {
  AndroidConfig,
  withAndroidManifest,
  createRunOncePlugin
} = require('expo/config-plugins')

const queries = {
  package: [
    { $: { 'android:name': 'io.metamask' } },
    { $: { 'android:name': 'com.wallet.crypto.trustapp' } },
    { $: { 'android:name': 'me.rainbow' } },
    { $: { 'android:name': 'com.uniswap.mobile' } },
    { $: { 'android:name': 'io.zerion.android' } }
  ]
}

const withAndroidWalletQueries = (config) => {
  return withAndroidManifest(config, (config) => {
    config.modResults.manifest = {
      ...config.modResults.manifest,
      queries
    }
    return config
  })
}

module.exports = createRunOncePlugin(
  withAndroidWalletQueries,
  'withAndroidWalletQueries',
  '1.0.0'
)
```

Add to `app.json`:

```json
{
  "expo": {
    "plugins": ["./android-wallet-queries.js"]
  }
}
```

</details>

<details>
<summary>⚛️ <b>Bare React Native</b></summary>

<br/>

Add to `AndroidManifest.xml`:

```xml
<queries>
  <package android:name="io.metamask"/>
  <package android:name="com.wallet.crypto.trustapp"/>
  <package android:name="me.rainbow"/>
  <package android:name="com.uniswap.mobile"/>
  <package android:name="io.zerion.android"/>
</queries>
```

</details>

#### 3. **Configure redirect URLs:**

```typescript
import { createNativeWalletConnect } from '@human.tech/waap-sdk-react-native'

const walletConnect = createNativeWalletConnect({
  redirect: {
    native: 'myapp://', // Your custom URL scheme
    universal: 'https://myapp.com' // Your universal link (optional)
  }
})
```

Don't forget to register your URL scheme in `app.json` (Expo) or native config files.

[→ See WalletConnect integration example](https://github.com/holonym-foundation/waap-examples)

## Complete Example

<details open>
<summary>📦 <b>Expo Example</b></summary>

<br/>

```typescript
import React, { useState, useEffect } from 'react'
import { View, Button, Text, StyleSheet, ActivityIndicator } from 'react-native'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import * as WebBrowser from 'expo-web-browser'
import {
  initWaapNative,
  WalletComponent,
  createExpoNativeBrowser
} from '@human.tech/waap-sdk-react-native'
import InAppBrowser from 'react-native-inappbrowser-reborn'

export default function App() {
  const [provider, setProvider] = useState(null)
  const [account, setAccount] = useState(null)
  const [chainId, setChainId] = useState(null)
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    const provider = initWaapNative({
      project: {
        name: 'My DApp',
        appId: 'com.myapp.mobile',
        logo: 'data:image/png;base64,...'
      },
      customConfig: {
        styles: {
          darkMode: true
        }
      },
      nativeBrowser: createExpoNativeBrowser(WebBrowser)
    })

    setProvider(provider)

    // Event listeners
    provider.on('accountsChanged', (accounts) => {
      setAccount(accounts[0] || null)
    })

    provider.on('chainChanged', (newChainId) => {
      setChainId(newChainId)
    })

    provider.on('disconnect', () => {
      setAccount(null)
      setChainId(null)
    })

    // Try auto-connect
    provider
      .request({ method: 'eth_requestAccounts' })
      .then((accounts) => setAccount(accounts[0]))
      .catch(() => console.log('Not connected'))

    return () => {
      provider.removeAllListeners()
    }
  }, [])

  const connectWallet = async () => {
    setLoading(true)
    try {
      await provider.login()
      const accounts = await provider.request({
        method: 'eth_requestAccounts'
      })
      setAccount(accounts[0])
    } catch (error) {
      console.error('Failed to connect:', error)
    } finally {
      setLoading(false)
    }
  }

  const sendTransaction = async () => {
    setLoading(true)
    try {
      const txHash = await provider.request({
        method: 'eth_sendTransaction',
        params: [
          {
            from: account,
            to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
            value: '0x0'
          }
        ]
      })
      console.log('Transaction sent:', txHash)
    } catch (error) {
      console.error('Transaction failed:', error)
    } finally {
      setLoading(false)
    }
  }

  const disconnect = async () => {
    setLoading(true)
    try {
      await provider.logout()
      setAccount(null)
      setChainId(null)
    } catch (error) {
      console.error('Failed to disconnect:', error)
    } finally {
      setLoading(false)
    }
  }

  if (!provider) {
    return (
      <SafeAreaProvider>
        <View style={styles.centerContainer}>
          <ActivityIndicator size='large' />
          <Text>Initializing...</Text>
        </View>
      </SafeAreaProvider>
    )
  }

  return (
    <SafeAreaProvider>
      <View style={styles.container}>
        <Text style={styles.title}>WaaP SDK Demo</Text>

        {account ? (
          <View style={styles.section}>
            <Text style={styles.label}>Account:</Text>
            <Text style={styles.value}>
              {account.slice(0, 6)}...{account.slice(-4)}
            </Text>

            {chainId && (
              <>
                <Text style={styles.label}>Chain ID:</Text>
                <Text style={styles.value}>{chainId}</Text>
              </>
            )}

            <View style={styles.buttonSpacing}>
              <Button
                title='Send Transaction'
                onPress={sendTransaction}
                disabled={loading}
              />
            </View>
            <Button title='Disconnect' onPress={disconnect} disabled={loading} />
          </View>
        ) : (
          <Button
            title='Connect Wallet'
            onPress={connectWallet}
            disabled={loading}
          />
        )}

        {loading && <ActivityIndicator style={{ marginTop: 20 }} />}

        <WalletComponent />
      </View>
    </SafeAreaProvider>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20
  },
  centerContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20
  },
  section: {
    width: '100%',
    padding: 16,
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    marginBottom: 20
  },
  label: {
    fontSize: 14,
    color: '#666',
    marginTop: 8
  },
  value: {
    fontSize: 16,
    fontWeight: '500',
    marginBottom: 8
  },
  buttonSpacing: {
    marginBottom: 12
  }
})
```

</details>

<details>
<summary>⚛️ <b>Bare React Native Example</b></summary>

<br/>

```typescript
import React, { useState, useEffect } from 'react'
import { View, Button, Text, StyleSheet, ActivityIndicator } from 'react-native'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import InAppBrowser from 'react-native-inappbrowser-reborn'
import {
  initWaapNative,
  WalletComponent,
  createInAppNativeBrowser
} from '@human.tech/waap-sdk-react-native'

export default function App() {
  const [provider, setProvider] = useState(null)
  const [account, setAccount] = useState(null)
  const [chainId, setChainId] = useState(null)
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    const provider = initWaapNative({
      project: {
        name: 'My DApp',
        appId: 'com.myapp.mobile',
        logo: 'data:image/png;base64,...'
      },
      customConfig: {
        styles: {
          darkMode: true
        }
      },
      nativeBrowser: createInAppNativeBrowser(InAppBrowser)
    })

    setProvider(provider)

    // Event listeners
    provider.on('accountsChanged', (accounts) => {
      setAccount(accounts[0] || null)
    })

    provider.on('chainChanged', (newChainId) => {
      setChainId(newChainId)
    })

    provider.on('disconnect', () => {
      setAccount(null)
      setChainId(null)
    })

    // Try auto-connect
    provider
      .request({ method: 'eth_requestAccounts' })
      .then((accounts) => setAccount(accounts[0]))
      .catch(() => console.log('Not connected'))

    return () => {
      provider.removeAllListeners()
    }
  }, [])

  const connectWallet = async () => {
    setLoading(true)
    try {
      await provider.login()
      const accounts = await provider.request({
        method: 'eth_requestAccounts'
      })
      setAccount(accounts[0])
    } catch (error) {
      console.error('Failed to connect:', error)
    } finally {
      setLoading(false)
    }
  }

  const sendTransaction = async () => {
    setLoading(true)
    try {
      const txHash = await provider.request({
        method: 'eth_sendTransaction',
        params: [
          {
            from: account,
            to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
            value: '0x0'
          }
        ]
      })
      console.log('Transaction sent:', txHash)
    } catch (error) {
      console.error('Transaction failed:', error)
    } finally {
      setLoading(false)
    }
  }

  const disconnect = async () => {
    setLoading(true)
    try {
      await provider.logout()
      setAccount(null)
      setChainId(null)
    } catch (error) {
      console.error('Failed to disconnect:', error)
    } finally {
      setLoading(false)
    }
  }

  if (!provider) {
    return (
      <SafeAreaProvider>
        <View style={styles.centerContainer}>
          <ActivityIndicator size='large' />
          <Text>Initializing...</Text>
        </View>
      </SafeAreaProvider>
    )
  }

  return (
    <SafeAreaProvider>
      <View style={styles.container}>
        <Text style={styles.title}>WaaP SDK Demo</Text>

        {account ? (
          <View style={styles.section}>
            <Text style={styles.label}>Account:</Text>
            <Text style={styles.value}>
              {account.slice(0, 6)}...{account.slice(-4)}
            </Text>

            {chainId && (
              <>
                <Text style={styles.label}>Chain ID:</Text>
                <Text style={styles.value}>{chainId}</Text>
              </>
            )}

            <View style={styles.buttonSpacing}>
              <Button
                title='Send Transaction'
                onPress={sendTransaction}
                disabled={loading}
              />
            </View>
            <Button title='Disconnect' onPress={disconnect} disabled={loading} />
          </View>
        ) : (
          <Button
            title='Connect Wallet'
            onPress={connectWallet}
            disabled={loading}
          />
        )}

        {loading && <ActivityIndicator style={{ marginTop: 20 }} />}

        <WalletComponent />
      </View>
    </SafeAreaProvider>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20
  },
  centerContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20
  },
  section: {
    width: '100%',
    padding: 16,
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    marginBottom: 20
  },
  label: {
    fontSize: 14,
    color: '#666',
    marginTop: 8
  },
  value: {
    fontSize: 16,
    fontWeight: '500',
    marginBottom: 8
  },
  buttonSpacing: {
    marginBottom: 12
  }
})
```

</details>

<br/>

## Troubleshooting

### Metro bundler errors

If you see module resolution errors for `viem` or `ox`:

```javascript
// metro.config.js
const { getDefaultConfig } = require('expo/metro-config')
const {
  withWaapMetroConfig
} = require('@human.tech/waap-sdk-react-native/metro-plugin')

const config = getDefaultConfig(__dirname)
module.exports = withWaapMetroConfig(config)
```

### Authentication not working

- **Missing SafeAreaProvider:** Ensure your app is wrapped with `<SafeAreaProvider>`:
  ```typescript
  import { SafeAreaProvider } from 'react-native-safe-area-context'
  
  return (
    <SafeAreaProvider>
      <YourApp />
    </SafeAreaProvider>
  )
  ```

- **Missing native browser:** Ensure you create and pass the browser function correctly:
  
  **For Expo:**
  ```typescript
  import * as WebBrowser from 'expo-web-browser'
  import { createExpoNativeBrowser } from '@human.tech/waap-sdk-react-native'
  
  const provider = initWaapNative({
    nativeBrowser: createExpoNativeBrowser(WebBrowser),
    // ... other options
  })
  ```
  
  **For Bare React Native:**
  ```typescript
  import InAppBrowser from 'react-native-inappbrowser-reborn'
  import { createInAppNativeBrowser } from '@human.tech/waap-sdk-react-native'
  
  const provider = initWaapNative({
    nativeBrowser: createInAppNativeBrowser(InAppBrowser),
    // ... other options
  })
  ```

- **iOS:** Verify `associatedDomains` includes `applinks:waap.xyz` and bundle ID matches `project.appId`
- **Android:** Check `android:autoVerify="true"` is set and package name matches `project.appId`
- Test on real devices (simulators have limited Universal Link support)
- Confirm `project.appId` exactly matches your bundle ID/package name

[→ More troubleshooting tips](https://docs.wallet.human.tech/support)

## Resources

- [📘 Full Documentation](https://docs.wallet.human.tech/)
- [🎮 Interactive Playground](https://docs.wallet.human.tech/playground)
- [💡 Examples & Templates](https://docs.wallet.human.tech/examples)
- [🔐 Security & Architecture](https://docs.wallet.human.tech/architecture-security-model/architecture)
- [💬 Developer Telegram](https://t.me/+YjZwY_a6EqU2NzNh)
- [💼 GitHub Issues](https://github.com/holonym-foundation/silk)

## License

MIT