Skip to content

TrueCarry/walletkit-react-native-test

Repository files navigation

ton-app-native

A demonstration of integrating @ton/walletkit into a React Native application using Expo. This project shows how to properly setup the required polyfills and configure WalletKit for cross-platform mobile development.

Features

  • Full @ton/walletkit integration with React Native
  • Cross-platform storage adapter (SecureStore on native, fallback for web)
  • TON Connect support with bridge communication
  • Wallet management (create, restore, delete)
  • Transaction signing and approval flow
  • Balance checking

Prerequisites

  • Node.js 18+
  • Expo CLI
  • iOS Simulator or Android Emulator (or physical device)

Required Polyfills

@ton/walletkit depends on several Node.js APIs that are not available in React Native. This project implements three critical polyfills:

1. Buffer Polyfill

Located in lib/polyfills/buffer.js, this polyfill:

  • Installs the buffer package
  • Sets up global Buffer object for both global and globalThis
  • Enhances Buffer.prototype.subarray() to return a Buffer instead of plain Uint8Array (required for @ton/core compatibility)
import { Buffer as BufferPolyfill } from 'buffer';

globalThis.Buffer = BufferPolyfill;
global.Buffer = BufferPolyfill;

// Enhance subarray to return Buffer
const originalSubarray = Buffer.prototype.subarray;
Buffer.prototype.subarray = function(start, end) {
  const view = originalSubarray.call(this, start, end);
  return Buffer.from(view.buffer, view.byteOffset, view.byteLength);
};

2. Crypto Polyfill

Located in lib/polyfills/crypto.js, provides:

  • crypto.getRandomValues() via react-native-get-random-values
  • crypto.randomUUID() via expo-crypto
import { randomUUID } from 'expo-crypto';
import 'react-native-get-random-values';

if (typeof global.crypto === 'undefined') {
  global.crypto = {};
}
global.crypto.randomUUID = randomUUID;

3. EventSource Polyfill

Located in lib/polyfills/eventsource.js, enables Server-Sent Events (SSE) required for TON Connect bridge.

All polyfills are loaded in lib/polyfills/index.ts and imported in the app entry point (lib/index.js) before any other code runs.

Setup

1. Install Dependencies

npm install

Key dependencies:

  • @ton/walletkit - TON wallet integration SDK
  • buffer - Buffer polyfill
  • react-native-get-random-values - Crypto random values
  • expo-crypto - UUID generation
  • react-native-sse - EventSource for bridge communication
  • expo-secure-store - Secure storage for native platforms
  • react-native-fast-pbkdf2 - PBKDF2 implementation for key derivation

2. Setup Polyfills

Create the polyfill structure in your project:

lib/
├── polyfills/
│   ├── buffer.js      # Buffer polyfill with subarray fix
│   ├── crypto.js      # Crypto API polyfill
│   ├── eventsource.js # EventSource polyfill
│   └── index.ts       # Import all polyfills
└── index.js           # Entry point (imports polyfills first)

Import polyfills before any other code in your app entry point:

// lib/index.js
import 'expo-router/entry';
import './polyfills/index'; // Must be imported first

3. Create Storage Adapter

Implement a storage adapter compatible with WalletKit's interface. See lib/SecureStoreAdapter.ts for a example implementation:

import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';

export class SecureStoreAdapter {
  private prefix: string;
  private fallbackStorage: Map<string, any> = new Map();
  private useSecureStore: boolean = Platform.OS !== 'web';

  async get<T>(key: string): Promise<T | null> {
    const fullKey = this.makeKey(key);
    
    if (this.useSecureStore) {
      const available = await SecureStore.isAvailableAsync();
      if (available) {
        const value = await SecureStore.getItemAsync(fullKey);
        return value ? JSON.parse(value) : null;
      }
    }
    
    return this.fallbackStorage.get(fullKey) || null;
  }

  async set<T>(key: string, value: T): Promise<void> {
    const fullKey = this.makeKey(key);
    const serialized = JSON.stringify(value);
    
    if (this.useSecureStore) {
      const available = await SecureStore.isAvailableAsync();
      if (available) {
        await SecureStore.setItemAsync(fullKey, serialized);
        return;
      }
    }
    
    this.fallbackStorage.set(fullKey, value);
  }

  // ... implement remove() and clear() similarly
}

4. Initialize WalletKit

import { TonWalletKit, CHAIN, Signer, WalletV5R1Adapter } from '@ton/walletkit';
import { SecureStoreAdapter } from './lib/SecureStoreAdapter';

// Create storage adapter
const storage = new SecureStoreAdapter({ prefix: 'tonwalletkit:' });

// Initialize WalletKit
const kit = new TonWalletKit({
  storage,
  bridge: {
    bridgeUrl: 'https://bridge.tonapi.io/bridge',
    heartbeatInterval: 15000,
    reconnectInterval: 15000,
  },
  network: CHAIN.MAINNET,
});

// Wait for initialization
await kit.waitForReady();

// Create wallet from mnemonic
const signer = await Signer.fromMnemonic(mnemonicPhrase);
const wallet = await WalletV5R1Adapter.create(signer, {
  client: kit.getApiClient(),
  network: CHAIN.MAINNET,
});

// Add wallet to kit
await kit.addWallet(wallet);

5. Setup Event Handlers

Handle TON Connect events:

// Connection requests
kit.onConnectRequest((event) => {
  const wallets = kit.getWallets();
  event.walletAddress = wallets[0].getAddress();
  kit.approveConnectRequest(event);
});

// Transaction requests
kit.onTransactionRequest((event) => {
  // Show approval UI to user
  Alert.alert('Approve Transaction?', '', [
    {
      text: 'Approve',
      onPress: () => kit.approveTransactionRequest(event),
    },
    {
      text: 'Cancel',
      onPress: () => kit.rejectTransactionRequest(event),
    },
  ]);
});

// Sign data requests
kit.onSignDataRequest((event) => {
  // Handle sign data request
});

// Disconnect
kit.onDisconnect(() => {
  // Handle disconnect
});

Running the App

Development

npx expo start

Then press:

  • i for iOS simulator
  • a for Android emulator
  • w for web

Or:

# iOS
npx expo run:ios

# Android
npx expo run:android

Key Files

  • lib/polyfills/ - All required polyfills for @ton/walletkit
  • lib/SecureStoreAdapter.ts - Cross-platform storage adapter
  • app/(tabs)/index.tsx - Main WalletKit integration example
  • app.json - Expo configuration with required plugins

Important Notes

  1. Polyfills must be loaded first - Import them in your entry point before any other code
  2. Buffer.subarray enhancement is critical - Without it, @ton/core operations will fail
  3. EventSource is required for bridge - TON Connect won't work without it
  4. SecureStore is iOS/Android only - Provide a fallback (memory or localStorage) for web
  5. Development builds required - Native modules prevent using Expo Go

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors