4
0

モバイルdAppをBerachain上に構築しましょう [Berachain翻訳]

Posted at

本記事は下記の翻訳となります。
『Build A Berachain Mobile dApp With WalletConnect & Expo』

image.png

🛠️ Let’s Build A Mobile dApp On Berachain

ほとんどの Web3 dApp は通常、Web 用に構築されており、モバイルにはあまり対応していません。このチュートリアルでは、**Expoを使用して、Berachain**と連携する iOS アプリを構築します。

私たちのモバイル dApp は、MetaMask モバイルウォレットに接続し、メッセージに署名し、**HelloWorld コントラクト**のバイトコードを Berachain Artio(Berachain テストネット)にデプロイすることができます。

Berachain Mobile dApp With WalletConnect Web3Modal & Expo

なぜ Expo を選ぶのか?

Expo は、モバイル開発における React Native の分野で人気を博しており、開発者が Native 開発や単なる React Native ではなく Expo を選択する 3 つの主な理由があります。

  1. 複数のプラットフォーム(iOS と Android)のサポート
  2. 事前に構築されたコンポーネントと機能
  3. Expo EAS(Expo Application Service)による即時のアップデート。これにより、各アップデートごとに AppStore の承認を経る必要がありません。

https://expo.dev

WalletConnect & モバイル

WalletConnect は、ほとんどの web3 dApps で重要な役割を果たしており、プロジェクトが多くのウォレットをサポートするためのセットアップを行い、開発者が SDK との簡単な統合を行うためのツールを提供しています。

WalletConnect には、モバイル専用の SDK もあり、ウォレットの接続とやり取りを直接モバイルデバイス上で行うことができます。本チュートリアルでは、この SDK を使用します。

WalletConnect Web3Modal For React Native


📋 必要要件

続行する前に、以下の項目がインストールまたはセットアップされていることを確認してください。

NOTE: このチュートリアルでは、iOS に焦点を当てます。


最新の Mac OS Sonoma と Xcode では、Apple は事前にインストールされていない特定のランタイムシミュレータをダウンロードする必要がある追加の手順を作成することにしました。

まず、Xcodeを実行し、Window > **Devices & Simulatorsに移動します。これにより、新しいウィンドウが開きます。左上のSimulatorsを選択し、Device TypeのドロップダウンからiPhone 15 Pro Maxを選択し、OS VersionのドロップダウンからDownload more simulator runtimes…**を選択します。


Xcode Simulator Runtimes

これにより、**iOS 17.2**をダウンロードするための別のウィンドウが開きます。


Xcode Simulator Runtimes Download Platforms

このダウンロードが完了するまで待ち、次のコマンドを実行して Simulator.app が正常にダウンロードされたことを確認してください。

open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app;


iOS Simulator Successfully Running


📱 Berachain モバイル dApp の構築

iOS シミュレータのセットアップが完了したので、モバイルアプリケーション全体を構築する準備が整いました。

WalletConnect Project ID

コーディングを始める前に、https://cloud.walletconnect.com/appで WalletConnect プロジェクト ID を設定する必要があります。

すでにプロジェクト ID を持っている場合は、このステップをスキップできます。

WalletConnect Cloud Sign-Inにアクセスして新しいアカウントを作成してください。

https://cloud.walletconnect.com/sign-in

ダッシュボードに移動し、新しいプロジェクトを作成します。


WalletConnect — Create Project

プロジェクトの詳細を入力してください。


WalletConnect — Project Details

プロジェクト ID を取得してください。後で使用します。


WalletConnect Project ID


プロジェクトのセットアップ

WalletConnect のプロジェクト ID を取得したので、ベースの Expo プロジェクトを作成し、必要な依存関係を追加しましょう。

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

必要な依存関係をインストールします。

NOTE: pnpm は expo との互換性に問題があることが知られています。可能な限り、expo と一緒にyarnを使用することをおすすめします。

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 expo-linking;
# 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
# expo-linking - allows for external links to open the browser

アプリが正しく動作しているかテストしてみましょう - ヒント:動作しません 😅。

Note: これはpnpmに特有の問題です。もしyarnで全てを行った場合は、この問題は発生しません。

# FROM: ./berachain-walletconnect-expo;

