Using Stacks.js with React Native

Learn how to use Stacks.js with React Native.

Using Stacks.js with React Native allows you to integrate Stacks blockchain functionalities into mobile applications.

In this guide, you will learn how to:

  1. Set up the Expo project.
  2. Install necessary dependencies.
  3. Add NodeJS polyfills.
  4. Add global polyfills.
  5. Use Stacks.js in the project.

Set up the Expo project

Start by creating a new Expo project using create-expo-app.

Terminal
npx create-expo-app@latest

This will generate a boilerplate Expo project. You can run the project with npm start and connect a mobile device for previewing via the shown QR code.

Install necessary dependencies

Install Stacks.js libraries along with other dependencies needed for polyfilling browser-specific and NodeJS-specific APIs.

Terminal
npm install @stacks/transactions @stacks/wallet-sdk
npm install --save-dev buffer process react-native-get-random-values text-encoding readable-stream crypto-browserify @peculiar/webcrypto

Add NodeJS polyfills

Modify the project's Metro configuration to include polyfills for missing NodeJS modules.

Terminal
npx expo customize metro.config.js
metro.config.js
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;

Add global polyfills

Update the Expo entry point to include polyfills.

  1. Create polyfill.js file
  2. Create index.js file
  3. Update the package.json
polyfill.js
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;
index.js
import "./polyfill";
import { Crypto } from "@peculiar/webcrypto";

Object.assign(global.crypto, new Crypto());

import "expo-router/entry";
package.json
"main": "index.js", 

Ensure that the polyfills live in their own file as specified to avoid any runtime issues.

Use Stacks.js in the project

Edit the app/(tabs)/index.tsx file to integrate Stacks.js functionalities, starting with the imports.

app/(tabs)/index.tsx
import {
  TransactionVersion,
  getAddressFromPrivateKey,
  makeSTXTokenTransfer,
} from "@stacks/transactions";
import { Wallet, generateSecretKey, generateWallet } from "@stacks/wallet-sdk";
import { useState } from "react";

Now you can start to manage the state as follows:

app/(tabs)/index.tsx
export default function HomeScreen() {
  const [mnemonic, setMnemonic] = useState("...");
  const [wallet, setWallet] = useState<Wallet | null>(null);
  const [log, setLog] = useState("");
}

Next, to generate a wallet and sign a transaction:

app/(tabs)/index.tsx
const generate = async () => {
  const mnemonic = generateSecretKey();
  setMnemonic(mnemonic);

  const wallet = await generateWallet({
    secretKey: mnemonic,
    password: "",
  });
  setWallet(wallet);

  await makeSTXTokenTransfer({
    amount: 1000,
    anchorMode: "any",
    recipient: "SP3W993D3BRDYB284CY3SBFDEGTC5XEDJPDEA21CN",
    senderKey: wallet.accounts[0].stxPrivateKey,
    fee: 10,
    network: "mainnet",
    nonce: 0,
  });
  setLog("Transaction signed successfully ☑");
};

And lastly, to integrate the UI:

app/(tabs)/index.tsx
<ThemedView>
  <ThemedText type="subtitle">Seed Phrase</ThemedText>
  <ThemedText>{mnemonic}</ThemedText>
  <Button title="Generate Seed Phrase" onPress={generate} />
  {wallet && (
    <>
      <ThemedText type="subtitle">Address</ThemedText>
      <ThemedText>
        {getAddressFromPrivateKey(
          wallet.accounts[0].stxPrivateKey,
          TransactionVersion.Mainnet
        )}
      </ThemedText>
    </>
  )}
  {log && <ThemedText>{log}</ThemedText>}
</ThemedView>

Next steps