跳到主要内容

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将继续为互联网带来革命性的变化。