pnpm ios;

# [Expected Output]:
# (See Below)


Expo Not Working — Expected

⚠️ PNPM Expo の修正

yarnを使用している場合、これらの修正を行うことで、すべてのパッケージマネージャーで動作します。

この特定のpnpmの問題を修正するために、プロジェクトに 3 つの修正を加える必要があります。

1 — Babel ランタイム依存関係をインストールする

# FROM: ./berachain-walletconnect-expo;

pnpm add -D @babel/runtime;

2 — パッケージ JSON のアプリエントリを変更

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": {
    "@react-native-async-storage/async-storage": "^1.22.1",
    "@react-native-community/netinfo": "^11.3.0",
    "@walletconnect/react-native-compat": "^2.11.1",
    "@web3modal/wagmi-react-native": "^1.2.0",
    "expo": "~50.0.7",
    "expo-application": "^5.8.3",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-native": "0.73.4",
    "react-native-get-random-values": "^1.10.0",
    "react-native-modal": "^13.0.1",
    "react-native-svg": "^14.1.0",
    "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
}

3 — 新しいエントリファイルを追加し、App.tsxを移動します。

# FROM: ./berachain-walletconnect-expo;

touch index.ts;
mkdir app;
mv App.tsx app;

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);

pnpm iosを使用してもう一度試してみましょう。これで以下の作業ができるはずです。これはyarnまたはnpmでも機能するはずです。


Expo iOS Simulator Working After PNPM Fix


プロジェクトのスタイリング

スタイリングには、TailwindNativewindを使用して、アプリ全体で同じ一貫したスタイリングを維持します。

次の数ステップは少ないですが、セットアップが完了すると、Tailwind が正しく設定されていることを確認します。

# FROM: ./berachain-walletconnect-expo;

pnpm add nativewind@^4.0.1 tailwindcss react-native-css-interop;
npx tailwindcss init;

# Move our main App.tsx to an app directory for better tailwind changes
mkdir app;
mv App.tsx app/;

新しく生成されたtailwind.config.jsファイルを適切に修正してください。

File: ./tailwind.config.js

