Wallet Integration
Fetch Quests uses wagmi + viem for Ethereum wallet connectivity with SIWE for authentication.
Supported Wallets
- MetaMask (injected provider)
- WalletConnect (coming soon)
- Coinbase Wallet (coming soon)
Configuration
Chain Setup
typescript
// frontend/src/config/web3.ts
export const BASE_SEPOLIA = {
id: 84532,
name: 'Base Sepolia',
testnet: true,
blockExplorerUrl: 'https://sepolia.basescan.org',
blockExplorerName: 'BaseScan',
};
export const BASE_MAINNET = {
id: 8453,
name: 'Base',
testnet: false,
blockExplorerUrl: 'https://basescan.org',
blockExplorerName: 'BaseScan',
};
// Toggle via environment variable
export const ACTIVE_CHAIN = import.meta.env.VITE_NETWORK === 'mainnet'
? BASE_MAINNET
: BASE_SEPOLIA;
export const SUPPORTED_CHAIN_ID = ACTIVE_CHAIN.id;wagmi Configuration
typescript
// frontend/src/config/wagmi.ts
import { createConfig, http } from 'wagmi';
import { baseSepolia, base } from 'wagmi/chains';
import { ACTIVE_CHAIN } from './web3';
export const config = ACTIVE_CHAIN.testnet
? createConfig({
chains: [baseSepolia],
transports: { [baseSepolia.id]: http() },
})
: createConfig({
chains: [base],
transports: { [base.id]: http() },
});Connection Flow
1. User Clicks "Connect Wallet"
typescript
const { connect } = useConnect();
// Trigger MetaMask popup
connect({ connector: injected() });2. Network Detection
typescript
const chainId = useChainId();
const isCorrectNetwork = chainId === SUPPORTED_CHAIN_ID;3. Network Switch (if needed)
typescript
const { switchChain } = useSwitchChain();
// Prompt user to switch to Base
await switchChain({ chainId: SUPPORTED_CHAIN_ID });4. MetaMask Detection
typescript
// Check if MetaMask is installed
const hasInjected = typeof window !== 'undefined'
&& typeof window.ethereum !== 'undefined';
if (!hasInjected) {
// Show "Install MetaMask" UI
}Block Explorer URLs
Helper functions for linking to block explorers:
typescript
export function getExplorerAddressUrl(address: string): string {
return `${BLOCK_EXPLORER_URL}/address/${address}`;
}
export function getExplorerTxUrl(txHash: string): string {
return `${BLOCK_EXPLORER_URL}/tx/${txHash}`;
}
export function getExplorerTokenUrl(tokenAddress: string): string {
return `${BLOCK_EXPLORER_URL}/token/${tokenAddress}`;
}ENS Resolution
typescript
// frontend/src/config/ens.ts
export async function lookupEnsName(address: string): Promise<string | null> {
// Uses mainnet ENS (works for all addresses)
const client = createPublicClient({
chain: mainnet,
transport: http('https://cloudflare-eth.com'),
});
return client.getEnsName({ address });
}
export async function resolveEnsAddress(name: string): Promise<string | null> {
const client = createPublicClient({
chain: mainnet,
transport: http('https://cloudflare-eth.com'),
});
return client.getEnsAddress({ name });
}AppContext Integration
The AppContext manages wallet state globally:
typescript
const { address: account } = useAccount();
const { connect } = useConnect();
const { disconnect } = useDisconnect();
const { switchChain } = useSwitchChain();
// Expose to components
<AppContext.Provider value={{
account,
connect,
disconnect,
switchNetwork,
isCorrectNetwork,
// ...
}}>Network Banner
When user is on wrong network, a banner appears:
tsx
function NetworkBanner() {
const { isCorrectNetwork, switchNetwork } = useApp();
if (isCorrectNetwork) return null;
return (
<div className="bg-yellow-500 text-black p-2 text-center">
Wrong network. Please switch to Base.
<button onClick={switchNetwork}>Switch Network</button>
</div>
);
}Environment Variables
| Variable | Description | Example |
|---|---|---|
VITE_NETWORK | Target network | mainnet or omit for testnet |
Troubleshooting
"MetaMask not detected"
User needs to install MetaMask browser extension or use a Web3-enabled browser.
"Wrong network"
User needs to switch to Base (or Base Sepolia for testnet). The app will prompt automatically.
Connection fails silently
Check browser console for errors. Common causes:
- User rejected connection request
- MetaMask locked
- RPC endpoint unreachable