Wallet Connection App Documentation
Overview
This application is a React-based web interface that allows users to connect their Ethereum wallets. It supports multiple wallet providers, including MetaMask, WalletConnect, Safe, and injected wallets. The app is built using React with TypeScript and leverages the Wagmi library for Ethereum wallet connections.
Project Structure
The application follows this structure:
connect-wallet-example/
├── src/
│ ├── components/
│ │ ├── Account.tsx
│ │ ├── Connect.tsx
│ │ └── ConnectWallet.tsx
│ ├── App.tsx
│ ├── index.tsx
│ ├── wagmi.tsx
│ └── index.css
├── package.json
└── tsconfig.json
Dependencies
The application relies on these dependencies:
- React & React DOM: UI framework
- Wagmi: Ethereum wallet connection hooks
- Viem: Low-level Ethereum interface
- TanStack React Query: Data fetching and caching
- TypeScript: Type safety
- Vite: Build tool and development server
Package Management
The project uses pnpm as its package manager.
Configuration
Wagmi Configuration
The application configures Wagmi in the wagmi.ts
file:
import { http, createConfig } from "wagmi";
import { base, mainnet, optimism } from "wagmi/chains";
import { injected, metaMask, safe, walletConnect } from "wagmi/connectors";
const projectId = "3fbb6bba6f1de962d911bb5b5c9dba88";
export const config = createConfig({
chains: [mainnet, optimism, base],
connectors: [injected(), walletConnect({ projectId }), metaMask(), safe()],
transports: {
[mainnet.id]: http(),
[optimism.id]: http(),
[base.id]: http(),
},
});
This configuration:
- Supports Ethereum Mainnet, Optimism, and Base chains
- Enables wallet connections via injected providers, WalletConnect, MetaMask, and Safe
- Configures HTTP transport for each chain
Note: The projectId
is used for WalletConnect integration.
Components
App Component
The main App component sets up the Wagmi provider and React Query:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider } from "wagmi";
import { ConnectWallet } from "./components/ConnectWallet";
import { config } from "./wagmi";
const queryClient = new QueryClient();
export default function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<ConnectWallet />
</QueryClientProvider>
</WagmiProvider>
);
}
ConnectWallet Component
This component conditionally renders either the Connect or Account component based on the connection status:
import { useAccount } from "wagmi";
import { Account } from "./Account";
import { Connect } from "./Connect";
export function ConnectWallet() {
const { isConnected } = useAccount();
return (
<div className="container">{isConnected ? <Account /> : <Connect />}</div>
);
}
Connect Component
Displays buttons for all available wallet connectors:
import * as React from "react";
import { Connector, useChainId, useConnect } from "wagmi";
export function Connect() {
const chainId = useChainId();
const { connectors, connect } = useConnect();
return (
<div className="buttons">
{connectors.map((connector) => (
<ConnectorButton
key={connector.uid}
connector={connector}
onClick={() => connect({ connector, chainId })}
/>
))}
</div>
);
}
function ConnectorButton({
connector,
onClick,
}: {
connector: Connector;
onClick: () => void;
}) {
const [ready, setReady] = React.useState(false);
React.useEffect(() => {
(async () => {
const provider = await connector.getProvider();
setReady(!!provider);
})();
}, [connector, setReady]);
return (
<button
className="button"
disabled={!ready}
onClick={onClick}
type="button"
>
{connector.name}
</button>
);
}
Account Component
Displays connected account information and a disconnect button:
import { useAccount, useDisconnect, useEnsAvatar, useEnsName } from "wagmi";
export function Account() {
const { address, connector } = useAccount();
const { disconnect } = useDisconnect();
const { data: ensName } = useEnsName({ address });
const { data: ensAvatar } = useEnsAvatar({ name: ensName! });
const formattedAddress = formatAddress(address);
return (
<div className="row">
<div className="inline">
{ensAvatar ? (
<img alt="ENS Avatar" className="avatar" src={ensAvatar} />
) : (
<div className="avatar" />
)}
<div className="stack">
{address && (
<div className="text">
{ensName ? `${ensName} (${formattedAddress})` : formattedAddress}
</div>
)}
<div className="subtext">
Connected to {connector?.name} Connector
</div>
</div>
</div>
<button className="button" onClick={() => disconnect()} type="button">
Disconnect
</button>
</div>
);
}
function formatAddress(address?: string) {
if (!address) return null;
return `${address.slice(0, 6)}…${address.slice(38, 42)}`;
}
User Flow
- Initial State: User is presented with wallet connection options
- Wallet Selection: User clicks on their preferred wallet provider
- Wallet Connection: The wallet provider’s interface opens, allowing the user to connect
- Connected State: Once connected, the UI switches to show account information
- Disconnection: User can disconnect by clicking the “Disconnect” button
Getting Started
Prerequisites
- Node.js
- pnpm
Installation
-
Set up the files as shown in the project structure
-
Install dependencies:
pnpm install
-
Run the development server:
pnpm dev
-
Open your browser to the URL shown in the terminal (typically http://localhost:5173)
Using in Ledger Live
-
Set up the files as shown in the project structure
-
Install dependencies:
pnpm install
-
Run the development server:
pnpm dev
-
Create a manifest file
Manifest file example
{
"$schema": "https://live-app-catalog.ledger.com/schema.json",
"id": "WagmiExample",
"name": "Wagmi Example",
"private": false,
"url": "http://localhost:5173/",
"dapp": {
"provider": "evm",
"nanoApp": "Ethereum",
"networks": [
{
"currency": "ethereum",
"chainID": 1,
"nodeURL": "https://eth-dapps.api.live.ledger.com"
},
{
"currency": "ethereum_holesky",
"chainID": 17000,
"nodeURL": "https://ethereum-holesky-rpc.publicnode.com"
}
]
},
"homepageUrl": "http://localhost:5173/",
"platforms": ["ios", "android", "desktop"],
"apiVersion": "^2.0.0",
"manifestVersion": "2",
"branch": "stable",
"categories": ["staking", "defi"],
"currencies": ["ethereum", "ethereum_holesky"],
"content": {
"shortDescription": {
"en": "Desc"
},
"description": {
"en": "Desc"
}
},
"permissions": [],
"domains": ["http://", "https://"],
"visibility": "complete"
}
- Go to Ledger Live, Settings, Developer, Add a Local app and add your manifest