Web3开发基础
Web3是指基于区块链技术的去中心化互联网,它通过智能合约和去中心化应用(DApp)为用户提供更加开放、透明和安全的网络体验。Web3开发涉及前端界面、智能合约、区块链交互等多个方面。
Web3概述
Web演进历程
Web 1.0(1990s-2000s)
- 静态网页,只读内容
- 用户主要是信息接收者
- 代表:Yahoo、AOL
Web 2.0(2000s-现在)
- 动态交互,用户生成内容
- 中心化平台主导
- 代表:Facebook、Google、Amazon
Web 3.0(现在-未来)
- 去中心化,用户拥有数据
- 基于区块链技术
- 代表:以太坊、IPFS、Filecoin
Web3核心特征
graph TD
A[Web3特征] --> B[去中心化]
A --> C[用户拥有数据]
A --> D[无需信任]
A --> E[可组合性]
A --> F[代币经济]
B --> B1[无单点故障]
B --> B2[抗审查]
C --> C1[数字身份]
C --> C2[数据可携带]
D --> D1[智能合约]
D --> D2[密码学验证]
E --> E1[DeFi协议]
E --> E2[NFT生态]
F --> F1[激励机制]
F --> F2[价值转移]
Web3技术栈
前端技术
Web3.js库
// 安装Web3.js
npm install web3
// 基本使用
const Web3 = require('web3');
// 连接到以太坊节点
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');
// 或者使用MetaMask提供的provider
const web3 = new Web3(window.ethereum);
// 获取账户余额
async function getBalance(address) {
const balance = await web3.eth.getBalance(address);
console.log(`Balance: ${web3.utils.fromWei(balance, 'ether')} ETH`);
}
// 发送交易
async function sendTransaction() {
const accounts = await web3.eth.getAccounts();
const tx = {
from: accounts[0],
to: '0x...',
value: web3.utils.toWei('0.1', 'ether'),
gas: 21000,
gasPrice: await web3.eth.getGasPrice()
};
const receipt = await web3.eth.sendTransaction(tx);
console.log('Transaction hash:', receipt.transactionHash);
}
Ethers.js库
// 安装Ethers.js
npm install ethers
// 基本使用
const { ethers } = require('ethers');
// 连接到以太坊网络
const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');
// 或者使用MetaMask
const provider = new ethers.providers.Web3Provider(window.ethereum);
// 获取签名器
const signer = provider.getSigner();
// 获取余额
async function getBalance(address) {
const balance = await provider.getBalance(address);
console.log(`Balance: ${ethers.utils.formatEther(balance)} ETH`);
}
// 发送交易
async function sendTransaction() {
const tx = await signer.sendTransaction({
to: '0x...',
value: ethers.utils.parseEther('0.1')
});
console.log('Transaction hash:', tx.hash);
await tx.wait(); // 等待确认
console.log('Transaction confirmed!');
}
智能合约交互
合约实例化
// 合约ABI(应用二进制接口)
const abi = [
"function balanceOf(address owner) view returns (uint256)",
"function transfer(address to, uint256 amount) returns (bool)",
"event Transfer(address indexed from, address indexed to, uint256 value)"
];
// 合约地址
const contractAddress = '0x...';
// 使用Ethers.js创建合约实例
const contract = new ethers.Contract(contractAddress, abi, provider);
// 查询合约数据
async function queryContract() {
const balance = await contract.balanceOf('0x...');
console.log(`Token balance: ${balance.toString()}`);
}
// 调用合约函数
async function interactWithContract() {
// 使用签名器进行写操作
const contractWithSigner = contract.connect(signer);
const tx = await contractWithSigner.transfer('0x...', 100);
console.log('Transaction hash:', tx.hash);
await tx.wait();
}
事件监听
// 监听合约事件
contract.on('Transfer', (from, to, value, event) => {
console.log(`Transfer event: ${from} -> ${to}, Amount: ${value.toString()}`);
console.log('Block number:', event.blockNumber);
});
// 监听特定事件
const filter = contract.filters.Transfer('0x123...'); // 只监听来自特定地址的转账
contract.on(filter, (from, to, value) => {
console.log(`Specific transfer: ${value.toString()}`);
});
// 查询历史事件
async function queryEvents() {
const events = await contract.queryFilter('Transfer', 1000000, 1000100);
events.forEach(event => {
console.log(`Transfer: ${event.args.from} -> ${event.args.to}`);
});
}
IPFS集成
IPFS基础
IPFS(InterPlanetary File System)是一个去中心化的文件存储系统。
// 安装IPFS客户端
npm install ipfs-http-client
// 基本使用
const { create } = require('ipfs-http-client');
// 连接到IPFS节点
const client = create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
headers: {
authorization: 'Bearer YOUR_JWT_TOKEN'
}
});
// 上传文件
async function uploadFile(content) {
const result = await client.add(content);
console.log('IPFS hash:', result.path);
return result.path;
}
// 获取文件
async function getFile(hash) {
const chunks = [];
for await (const chunk of client.cat(hash)) {
chunks.push(chunk);
}
return Buffer.concat(chunks).toString();
}
去中心化应用(DApp)架构
典型DApp架构
graph TB
subgraph "前端界面"
A[React/Vue.js]
B[Web3.js/Ethers.js]
C[MetaMask]
end
subgraph "后端服务"
D[智能合约]
E[IPFS存储]
F[The Graph索引]
end
subgraph "区块链网络"
G[以太坊主网]
H[Layer 2解决方案]
I[侧链]
end
A --> B
B --> C
B --> D
B --> F
D --> G
E --> B
F --> B
前端开发框架
React集成
// 安装依赖
npm install react ethers @usedapp/core
// React组件中使用Web3
import React, { useState, useEffect } from 'react';
import { ethers } from 'ethers';
function WalletConnect() {
const [account, setAccount] = useState('');
const [balance, setBalance] = useState('');
const connectWallet = async () => {
try {
// 请求账户访问
await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const address = await signer.getAddress();
const balance = await signer.getBalance();
setAccount(address);
setBalance(ethers.utils.formatEther(balance));
} catch (error) {
console.error('Failed to connect wallet:', error);
}
};
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
{account && (
<div>
<p>Account: {account}</p>
<p>Balance: {balance} ETH</p>
</div>
)}
</div>
);
}
Vue.js集成
// Vue 3 Composition API
import { ref, onMounted } from 'vue';
import { ethers } from 'ethers';
export default {
setup() {
const account = ref('');
const balance = ref('');
const connectWallet = async () => {
if (typeof window.ethereum !== 'undefined') {
try {
await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
account.value = await signer.getAddress();
const bal = await signer.getBalance();
balance.value = ethers.utils.formatEther(bal);
} catch (error) {
console.error(error);
}
} else {
alert('Please install MetaMask!');
}
};
return {
account,
balance,
connectWallet
};
}
};
状态管理
使用Redux管理Web3状态
// Redux actions
const CONNECT_WALLET = 'CONNECT_WALLET';
const DISCONNECT_WALLET = 'DISCONNECT_WALLET';
const SET_PROVIDER = 'SET_PROVIDER';
// Action creators
export const connectWallet = (account) => ({
type: CONNECT_WALLET,
payload: account
});
// Redux reducer
const initialState = {
account: null,
provider: null,
isConnected: false
};
export function web3Reducer(state = initialState, action) {
switch (action.type) {
case CONNECT_WALLET:
return {
...state,
account: action.payload,
isConnected: true
};
case DISCONNECT_WALLET:
return {
...state,
account: null,
isConnected: false
};
case SET_PROVIDER:
return {
...state,
provider: action.payload
};
default:
return state;
}
}
钱包集成
MetaMask集成
检测MetaMask
// 检测MetaMask是否安装
function detectMetaMask() {
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask is installed!');
return true;
} else {
console.log('MetaMask is not installed');
return false;
}
}
// 监听账户变化
window.ethereum.on('accountsChanged', (accounts) => {
if (accounts.length === 0) {
console.log('User disconnected wallet');
} else {
console.log('Account changed to:', accounts[0]);
// 更新应用状态
}
});
// 监听链变化
window.ethereum.on('chainChanged', (chainId) => {
console.log('Network changed to:', chainId);
// 重新加载页面或更新应用
window.location.reload();
});
网络切换
// 请求切换到特定网络
async function switchNetwork(chainId) {
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: chainId }],
});
} catch (error) {
// 如果网络不存在,添加网络
if (error.code === 4902) {
try {
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [{
chainId: chainId,
chainName: 'Polygon Mainnet',
nativeCurrency: {
name: 'MATIC',
symbol: 'MATIC',
decimals: 18
},
rpcUrls: ['https://polygon-rpc.com'],
blockExplorerUrls: ['https://polygonscan.com/']
}],
});
} catch (addError) {
console.error('Failed to add network:', addError);
}
} else {
console.error('Failed to switch network:', error);
}
}
}
WalletConnect集成
多钱包支持
// 安装WalletConnect
npm install @walletconnect/web3-provider
// 配置WalletConnect
import WalletConnectProvider from '@walletconnect/web3-provider';
const provider = new WalletConnectProvider({
infuraId: 'YOUR_INFURA_PROJECT_ID',
qrcode: true,
qrcodeModalOptions: {
mobileLinks: [
'rainbow',
'metamask',
'trust',
'argent'
]
}
});
// 连接钱包
async function connectWalletConnect() {
try {
await provider.enable();
const web3 = new Web3(provider);
const accounts = await web3.eth.getAccounts();
console.log('Connected account:', accounts[0]);
// 订阅账户变化
provider.on('accountsChanged', (accounts) => {
console.log('Accounts changed:', accounts);
});
// 订阅断开连接
provider.on('disconnect', (code, reason) => {
console.log('Wallet disconnected:', code, reason);
});
} catch (error) {
console.error('Failed to connect:', error);
}
}
去中心化存储
IPFS文件上传
// 文件上传组件
import React, { useState } from 'react';
import { create } from 'ipfs-http-client';
const ipfs = create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
headers: {
authorization: 'Bearer YOUR_JWT_TOKEN'
}
});
function FileUpload() {
const [fileUrl, setFileUrl] = useState('');
const [uploading, setUploading] = useState(false);
const uploadFile = async (file) => {
setUploading(true);
try {
const added = await ipfs.add(file);
const url = `https://ipfs.io/ipfs/${added.path}`;
setFileUrl(url);
console.log('IPFS URL:', url);
} catch (error) {
console.error('Error uploading file:', error);
} finally {
setUploading(false);
}
};
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
uploadFile(file);
}
};
return (
<div>
<input type="file" onChange={handleFileChange} disabled={uploading} />
{uploading && <p>Uploading to IPFS...</p>}
{fileUrl && (
<div>
<p>File uploaded successfully!</p>
<a href={fileUrl} target="_blank" rel="noopener noreferrer">
View on IPFS
</a>
</div>
)}
</div>
);
}
NFT元数据存储
// NFT元数据结构
const createNFTMetadata = (name, description, image, attributes) => {
return {
name: name,
description: description,
image: image, // IPFS hash
attributes: attributes
};
};
// 上传NFT元数据
async function uploadNFTMetadata(metadata) {
try {
const added = await ipfs.add(JSON.stringify(metadata));
const metadataUrl = `https://ipfs.io/ipfs/${added.path}`;
return metadataUrl;
} catch (error) {
console.error('Error uploading metadata:', error);
throw error;
}
}
// 完整的NFT创建流程
async function createNFT(name, description, imageFile, attributes) {
// 1. 上传图片到IPFS
const imageAdded = await ipfs.add(imageFile);
const imageUrl = `https://ipfs.io/ipfs/${imageAdded.path}`;
// 2. 创建元数据
const metadata = createNFTMetadata(name, description, imageUrl, attributes);
// 3. 上传元数据到IPFS
const metadataUrl = await uploadNFTMetadata(metadata);
return metadataUrl;
}
The Graph协议
子图开发
The Graph是一个去中心化的区块链数据索引协议,可以为DApp提供高效的链上数据查询。
// 安装Graph CLI
npm install -g @graphprotocol/graph-cli
// 初始化子图项目
graph init --product hosted-service --studio YOUR_SUBGRAPH_NAME
// 示例子图schema.graphql
type Transfer @entity {
id: ID!
from: Bytes!
to: Bytes!
value: BigInt!
timestamp: BigInt!
transactionHash: Bytes!
}
type Token @entity {
id: ID!
name: String!
symbol: String!
totalSupply: BigInt!
transfers: [Transfer!]! @derivedFrom(field: "token")
}
GraphQL查询
// 使用Apollo Client查询The Graph
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
uri: 'https://api.thegraph.com/subgraphs/name/YOUR_SUBGRAPH_NAME',
cache: new InMemoryCache()
});
// 查询代币转账
const GET_TRANSFERS = gql`
query GetTransfers($first: Int!, $skip: Int!) {
transfers(first: $first, skip: $skip, orderBy: timestamp, orderDirection: desc) {
id
from
to
value
timestamp
transactionHash
}
}
`;
async function getTransfers() {
const { data } = await client.query({
query: GET_TRANSFERS,
variables: {
first: 10,
skip: 0
}
});
return data.transfers;
}
最佳实践
1. 错误处理
// 完善的错误处理
async function safeContractCall(contract, method, ...args) {
try {
const tx = await contract[method](...args);
const receipt = await tx.wait();
return { success: true, receipt };
} catch (error) {
console.error(`Contract call failed: ${error.message}`);
// 解析错误信息
if (error.code === 'UNPREDICTABLE_GAS_LIMIT') {
console.error('Transaction would fail');
} else if (error.code === 'INSUFFICIENT_FUNDS') {
console.error('Insufficient funds');
}
return { success: false, error: error.message };
}
}
2. 状态管理
// 使用React Context管理Web3状态
import React, { createContext, useContext, useReducer } from 'react';
const Web3Context = createContext();
const initialState = {
account: null,
provider: null,
chainId: null,
isConnected: false
};
function web3Reducer(state, action) {
switch (action.type) {
case 'CONNECT':
return {
...state,
account: action.payload.account,
provider: action.payload.provider,
chainId: action.payload.chainId,
isConnected: true
};
case 'DISCONNECT':
return initialState;
default:
return state;
}
}
export function Web3Provider({ children }) {
const [state, dispatch] = useReducer(web3Reducer, initialState);
return (
<Web3Context.Provider value={{ state, dispatch }}>
{children}
</Web3Context.Provider>
);
}
export function useWeb3() {
const context = useContext(Web3Context);
if (!context) {
throw new Error('useWeb3 must be used within a Web3Provider');
}
return context;
}
3. 性能优化
// 使用React Query缓存区块链数据
import { useQuery } from 'react-query';
function useTokenBalance(tokenAddress, account) {
return useQuery(
['tokenBalance', tokenAddress, account],
async () => {
const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
return await contract.balanceOf(account);
},
{
enabled: !!account && !!tokenAddress,
staleTime: 30000, // 30秒
refetchInterval: 60000, // 1分钟
}
);
}
Web3开发是一个快速发展的领域,需要不断学习和实践。通过掌握这些基础知识和最佳实践,您将能够构建出安全、高效和用户友好的去中心化应用。随着技术的不断演进,Web3将继续为互联网带来革命性的变化。