Web3 与区块链开发技能,包括智能合约开发、DApp 前端集成、钱包连接、DeFi 协议对接等。适用于开发 Ethereum/EVM 兼容链上的去中心化应用,特别是任务撮合、理财集成(Aave)、DAO 治理等场景。
本技能专为 Web3 智能体任务平台开发而设计,涵盖区块链全栈开发最佳实践。
contracts/
├── core/ # 核心业务合约
│ ├── TaskEscrow.sol # 任务托管
│ ├── AgentRegistry.sol # Agent 注册
│ └── DAOGovernance.sol # DAO 治理
├── integrations/ # 第三方协议集成
│ └── AaveIntegration.sol # Aave 理财对接
├── interfaces/ # 接口定义
├── libraries/ # 工具库
└── test/ # 测试文件
访问控制
Ownable、AccessControlonlyOwner、onlyRole 修饰符重入攻击防护
ReentrancyGuard// ✅ 正确模式
function withdraw(uint amount) external nonReentrant {
require(balances[msg.sender] >= amount); // Checks
balances[msg.sender] -= amount; // Effects
payable(msg.sender).transfer(amount); // Interactions
}
整数溢出
Math 库权限分离
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title TaskEscrow
* @notice 任务资金托管合约,支持 ETH 和 ERC20 代币
* @dev 实现任务创建、承接、交付、结算的完整生命周期
*/
contract TaskEscrow is ReentrancyGuard, Ownable {
// 使用 uint256 而非 uint
// 常量使用 UPPER_SNAKE_CASE
uint256 public constant MIN_COMMISSION_RATE = 500; // 5%
uint256 public constant MAX_COMMISSION_RATE = 1000; // 10%
// 事件命名使用过去式
event TaskCreated(uint256 indexed taskId, address indexed employer);
event TaskCompleted(uint256 indexed taskId, address indexed agent);
// 错误使用 custom errors(省 gas)
error InsufficientFunds();
error TaskNotFound();
error Unauthorized();
}
// config/wagmi.ts
import { getDefaultConfig } from "@rainbow-me/rainbowkit";
import { mainnet, sepolia, polygon, arbitrum } from "wagmi/chains";
export const config = getDefaultConfig({
appName: "Web3 Agent Marketplace",
projectId: process.env.NEXT_PUBLIC_WALLET_CONNECT_ID!,
chains: [mainnet, sepolia, polygon, arbitrum],
ssr: false,
});
// hooks/useTaskContract.ts
import {
useReadContract,
useWriteContract,
useWaitForTransactionReceipt,
} from "wagmi";
import { parseEther } from "viem";
export function useCreateTask() {
const { writeContract, data: hash, isPending, error } = useWriteContract();
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
hash,
});
const createTask = async (title: string, budget: string) => {
writeContract({
address: TASK_ESCROW_ADDRESS,
abi: TaskEscrowABI,
functionName: "createTask",
args: [title],
value: parseEther(budget),
});
};
return { createTask, isPending, isConfirming, isSuccess, error, hash };
}
// 三态处理:等待签名 → 确认中 → 完成/失败
const TransactionButton = ({ onSubmit }) => {
const { isPending, isConfirming, isSuccess, error, hash } = useTransaction();
if (isPending) return <Button disabled>等待钱包签名...</Button>;
if (isConfirming) return <Button disabled>交易确认中...</Button>;
if (isSuccess) return <Success txHash={hash} />;
if (error) return <ErrorMessage error={error} />;
return <Button onClick={onSubmit}>提交交易</Button>;
};
// Aave V3 Pool 接口
interface IAavePool {
supply(
asset: address,
amount: uint256,
onBehalfOf: address,
referralCode: uint16
): void;
withdraw(asset: address, amount: uint256, to: address): uint256;
borrow(
asset: address,
amount: uint256,
interestRateMode: uint256,
referralCode: uint16,
onBehalfOf: address
): void;
repay(
asset: address,
amount: uint256,
interestRateMode: uint256,
onBehalfOf: address
): uint256;
}
// hooks/useAavePosition.ts
export function useAavePosition(userAddress: string) {
const { data: position } = useReadContract({
address: AAVE_POOL_ADDRESS,
abi: AavePoolABI,
functionName: "getUserAccountData",
args: [userAddress],
});
return {
totalCollateral: position?.[0],
totalDebt: position?.[1],
availableBorrows: position?.[2],
healthFactor: position?.[5],
};
}
struct Proposal {
uint256 id;
address proposer;
string description;
uint256 forVotes;
uint256 againstVotes;
uint256 startBlock;
uint256 endBlock;
bool executed;
ProposalType proposalType; // protocol | treasury | arbitration | fee
}
// test/TaskEscrow.t.sol
contract TaskEscrowTest is Test {
TaskEscrow escrow;
address employer = makeAddr("employer");
address agent = makeAddr("agent");
function setUp() public {
escrow = new TaskEscrow();
vm.deal(employer, 10 ether);
}
function test_CreateTask() public {
vm.prank(employer);
uint256 taskId = escrow.createTask{value: 1 ether}("Test Task");
assertEq(escrow.getTaskBudget(taskId), 1 ether);
}
function testFuzz_CreateTaskWithVariousBudgets(uint256 budget) public {
vm.assume(budget > 0.01 ether && budget < 100 ether);
vm.prank(employer);
escrow.createTask{value: budget}("Fuzz Task");
}
}
// __tests__/useTaskContract.test.ts
import { renderHook, waitFor } from "@testing-library/react";
import { useCreateTask } from "../hooks/useTaskContract";
describe("useCreateTask", () => {
it("should create task with correct parameters", async () => {
const { result } = renderHook(() => useCreateTask());
await result.current.createTask("Test Task", "1.0");
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
});
});
A: 使用 try-catch 捕获错误,解析错误信息,向用户展示友好提示。
A: 批量操作、存储打包、使用 calldata、避免循环中的 storage 访问。
A: 使用事件索引 + The Graph 查询,实现链上链下数据同步。