/** @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: [],
};

新しいglobal.cssを作成し、Tailwind のスタイルを追加してください。

# FROM: ./berachain-walletconnect-expo;

touch global.css;

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;
  }

  .TextInput {
    @apply bg-white text-base h-12 px-2 align-text-top rounded w-full mb-4;
  }

  .TextError {
    @apply text-red-800 bg-red-200 mb-2 text-base p-4;
  }

  .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;
  }

  .Balance {
    @apply block w-full px-8;
  }

  .SignMessage {
    @apply block w-full px-8;
  }

  .Deploy {
    @apply block w-full px-8;
  }
}

babel.config.jsを変更してnativewindをサポートします。

File: ./babel.config.js

module.exports = (api) => {
  api.cache(true);
  return {
    presets: [
      ["babel-preset-expo", { jsxImportSource: "nativewind" }],
      "nativewind/babel",
    ],
  };
};

ビルドをサポートするための新しいmetro.config.jsファイルを生成します。

# FROM: ./berachain-walletconnect-expo;

npx expo customize metro.config.js;

その設定ファイルをいくつか変更します。

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' });

メインの App.tsx を以下のコードで置き換えます。

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>
  );
}

アプリを再実行すると、以下のように表示されるはずです。


Berachain モバイル iOS dApp が Tailwind と連携して動作しています。

また、アプリに SVG ロゴを別のコンポーネントとして追加しましょう。

# FROM: ./berachain-walletconnect-expo;

mkdir components;
mkdir components/Icons;
touch components/Icons/index.tsx;

以下のコードを新しいアイコンファイルに追加します。

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"
    xmlns="http://www.w3.org/2000/svg"
  >
    <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>
);

次に、ロゴを含めるためにメインのApp.tsxファイルを変更する必要があります。

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>
  );
};

Berachain Mobile Web3 Expo App With Berachain Logo


WalletConnect Web3Modal

次に、Expo アプリに WalletConnect の Web3Modal サポートを追加します。

最初のステップは、環境変数を設定することです。

Note: この情報を git リポジトリにコミットしないようにしてください

# FROM: ./berachain-walletconnect-expo;

touch .env;

以下の内容を追加し、WALLET_CONNECT_PROJECT_IDを WalletConnect Cloud で新しく作成したプロジェクトに置き換えてください。

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"

この設定が完了したので、App.tsx を WalletConnect の設定を追加した wagmi ライブラリの設定と共にラップします。

# FROM: ./berachain-walletconnect-expo;

mkdir providers;
touch providers/index.tsx;
touch providers/wagmi.tsx;

まずは、wagmi プロバイダーの設定を行います。これにより、wagmi のフックと WalletConnect Web3Modal に組み込まれたいくつかのデフォルト機能を利用することができます。

File: ./providers/wagmi.tsx

// Imports
// ========================================================
import "@walletconnect/react-native-compat";
import {
  createWeb3Modal,
  defaultWagmiConfig,
} from "@web3modal/wagmi-react-native";
import { defineChain } from "viem";
import { WagmiConfig } from "wagmi";

// 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,
});

// Provider
// ========================================================
export default function Wagmi({ children }: { children: React.ReactNode }) {
  return <WagmiConfig config={wagmiConfig}>{children}</WagmiConfig>;
}

次に、アプリケーション全体をラップするメインプロバイダーファイルを変更します。これにより、App.tsxファイルを整理し、メインプロバイダーラッパーを使用して簡単に他のプロバイダーを追加できるようになります。

File: ./providers/index.tsx

// Imports
// ========================================================
import WagmiProvider from "./wagmi";

// Root Provider
// ========================================================
export default function RootProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return <WagmiProvider>{children}</WagmiProvider>;
}

次に、このルートプロバイダーをApp.tsxでラップし、Web3Modal ボタンを追加します。

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 RootProvider from "../providers";
+ import { Web3Modal } from "@web3modal/wagmi-react-native";

// Main App Component
// ========================================================
export default function App() {
 return (
+   <RootProvider>
   <View className="App">
    <StatusBar style="auto" />
+     <Web3Modal />
    <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>
+   </RootProvider>
 );
}

Connect Button

アプリが完全に WalletConnect をサポートするようになったので、接続ボタンのサポートを追加することができます。これを別のファイルに配置して、単独で簡単に変更できるようにします。

# FROM: ./berachain-walletconnect-expo;

mkdir components/Connect;
touch components/Connect/index.tsx;

File: ./components/Connect/index.tsx

// Imports
// ========================================================
import { W3mButton } from "@web3modal/wagmi-react-native";
import { View } from "react-native";

// Component
// ========================================================
export default function Connect() {
  return (
    <View className="Connect">
      {/* Customizing the web3modal button requires passing it certain props */}
      <W3mButton
        connectStyle={{
          backgroundColor: "#2E1E1A",
        }}
        accountStyle={{
          backgroundColor: "#2E1E1A",
        }}
      />
    </View>
  );
}

このボタンを App.tsx ファイルに追加しましょう。

// Imports
// ========================================================
import { StatusBar } from "expo-status-bar";
import { Text, View } from "react-native";
import "../global.css";
import { Logo } from "../components/Icons";
+ import Connect from "../components/Connect";
import RootProvider from "../providers";
import { Web3Modal } from "@web3modal/wagmi-react-native";


// Main App Component
// ========================================================
export default function App() {
 return (
  <RootProvider>
   <View className="App">
    <StatusBar style="auto" />
        <Web3Modal />
    <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>
+     <Connect />
   </View>
  </RootProvider>
 );
}

これでサポートされた接続ボタンが表示されるはずですが、シミュレーター上ではウォレットとの接続方法がないことにすぐに気付くでしょう。これは、シミュレーターに MetaMask がインストールされていないためです。


Berachain WalletConnect Web3Modal Working

Connect ボタンをクリックすると、利用可能なウォレットがゼロであることがわかります。


Berachain WalletConnect Web3Modal Cannot Connect To Wallet On Simulator

This is the part where we can take advantage of Expo Go on our phone to connect with our existing wallets.

これは、携帯電話のExpo Goを利用して、既存のウォレットと接続できる部分です。

Note: 携帯電話に MetaMask Mobile がインストールされていることを確認し、MetaMask Mobile を Berachain と新しいネットワークを持つように設定する

