XION
DiscordGithub
  • Welcome to XION
  • XION'S Core
    • Concepts
      • Generalized Chain Abstraction
      • Intro to Account Abstraction
      • XION's Meta Accounts
      • Meta Accounts Design
      • Architecture & Tech Glossary
      • Use Cases
  • developers
    • XION Quick Start
      • Zero to App in 5 Minutes
        • Launch a User Map App on XION in 5 Minutes
        • React Native Mobile App on XION in 5 Minutes
    • Mobile App Development
      • Set up your XION Mobile Development Environment
      • Create Mobile App and Integrate Meta Account Authentication
      • Building a React Native Mobile App with Abstraxion (Xion.js)
    • Getting Started (Advanced)
      • Set Up Local Environment
        • Setting up your Local Smart Contract Development Environment for XION
          • Setting up your XION Smart Contract Development Environment on Windows (WSL2 + Ubuntu)
        • Set Up an Integrated Development Environment (IDE)
        • Interacting with Xion Chain using Xion Daemon
      • Your First Contract
        • Deploying Your First Smart Contract on XION
      • Gasless UX & Permission Grants
        • Enabling Gasless Transactions with Treasury Contracts
      • App Development
        • Account Abstraction with Gasless Transactions
        • Interact with XION via your Backend Service
    • Re-using Existing Contracts
      • Deployed Contracts on XION
      • Non-Fungible Tokens (NFTs)
      • Fungible Tokens
      • Marketplace
      • Multisig
      • Proxy Contracts
      • Membership Management
      • Governance
      • Valuts
      • SCV Audited Contracts
    • Web3 for Web2 Developers
      • Web2 vs Web3 App Architecture: A Comparison
      • Misconceptions and Misapplied Web2 Patterns
      • Recommended Architecture for Apps on XION
    • Building for Mainnet
      • Xion Testnet: Your Development Playground
      • Building with Audited & Battle-Tested Contracts
      • Community Engagement: Building Support for Your app
      • Deploying to Xion Mainnet
        • Smart Contract Audits: Process, Costs & Support
        • Governance Process to Deploying Smart Contracts to Mainnet
    • Learn & Build
      • Token Factory
        • Creating, Minting, and Interacting with a Token Factory Token
        • Building a React dApp to Interact with Token Factory Tokens
        • Integrating a Token Factory Token in a Smart Contract
      • Websockets
        • WebSockets with Xion: Real-Time Communication
      • Oracles
        • Creating a Smart Contract with Pyth Oracle Integration
      • Indexers: Optimized Data Retrieval
        • SubQuery
      • Use Cases
        • Building a Per-User Data Storage App
    • Reference and Resources
      • Requesting XION Testnet Tokens
      • Public Endpoints & Resources
      • Block Explorers
      • Governance
        • Deploying Smart Contracts to Mainnet
      • Developer Tools: Abstract
      • IBC Denoms on XION Networks
      • Frequently Asked Questions
      • XION Token Contract Addresses on EVM Chains
  • Nodes & Validators
    • Run a Node
      • System Specifications
      • Build the Xion Daemon
      • Download the Xion Daemon
      • Configure the Xion Daemon
        • app.toml
        • client.toml
        • config.toml
      • Join the XION Network
        • xion-testnet-1
      • Confirm node is running
    • Become a Validator
      • Initial Setup
      • Obtain a XION Wallet Address
      • Obtain Funds
        • Testnet
      • Create Validator
    • IBC Relayers and Tokens
  • Others
    • Resources
Powered by GitBook
On this page
  • Prerequisites
  • Project Setup
  • Create a New Expo Project
  • Install Required Dependencies
  • Update Project Configuration
  • Update the Main Tab (index.tsx)
  • Remove explore tab
  • Update the Layout (_layout.tsx)
  • Add Metro Configuration
  • Run the Project
  • Video Demo

Was this helpful?

Edit on GitHub
  1. developers
  2. Mobile App Development

Building a React Native Mobile App with Abstraxion (Xion.js)

PreviousCreate Mobile App and Integrate Meta Account AuthenticationNextGetting Started (Advanced)

Last updated 2 months ago

Was this helpful?

Mobile apps are an integral part of modern life, and therefore integrating XION into mobile applications is a crucial step toward mass adoption. This guide will walk you through creating a React Native app using and the , based on the .

Prerequisites

Before you begin, ensure you have the following installed:

  • Android Emulator or iOS Simulator (or a physical device for testing)

Project Setup

Create a New Expo Project

Start by creating a new Expo project using the default template. This template is ideal for multi-screen apps.

npx create-expo-app@latest abstraxion-app --template default

You’ll be prompted to name your app. Once the setup is complete, navigate into the project directory:

cd abstraxion-app

Install Required Dependencies

Install the necessary dependencies for Abstraxion and other required libraries:

npm install @burnt-labs/abstraxion-react-native @react-native-async-storage/async-storage@2.1.2 react-native-get-random-values react-native-libsodium react-native-quick-crypto expo-dev-client

These libraries enable authentication, cryptographic operations, and secure storage.

Update Project Configuration

Modify app.json

Update the app.json file to configure your app’s package name (for Android apps) or bundle identifier (for IOS apps).

For Android:

Add the following under the "android" section changing the value to your unique identifier:

"package": "com.anonymous.abstraxionexpodemo"

For iOS:

Add the following under the "ios" section:

"bundleIdentifier": "com.anonymous.abstraxionexpodemo"

Note: Ensure that the package and bundleIdentifier values are unique to your app. These must be distinct and not shared with other apps to successfully submit your application to the Google Play Store or Apple App Store.

Update the Main Tab (index.tsx)

Replace the contents of the app/(tabs)/index.tsx file with the following code to integrate Abstraxion authentication and transaction signing:

import { useState } from "react";
import { View, StyleSheet, Text, TouchableOpacity, Alert } from "react-native";
import {
  useAbstraxionAccount,
  useAbstraxionSigningClient,
} from "@burnt-labs/abstraxion-react-native";

export default function Index() {
  const {
    data: account,
    logout,
    login,
    isConnected,
    isConnecting,
  } = useAbstraxionAccount();
  const { client, signArb } = useAbstraxionSigningClient();

  const [signArbResponse, setSignArbResponse] = useState("");
  const [txHash, setTxHash] = useState("");
  const [loadingInstantiate, setLoadingInstantiate] = useState(false);

  async function handleInstantiate() {
    setLoadingInstantiate(true);
    try {
      const msg = {
        type_urls: ["/cosmwasm.wasm.v1.MsgInstantiateContract"],
        grant_configs: [
          {
            description: "Ability to instantiate contracts",
            optional: false,
            authorization: {
              type_url: "/cosmos.authz.v1beta1.GenericAuthorization",
              value: "CigvY29zbXdhc20ud2FzbS52MS5Nc2dJbnN0YW50aWF0ZUNvbnRyYWN0",
            },
          },
        ],
        fee_config: {
          description: "Sample fee config for testnet-2",
          allowance: {
            type_url: "/cosmos.feegrant.v1beta1.BasicAllowance",
            value: "Cg8KBXV4aW9uEgY1MDAwMDA=",
          },
        },
        admin: account.bech32Address,
      };

      const instantiateRes = await client?.instantiate(
        account.bech32Address,
        33,
        msg,
        "instantiate on expo demo",
        "auto"
      );

      if (!instantiateRes) {
        throw new Error("Instantiate failed.");
      }

      setTxHash(instantiateRes.transactionHash);
    } catch (error) {
      Alert.alert("Error", (error as Error).message);
    } finally {
      setLoadingInstantiate(false);
    }
  }

  async function handleSign(): Promise<void> {
    if (client?.granteeAddress) {
      const response = await signArb?.(
        client.granteeAddress,
        "abstraxion challenge"
      );
      if (response) setSignArbResponse(response);
    }
  }

  function handleLogout() {
    logout();
    setSignArbResponse("");
    setTxHash("");
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Abstraxion React-Native Demo</Text>
      {isConnected ? (
        <>
          <TouchableOpacity
            onPress={handleInstantiate}
            style={styles.button}
            disabled={loadingInstantiate}
          >
            <Text style={styles.buttonText}>
              {loadingInstantiate ? "Loading..." : "Sample instantiate"}
            </Text>
          </TouchableOpacity>
          <TouchableOpacity onPress={handleSign} style={styles.button}>
            <Text style={styles.buttonText}>Sign Arb</Text>
          </TouchableOpacity>
        </>
      ) : null}
      {isConnected ? (
        <TouchableOpacity onPress={handleLogout} style={styles.button}>
          <Text style={styles.buttonText}>Logout</Text>
        </TouchableOpacity>
      ) : (
        <TouchableOpacity
          onPress={login}
          style={[styles.button, isConnecting && styles.disabledButton]}
          disabled={isConnecting}
        >
          <Text style={styles.buttonText}>
            {isConnecting ? "Connecting..." : "Login"}
          </Text>
        </TouchableOpacity>
      )}
      {signArbResponse || txHash ? (
        <View style={styles.card}>
          {signArbResponse ? (
            <Text style={styles.responseText}>{signArbResponse}</Text>
          ) : null}
          {txHash ? <Text style={styles.responseText}>{txHash}</Text> : null}
        </View>
      ) : null}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#f0f0f0",
    alignItems: "center",
    justifyContent: "center",
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: "bold",
    marginBottom: 20,
    color: "#333",
  },
  button: {
    marginVertical: 10,
    padding: 15,
    borderRadius: 5,
    backgroundColor: "#2196F3",
    width: "80%",
    alignItems: "center",
  },
  buttonText: {
    color: "#fff",
    fontSize: 16,
  },
  card: {
    backgroundColor: "#fff",
    padding: 15,
    borderRadius: 10,
    marginTop: 20,
    width: "90%",
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.2,
    shadowRadius: 4,
    elevation: 5,
  },
  responseText: {
    color: "#000",
    marginTop: 10,
    fontSize: 16,
  },
  disabledButton: {
    backgroundColor: "#B0BEC5",
  },
});

