Fatskills
Practice. Master. Repeat.
Study Guide: Blockchain and Web3 Development: Decentralized Applications dApps Connecting to Wallets MetaMask WalletConnect RainbowKit
Source: https://www.fatskills.com/cryptocurrency-bitcoin-blockchain-and-more/chapter/blockchain-and-web3-development-blockchain-and-web3-development-decentralized-applications-dapps-connecting-to-wallets-metamask-walletconnect-rainbowkit

Blockchain and Web3 Development: Decentralized Applications dApps Connecting to Wallets MetaMask WalletConnect RainbowKit

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~6 min read

What This Is

Connecting to wallets is the bridge that lets a web page talk to a user’s private keys on a blockchain. Instead of handing over passwords, a dApp asks a wallet (MetaMask, WalletConnect, RainbowKit, etc.) to sign transactions, prove ownership, and read balances. This makes decentralized apps feel like native apps—e.g., a user clicks “Swap” on Uniswap, the UI pops up MetaMask, the user signs the trade, and the swap lands on‑chain without ever exposing a secret key.


Key Terms & Code Snippets

  • MetaMask Provider (window.ethereum) – The JavaScript object injected by the MetaMask browser extension that implements the EIP‑1193 “Ethereum Provider” API.
    js const provider = window.ethereum; // injected by MetaMask await provider.request({ method: "eth_requestAccounts" });

  • WalletConnect Session – A JSON‑RPC bridge that lets mobile wallets (Trust Wallet, Rainbow, etc.) connect to a desktop dApp via QR‑code or deep‑link.
    js import { WalletConnectConnector } from "@web3-react/walletconnect-connector"; const connector = new WalletConnectConnector({
    rpc: { 1: INFURA_MAINNET_URL },
    qrcode: true, });

  • RainbowKit – A React component library that wraps wagmi + ethers.js to provide a polished “Connect Wallet” button, handling multiple wallet types out‑of‑the‑box.
    tsx import { ConnectButton } from "@rainbow-me/rainbowkit"; <ConnectButton />

  • EIP‑1193 – The standard interface (request({method, params})) that all modern wallets implement, enabling a uniform way to query accounts, sign messages, and send transactions.

  • eth_requestAccounts – The provider method that prompts the user to expose their address(es). Must be called after a user gesture (click) to satisfy browser wallet security policies.

  • signTypedDataV4 (EIP‑712) – A method for signing structured data (e.g., a DAO vote) that prevents phishing attacks by showing the exact fields being signed.
    js const signature = await provider.request({
    method: "eth_signTypedData_v4",
    params: [account, JSON.stringify(typedData)], });

  • ethers.js Signer – An abstraction that represents an account capable of signing transactions. When you call provider.getSigner(), you get a Signer bound to the connected wallet.
    js const signer = new ethers.providers.Web3Provider(provider).getSigner(); const tx = await signer.sendTransaction({ to, value });

  • chainId – The numeric identifier of the network (1 = Ethereum Mainnet, 5 = Goerli, 137 = Polygon). Wallets expose it via eth_chainId; dApps should verify it matches the intended network before proceeding.

  • onAccountsChanged / onChainChanged – Event listeners that let the UI react when the user switches accounts or networks in their wallet.
    js provider.on("accountsChanged", (accounts) => setAccount(accounts[0])); provider.on("chainChanged", (chainId) => window.location.reload());

  • Web3Modal – A UI‑agnostic modal that aggregates many wallet connectors (MetaMask, WalletConnect, Coinbase Wallet, etc.) into a single “Connect” button. Useful for quick prototypes.

  • allowance (ERC‑20) – Before a contract can pull tokens from a user’s wallet, the user must approve the contract. The dApp must read allowance and, if zero, prompt an approve transaction.


Step‑by‑Step / Process Flow

  1. Add a wallet connector – Install the library you prefer (e.g., @rainbow-me/rainbowkit + wagmi).
    bash
    npm i @rainbow-me/rainbowkit wagmi ethers

  2. Configure the provider – Wrap your React app with WagmiConfig and RainbowKitProvider, passing the desired chains (Mainnet, Goerli, etc.).
    tsx
    const { chains, provider } = configureChains(
    [mainnet, goerli],
    [infuraProvider({ apiKey: INFURA_KEY })]
    );
    const wagmiClient = createClient({ autoConnect: true, provider });
    <WagmiConfig client={wagmiClient}>
    <RainbowKitProvider chains={chains}>…</RainbowKitProvider>
    </WagmiConfig>

  3. Render the Connect button – Drop <ConnectButton /> anywhere in your UI. When the user clicks, the modal shows MetaMask, WalletConnect QR, etc.

  4. Obtain a Signer – After connection, retrieve the active account and signer:
    js
    const { address, connector, isConnected } = useAccount();
    const { data: signer } = useSigner(); // ethers.Signer bound to the wallet

  5. Interact with a contract – Use the signer to call contract methods (e.g., swapExactETHForTokens).
    js
    const router = new ethers.Contract(UNISWAP_ROUTER, routerABI, signer);
    const tx = await router.swapExactETHForTokens(
    0, // amountOutMin
    [WETH, DAI], // path
    address, // to
    Math.floor(Date.now() / 1000) + 60 * 10 // deadline
    );
    await tx.wait();

  6. Handle events – Listen for accountsChanged and chainChanged to keep UI state in sync, and gracefully disconnect when the user clicks “Disconnect”.