pnpm iosを実行すると QR コードが表示されます。この QR コードを**Expo Go app**と一緒に使うことで、アプリを直接携帯電話に読み込むことができるは図です。


Warp Terminal Running Expo With QR Code

これで iPhone のカメラを使用して、Expo Go に接続してアプリを開くことができます。


Connecting To Expo Go On With Your iPhone

携帯電話にアプリがロードされると、**Connectをタップし、オプションとしてMetaMaskが表示され、MetaMaskを選択し、MetaMask**アプリ経由で接続を確認し、接続を確認するためにアプリにプッシュバックされるはずです。


Berachain Expo WalletConnect Successfully Connecting To MetaMask


$BERA 残高の表示

MetaMask とのアカウントの接続に成功したので、Berachain の現在の残高を表示する基本的なコンポーネントを追加しましょう。

Note: 事前に MetaMask ウォレットを Berachain Artio Testnet Network に切り替えてください。

このコンポーネントでは、アカウントが既に接続されているかどうかをチェックし、現在の残高を表示するためのリクエストを行います。

# FROM: ./berachain-walletconnect-expo;

mkdir components/Balance;
touch components/Balance/index.tsx;

新しいBalanceコンポーネントのために、以下のコードを追加しましょう。

File: ./components/Balance/index.tsx

// Imports
// ========================================================
import { View, Text } from "react-native";
import { useAccount, useBalance } from "wagmi";

// Component
// ========================================================
export default function Balance() {
  // Hooks
  const { isConnected, address } = useAccount();
  const { data, isError, isLoading } = useBalance({
    address,
  });

  // Return
  /**
   * If still loading, show a loading state
   */
  if (isLoading) return <Text className="Text">Fetching balance...</Text>;

  /**
   * Show error if having a problem fetching the balance
   */
  if (isError) return <Text className="mText">Error fetching balance</Text>;

  /**
   * If not connected don't show anything
   */
  if (!isConnected) return null;

  /**
   * Successfully connected
   */
  return (
    <View className="Balance">
      <Text className="Text">Balance</Text>
      <Text className="Code">
        {(
          parseInt((data?.value ?? "").toString()) / 1000000000000000000
        ).toFixed(2)}{" "}
        $BERA
      </Text>
    </View>
  );
}

次に、BalanceコンポーネントをApp.tsxに追加します。

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 Connect from "../components/Connect";
+ import Balance from "../components/Balance";
import RootProvider from "../providers";
import { Web3Modal } from "@web3modal/wagmi-react-native";

// Main App Component
// ========================================================
export default function App() {
 return (
  <RootProvider>
   <View className="App">
    <StatusBar style="auto" />
        <Web3Modal />
    <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>
    <Connect />
+     <Balance />
   </View>
  </RootProvider>
 );
}

これで MetaMask と接続すると、$BERAの残高が表示されるはずです。


Berachain WalletConnect Expo Showing $BERA Balance Functionality


Wallet Sign Message

基本的な RPC リクエストに加え、基本的なウォレットとのやり取りも行いましょう。最もシンプルなのは、MetaMask ウォレットでメッセージに署名して、その署名を受け取るというものです。

メッセージを受け入れ、ユーザーの MetaMask ウォレットにメッセージの署名を促し、署名を出力する入力を作成します。

まず、ファイルを作成します。

# FROM: ./berachain-walletconnect-expo;

mkdir components/SignMessage;
touch components/SignMessage/index.tsx;

Add the functionality to it.

File: ./components/SignMessage/index.tsx

// Imports
// ========================================================
import { useState } from "react";
import { View, Pressable, Text, TextInput } from "react-native";
import { useAccount, useSignMessage } from "wagmi";

