Skip to content

tetherto/wdk-react-native-provider

@tetherto/wdk-react-native-provider

A React Native library providing wallet context and WDK (Wallet Development Kit) service integration for building secure, multi-chain cryptocurrency wallets.

Features

  • Multi-chain Support: Bitcoin, Ethereum, Polygon, Arbitrum, TON, Solana, and Tron
  • Multi-asset Management: BTC, USDT, XAUT, and more
  • Secure Seed Management: Encrypted seed phrase storage using native keychain
  • React Context API: Easy-to-use wallet context provider and hooks
  • Account Management: Create, import, and unlock wallets
  • Balance & Transactions: Real-time balance updates and transaction history
  • Send & Quote: Transaction sending and fee estimation
  • TypeScript Support: Full type definitions included

Requirements

  • Android minSdkVersion: 29 or higher
  • iOS Deployment Target: 15.1 or higher
  • React Native: 0.81.0+

Installation

npm install @tetherto/wdk-react-native-provider

Android Configuration

The library requires Android minSdkVersion 29 to properly run react-native-bare-kit.

For Expo projects with prebuild:

Add to your app.json or app.config.js:

{
  "expo": {
    "plugins": [
      [
        "expo-build-properties",
        {
          "android": {
            "minSdkVersion": 29
          }
        }
      ]
    ]
  }
}

For bare React Native projects:

Update android/build.gradle:

buildscript {
    ext {
        minSdkVersion = 29
        // ... other config
    }
}

Peer Dependencies

This library requires several peer dependencies. Install them using:

npm install \
  @craftzdog/react-native-buffer \
  @react-native-async-storage/async-storage \
  @tetherto/pear-wrk-wdk \
  @tetherto/wdk-secret-manager \
  b4a \
  bip39 \
  browserify-zlib \
  decimal.js \
  events \
  http2-wrapper \
  https-browserify \
  nice-grpc-web \
  path-browserify \
  process \
  querystring-es3 \
  react-native-bare-kit \
  react-native-crypto \
  react-native-device-info \
  react-native-get-random-values \
  react-native-keychain \
  react-native-tcp-socket \
  react-native-url-polyfill \
  sodium-javascript \
  stream-browserify \
  stream-http

Metro Configuration

The library requires Node.js core module polyfills for React Native. Configure your Metro bundler using the provided helper function.

For Expo projects:

Update your metro.config.js:

const { getDefaultConfig } = require('expo/metro-config');
const { configureMetroForWDK } = require('@tetherto/wdk-react-native-provider/metro-polyfills');

const config = getDefaultConfig(__dirname);
const configWdk = configureMetroForWDK(config);

module.exports = configWdk;

Manual configuration (if needed):

If you prefer to manually configure the polyfills:

const { getDefaultConfig } = require('expo/metro-config');
const { getMetroPolyfills } = require('@tetherto/wdk-react-native-provider/metro-polyfills');

const config = getDefaultConfig(__dirname);

config.resolver.extraNodeModules = {
  ...config.resolver.extraNodeModules,
  ...getMetroPolyfills(),
};

module.exports = config;

Note: Runtime polyfills for Buffer, process, and crypto are automatically initialized when you import from @tetherto/wdk-react-native-provider. No additional setup is required.

Quick Start

1. Setup the WalletProvider

Wrap your app with the WalletProvider and provide the required configuration.

For Expo Router projects:

Add the provider to your app/_layout.tsx file to make the useWallet hook accessible throughout your app:

// app/_layout.tsx
import { WalletProvider } from '@tetherto/wdk-react-native-provider';
import { Stack } from 'expo-router';

// Define your chain configurations
const CHAINS_CONFIG = {
  ethereum: {
    chainId: 1,
    blockchain: 'ethereum',
    provider: 'https://mainnet.gateway.tenderly.co/YOUR_KEY',
    bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
    transferMaxFee: 5000000,
    swapMaxFee: 5000000,
    bridgeMaxFee: 5000000,
    paymasterToken: {
      address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
    },
  },
  bitcoin: {
    host: 'api.ordimint.com',
    port: 50001,
  },
  // ... add other chains as needed
};