Common Mistakes

  • Mistake: Calling eth_requestAccounts on page load.
    Correction: Trigger it only inside a click handler (onClick={() => requestAccounts()}) because browsers block unsolicited pop‑ups, causing the wallet to stay silent.

  • Mistake: Assuming the provider always returns the selected network.
    Correction: Always read await provider.request({ method: "eth_chainId" }) and compare it to your expected chainId. Users can switch networks at any time, and a mismatched chain leads to failed transactions and lost gas.

  • Mistake: Forgetting to handle onAccountsChanged.
    Correction: Register the listener and update your UI state; otherwise the dApp may keep showing the old address, leading to “insufficient funds” errors.

  • Mistake: Using window.ethereum directly in a server‑side rendered (SSR) Next.js page.
    Correction: Guard with if (typeof window !== "undefined") or load the wallet code inside a useEffect hook to avoid “window is not defined” crashes.

  • Mistake: Not checking allowance before calling a token‑transfer function.
    Correction: Read allowance(owner, spender) first; if it’s zero, prompt an approve transaction. Skipping this step makes the contract revert with “ERC20: transfer amount exceeds allowance”.


Blockchain Developer Interview / Practical Insights

  1. EIP‑1193 vs. Legacy web3.js – Interviewers love to ask why the new provider pattern (window.ethereum.request) is preferred: it’s promise‑based, avoids callback hell, and standardizes error handling across wallets.

  2. MetaMask vs. WalletConnect security model – Explain that MetaMask stores the private key in the browser extension (subject to the host OS), while WalletConnect delegates signing to a separate mobile app, reducing the attack surface of the dApp’s origin.

  3. call vs. delegatecall in a wallet‑connected contract – Auditors check that any external contract interaction that modifies state uses call (isolated) unless you deliberately need the callee’s code to run in your context (delegatecall). Misusing delegatecall can open proxy‑upgrade attacks.

  4. ERC‑20 vs. ERC‑777 approvals – ERC‑777 adds operator semantics that can auto‑approve transfers; interviewers may probe whether you understand the extra security considerations (e.g., “operator hijack”).


Quick Check Questions

  1. Scenario: A dApp reads window.ethereum.selectedAddress without prompting the user.
    Answer: Wrong – the address is only exposed after the user approves eth_requestAccounts.
    Explanation: Browsers block silent access to accounts; you must request permission first.

  2. Scenario: A user switches from Ethereum Mainnet to Polygon in MetaMask while your dApp is still showing a “Swap” button.
    Answer: The dApp should detect chainChanged and either reload or disable the UI until the correct network is selected.
    Explanation: Transactions on the wrong chain will revert and waste gas.

  3. Scenario: You sign a DAO vote with eth_sign.
    Answer: Unsafe – use eth_signTypedData_v4 (EIP‑712) instead.
    Explanation: eth_sign signs raw data, making phishing attacks easy; EIP‑712 shows the exact fields being signed.


Last‑Minute Cram Sheet (10 one‑liners)

  1. ⚠️ Never rely on tx.origin for auth; it can be spoofed via contract calls.
  2. MetaMask injects window.ethereum once per page load; re‑load the page after a wallet install.
  3. WalletConnect sessions are persisted in localStorage; clearing it forces a new QR‑code scan.
  4. EIP‑1193 error codes: 4001 = user rejected request, -32002 = request pending.
  5. Gas tip: Use ethers.utils.parseUnits("0.001", "ether") instead of hard‑coding wei for readability.
  6. Chain IDs: 1‑Ethereum, 5‑Goerli, 56‑BSC, 137‑Polygon, 42161‑Arbitrum.
  7. ERC‑20 approve should be set to 0 before changing to a new non‑zero value to mitigate the race‑condition attack.
  8. RainbowKit auto‑detects the best wallet for the user’s device (MetaMask on desktop, WalletConnect on mobile).
  9. onChainChanged returns a hex string (0x1); convert with parseInt(chainId, 16).
  10. Security tip: Always verify the to address of a signed transaction; a malicious dApp can redirect funds to an attacker’s contract.


ADVERTISEMENT