// Component
// ========================================================
export default function SignMessage() {
  // Hooks
  const [message, setMessage] = useState("");
  const [signature, setSignature] = useState("(Signature will show up here)");
  const [error, setError] = useState("");
  const { isConnected, address } = useAccount();
  const { signMessageAsync } = useSignMessage();

  // Functions
  /**
   * @dev Handles signing message
   */
  const onPressSignMessage = async () => {
    console.group("onPressSignMessage");
    setError("");

    try {
      const signature = await signMessageAsync({
        message,
      });
      setSignature(signature);
    } catch (error: unknown) {
      console.error({ error });
      setError("Error signing message.");
    }
    console.groupEnd();
  };

  // Return
  /**
   * If not connected and no address, then don't show anything
   */
  if (!isConnected || !address) return null;

  return (
    <View className="SignMessage">
      <Text className="Text">Sign Message</Text>
      <TextInput
        className="TextInput"
        placeholder="Message to sign"
        onChangeText={setMessage}
        value={message}
      />
      <Text className="Text">Signature Generated</Text>
      <Text className="Code">{signature}</Text>
      <Pressable className="Button" onPress={onPressSignMessage}>
        <Text className="text-white text-base">Sign Message</Text>
      </Pressable>

      {error ? <Text className="TextError">{error}</Text> : null}
    </View>
  );
}

App.tsxにサインメッセージ機能を追加します。 **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 Connect from "../components/Connect";
import Balance from "../components/Balance";
+ import SignMessage from "../components/SignMessage";
import RootProvider from "../providers";
import { Web3Modal } from "@web3modal/wagmi-react-native";

// Main App Component
// ========================================================
export default function App() {
 return (
  <RootProvider>
   <View className="App">
    <StatusBar style="auto" />
        <Web3Modal />
    <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>
    <Connect />
    <Balance />
+     <SignMessage />
   </View>
  </RootProvider>
 );
}

これで、メッセージを入力し、ウォレットにメッセージを署名するよう促し、生成された署名を見ることができるようにな離ました。


Berachain WalletConnect Wallet Signature Working With Ooga Booga


Deploy Contract

このアプリに追加したい最後の機能は、モバイルアプリ自体からコントラクトのバイトコードを直接デプロイできる機能です。これにより、ウォレットが Berachain にコントラクトをデプロイするトランザクションを開始することができます。

手始めに、新しい Deploy コンポーネントを作ってみよう。

# FROM: ./berachain-walletconnect-expo;

mkdir components/Deploy;
touch components/Deploy/index.tsx;

Deploy コンポーネントに以下の機能を追加します。
File: ./components/Deploy/index.tsx

// Imports
// ========================================================
import { useState } from "react";
import { Pressable, Text } from "react-native";
import { useAccount, useWaitForTransaction } from "wagmi";
import { encodeAbiParameters } from "viem";
import { openURL } from "expo-linking";

// Constants
// ========================================================
/**
 * @dev ByteCode for HelloWorld Contract see https://github.com/berachain/guides/blob/main/apps/hardhat-viem-helloworld/contracts/HelloWorld.sol
 */
