Build A Basic Mobile Web3 dApp With Berachain & WalletConnect
Let's learn how to quickly setup WalletConnect with Expo on Berachain Testnet.
Requirements
Before we start, make sure you have the following installed and or setup.
- NVM or Node
v20.11.0
- Expo Go - Needed to get the app on your iPhone
- Xcode with iOS Simulator
- Berachain
$BERA
tokens - See Berachain Faucet - WalletConnect Project ID - See WalletConnect Cloud
- MetaMask iOS App
- Your wallet configured with Berachain - See Connecting To Berachain
Setting Up Our Expo Project
Let's start with the first step of setting up a Blank (TypeScript) expo app.
npx create-expo-app berachain-walletconnect-expo -t;
# [Expected Prompt & Output]:
# ? Choose a template: › - Use arrow-keys. Return to submit.
# Blank
# ❯ Blank (TypeScript) - blank app with TypeScript enabled
# Navigation (TypeScript)
# Blank (Bare)
# ...
# ✅ Your project is ready!
#
# To run your project, navigate to the directory and run one of the following npm commands.
#
# - cd berachain-walletconnect-expo
# - npm run android
# - npm run ios
# - npm run web
We'll also install some dependencies.
cd berachain-walletconnect-expo;
pnpm add @web3modal/wagmi-react-native wagmi@1.4.13 viem@1.21.4 @react-native-async-storage/async-storage react-native-get-random-values react-native-svg react-native-modal @react-native-community/netinfo @walletconnect/react-native-compat expo-application @babel/runtime nativewind@^4.0.1 tailwindcss react-native-css-interop;
# NOTE: If in a monorepo / turbo repo, run the following right after in the dir
# pnpm install --ignore-workspace;
# @web3modal/wagmi-react-native - walletconnect react native web3modal
# wagmi@1.4.13 - web3 react hooks (currently only supports v1)
# viem@1.21.4 # js library for interacting with EVM (currently only support
# @react-native-async-storage/async-storage - for local device storage
# react-native-get-random-values - local random val generator
# react-native-svg - native svg support
# react-native-modal - modals support
# @react-native-community/netinfo - api for network info for device
# @walletconnect/react-native-compat - shims / polyfills for additional support
# expo-application - for native app information
# @babel/runtime - needed to handle specific runtime for pnpm
# nativewind@^4.0.1 - to add native support for tailwind
# tailwindcss - for styling from tailwind
# react-native-css-interop - allows handling of css files
We'll also need to make some modifications to our package.json
, create a new index.ts
file as a our root, and place our App.tsx
file under a new folder called app
.
File: ./package.json
{
"name": "berachain-walletconnect-expo",
"version": "1.0.0",
- "main": "node_modules/expo/AppEntry.js",
+ "main": "index.ts",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"@babel/runtime": "^7.24.0",
"@react-native-async-storage/async-storage": "^1.22.3",
"@react-native-community/netinfo": "^11.3.1",
"@walletconnect/react-native-compat": "^2.11.2",
"@web3modal/wagmi-react-native": "^1.2.0",
"expo": "~50.0.8",
"expo-application": "^5.8.3",
"expo-status-bar": "~1.11.1",
"nativewind": "^4.0.1",
"react": "18.2.0",
"react-native": "0.73.4",
"react-native-css-interop": "^0.0.34",
"react-native-get-random-values": "^1.10.0",
"react-native-modal": "^13.0.1",
"react-native-svg": "^15.0.0",
"tailwindcss": "^3.4.1",
"viem": "1.21.4",
"wagmi": "1.4.13"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "~18.2.45",
"typescript": "^5.1.3"
},
"private": true
}
Let's make the files and folders.
# FROM: ./berachain-walletconnect-expo
mkdir app;
mv App.tsx app;
touch index.ts;
Add the following to our index.ts
file.
File: ./index.ts
// Imports
// ========================================================
import { registerRootComponent } from "expo";
// Main App
// ========================================================
import App from "./app/App";
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
Configure Styling
To make sure that our app is working correctly, we just need get some of the styling setup correctly.
# FROM: ./berachain-walletconnect-expo
touch global.css;
npx expo customize metro.config.js;
npx tailwindcss init;
Modify our newly created tailwind configuration file, new global stylesheet, and our existing babel configuration file.
File: ./tailwind.config.ts
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all of your component files.
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}"
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
}
File: ./global.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
.App {
@apply bg-[#F47226] text-[#2E1E1A] flex w-full h-full items-center justify-center;
}
.H1 {
@apply text-lg mb-2 block font-semibold text-[#121312] text-center;
}
.Text {
@apply mb-2 text-[#2E1E1A] block;
}
.Button {
@apply bg-[#2E1E1A] h-12 flex items-center justify-center rounded-lg mb-4 w-full;
}
.Code {
@apply block bg-[#ff843d] whitespace-nowrap overflow-scroll mb-4 text-[#874c2a] text-base h-12 leading-[3rem] px-2 rounded w-full;
}
.Connect {
@apply my-4 block;
}
}
File: ./babel.config.js
module.exports = (api) => {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
};
};
File: ./metro.config.js
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
+ const { withNativeWind } = require('nativewind/metro');
/** @type {import('expo/metro-config').MetroConfig} */
- const config = getDefaultConfig(__dirname);
+ const config = getDefaultConfig(__dirname, { isCSSEnabled: true })
- module.exports = config;
+ module.exports = withNativeWind(config, { input: './global.css' });
Lastly, let's modify our main App component to incorporate these changes.
File: ./app/App.tsx
// Imports
// ========================================================
import { StatusBar } from 'expo-status-bar';
import { Text, View } from 'react-native';
import '../global.css';
// Main App Component
// ========================================================
export default function App() {
return (
<View className="App">
<StatusBar style="auto" />
<Text className="H1">Berachain WalletConnect Expo Example</Text>
<Text className="Text">Demonstrating how to build mobile dApps</Text>
</View>
);
};
Let's run our application.
NOTE: Make sure that you have Simulator Runtime installed.
# FROM: ./berachain-walletconnect-expo
pnpm ios;
We should now something similar to the following.
Before we move on, let's add a logo, to make it look more official.
# FROM: ./berachain-walletconnect-expo
mkdir components;
mkdir components/Icons;
touch components/Icons/index.tsx;
Add the following SVG.
File: ./components/Icons/index.tsx
// Imports
// ========================================================
import Svg, { Path } from "react-native-svg";
// Icons
// ========================================================
export const Logo = ({ className = '', width = 128, height = 128 }) => <Svg className={className} width={width} height={height} viewBox="0 0 1024 1024" fill="none">
<Path d="M477.298 474.489C476.946 472.605 476.506 470.802 475.801 469.084C476.066 468.675 534.55 392.929 480.381 346.092C426.299 299.252 363.145 360.339 362.793 360.667C352.751 357.718 342.622 355.918 332.581 355.099C332.581 355.099 332.581 355.099 332.493 355.099C311.882 351.906 282.99 355.099 282.99 355.099C273.037 355.918 262.996 357.718 253.042 360.585C252.69 360.258 189.536 299.17 135.454 346.01C81.3722 392.847 139.77 468.675 140.034 469.002C139.418 470.802 138.889 472.605 138.537 474.407C132.724 506.833 92.8228 516.823 92.8228 573.325C92.8228 630.891 134.485 676.256 219.572 676.256H254.452C254.628 676.42 268.106 694.27 295.938 695.335C295.938 695.335 302.369 695.99 317.165 695.499C346.673 695.499 361.031 676.583 361.12 676.338H395.999C481.085 676.338 522.748 630.972 522.748 573.407C523.012 516.987 483.111 506.915 477.298 474.489Z" fill="#F9F4D5" />
<Path d="M692.83 628.84V584.622C720.048 575.287 739.867 546.3 739.867 511.99C739.867 477.679 720.048 448.61 692.83 439.355V395.137C718.463 386.376 737.577 360.092 739.69 328.319H708.51V341.83C708.51 352.229 702.167 361.4 692.83 365.986V359.682C692.83 350.429 684.726 342.894 674.773 342.894H673.188C663.234 342.894 655.133 350.429 655.133 359.682V365.986C645.796 361.4 639.453 352.311 639.453 341.83V328.319H608.272C610.386 360.092 629.5 386.376 655.133 395.137V439.355C628.003 448.61 608.096 477.598 608.096 511.99C608.096 546.382 627.915 575.369 655.133 584.622V628.84C629.5 637.602 610.386 663.888 608.272 695.658H639.453V682.148C639.453 671.748 645.796 662.577 655.133 657.992V664.297C655.133 673.55 663.234 681.083 673.188 681.083H674.773C684.726 681.083 692.83 673.55 692.83 664.297V657.992C702.167 662.577 708.51 671.666 708.51 682.148V695.658H739.69C737.577 663.888 718.463 637.602 692.83 628.84ZM639.453 531.315V492.583C639.453 482.183 645.796 473.012 655.133 468.427V474.73C655.133 483.983 663.234 491.518 673.188 491.518H674.773C684.726 491.518 692.83 483.983 692.83 474.73V468.427C702.167 473.012 708.51 482.101 708.51 492.583V531.315C708.51 541.714 702.167 550.885 692.83 555.471V549.165C692.83 539.912 684.726 532.38 674.773 532.38H673.188C663.234 532.38 655.133 539.912 655.133 549.165V555.471C645.884 550.885 639.453 541.796 639.453 531.315Z" fill="#F9F4D5" />
<Path d="M884.142 535.49V488.407C911.358 479.07 931.176 450.083 931.176 415.773C931.176 381.462 911.358 352.393 884.142 343.14V328.319H846.53V343.14C819.315 352.475 799.496 381.462 799.496 415.773C799.496 450.083 819.315 479.152 846.53 488.407V535.49C819.315 544.825 799.496 573.813 799.496 608.123C799.496 642.433 819.315 671.502 846.53 680.755V695.576H884.142V680.755C911.358 671.42 931.176 642.433 931.176 608.123C931.176 573.813 911.358 544.825 884.142 535.49ZM830.765 435.097V396.366C830.765 385.966 837.106 376.795 846.442 372.21V378.515C846.442 387.768 854.546 395.301 864.5 395.301H865.997C875.95 395.301 884.054 387.768 884.054 378.515V372.21C893.391 376.795 899.731 385.884 899.731 396.366V435.097C899.731 445.497 893.391 454.668 884.054 459.254V452.95C884.054 443.697 875.95 436.162 865.997 436.162H864.412C854.458 436.162 846.354 443.697 846.354 452.95V459.254C837.194 454.668 830.765 445.579 830.765 435.097ZM899.819 627.53C899.819 637.929 893.479 647.1 884.142 651.686V642.433C884.142 633.18 876.038 625.648 866.085 625.648H864.588C854.634 625.648 846.53 633.18 846.53 642.433V651.686C837.194 647.1 830.853 638.011 830.853 627.53V588.798C830.853 578.398 837.194 569.227 846.53 564.642V567.998C846.53 577.253 854.634 584.786 864.588 584.786H866.173C876.126 584.786 884.23 577.253 884.23 567.998V564.642C893.567 569.227 899.907 578.316 899.907 588.798V627.53H899.819Z" fill="#F9F4D5" />
</Svg>
Import this file into our main App component.
File: ./app/App.tsx
// Imports
// ========================================================
import { StatusBar } from 'expo-status-bar';
import { Text, View } from 'react-native';
import '../global.css';
+ import { Logo } from "../components/Icons";
// Main App Component
// ========================================================
export default function App() {
return (
<View className="App">
<StatusBar style="auto" />
+ <Logo className="w-auto h-10 mx-auto" />
<Text className="H1">Berachain WalletConnect Expo Example</Text>
<Text className="Text">Demonstrating how to build mobile dApps</Text>
</View>
);
};
We should now see the official Berachain logo in our app.
Add Connect Button
This step might be a bit more involved because we first need to modify our main App component to support wagmi with the correct providers.
Let's make an environment variable file that we'll be using to load in our app.
# FROM: ./berachain-walletconnect-expo
touch .env; # remember to add this to your .gitignore
File: ./.env
# Expo Metadata
EXPO_PUBLIC_METADATA_NAME="Berachain WalletConnect Expo"
EXPO_PUBLIC_METADATA_DESCRIPTION="Berachain WalletConnect Expo Example"
EXPO_PUBLIC_METADATA_URL="https://berachain.com"
EXPO_PUBLIC_METADATA_ICONS="https://avatars.githubusercontent.com/u/96059542"
EXPO_PUBLIC_METADATA_REDIRECT_NAME="YOUR_APP_SCHEME://"
EXPO_PUBLIC_METADATA_REDIRECT_UNIVERSAL="YOUR_APP_UNIVERSAL_LINK.com"
# WalletConnect - See https://cloud.walletconnect.com
EXPO_PUBLIC_WALLET_CONNECT_PROJECT_ID="YOUR_PROJECT_ID"
# Chain
EXPO_PUBLIC_CHAIN_ID=80085
EXPO_PUBLIC_CHAIN_NAME="berachainTestnet"
EXPO_PUBLIC_CHAIN_NETWORK="Berachain"
EXPO_PUBLIC_CHAIN_NATIVECURRENCY_DECIMALS=18
EXPO_PUBLIC_CHAIN_NATIVECURRENCY_NAME="Bera Token"
EXPO_PUBLIC_CHAIN_NATIVECURRENCY_SYMBOL="BERA"
EXPO_PUBLIC_CHAIN_RPC_URL="https://rpc.ankr.com/berachain_testnet"
EXPO_PUBLIC_CHAIN_BLOCKEXPLORER_NAME="Beratrail"
EXPO_PUBLIC_CHAIN_BLOCKEXPLORER_URL="https://artio.beratrail.io"
Now we can make some bigger modifications to our main App component.
File: ./app/App.tsx
// Imports
// ========================================================
import { StatusBar } from 'expo-status-bar';
import { Text, View } from 'react-native';
import '../global.css';
import { Logo } from "../components/Icons";
+ import "@walletconnect/react-native-compat";
+ import {
+ createWeb3Modal,
+ defaultWagmiConfig,
+ } from "@web3modal/wagmi-react-native";
+ import { defineChain } from "viem";
+ import { WagmiConfig } from "wagmi";
+ import { Web3Modal, W3mButton } from "@web3modal/wagmi-react-native";
+ // Config
+ // ========================================================
+ // 1. Get projectId at https://cloud.walletconnect.com
+ const projectId = `${process.env.EXPO_PUBLIC_WALLET_CONNECT_PROJECT_ID}`;
+
+ if (!projectId) throw Error('Error: Missing `EXPO_PUBLIC_WALLET_CONNECT_PROJECT_ID`.');
+
+ // 2. Create config for our app - defined by our env vars
+ const metadata = {
+ name: `${process.env.EXPO_PUBLIC_METADATA_NAME}`,
+ description: `${process.env.EXPO_PUBLIC_METADATA_DESCRIPTION}`,
+ url: `${process.env.EXPO_PUBLIC_METADATA_URL}`,
+ icons: [`${process.env.EXPO_PUBLIC_METADATA_ICONS}`],
+ redirect: {
+ native: `${process.env.EXPO_PUBLIC_METADATA_REDIRECT_NATIVE}`,
+ universal: `${process.env.EXPO_PUBLIC_METADATA_REDIRECT_UNIVERSAL}`,
+ },
+ };
+
+ // 3. Configure our custom chain - Note this is needed for wagmi and viem v1
+ /**
+ * @dev Custom chain configuration
+ */
+ const chainConfiguration = defineChain({
+ id: parseInt(`${process.env.EXPO_PUBLIC_CHAIN_ID}`),
+ name:`${process.env.EXPO_PUBLIC_CHAIN_NAME}`,
+ network: `${process.env.EXPO_PUBLIC_CHAIN_NETWORK}`,
+ nativeCurrency: {
+ decimals: parseInt(`${process.env.EXPO_PUBLIC_CHAIN_NATIVECURRENCY_DECIMALS}`),
+ name: `${process.env.EXPO_PUBLIC_CHAIN_NATIVECURRENCY_NAME}`,
+ symbol:`${process.env.EXPO_PUBLIC_CHAIN_NATIVECURRENCY_SYMBOL}`,
+ },
+ rpcUrls: {
+ default: {
+ http: [`${process.env.EXPO_PUBLIC_CHAIN_RPC_URL}`],
+ },
+ public: {
+ http: [`${process.env.EXPO_PUBLIC_CHAIN_RPC_URL}`],
+ },
+ },
+ blockExplorers: {
+ default: {
+ name: `${process.env.EXPO_PUBLIC_CHAIN_BLOCKEXPLORER_NAME}`,
+ url: `${process.env.EXPO_PUBLIC_CHAIN_BLOCKEXPLORER_URL}`
+ },
+ },
+ });
+
+ /**
+ * @dev supported chains
+ */
+ const chains = [chainConfiguration];
+
+ /**
+ *
+ */
+ const wagmiConfig = defaultWagmiConfig({ chains, projectId, metadata });
+
+ // 4. Create modal configuration
+ createWeb3Modal({
+ projectId,
+ chains,
+ wagmiConfig,
+ });
// Main App Component
// ========================================================
export default function App() {
return (
+ <WagmiConfig config={wagmiConfig}>
<View className="App">
<StatusBar style="auto" />
<Logo className="w-auto h-10 mx-auto" />
<Text className="H1">Berachain WalletConnect Expo Example</Text>
<Text className="Text">Demonstrating how to build mobile dApps</Text>
+ <Web3Modal />
+ <W3mButton
+ connectStyle={{
+ backgroundColor: "#2E1E1A",
+ }}
+ accountStyle={{
+ backgroundColor: "#2E1E1A",
+ }}
+ />
</View>
+ </WagmiConfig>);
}
Run our app again, but this time, we'll need to use Expo Go on our iPhone to scan the QR code in order to take advantage of the MetaMask wallet connection.
Once the app is loaded on our phone, we should be able to connect to our MetaMask wallet, and successfully show implementing WalletConnect.
And there we have it! We have successfully setup WalletConnect to work with Expo and Berachain.
Full Code & More
Make sure to take a look at the full Berachain WalletConnect Expo code and with additional functionality.
berachain / guides
A demonstration of different contracts, languages, and libraries that work with Berachain EVM.
Berachain Guides
A collection of Berachain EVM examples: code, frameworks, languages, contracts, and more.
Requirements
- NVM or Node
v18.18.2+
- pnpm (recommended)
Turborepo Folder Structure
This Turborepo includes the following packages/apps:
Apps
-
apps/ethers6-solc-helloworld
- Deploy HelloWorld contract with ethers6 -
apps/viem-solc-helloworld
- Deploy HelloWorld contract with viem -
apps/foundry-erc20
- Deploy ERC20 contract with foundry -
apps/hardhat-ethers6-erc1155
- Deploy ERC1155 contract with hardhat ethers6 -
apps/hardhat-viem-helloworld
- Deploy HelloWorld contract with hardhat viem -
apps/walletconnect-nextjs
- WalletConnect Web3Modal frontend contract deployment
Quick Start
Install dependencies for all apps and packages.
# FROM: ./
pnpm install;
Create and modify your .env
and make the modifications you need to it.
cp .env.example .env;
If you'd like to deploy to the chain:
# FROM: ./
# IMPORTANT: --no-cache is important to avoid caching the result of the deployments
pnpm deploy:berachain --filter foundry-erc20 --no-cache;
Want To Build More?
Make sure to check out the Berachain Docs for everything related to Berachain, including different guides and high-level concepts.
Looking to be part of the developer community, make sure to join the Berachain Discord.
🐻⛓️ Don't forget to show some ❤️ love for this post.
Top comments (0)