React Native Integration
Stacks.js can be integrated into React Native applications to bring blockchain functionality to mobile devices. This tutorial walks you through setting up a React Native project with Expo and configuring it to work with Stacks.js libraries.
Objectives
Set up an Expo project configured for Stacks.js
Install and configure necessary polyfills for React Native
Generate wallets and sign transactions in a mobile app
Handle React Native's JavaScript environment limitations
Build a working Stacks mobile application
Prerequisites
Node.js and npm installed on your development machine
Basic knowledge of React Native and Expo
Familiarity with Stacks.js concepts
iOS or Android device or simulator for testing
Set up the Expo project
Start by creating a new Expo project. The latest version of Expo provides the best compatibility with Stacks.js polyfills.
npx create-expo-app@latest my-stacks-app
cd my-stacks-appThe boilerplate project includes everything needed to start building. Test the initial setup by running the development server.
npm startConnect your mobile device using the Expo Go app and scan the QR code to verify the base project works correctly.
Install necessary dependencies
React Native's JavaScript environment lacks certain Node.js and browser APIs that Stacks.js requires. Install the core Stacks libraries along with necessary polyfills.
npm install @stacks/transactions @stacks/wallet-sdkInstall the polyfill dependencies as dev dependencies to handle missing APIs.
npm install --save-dev buffer process react-native-get-random-values \
text-encoding readable-stream crypto-browserify @peculiar/webcryptoThese polyfills provide:
bufferandprocessfor Node.js globalsreact-native-get-random-valuesfor crypto random valuestext-encodingforTextEncoderandTextDecodercrypto-browserifyand@peculiar/webcryptofor cryptographic functions
Configure Metro bundler
Metro bundler needs configuration to properly resolve Node.js modules. Create a custom Metro configuration file.
npx expo customize metro.config.jsUpdate metro.config.js to map Node.js modules to their React Native-compatible versions.
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.extraNodeModules = {
stream: require.resolve('readable-stream'),
crypto: require.resolve('crypto-browserify'),
};
module.exports = config;This configuration ensures that when Stacks.js requests Node.js modules, Metro provides the appropriate polyfills.
Set up global polyfills
Create a polyfill system to make browser and Node.js APIs available in React Native. This requires modifying the app's entry point.
Create the polyfill file
Create polyfill.js to initialize the required global objects.
import { Buffer } from 'buffer/';
import process from 'process';
import 'react-native-get-random-values';
import { TextDecoder, TextEncoder } from 'text-encoding';
global.process = process;
global.Buffer = Buffer;
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;Create a custom entry point
Create index.js so the app loads polyfills before the UI renders.
import './polyfill';
import { Crypto } from '@peculiar/webcrypto';
Object.assign(global.crypto, new Crypto());
import 'expo-router/entry';Runtime initialization errors: Polyfills must be loaded in separate files as shown. Loading them in the same file can cause runtime initialization errors.
Update package.json
Point the app to use the new entry point.
{
"main": "index.js"
}Implement Stacks functionality
With the environment configured, you can now use Stacks.js in your React Native components. Update the main screen to demonstrate wallet generation and transaction signing.
Import Stacks.js modules
Edit app/(tabs)/index.tsx to import the necessary Stacks.js functions.
import {
TransactionVersion,
getAddressFromPrivateKey,
makeSTXTokenTransfer,
} from '@stacks/transactions';
import { Wallet, generateSecretKey, generateWallet } from '@stacks/wallet-sdk';
import { useState } from 'react';
import { Button } from 'react-native';Set up component state
Create state variables to manage wallet data and user feedback.
export default function HomeScreen() {
const [mnemonic, setMnemonic] = useState('Press button to generate');
const [wallet, setWallet] = useState<Wallet | null>(null);
const [log, setLog] = useState('');
// Component implementation continues...
}Generate a wallet and sign a transaction
Implement the core functionality to create a wallet and sign a transaction.
const generate = async () => {
try {
const mnemonic = generateSecretKey();
setMnemonic(mnemonic);
const wallet = await generateWallet({
secretKey: mnemonic,
password: '',
});
setWallet(wallet);
const txOptions = {
amount: 1000,
anchorMode: 'any' as const,
recipient: 'SP3W993D3BRDYB284CY3SBFDEGTC5XEDJPDEA21CN',
senderKey: wallet.accounts[0].stxPrivateKey,
fee: 300,
network: 'testnet' as const,
nonce: 0,
};
const transaction = await makeSTXTokenTransfer(txOptions);
setLog('Transaction signed successfully');
} catch (error) {
setLog(`Error: ${error.message}`);
}
};Build the user interface
Show wallet information and trigger wallet generation from the UI.
return (
<ThemedView style={{ padding: 20 }}>
<ThemedText type="title">Stacks Wallet Demo</ThemedText>
<ThemedView style={{ marginVertical: 20 }}>
<ThemedText type="subtitle">Seed Phrase</ThemedText>
<ThemedText style={{ marginBottom: 10 }}>{mnemonic}</ThemedText>
<Button title="Generate New Wallet" onPress={generate} />
</ThemedView>
{wallet && (
<ThemedView style={{ marginVertical: 20 }}>
<ThemedText type="subtitle">Wallet Address</ThemedText>
<ThemedText>
{getAddressFromPrivateKey(
wallet.accounts[0].stxPrivateKey,
TransactionVersion.Testnet
)}
</ThemedText>
</ThemedView>
)}
{log && (
<ThemedView style={{ marginTop: 20 }}>
<ThemedText type="subtitle">Status</ThemedText>
<ThemedText>{log}</ThemedText>
</ThemedView>
)}
</ThemedView>
);Test your implementation
Run the app to verify everything works correctly.
npm startTry it out
Extend the basic implementation with additional features.
// Challenge: Add a function to check STX balance
const checkBalance = async (address: string) => {
// Implement balance checking
// Hint: You'll need to use @stacks/blockchain-api-client
};
// Challenge: Implement transaction broadcasting
const broadcastTransaction = async (transaction: StacksTransaction) => {
// Implement broadcasting logic
// Remember to handle network selection
};Last updated
Was this helpful?