export default function RootLayout() {
  return (
    <WalletProvider
      config={{
        indexer: {
          apiKey: 'your-api-key-here',
          url: 'https://your-indexer-url.com',
        },
        chains: CHAINS_CONFIG,
        enableCaching: true, // Optional: enable caching for better performance
      }}
    >
      <Stack />
    </WalletProvider>
  );
}

For standard React Native projects:

Wrap your root component:

// App.tsx
import { WalletProvider } from '@tetherto/wdk-react-native-provider';

const CHAINS_CONFIG = {
  ethereum: {
    chainId: 1,
    blockchain: 'ethereum',
    provider: 'https://mainnet.gateway.tenderly.co/YOUR_KEY',
    bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
    transferMaxFee: 5000000,
    swapMaxFee: 5000000,
    bridgeMaxFee: 5000000,
    paymasterToken: {
      address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
    },
  },
  bitcoin: {
    host: 'api.ordimint.com',
    port: 50001,
  },
  // ... other chains
};

function App() {
  return (
    <WalletProvider
      config={{
        indexer: {
          apiKey: 'your-api-key-here',
          url: 'https://your-indexer-url.com',
        },
        chains: CHAINS_CONFIG,
        enableCaching: true, // Optional: enable caching for balances and transactions
      }}
    >
      <YourApp />
    </WalletProvider>
  );
}

2. Use the Wallet Context

Access wallet functionality using the useWallet hook:

import { useWallet } from '@tetherto/wdk-react-native-provider';

function WalletScreen() {
  const {
    wallet,
    balances,
    transactions,
    isLoading,
    isInitialized,
    isUnlocked,
    createWallet,
    unlockWallet,
    refreshWalletBalance,
    refreshTransactions,
  } = useWallet();

  // Create a new wallet
  const handleCreateWallet = async () => {
    try {
      const wallet = await createWallet({
        name: 'Imported Wallet',
        mnemonic: 'your twelve word seed phrase goes here',
      });
      console.log('Wallet created:', wallet);
    } catch (error) {
      console.error('Failed to create wallet:', error);
    }
  };

  // Unlock wallet
  const handleUnlockWallet = async () => {
    try {
      await unlockWallet();
      console.log('Wallet unlocked');
    } catch (error) {
      console.error('Failed to unlock wallet:', error);
    }
  };

  if (!isInitialized) {
    return <Text>Initializing...</Text>;
  }

  if (!wallet) {
    return (
      <View>
        <Button title="Create Wallet" onPress={handleCreateWallet} />
        <Button title="Import Wallet" onPress={handleImportWallet} />
      </View>
    );
  }

  if (!isUnlocked) {
    return <Button title="Unlock Wallet" onPress={handleUnlockWallet} />;
  }

  return (
    <View>
      <Text>Wallet Name: {wallet.name}</Text>
      <Button title="Refresh Balance" onPress={refreshWalletBalance} />
      <Button title="Refresh Transactions" onPress={refreshTransactions} />
    </View>
  );
}

API Reference

WalletProvider

The main provider component that manages wallet state.

Props:

  • config.indexer (object, required): Indexer service configuration
    • config.indexer.apiKey (string, required): API key for the indexer service
    • config.indexer.url (string, required): URL of the indexer service
    • config.indexer.version (string, optional): API version (defaults to 'v1')
  • config.chains (ChainsConfig, required): Chain configuration object containing network-specific settings
  • config.enableCaching (boolean, optional): Enable caching for balances and transactions to improve performance

See Chain Configuration for detailed configuration options.

useWallet()

Hook to access wallet context and functionality.

Returns:

