By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
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.
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" });
window.ethereum
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, });
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 />
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.
request({method, params})
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.
eth_requestAccounts
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)], });
signTypedDataV4
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 });
ethers.js
Signer
provider.getSigner()
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.
chainId
eth_chainId
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());
onAccountsChanged
onChainChanged
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.
Web3Modal
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.
allowance
approve
Add a wallet connector – Install the library you prefer (e.g., @rainbow-me/rainbowkit + wagmi). bash npm i @rainbow-me/rainbowkit wagmi ethers
@rainbow-me/rainbowkit
wagmi
bash npm i @rainbow-me/rainbowkit wagmi ethers
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>
WagmiConfig
RainbowKitProvider
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>
Render the Connect button – Drop <ConnectButton /> anywhere in your UI. When the user clicks, the modal shows MetaMask, WalletConnect QR, etc.
<ConnectButton />
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
js const { address, connector, isConnected } = useAccount(); const { data: signer } = useSigner(); // ethers.Signer bound to the wallet
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();
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();
Handle events – Listen for accountsChanged and chainChanged to keep UI state in sync, and gracefully disconnect when the user clicks “Disconnect”.
accountsChanged
chainChanged
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.
onClick={() => requestAccounts()}
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.
await provider.request({ method: "eth_chainId" })
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.
if (typeof window !== "undefined")
useEffect
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”.
allowance(owner, spender)
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.
web3.js
window.ethereum.request
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.
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.
call
delegatecall
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”).
operator
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.
window.ethereum.selectedAddress
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.
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.
eth_sign
eth_signTypedData_v4
tx.origin
localStorage
4001
-32002
ethers.utils.parseUnits("0.001", "ether")
0
0x1
parseInt(chainId, 16)
to
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.