The Wallet Providers module provides a comprehensive, unified interface for multiple wallet solutions in React Native Solana applications. It abstracts away the complexity of different wallet providers while maintaining their unique features and security standards.

Core Features

Multi-Provider Support

Unified interface for Privy, Dynamic, Turnkey, and Mobile Wallet Adapter integration

Transaction Management

Complete transaction lifecycle management with signing, simulation, and status tracking

Authentication & Security

Robust authentication flows with social login, biometrics, and institutional-grade security

Developer Experience

Simple, consistent APIs that work across all wallet providers with minimal configuration

Supported Wallet Providers

Social Login & Embedded Wallets - Perfect for mainstream user adoption

import { EmbeddedWalletAuth } from '@/modules/wallet-providers';

function PrivyWalletIntegration() {
  return (
    <EmbeddedWalletAuth
      config={{
        appId: process.env.PRIVY_APP_ID,
        clientId: process.env.PRIVY_CLIENT_ID,
        loginMethods: ['email', 'google', 'apple', 'twitter'],
        appearance: {
          theme: 'dark',
          accentColor: '#9945FF',
          logo: 'https://your-logo.png'
        }
      }}
      onConnect={(wallet) => {
        console.log('Privy wallet connected:', wallet.address);
      }}
      onDisconnect={() => {
        console.log('Privy wallet disconnected');
      }}
    />
  );
}

Features:

  • OAuth authentication (Google, Apple, Twitter, Discord)
  • Email/password login with verification
  • Phone number authentication
  • Custodial and non-custodial wallet options
  • Cross-app wallet recovery
  • Embedded wallet creation for users without existing wallets

Core Hooks

useWallet - Universal Wallet Interface

The primary hook for wallet interactions across all providers:

import { useWallet } from '@/modules/wallet-providers';

function UniversalWalletComponent() {
  const {
    // Connection state
    wallet,
    connected,
    connecting,
    publicKey,
    
    // Provider information
    provider,
    providerName,
    
    // Transaction functions
    sendTransaction,
    signTransaction,
    signAllTransactions,
    signMessage,
    
    // Connection management
    connect,
    disconnect,
    
    // Utility functions
    getBalance,
    requestAirdrop, // devnet only
    
    // Error handling
    error,
    clearError
  } = useWallet();

  const handleSendTransaction = async (transaction) => {
    try {
      clearError();
      const signature = await sendTransaction(transaction, connection, {
        simulate: true,
        commitment: 'confirmed',
        skipPreflight: false
      });
      
      console.log('Transaction sent:', signature);
      return signature;
    } catch (error) {
      console.error('Transaction failed:', error);
      throw error;
    }
  };

  if (!connected) {
    return (
      <View style={styles.connectPrompt}>
        <Text style={styles.title}>Connect Your Wallet</Text>
        <Button title="Connect" onPress={connect} />
      </View>
    );
  }

  return (
    <View style={styles.walletInfo}>
      <Text style={styles.provider}>Provider: {providerName}</Text>
      <Text style={styles.address}>
        Address: {publicKey?.toString().slice(0, 8)}...{publicKey?.toString().slice(-8)}
      </Text>
      <Button title="Disconnect" onPress={disconnect} />
    </View>
  );
}

useAuth - Authentication Management

Unified authentication interface across all providers:

import { useAuth } from '@/modules/wallet-providers';

function AuthenticationComponent() {
  const {
    // Authentication state
    isAuthenticated,
    user,
    loading,
    error,
    
    // Authentication actions
    login,
    logout,
    
    // User management
    updateProfile,
    linkAccount,
    unlinkAccount,
    
    // Session management
    refreshSession,
    getSession
  } = useAuth();

  const handleSocialLogin = async (provider) => {
    try {
      await login({
        provider, // 'google', 'apple', 'twitter', etc.
        redirectUrl: 'your-app://auth-callback',
        scopes: ['email', 'profile']
      });
    } catch (error) {
      console.error('Login failed:', error);
    }
  };

  const handleEmailLogin = async (email, password) => {
    try {
      await login({
        provider: 'email',
        email,
        password
      });
    } catch (error) {
      console.error('Email login failed:', error);
    }
  };

  if (loading) {
    return <LoadingSpinner />;
  }

  if (!isAuthenticated) {
    return (
      <View style={styles.loginContainer}>
        <Text style={styles.title}>Sign In</Text>
        
        <SocialLoginButtons onLogin={handleSocialLogin} />
        
        <EmailLoginForm onLogin={handleEmailLogin} />
      </View>
    );
  }

  return (
    <View style={styles.userProfile}>
      <Text style={styles.welcome}>Welcome, {user?.email || user?.name}!</Text>
      <Button title="Logout" onPress={logout} />
    </View>
  );
}