{
  // State
  wallet?: Wallet | null;
  addresses?: AddressMap;
  balances: {
    list: Amount[];
    map: BalanceMap;
    isLoading: boolean;
  };
  transactions: {
    list: Transaction[];
    map: TransactionMap;
    isLoading: boolean;
  };
  isLoading: boolean;
  error: string | null;
  isInitialized: boolean;
  isUnlocked: boolean;

  // Actions
  createWallet: (params: { name: string; mnemonic?: string }) => Promise<Wallet | null>;
  clearWallet: () => Promise<void>;
  clearError: () => void;
  refreshWalletBalance: () => Promise<void>;
  refreshTransactions: () => Promise<void>;
  unlockWallet: () => Promise<boolean | undefined>;
}

WDKService

Low-level service for direct wallet operations. Available as a singleton.

import { WDKService } from '@tetherto/wdk-react-native-provider';

// Initialize WDK
await WDKService.initialize();

// Create seed
const seed = await WDKService.createSeed({ prf: 'passkey' });

// Import seed phrase
await WDKService.importSeedPhrase({
  prf: 'passkey',
  seedPhrase: 'your mnemonic here',
});

// Create wallet
const wallet = await WDKService.createWallet({
  walletName: 'My Wallet',
  prf: 'passkey',
});

// Get balances
const balances = await WDKService.resolveWalletBalances(
  enabledAssets,
  addressMap
);

// Send transaction
const result = await WDKService.sendByNetwork(
  NetworkType.ETHEREUM,
  0, // account index
  100, // amount
  '0x...', // recipient address
  AssetTicker.USDT
);

Chain Configuration

The library supports multiple blockchain networks, each with its own configuration structure.

Chains Configuration Structure

The chains configuration object supports the following blockchain networks:

const chains = {
  ethereum?: EVMChainConfig;
  arbitrum?: EVMChainConfig;
  polygon?: EVMChainConfig;
  ton?: TONChainConfig;
  bitcoin?: BitcoinChainConfig;
  tron?: TronChainConfig;
}

EVM Chain Configuration

For Ethereum, Polygon, and Arbitrum:

const ethereumConfig = {
  chainId: 1,
  blockchain: 'ethereum',
  provider: 'https://mainnet.gateway.tenderly.co/YOUR_KEY',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  transferMaxFee: 5000000,
  swapMaxFee: 5000000,
  bridgeMaxFee: 5000000,
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  },
  safeModulesVersion: '0.3.0', // Optional, for Polygon
};

TON Chain Configuration

const tonConfig = {
  tonApiClient: {
    url: 'https://tonapi.io',
  },
  tonClient: {
    url: 'https://toncenter.com/api/v2/jsonRPC',
  },
  paymasterToken: {
    address: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',
  },
  transferMaxFee: 1000000000,
};

Bitcoin Chain Configuration

const bitcoinConfig = {
  host: 'api.ordimint.com',
  port: 50001,
};

Tron Chain Configuration

const tronConfig = {
  chainId: 3448148188,
  provider: 'https://trongrid.io',
  gasFreeProvider: 'https://gasfree.io',
  apiKey: 'your-api-key',
  apiSecret: 'your-api-secret',
  serviceProvider: 'TKtWbdzEq5ss9vTS9kwRhBp5mXmBfBns3E',
  verifyingContract: 'THQGuFzL87ZqhxkgqYEryRAd7gqFqL5rdc',
  transferMaxFee: 10000000,
  swapMaxFee: 1000000,
  bridgeMaxFee: 1000000,
  paymasterToken: {
    address: 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf',
  },
};

Complete Configuration Example

import { WalletProvider } from '@tetherto/wdk-react-native-provider';