const CONTRACT_BYTECODE =
  "0x60806040523480156200001157600080fd5b5060405162000da238038062000da283398181016040528101906200003791906200021e565b8060009081620000489190620004ba565b507fcbc299eeb7a1a982d3674880645107c4fe48c3227163794e48540a752272235433826040516200007c92919062000638565b60405180910390a1506200066c565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000f482620000a9565b810181811067ffffffffffffffff82111715620001165762000115620000ba565b5b80604052505050565b60006200012b6200008b565b9050620001398282620000e9565b919050565b600067ffffffffffffffff8211156200015c576200015b620000ba565b5b6200016782620000a9565b9050602081019050919050565b60005b838110156200019457808201518184015260208101905062000177565b60008484015250505050565b6000620001b7620001b1846200013e565b6200011f565b905082815260208101848484011115620001d657620001d5620000a4565b5b620001e384828562000174565b509392505050565b600082601f8301126200020357620002026200009f565b5b815162000215848260208601620001a0565b91505092915050565b60006020828403121562000237576200023662000095565b5b600082015167ffffffffffffffff8111156200025857620002576200009a565b5b6200026684828501620001eb565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620002c257607f821691505b602082108103620002d857620002d76200027a565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620003427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000303565b6200034e868362000303565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006200039b620003956200038f8462000366565b62000370565b62000366565b9050919050565b6000819050919050565b620003b7836200037a565b620003cf620003c682620003a2565b84845462000310565b825550505050565b600090565b620003e6620003d7565b620003f3818484620003ac565b505050565b5b818110156200041b576200040f600082620003dc565b600181019050620003f9565b5050565b601f8211156200046a576200043481620002de565b6200043f84620002f3565b810160208510156200044f578190505b620004676200045e85620002f3565b830182620003f8565b50505b505050565b600082821c905092915050565b60006200048f600019846008026200046f565b1980831691505092915050565b6000620004aa83836200047c565b9150826002028217905092915050565b620004c5826200026f565b67ffffffffffffffff811115620004e157620004e0620000ba565b5b620004ed8254620002a9565b620004fa8282856200041f565b600060209050601f8311600181146200053257600084156200051d578287015190505b6200052985826200049c565b86555062000599565b601f1984166200054286620002de565b60005b828110156200056c5784890151825560018201915060208501945060208101905062000545565b868310156200058c578489015162000588601f8916826200047c565b8355505b6001600288020188555050505b505050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620005ce82620005a1565b9050919050565b620005e081620005c1565b82525050565b600082825260208201905092915050565b600062000604826200026f565b620006108185620005e6565b93506200062281856020860162000174565b6200062d81620000a9565b840191505092915050565b60006040820190506200064f6000830185620005d5565b8181036020830152620006638184620005f7565b90509392505050565b610726806200067c6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063fe50cc7214610057575b600080fd5b610055600480360381019061005091906102ad565b610075565b005b61005f6100c1565b60405161006c9190610375565b60405180910390f35b806000908161008491906105ad565b507fcbc299eeb7a1a982d3674880645107c4fe48c3227163794e48540a752272235433826040516100b69291906106c0565b60405180910390a150565b6060600080546100d0906103c6565b80601f01602080910402602001604051908101604052809291908181526020018280546100fc906103c6565b80156101495780601f1061011e57610100808354040283529160200191610149565b820191906000526020600020905b81548152906001019060200180831161012c57829003601f168201915b5050505050905090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6101ba82610171565b810181811067ffffffffffffffff821117156101d9576101d8610182565b5b80604052505050565b60006101ec610153565b90506101f882826101b1565b919050565b600067ffffffffffffffff82111561021857610217610182565b5b61022182610171565b9050602081019050919050565b82818337600083830152505050565b600061025061024b846101fd565b6101e2565b90508281526020810184848401111561026c5761026b61016c565b5b61027784828561022e565b509392505050565b600082601f83011261029457610293610167565b5b81356102a484826020860161023d565b91505092915050565b6000602082840312156102c3576102c261015d565b5b600082013567ffffffffffffffff8111156102e1576102e0610162565b5b6102ed8482850161027f565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610330578082015181840152602081019050610315565b60008484015250505050565b6000610347826102f6565b6103518185610301565b9350610361818560208601610312565b61036a81610171565b840191505092915050565b6000602082019050818103600083015261038f818461033c565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806103de57607f821691505b6020821081036103f1576103f0610397565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026104597fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8261041c565b610463868361041c565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006104aa6104a56104a08461047b565b610485565b61047b565b9050919050565b6000819050919050565b6104c48361048f565b6104d86104d0826104b1565b848454610429565b825550505050565b600090565b6104ed6104e0565b6104f88184846104bb565b505050565b5b8181101561051c576105116000826104e5565b6001810190506104fe565b5050565b601f82111561056157610532816103f7565b61053b8461040c565b8101602085101561054a578190505b61055e6105568561040c565b8301826104fd565b50505b505050565b600082821c905092915050565b600061058460001984600802610566565b1980831691505092915050565b600061059d8383610573565b9150826002028217905092915050565b6105b6826102f6565b67ffffffffffffffff8111156105cf576105ce610182565b5b6105d982546103c6565b6105e4828285610520565b600060209050601f8311600181146106175760008415610605578287015190505b61060f8582610591565b865550610677565b601f198416610625866103f7565b60005b8281101561064d57848901518255600182019150602085019450602081019050610628565b8683101561066a5784890151610666601f891682610573565b8355505b6001600288020188555050505b505050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006106aa8261067f565b9050919050565b6106ba8161069f565b82525050565b60006040820190506106d560008301856106b1565b81810360208301526106e7818461033c565b9050939250505056fea264697066735822122051a137f3f2f370792efdafdfd52aa1721451dfaa2e804a5236730d97a26f237664736f6c63430008110033";