Transaction Management

TransactionService - Comprehensive Transaction Handling

import { TransactionService } from '@/modules/wallet-providers';

// Send transaction with full configuration
const sendAdvancedTransaction = async (transaction, options = {}) => {
  try {
    const result = await TransactionService.sendTransaction(
      transaction,
      connection,
      {
        // Simulation options
        simulate: true,
        simulationCommitment: 'processed',
        
        // Execution options
        commitment: 'confirmed',
        skipPreflight: false,
        maxRetries: 3,
        
        // Fee configuration
        priorityFee: 0.001, // SOL
        
        // Callbacks
        statusCallback: (status) => {
          console.log('Transaction status:', status);
          // Update UI with progress
        },
        
        confirmationCallback: (signature) => {
          console.log('Transaction confirmed:', signature);
          TransactionService.showSuccess(signature);
        },
        
        errorCallback: (error) => {
          console.error('Transaction error:', error);
          TransactionService.showError(error.message);
        }
      }
    );
    
    return result;
  } catch (error) {
    TransactionService.showError('Transaction failed: ' + error.message);
    throw error;
  }
};

// Batch transaction sending
const sendBatchTransactions = async (transactions) => {
  try {
    const results = await TransactionService.sendBatch(
      transactions,
      connection,
      {
        concurrent: false, // Send sequentially
        stopOnError: true,
        batchSize: 5
      }
    );
    
    console.log('Batch completed:', results);
    return results;
  } catch (error) {
    console.error('Batch failed:', error);
    throw error;
  }
};

Provider Initialization

import { 
  initDynamicClient,
  initPrivyClient,
  initTurnkeyClient,
  getDynamicClient 
} from '@/modules/wallet-providers';

// Initialize all providers at app startup
const initializeWalletProviders = async () => {
  try {
    // Initialize Dynamic
    if (process.env.DYNAMIC_ENVIRONMENT_ID) {
      await initDynamicClient({
        environmentId: process.env.DYNAMIC_ENVIRONMENT_ID,
        walletConnectors: ['solana'],
        options: {
          initialAuthenticationMode: 'connect-only'
        }
      });
    }
    
    // Initialize Privy
    if (process.env.PRIVY_APP_ID) {
      await initPrivyClient({
        appId: process.env.PRIVY_APP_ID,
        clientId: process.env.PRIVY_CLIENT_ID,
        config: {
          loginMethods: ['email', 'google', 'apple'],
          appearance: {
            theme: 'dark',
            accentColor: '#9945FF'
          }
        }
      });
    }
    
    // Initialize Turnkey
    if (process.env.TURNKEY_ORGANIZATION_ID) {
      await initTurnkeyClient({
        apiKey: process.env.TURNKEY_API_PUBLIC_KEY,
        organizationId: process.env.TURNKEY_ORGANIZATION_ID,
        rpId: process.env.TURNKEY_RP_ID,
        rpName: process.env.TURNKEY_RP_NAME
      });
    }
    
    console.log('All wallet providers initialized');
  } catch (error) {
    console.error('Provider initialization failed:', error);
  }
};

Quick Start Examples

import { WalletProvider, useWallet } from '@/modules/wallet-providers';

function App() {
  return (
    <WalletProvider
      config={{
        autoConnect: true,
        providers: ['privy', 'dynamic', 'turnkey', 'mwa'],
        defaultProvider: 'privy'
      }}
    >
      <MainApp />
    </WalletProvider>
  );
}

function MainApp() {
  const { connected, connect, disconnect } = useWallet();
  
  return (
    <View style={styles.container}>
      {connected ? (
        <ConnectedView />
      ) : (
        <WalletSelectionScreen />
      )}
    </View>
  );
}

function WalletSelectionScreen() {
  const { connect } = useWallet();
  
  const walletOptions = [
    { name: 'Privy', provider: 'privy', icon: '🔐', description: 'Social login' },
    { name: 'Dynamic', provider: 'dynamic', icon: '⚡', description: 'Multi-chain' },
    { name: 'Turnkey', provider: 'turnkey', icon: '🏛️', description: 'Institutional' },
    { name: 'Mobile Wallet', provider: 'mwa', icon: '📱', description: 'Native wallets' }
  ];
  
  return (
    <View style={styles.walletSelection}>
      <Text style={styles.title}>Choose Your Wallet</Text>
      {walletOptions.map((option) => (
        <TouchableOpacity
          key={option.provider}
          style={styles.walletOption}
          onPress={() => connect(option.provider)}
        >
          <Text style={styles.walletIcon}>{option.icon}</Text>
          <View style={styles.walletInfo}>
            <Text style={styles.walletName}>{option.name}</Text>
            <Text style={styles.walletDescription}>{option.description}</Text>
          </View>
        </TouchableOpacity>
      ))}
    </View>
  );
}

