DEV Community

Cover image for How I integrated the blockchain donation feature in my Expo project
royson menezes
royson menezes

Posted on

How I integrated the blockchain donation feature in my Expo project

Hi! In this article, I’m going to walk you through how I integrated a blockchain-based donation system into my Expo project. I’ll explain everything step-by-step in a beginner-friendly way — why we need a global Web3 provider, how WalletConnect’s projectId and RPC URLs are created and used, and how the donation flow works in the app. I’ll also show minimal code snippets from my actual project files so you can easily follow along and implement the same setup in your own app.

Overview

  • Add a global Web3 provider so all screens can access wallet state (account, signer, network).
  • Use WalletConnect (mobile) via a projectId and RPC endpoints (Alchemy/Infura or public RPC) to talk to an Ethereum testnet/mainnet.
  • On the donation screen user: Connect wallet → select fund → enter ETH → Send transaction → wait for confirmation.

Prerequisites

  • Node / npm installed.
  • Expo project (your Frontend folder).
  • Install required packages (run in Frontend folder):
npm install wagmi viem @reown/appkit-wagmi-react-native @walletconnect/client 
Enter fullscreen mode Exit fullscreen mode

Why a global provider?

  • Centralizes wallet state (useAccount, useSigner, useBalance).
  • Lets components call sendTransaction / useSendTransaction without reimplementing connectors.
  • Handles: autoConnect, network switching, multiple connectors

Create WalletConnect Project ID

WalletConnect v2 uses a cloud projectId that enables:

  • the WalletConnect modal
  • mobile deep-linking
  • session management

Without projectId, wallet connection won’t work on mobile.

  1. Go to https://cloud.walletconnect.com
  2. Sign up or log in
  3. Create a Project
  4. Copy the Project ID (a long string)

This becomes your PROJECT_ID, used by the Wagmi + WalletConnect connector.

Store it in .env

Get RPC URLs

Wallet connectors need an RPC endpoint to:

  • read blockchain state
  • get balance
  • simulate transactions
  • broadcast ETH transactions

How to get RPC

Infura

  • Create a project
  • Choose the network
  • Copy the RPC URL using your Infura project ID

Add to .env

WALLETCONNECT_PROJECT_ID=your_project_id_here
RPC_GOERLI=https://eth-goerli.g.alchemy.com/v2/yourKey
Enter fullscreen mode Exit fullscreen mode

Web3 Provider (create file)

Create app/Web3Provider.tsx and configure chains/connectors.

Replace your .env values where needed.


app/Web3Provider.tsx

import React from "react";
import { WagmiConfig, createClient, configureChains } from "wagmi";
import { publicProvider } from "wagmi/providers/public";
import { goerli, mainnet } from "wagmi/chains";
import { WalletConnectConnector } from "wagmi/connectors/walletConnect";
import { InjectedConnector } from "wagmi/connectors/injected";

const WALLETCONNECT_PROJECT_ID = process.env.WALLETCONNECT_PROJECT_ID || "<YOUR_PROJECT_ID>";
const RPC_GOERLI = process.env.RPC_GOERLI || "https://rpc.ankr.com/eth_goerli";

// configure chains & provider (use publicProvider or custom RPCs)
const { provider } = configureChains(
  [goerli, mainnet],
  [publicProvider()] // or add jsonRpcProvider with RPC_GOERLI
);

// create client with connectors
const client = createClient({
  autoConnect: true,
  connectors: [
    new InjectedConnector({ chains: [goerli, mainnet] }), // MetaMask web
    new WalletConnectConnector({
      options: {
        projectId: WALLETCONNECT_PROJECT_ID,
        metadata: { 
          name: "SmartVillageApp", 
          description: "Donate via Wallet", 
          url: "https://example.com" 
        },
      },
    }),
  ],
  provider,
});

export default function Web3Provider({ children }: { children: React.ReactNode }) {
  return <WagmiConfig client={client}>{children}</WagmiConfig>;
}
Enter fullscreen mode Exit fullscreen mode

Note

  • Use your RPC URLs if you want guaranteed RPC access.
  • For React Native + Expo, WalletConnect deep linking behavior may need additional config; AppKit helps simplify this.

Wrap the app root with the provider

Edit app/_layout.tsx (root layout) to include Web3Provider so Wagmi hooks work everywhere.

app/_layout.tsx

import React from "react";
import Web3Provider from "./Web3Provider";
import { Slot } from "expo-router";

export default function RootLayout() {
  return (
    <Web3Provider>
      <Slot />
    </Web3Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode

How donation flow works in the frontend (user steps)

  1. User opens Donation screen (app/(tabs)/villager/donation.tsx).

    The app shows a Connect button (AppKitButton).

  2. User taps Connect → WalletConnect modal / MetaMask opens → user approves the connection.

  3. Wagmi updates the following hooks with active wallet data:

    • useAccount → wallet address
    • useSigner → signer for sending transactions
    • useBalance → account balance
  4. User selects a fund (e.g., education or infrastructure) and enters the donation amount.

  5. When the user clicks Donate, the frontend sends a transaction using:

    • to: recipientAddress
    • value: parseEther(donationAmount) → returns a bigint
  6. UI displays: "Waiting for Wallet..." while the transaction is pending.

  7. After the transaction is mined:

    • show Success message
    • display transaction hash

Exam
ple donate call

Use parseEther and sendTransaction.

This snippet is similar to what already exists in your project:

// excerpt from donation.tsx (already present in your project)
const valueInWei = parseEther(donationAmount);
sendTransaction({
  to: recipientAddress,
  value: valueInWei,
});
Enter fullscreen mode Exit fullscreen mode

Testing locally

  • Use Ethereum testnets such as Goerli or Sepolia

  • Postman note:

    You can test your backend REST APIs, but on-chain blockchain transactions cannot be triggered via Postman because they require a wallet provider for signing.

Security & UX tips

  • Never store private keys — the wallet app signs transactions securely.
  • Validate user-entered amounts before sending the transaction.
  • Show gas estimate or at least inform users that gas fees exist.
  • Disable the Donate button while the transaction is pending.
  • Display a network mismatch warning if the user is connected to the wrong chain.
  • Always develop and test on testnets, not Mainnet.

Troubleshooting

  • If AppKitButton doesn’t open WalletConnect:

    • Check if your PROJECT_ID is correct.
    • Make sure Expo deep linking is properly configured.
  • If transactions fail:

    • Verify the RPC URL.
    • Confirm the chainId matches your configured chain.
    • Ensure the signer is connected to the same network as your contract.
  • For Expo SDK mismatches:

    • Update your Expo version or install a matching Expo Go build.

Top comments (0)