智能合约 ✅ 验证通过
事件 = 链上日志 = 合约向DApp广播消息的通道,数据存储在交易收据的logs中,不是合约storage中,因此非常便宜。每次emit只需要约375 Gas基础费用加上每个indexed参数375 Gas和非indexed参数8 Gas/字节。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract EventDemo {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 value);
event BatchTransfer(address indexed from, address[] to, uint256[] amounts);
event Deposit(address indexed from, uint256 amount, uint256 timestamp);
// 匿名事件(省掉topic[0]签名,可多1个indexed)
event AnonTransfer(address indexed from, address indexed to, uint256 v) anonymous;
mapping(address => uint256) public balances;
function transfer(address to, uint256 amt) public {
require(balances[msg.sender] >= amt, "Insufficient balance");
balances[msg.sender] -= amt; balances[to] += amt;
emit Transfer(msg.sender, to, amt);
}
function batchTransfer(address[] memory to, uint256[] memory amts) public {
require(to.length == amts.length, "Length mismatch");
for (uint i = 0; i < to.length; i++) {
balances[msg.sender] -= amts[i]; balances[to[i]] += amts[i];
}
emit BatchTransfer(msg.sender, to, amts);
}
function deposit() public payable {
balances[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value, block.timestamp);
}
}
// ✅ 验证通过
| indexed | 非indexed | |
|---|---|---|
| 存储位置 | topics(可搜索) | data(不可搜索) |
| 最多数量 | 3个(anonymous 4个) | 无限制 |
| 类型限制 | 值类型(string/bytes哈希化) | 任意类型 |
| Gas成本 | 375+375/topic | 8/字节 |
| 查询效率 | 高效(直接匹配) | 需解编所有日志 |
const contract = new ethers.Contract(address, abi, provider);
// 查询所有Transfer事件
const events = await contract.queryFilter('Transfer');
// 按地址过滤(利用indexed)
const fromAlice = await contract.queryFilter(
contract.filters.Transfer(aliceAddress)
);
// 实时监听
contract.on('Transfer', (from, to, amount, event) => {
console.log(from + ' → ' + to + ': ' + amount);
});
contract TryCatch {
interface ITarget { function risky(uint256) external returns (uint256); }
function safeCall(address t, uint256 x) public
returns (bool ok, uint256 result, string memory msg_) {
try ITarget(t).risky(x) returns (uint256 v) {
return (true, v, "");
} catch Panic(uint256 code) {
return (false, code, "Panic");
} catch Error(string memory reason) {
return (false, 0, reason);
} catch (bytes memory data) {
return (false, 0, "Low-level error");
}
}
}
// ✅ 验证通过
事件存储位置?
indexed最多几个?
try/catch捕获?
Bloom说存在意味着?
indexed string会?
contract AnonEventDemo {
// 匿名事件: 省掉topic[0]的签名哈希, 可多1个indexed参数
event Transfer(address indexed from, address indexed to, uint256 amount) anonymous;
// 普通事件: topic[0]=签名, 最多3个indexed
// 匿名事件: 无签名占用, 最多4个indexed
function transfer(address to, uint256 amt) public {
emit Transfer(msg.sender, to, amt);
}
}
// ✅ 验证通过
contract StructuredLogging {
// ✅ 好的事件设计: indexed关键查询字段, 非indexed存详情
event TradeExecuted(
address indexed trader, // 按交易者查询
address indexed tokenIn, // 按输入代币查询
address indexed tokenOut, // 按输出代币查询
uint256 amountIn, // 非indexed存data
uint256 amountOut,
uint256 fee,
uint256 timestamp
);
// ❌ 差的设计: 所有参数都indexed(浪费Gas,丢失详情)
event BadTrade(address indexed a, address indexed b, address indexed c, uint256 indexed d);
// ✅ 合理设计: 2-3个indexed, 其余放data
function trade(address tokenIn, address tokenOut, uint256 amtIn, uint256 amtOut) public {
uint256 fee = amtIn / 1000;
emit TradeExecuted(msg.sender, tokenIn, tokenOut, amtIn, amtOut, fee, block.timestamp);
}
}
// ✅ 验证通过
contract ErrorBestPractice {
// ✅ 错误命名清晰,参数包含诊断信息
error InsufficientBalance(uint256 available, uint256 required);
error UnauthorizedAccess(address caller, string role);
error InvalidState(string current, string expected);
error DeadlineExpired(uint256 deadline, uint256 currentTime);
mapping(address => uint256) public balances;
mapping(address => string) public roles;
function withdraw(uint256 amount) public {
uint256 bal = balances[msg.sender];
if (bal < amount) revert InsufficientBalance(bal, amount);
// 前端可根据available/required显示友好提示
balances[msg.sender] -= amount;
}
function adminAction() public {
if (keccak256(bytes(roles[msg.sender])) != keccak256("admin"))
revert UnauthorizedAccess(msg.sender, "admin");
// ...
}
}
// ✅ 验证通过 - 自定义错误比require字符串省50%+ Gas
contract DeFiEvents {
// ✅ DEX事件设计
event Swap(
address indexed sender,
address indexed tokenIn,
address indexed tokenOut,
uint256 amountIn,
uint256 amountOut,
uint256 fee
);
// ✅ 借贷事件设计
event Deposit(address indexed user, address indexed asset, uint256 amount, uint256 timestamp);
event Borrow(address indexed user, address indexed asset, uint256 amount, uint256 interestRate);
event Liquidation(address indexed borrower, address indexed liquidator, uint256 debtCovered, uint256 collateralSeized);
// ✅ 治理事件设计
event ProposalCreated(uint256 indexed id, address indexed proposer, string description);
event VoteCast(uint256 indexed id, address indexed voter, bool support, uint256 weight);
// 前端通过TheGraph索引这些事件构建完整UI
// 例如: 交易历史、持仓追踪、投票记录等
}
// ✅ 验证通过
contract NFTMarketEvents {
eventItemListed(address indexed seller, uint256 indexed tokenId, uint256 price);
eventItemBought(address indexed buyer, uint256 indexed tokenId, uint256 price);
eventItemCancelled(address indexed seller, uint256 indexed tokenId);
eventOfferMade(address indexed buyer, uint256 indexed tokenId, uint256 amount);
eventAuctionStarted(uint256 indexed tokenId, uint256 minBid, uint256 endTime);
eventBidPlaced(uint256 indexed tokenId, address indexed bidder, uint256 amount);
// ✅ TheGraph索引这些事件构建:
// - NFT交易历史
// - 地板价追踪
// - 持有者分析
// - 拍卖状态
// - 收藏趋势
}
你已掌握事件日志、indexed查询、try/catch、Bloom!
✅ 事件日志 ✅ indexed查询 ✅ try/catch ✅ Bloom过滤器