Error Handling & Recovery

common_issues
object
function RobustWalletErrorHandling() {
  const { connect, sendTransaction } = useWallet();
  const [retryCount, setRetryCount] = useState(0);
  const maxRetries = 3;

  const connectWithRetry = async (provider) => {
    try {
      await connect(provider);
      setRetryCount(0); // Reset on success
    } catch (error) {
      console.error('Connection attempt failed:', error);
      
      if (retryCount < maxRetries) {
        setRetryCount(prev => prev + 1);
        const delay = 1000 * Math.pow(2, retryCount); // Exponential backoff
        setTimeout(() => connectWithRetry(provider), delay);
      } else {
        // Show user-friendly error
        Alert.alert(
          'Connection Failed',
          'Unable to connect to wallet. Please check your internet connection and try again.',
          [
            { text: 'OK', onPress: () => setRetryCount(0) }
          ]
        );
      }
    }
  };

  const sendTransactionWithFallback = async (transaction) => {
    try {
      // Try with simulation first
      return await sendTransaction(transaction, connection, {
        simulate: true,
        commitment: 'confirmed'
      });
    } catch (simulationError) {
      // If simulation fails, try without simulation
      console.warn('Simulation failed, trying without:', simulationError);
      
      try {
        return await sendTransaction(transaction, connection, {
          simulate: false,
          skipPreflight: true,
          commitment: 'confirmed'
        });
      } catch (executionError) {
        // Provide specific error handling based on error type
        if (executionError.message.includes('insufficient funds')) {
          throw new Error('Insufficient SOL balance for transaction fees');
        } else if (executionError.message.includes('blockhash')) {
          throw new Error('Transaction expired. Please try again.');
        } else {
          throw new Error('Transaction failed: ' + executionError.message);
        }
      }
    }
  };

  return { connectWithRetry, sendTransactionWithFallback };
}

Security Best Practices

Private Key Security: Never store or transmit private keys. All providers handle key management securely.

Transaction Validation: Always simulate transactions before execution to catch errors early.

function SecureWalletOperations() {
  const { signMessage, sendTransaction } = useWallet();

  const secureSignMessage = async (message) => {
    try {
      // Always show user what they're signing
      const confirmed = await showSigningConfirmation(message);
      if (!confirmed) {
        throw new Error('User cancelled signing');
      }

      const signature = await signMessage(new TextEncoder().encode(message));
      return signature;
    } catch (error) {
      console.error('Secure signing failed:', error);
      throw error;
    }
  };

  const secureTransactionExecution = async (transaction) => {
    try {
      // Validate transaction contents
      const validation = await validateTransactionSecurity(transaction);
      if (!validation.safe) {
        throw new Error('Transaction failed security validation: ' + validation.reason);
      }

      // Show user transaction details
      const confirmed = await showTransactionConfirmation(transaction);
      if (!confirmed) {
        throw new Error('User cancelled transaction');
      }

      // Execute with monitoring
      return await sendTransaction(transaction, connection, {
        simulate: true,
        commitment: 'confirmed'
      });
    } catch (error) {
      console.error('Secure transaction failed:', error);
      throw error;
    }
  };

  return { secureSignMessage, secureTransactionExecution };
}

Performance Optimization

Provider Lazy Loading: Load wallet provider SDKs only when needed to reduce initial bundle size.

function useOptimizedWalletLoading() {
  const [loadedProviders, setLoadedProviders] = useState(new Set());

  const lazyLoadProvider = async (provider) => {
    if (loadedProviders.has(provider)) {
      return;
    }

    try {
      switch (provider) {
        case 'privy':
          const { initPrivyClient } = await import('@/modules/wallet-providers/services/privy');
          await initPrivyClient(privyConfig);
          break;
        
        case 'dynamic':
          const { initDynamicClient } = await import('@/modules/wallet-providers/services/dynamic');
          await initDynamicClient(dynamicConfig);
          break;
        
        case 'turnkey':
          const { initTurnkeyClient } = await import('@/modules/wallet-providers/services/turnkey');
          await initTurnkeyClient(turnkeyConfig);
          break;
      }

      setLoadedProviders(prev => new Set(prev.add(provider)));
    } catch (error) {
      console.error(`Failed to load ${provider} provider:`, error);
      throw error;
    }
  };

  return { lazyLoadProvider, loadedProviders };
}

Integration with Other Modules

API Reference

For detailed API documentation, see:


The Wallet Providers module serves as the foundation for all blockchain interactions in your Solana application, providing secure, user-friendly wallet integration that scales from mainstream users to institutional clients.