const chains = {
  ethereum: {
    chainId: 1,
    blockchain: 'ethereum',
    provider: 'https://mainnet.gateway.tenderly.co/YOUR_KEY',
    bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
    transferMaxFee: 5000000,
    swapMaxFee: 5000000,
    bridgeMaxFee: 5000000,
    paymasterToken: {
      address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
    },
  },
  polygon: {
    chainId: 137,
    blockchain: 'polygon',
    provider: 'https://polygon.gateway.tenderly.co/YOUR_KEY',
    bundlerUrl: 'https://api.candide.dev/public/v3/polygon',
    paymasterUrl: 'https://api.candide.dev/public/v3/polygon',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
    transferMaxFee: 5000000,
    swapMaxFee: 5000000,
    bridgeMaxFee: 5000000,
    paymasterToken: {
      address: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f',
    },
    safeModulesVersion: '0.3.0',
  },
  arbitrum: {
    chainId: 42161,
    blockchain: 'arbitrum',
    provider: 'https://arbitrum.gateway.tenderly.co/YOUR_KEY',
    bundlerUrl: 'https://api.candide.dev/public/v3/arbitrum',
    paymasterUrl: 'https://api.candide.dev/public/v3/arbitrum',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
    transferMaxFee: 5000000,
    swapMaxFee: 5000000,
    bridgeMaxFee: 5000000,
    paymasterToken: {
      address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
    },
  },
  ton: {
    tonApiClient: {
      url: 'https://tonapi.io',
    },
    tonClient: {
      url: 'https://toncenter.com/api/v2/jsonRPC',
    },
    paymasterToken: {
      address: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',
    },
    transferMaxFee: 1000000000,
  },
  bitcoin: {
    host: 'api.ordimint.com',
    port: 50001,
  },
  tron: {
    chainId: 3448148188,
    provider: 'https://trongrid.io',
    gasFreeProvider: 'https://gasfree.io',
    apiKey: 'your-api-key',
    apiSecret: 'your-api-secret',
    serviceProvider: 'TKtWbdzEq5ss9vTS9kwRhBp5mXmBfBns3E',
    verifyingContract: 'THQGuFzL87ZqhxkgqYEryRAd7gqFqL5rdc',
    transferMaxFee: 10000000,
    swapMaxFee: 1000000,
    bridgeMaxFee: 1000000,
    paymasterToken: {
      address: 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf',
    },
  },
};

function App() {
  return (
    <WalletProvider
      config={{
        indexer: {
          apiKey: 'your-indexer-api-key',
          url: 'https://your-indexer-url.com',
        },
        chains,
        enableCaching: true, // Optional: enable caching for better performance
      }}
    >
      <YourApp />
    </WalletProvider>
  );
}

Advanced Usage

Accessing Balances and Transactions

const { wallet, addresses, balances, transactions } = useWallet();

if (wallet) {
  // Addresses
  if (addresses) {
    Object.entries(addresses).forEach(([ticker, addressList]) => {
      console.log(`${ticker}: ${addressList[0]?.value}`);
    });
  }

  // Balances - available as both list and map
  balances.list.forEach(balance => {
    console.log(`${balance.denomination}: ${balance.value}`);
  });

  // Or access by ticker from the map
  const usdtBalance = balances.map.USDT?.[0];
  console.log('USDT Balance:', usdtBalance?.value);

  // Check loading state
  if (balances.isLoading) {
    console.log('Loading balances...');
  }

  // Transactions - available as both list and map
  transactions.list.forEach(tx => {
    console.log('Transaction:', tx);
  });

  // Or access by ticker from the map
  const usdtTransactions = transactions.map.USDT;
  console.log('USDT Transactions:', usdtTransactions);

  // Check loading state
  if (transactions.isLoading) {
    console.log('Loading transactions...');
  }
}

Network Types

import { NetworkType } from '@tetherto/wdk-react-native-provider';

// Available networks:
NetworkType.SEGWIT    // Bitcoin
NetworkType.ETHEREUM  // Ethereum
NetworkType.POLYGON   // Polygon
NetworkType.ARBITRUM  // Arbitrum
NetworkType.TON       // TON
NetworkType.SOLANA    // Solana
NetworkType.TRON      // Tron

Asset Tickers

import { AssetTicker } from '@tetherto/wdk-react-native-provider';

// Available assets:
AssetTicker.BTC   // Bitcoin
AssetTicker.USDT  // Tether USD
AssetTicker.XAUT  // Tether Gold

TypeScript Support

This library is written in TypeScript and includes complete type definitions. Import types as needed:

