{"content":{"title":"Solidity 触发事件","body":"从技术上讲，我们的 \"ERC20\" 代币并不完全符合 ERC20 标准。它缺少一个重要功能：**事件**。\r\n\r\n一般经验法则：**如果一个函数导致状态变化，它应该被记录。**\r\n\r\n* * *\r\n\r\n为什么要记录事件？区块链不是已经不可变地存储了每一笔交易吗？\r\n\r\n这是事实，事件并不是严格必需的。然而，它们使得审计过去的事件变得更加容易。相比浏览一堆交易，用户可以按他们关心的日志进行过滤，并快速找到可能感兴趣的事件（交易）。\r\n\r\n这就是你的加密货币钱包能够快速发现你的 ERC20 余额的方式。如果必须查看 ERC20 代币上发生的每笔交易来发现你是否拥有任何代币，那将是非常烦人的。但日志的存储方式使得这种检索变得高效。\r\n\r\n**事件不能被其他智能合约看到**。它们是为链下查询而优化的。\r\n\r\n让我们来看一个例子。\r\n\r\n```solidity\r\n\r\ncontract ExampleContract {\r\n\r\n    event Deposit(address indexed depositor, uint256 amount);\r\n\r\n    receive()\r\n        external\r\n        payable {\r\n            emit Deposit(msg.sender, msg.value);\r\n    }\r\n}\r\n\r\n```\r\n\r\n一个事件最多可以有 3 个索引类型，但对未索引参数的数量没有严格的限制。\r\n\r\n如果你有数据库背景，你可以将“索引”视为与数据库索引完全相同的方式。\r\n\r\n顺便说一下，数据类型后的参数名称是可选的。我们可以将上述事件写成：\r\n\r\n```solidity\r\n\r\nevent Deposit(address indexed, uint256);\r\n\r\n```\r\n\r\n除了可能稍微降低可读性外，不会有任何不良影响。\r\n\r\n什么时候应该对变量建立索引？如果你可能希望快速查找该值，比如“某个地址是否与此代币合约有关联”，那么你应该对其进行索引。你可能对“是否有人在此合约中正好转账了 1,370,904 个代币？”这样的问题不感兴趣，所以不要对金额建立索引。这是我们添加了事件的 ERC20 代币。请注意，这些事件是[规范](https://eips.ethereum.org/EIPS/eip-20)所要求的。\r\n\r\n特别注意事件添加的位置，尤其是 mint 函数！address(0) 作为来源的约定意味着代币是从无到有产生的，而不是从另一个地址转移而来。推荐阅读：[https://learnblockchain.cn/article/11239](https://learnblockchain.cn/article/11239)\r\n\r\n```solidity\r\n\r\ncontract ERC20 {\r\n    string public name;\r\n    string public symbol;\r\n\r\n    mapping(address => uint256) public balanceOf;\r\n    address public owner;\r\n    uint8 public decimals;\r\n\r\n    uint256 public totalSupply;\r\n\r\n    // owner -> spender -> allowance\r\n    // 这使所有者可以向多个地址授权\r\n    mapping(address => mapping(address => uint256)) public allowance;\r\n\r\n    event Transfer(\r\n        address indexed _from,\r\n        address indexed _to,\r\n        uint256 _value\r\n    );\r\n    event Approval(\r\n        address indexed _owner,\r\n        address indexed _spender,\r\n        uint256 _value\r\n    );\r\n\r\n    constructor(\r\n        string memory _name,\r\n        string memory _symbol\r\n    ) {\r\n        name = _name;\r\n        symbol = _symbol;\r\n        decimals = 18;\r\n\r\n        owner = msg.sender;\r\n    }\r\n\r\n    function mint(\r\n        address to,\r\n        uint256 amount\r\n    )\r\n        public {\r\n            require(msg.sender == owner, \"only owner can create tokens\");\r\n            totalSupply += amount;\r\n            balanceOf[owner] += amount;\r\n\r\n            emit Transfer(address(0), owner, amount);\r\n    }\r\n\r\n    function transfer(\r\n        address to,\r\n        uint256 amount\r\n    )\r\n        public\r\n        returns (bool) {\r\n            return helperTransfer(msg.sender, to, amount);\r\n    }\r\n\r\n    function approve(\r\n        address spender,\r\n        uint256 amount\r\n    )\r\n        public\r\n        returns (bool) {\r\n            allowance[msg.sender][spender] = amount;\r\n            emit Approval(msg.sender, spender, amount);\r\n\r\n            return true;\r\n    }\r\n\r\n    function transferFrom(\r\n        address from,\r\n        address to,\r\n        uint256 amount\r\n    )\r\n        public\r\n        returns (bool) {\r\n            if (msg.sender != from) {\r\n                require(\r\n                    allowance[from][msg.sender] >= amount,\r\n                    \"not enough allowance\"\r\n                );\r\n\r\n                allowance[from][msg.sender] -= amount;\r\n            }\r\n\r\n            return helperTransfer(from, to, amount);\r\n    }\r\n\r\n    function helperTransfer(\r\n        address from,\r\n        address to,\r\n        uint256 amount\r\n    )\r\n        internal\r\n        returns (bool) {\r\n            require(balanceOf[from] >= amount, \"not enough money\");\r\n            require(to != address(0), \"cannot send to address(0)\");\r\n            balanceOf[from] -= amount;\r\n            balanceOf[to] += amount;\r\n\r\n            emit Transfer(from, to, amount);\r\n            return true;\r\n    }\r\n}\r\n\r\n```\r\n\r\n**练习题**\r\n\r\n[Emitter](https://github.com/RareSkills/Solidity-Exercises/tree/main/Emitter)\r\n\r\n###  了解更多\r\n\r\n请查看 [区块链培训营](https://learnblockchain.cn/openspace/1)，了解更多关于智能合约开发和代币标准的内容。\r\n \r\n\r\n>- 原文链接： [rareskills.io/learn-soli...](https://www.rareskills.io/learn-solidity/events)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/20722","address":null},"history":"bafkreif53hnbyctnry2uxuxq5jdwekfhk536pdpztcau4rrks3zbxl4nke","timestamp":1740578243,"version":1}