Here are the key changes in the updated file:

  1. Integration with Abstraxion package

    • The new file now imports useAbstraxionAccount and useAbstraxionSigningClient from @burnt-labs/abstraxion-react-native, enabling authentication and transaction signing functionalities.

  2. State Management with useState

    • Introduces state variables (signArbResponse, txHash, loadingInstantiate) to manage transaction status and responses.

  3. New Authentication Logic

    • Includes authentication management (login, logout, isConnected, isConnecting) using useAbstraxionAccount().

  4. Transaction Signing & Contract Instantiation

    • Adds a function (handleInstantiate) to instantiate a smart contract using MsgInstantiateContract.

Remove explore tab

We'll not be using the Explore tab and so let's go ahead and remove it from the project. Delete the following file "app/(tabs)/explore.tsx".

Update the Layout (_layout.tsx)

Replace the contents of app/_layout.tsx with the following code to set up the Abstraxion provider:

import "react-native-reanimated";
import "react-native-get-random-values";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
import {
  DarkTheme,
  DefaultTheme,
  ThemeProvider,
} from "@react-navigation/native";
import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { AbstraxionProvider } from "@burnt-labs/abstraxion-react-native";
import { useColorScheme } from "@/hooks/useColorScheme";
import { Buffer } from "buffer";
import crypto from "react-native-quick-crypto";

global.crypto = crypto;
global.Buffer = Buffer;

SplashScreen.preventAutoHideAsync();

const treasuryConfig = {
  treasury: "xion1r0tt64mdld2svywzeaf4pa7ezsg6agkyajk48ea398njywdl28rs3jhvry",
  gasPrice: "0.001uxion",
  rpcUrl: "https://rpc.xion-testnet-2.burnt.com:443",
  restUrl: "https://api.xion-testnet-2.burnt.com:443",
  callbackUrl: "abstraxion-expo-demo://",
};

export default function RootLayout() {
  const colorScheme = useColorScheme();
  const [loaded] = useFonts({
    SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
  });

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  if (!loaded) {
    return null;
  }

  return (
    <AbstraxionProvider config={treasuryConfig}>
      <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
        <Stack>
          <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
          <Stack.Screen name="+not-found" />
        </Stack>
        <StatusBar style="auto" />
      </ThemeProvider>
    </AbstraxionProvider>
  );
}

Here’s a breakdown of the key modifications:

1. New Imports

  • import "react-native-get-random-values";

    • This import ensures that cryptographic random values can be properly generated.

  • import { AbstraxionProvider } from "@burnt-labs/abstraxion-react-native";

    • This adds support for the Abstraxion library.

  • import { Buffer } from "buffer"; and import crypto from "react-native-quick-crypto";

    • Commonly used for handling binary data.

2. Global Object Modifications

  • global.crypto = crypto;

    • Assigns react-native-quick-crypto as the global crypto library, ensuring cryptographic functions work correctly.

  • global.Buffer = Buffer;

    • Makes the Buffer object globally available.

3. New treasuryConfig Object

  • Contains configuration for interacting with the XION blockchain, including:

    • Treasury address: "xion1r0tt64mdld2svywzeaf4pa7ezsg6agkyajk48ea398njywdl28rs3jhvry" that allows for gasless transaction. You would update this contract with your own treasity address when building your own custom app.

    • RPC & REST URLs: Connecting to XION network

    • Callback URL: "abstraxion-expo-demo://" for handling deep linking.

4. Introduction of AbstraxionProvider

  • Wraps the application inside <AbstraxionProvider config={treasuryConfig}>, providing the app with Abstraxion functionalities.

Add Metro Configuration

Create a metro.config.js file in the root of your project to configure Metro:

const { getDefaultConfig } = require("expo/metro-config");
const {
  withLibsodiumResolver,
} = require("@burnt-labs/abstraxion-react-native/metro.libsodium");

const config = getDefaultConfig(__dirname);
module.exports = withLibsodiumResolver(config);

Run the Project

To build and run the app on your emulator or device, use the following commands for your respective environment:

For Android:

npx expo run:android

For iOS:

npx expo run:ios

Video Demo

For a visual walkthrough of the app, check out this video demo

Expo
Abstraxion authentication system
Abstraxion Expo Demo
Node.js (LTS version recommended) and NPM