import type {
  // Provider configuration
  WalletProviderConfig,

  // Wallet types
  Amount,
  Transaction,
  Wallet,

  // Enums (also available as values)
  AssetTicker,
  NetworkType,
} from '@tetherto/wdk-react-native-provider';

Note: Chain configuration types (ChainsConfig, EVMChainConfig, TONChainConfig, etc.) are defined in the underlying @tetherto/pear-wrk-wdk package. TypeScript will infer these types when you use them in the WalletProviderConfig, so explicit imports are typically not needed.

Security Considerations

  • Seed Phrase Storage: Seed phrases are encrypted and stored securely using device-specific encryption
  • Passkey/PRF: Uses device unique ID by default. In production, integrate with biometric authentication
  • Never Log Seeds: Never log or display seed phrases in production code
  • Secure Communication: All API calls use HTTPS and require API keys

Development

See CONTRIBUTING.md for development workflow and guidelines.

Build

npm run prepare

Type Check

npm run typecheck

Lint

npm run lint

Test

npm test

Troubleshooting

Setup Checklist

If you're experiencing issues, verify you've completed all setup steps:

For Expo projects:

  1. ✅ Install the package: npm install @tetherto/wdk-react-native-provider
  2. ✅ Install all peer dependencies (see Peer Dependencies)
  3. ✅ Configure Android minSdkVersion to 29 in app.json:
    {
      "expo": {
        "plugins": [
          ["expo-build-properties", { "android": { "minSdkVersion": 29 } }]
        ]
      }
    }
  4. ✅ Configure Metro polyfills in metro.config.js:
    const { configureMetroForWDK } = require('@tetherto/wdk-react-native-provider/metro-polyfills');
    const config = getDefaultConfig(__dirname);
    const configWdk = configureMetroForWDK(config);
    module.exports = configWdk;
  5. ✅ Add WalletProvider to app/_layout.tsx with proper config
  6. ✅ Use useWallet() hook in your components
  7. ✅ Check isInitialized before creating wallets

For bare React Native projects:

  1. ✅ Install the package and peer dependencies
  2. ✅ Set minSdkVersion to 29 in android/build.gradle
  3. ✅ Configure Metro polyfills in metro.config.js
  4. ✅ Wrap your root component with WalletProvider
  5. ✅ Rebuild native code: npx react-native run-android or npx react-native run-ios

"WDK Manager not initialized"

The WDK service is initialized automatically when the WalletProvider mounts. If you see this error, ensure:

  1. Your component is wrapped with WalletProvider
  2. The provider's config is properly set
  3. You're checking isInitialized before performing wallet operations:
const { isInitialized, createWallet } = useWallet();

if (isInitialized) {
  await createWallet({ name: 'My Wallet' });
}

"No wallet found"

Ensure a wallet has been created or imported before attempting transactions:

const { wallet, createWallet } = useWallet();
if (!wallet) {
  await createWallet({ name: 'My Wallet' });
}

Metro bundler errors or "Unable to resolve module"

If you see errors like Unable to resolve "stream" or other Node.js core modules:

  1. Ensure you've configured Metro polyfills correctly (see Metro Configuration)
  2. Clear Metro cache: npx expo start --clear or npx react-native start --reset-cache
  3. Delete node_modules and reinstall: rm -rf node_modules && npm install
  4. For Expo: Run prebuild if using custom native modules: npx expo prebuild --clean

Android build fails with "Execution failed for task ':app:checkDebugAarMetadata'"

This usually means minSdkVersion is too low. Ensure you've set minSdkVersion to 29:

For Expo:

{
  "expo": {
    "plugins": [
      ["expo-build-properties", { "android": { "minSdkVersion": 29 } }]
    ]
  }
}

Then rebuild: npx expo run:android or npx expo prebuild --clean && npx expo run:android

TypeScript errors about missing types

Some peer dependencies may not have type definitions. You can ignore these by adding to your tsconfig.json:

{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

Apache-2.0


Made with ❤️ by Tether

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 5