// Component
// ========================================================
export default function Deploy() {
  // Hooks
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState("");
  const [transactionHash, setTransactionHash] = useState<
    `0x${string}` | undefined
  >();
  const { isConnected, address, connector } = useAccount();

  // Functions
  /**
   * @dev hook that waits for a transaction hash
   */
  const txResult = useWaitForTransaction({
    hash: transactionHash,
  });

  /**
   * @dev handles deploying the contract
   */
  const onPressDeployContract = async () => {
    console.group("onPressDeployContract");
    setError("");
    setIsLoading(true);
    try {
      const provider = await connector?.getProvider(); // get's the provider from wagmi directly - needed for the walletconnection
      console.log({ provider });
      console.log({ request: provider?.request });

      // Based on constructor - constructor(string memory _greeting) {
      // encodes the function name and the input of `Hello World!`
      const encodedData = encodeAbiParameters(
        [{ name: "_greeting", type: "string" }],
        ["Hello World!"]
      );

      // Need slide(2) to remove 0x from encodedData at the beginning
      const fullByteCode = `${CONTRACT_BYTECODE}${encodedData.slice(2)}`;

      // Send eth transsaction
      const tx = await provider.request({
        method: "eth_sendTransaction",
        params: [
          {
            from: address,
            data: fullByteCode,
          },
        ],
      });
      console.log({ tx });

      // Set the state transaction hash for `useWaitForTransaction` to wait for it
      setTransactionHash(tx);
    } catch (error: unknown) {
      console.error(error);
      setError("Error could not deploy contract.");
    }
    setIsLoading(false);

    console.groupEnd();
  };

  /**
   * @dev function that handles opening url to the final transaction hash in a block explorer
   */
  const onPressSeeTransaction = () => {
    openURL(
      `${process.env.EXPO_PUBLIC_CHAIN_BLOCKEXPLORER_URL}/tx/${txResult?.data?.transactionHash}`
    );
  };

  /**
   * If not connected and no address, then don't show anything
   */
  if (!isConnected || !address) return null;

  return (
    <>
      <Text className="Text">Deploy Contract</Text>
      <Pressable
        disabled={isLoading}
        className={"Button"}
        onPress={onPressDeployContract}
      >
        <Text className="text-white text-base">Deploy</Text>
      </Pressable>

      {isLoading && <Text className="Code">Loading...</Text>}

      {!isLoading && txResult?.data?.transactionHash ? (
        <Pressable className="Button" onPress={onPressSeeTransaction}>
          <Text className="text-white text-base">
            See Successful Transaction
          </Text>
        </Pressable>
      ) : null}
      {error ? <Text className="TextError">{error}</Text> : null}
    </>
  );
}

これで、Deploy をタップし、ウォレットから取引を確認するプロンプトが表示され、取引が完了するのを待ち、ブロックエクスプローラー上で取引を確認することができるはずです。


Berachain WalletConnect Successfully Deployed Contract


🐻 Full Code Repository

最終的なコードや他のガイドをご覧になりたい方は、Berachain WalletConnect Expo Guide Codeをご覧ください。

🛠️ もっとビルドしたい?

Berachain でさらに開発を行いたい場合や、より多くの例を見たい場合は、Berachain GitHub Guides Repoをご覧ください。このリポジトリには、NextJS、Hardhat、Viem、Foundry など、さまざまな実装例が豊富に用意されています。

開発サポートをお探しですか?

私たちのBerachain Discordサーバーに参加して、私たちの開発者チャンネルをチェックして質問してください。

https://discord.com/invite/berachain

❤️ この記事をシェアして愛を示すことをお忘れなく。



【Sunrise とは】
Sunrise は Proof of Liquidity(PoL)と Fee Abstraction(手数料抽象化)を備えたデータ可用性レイヤーです。 私たちは DA の体験を再構築し、多様なエコシステムからのモジュラー型流動性を活用してロールアップを立ち上げています。

【Social Links】

【お問合せ】
Sunrise へのお問い合わせはこちらから 👉 Google Form

1080x360.jpeg

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0