DApp开发 ✅ 验证通过
ethers.js = DApp前端的以太坊交互库,v6基于ES模块,支持Tree-shaking。四大核心模块:Provider(只读)、Signer(读写)、Contract(合约交互)、Utils(工具)。ethers.js是目前最流行的以太坊JavaScript库,几乎所有DApp前端都使用它来与区块链交互。
import { ethers } from "ethers";
// 1. 连接MetaMask
async function connect() {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const address = await signer.getAddress();
const balance = await provider.getBalance(address);
console.log("地址:", address);
console.log("余额:", ethers.formatEther(balance), "ETH");
return { provider, signer };
}
// 2. 连接合约
const ABI = [
"function getCount() view returns (uint256)",
"function increment()",
"event CountIncremented(uint256,address)"
];
const contract = new ethers.Contract(ADDR, ABI, signer);
// 3. 读取(view函数, 免费)
const count = await contract.getCount();
// 4. 写入(需Gas)
const tx = await contract.increment();
const receipt = await tx.wait();
// 5. 事件监听
contract.on("CountIncremented", (n, caller) => {
console.log("Count:", n, "by", caller);
});
// 6. 查询历史事件
const events = await contract.queryFilter("CountIncremented");
import { useState, useEffect } from "react";
import { ethers } from "ethers";
function useCounter() {
const [count, setCount] = useState(null);
const [contract, setContract] = useState(null);
useEffect(() => {
async function init() {
if (!window.ethereum) return;
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const c = new ethers.Contract(ADDR, ABI, signer);
setContract(c);
setCount(Number(await c.getCount()));
c.on("CountIncremented", (n) => setCount(Number(n)));
}
init();
}, []);
const increment = async () => {
if (!contract) return;
const tx = await contract.increment();
await tx.wait();
};
return { count, increment };
}
function DApp() {
const { count, increment } = useCounter();
return <div><p>Count: {count}</p>
<button onClick={increment}>+1</button></div>;
}
// 监听链切换
window.ethereum.on("chainChanged", () => window.location.reload());
window.ethereum.on("accountsChanged", (accs) => console.log(accs[0]));
// 切换到Sepolia
async function switchChain() {
try {
await window.ethereum.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: "0xaa36a7" }],
});
} catch (err) {
if (err.code === 4902) {
await window.ethereum.request({
method: "wallet_addEthereumChain",
params: [{ chainId: "0xaa36a7", chainName: "Sepolia",
rpcUrls: ["https://rpc.sepolia.org"],
nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
blockExplorerUrls: ["https://sepolia.etherscan.io"] }],
});
}
}
}
ethers.js v6连接MetaMask?
view函数Gas?
tx.wait()?
error 4902?
contract.on监听?
function useTransaction() {
const [status, setStatus] = useState('idle');
// idle → pending → confirming → success/error
const sendTx = async (contractFn) => {
try {
setStatus('pending');
const tx = await contractFn();
setStatus('confirming');
const receipt = await tx.wait(2); // 等2个确认
setStatus('success');
return receipt;
} catch (err) {
setStatus('error');
if (err.code === 'ACTION_REJECTED') {
console.log('用户拒绝交易');
} else if (err.code === 'TRANSACTION_REPLACED') {
console.log('交易被替换');
}
throw err;
}
};
return { status, sendTx };
}
// 推荐使用wagmi+viem替代原生ethers.js
import { createConfig, http } from 'wagmi';
import { sepolia } from 'wagmi/chains';
import { useAccount, useConnect, useDisconnect } from 'wagmi';
import { injected } from 'wagmi/connectors';
const config = createConfig({
chains: [sepolia],
transports: { [sepolia.id]: http() },
});
function ConnectWallet() {
const { address } = useAccount();
const { connect } = useConnect();
const { disconnect } = useDisconnect();
if (address) return (
<div>
<p>{address.slice(0,6)}...{address.slice(-4)}</p>
<button onClick={() => disconnect()}>Disconnect</button>
</div>
);
return <button onClick={() => connect({ connector: injected() })}>Connect</button>;
}
import { useReadContract, useWriteContract } from 'wagmi';
import { parseEther } from 'viem';
const ABI = [
"function balanceOf(address) view returns (uint256)",
"function transfer(address to, uint256 amount) returns (bool)"
];
function useToken(ADDRESS, userAddress) {
const { data: balance } = useReadContract({
address: ADDRESS, abi: ABI,
functionName: 'balanceOf', args: [userAddress],
});
const { writeContract } = useWriteContract();
const transfer = (to, amount) => {
writeContract({
address: ADDRESS, abi: ABI,
functionName: 'transfer',
args: [to, parseEther(amount)],
});
};
return { balance, transfer };
}
import { EthereumClient, w3mConnectors, w3mProvider } from '@web3modal/ethereum'
import { Web3Modal } from '@web3modal/html'
import { configureChains, createConfig } from 'wagmi'
import { sepolia, mainnet } from 'wagmi/chains'
// WalletConnect配置
const projectId = 'YOUR_WALLETCONNECT_PROJECT_ID'
const chains = [mainnet, sepolia]
const { publicClient } = configureChains(chains, [
w3mProvider({ projectId })
])
const wagmiConfig = createConfig({
autoConnect: true,
connectors: w3mConnectors({ projectId, chains }),
publicClient,
})
const ethereumClient = new EthereumClient(wagmiConfig, chains)
const web3modal = new Web3Modal({ projectId }, ethereumClient)
// ✅ 支持移动端钱包连接(扫码/深度链接)
// 使用zustand管理Web3全局状态
import { create } from 'zustand';
const useWeb3Store = create((set) => ({
address: null,
chainId: null,
provider: null,
signer: null,
connect: async () => {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const address = await signer.getAddress();
const network = await provider.getNetwork();
set({ provider, signer, address, chainId: Number(network.chainId) });
},
disconnect: () => set({ address: null, chainId: null, provider: null, signer: null }),
}));
function useContract(address, abi) {
const { signer, provider } = useWeb3Store();
return useMemo(() => {
if (!provider) return null;
return new ethers.Contract(address, abi, signer || provider);
}, [address, signer, provider]);
}
| 框架 | 优点 | 缺点 |
|---|---|---|
| Next.js + wagmi | SSR/SSG,SEO友好 | 配置复杂 |
| Vite + RainbowKit | 极速开发,简单 | 无SSR |
| Remix + getRoute | 全栈Web3 | 生态较小 |
| React Native | 移动端DApp | 钱包集成困难 |
你已掌握DApp前端——ethers.js/钱包连接/事件监听!
✅ ethers.js ✅ 钱包连接 ✅ 合约交互 ✅ 事件监听