{"content":{"title":"入门小白简单快速地学会编写erc20（有标准的）","body":"### 思路\r\n\r\n题目：**发布一个erc20token，设置部署合约的地址为管理员，管理员可以增发token，但初始总量为2000万个，用户可以销毁自己的token**\r\n\r\n编写一个合约功能前我们要知道需要的参数\r\n\r\n1. 币叫什么\r\n\r\n2. 最小单位是多少\r\n\r\n3. 币量初始值是多少\r\n\r\n4. 之后呢，这些币应该是谁的，创始人的吧，那就要使用mapping捆绑其地址‘\r\n\r\n   但是后面铸造也不一定全是给创始人的\r\n\r\n5. 同时我们还需要实现授权功能，也就是创始人给的token赋权给一些人吧，那么当这些人使用这些授权的token的时候，授权资产减少，那么创始人的token也减少，那么需要写双重映射了\r\n\r\n6. 准备工作做好了，正片开始，首先肯定是要初始化的，咱们使用构造函数自动初始化\r\n\r\n7. 那么我们需要知道，什么时候token转了，授权了，铸造了，毁了，需要创建事件，emit触发事件，事件里面要使用indexed关键字\r\n\r\n8. 接着就是完善函数功能了吧\r\n\r\n### 开始写\r\n\r\n1. 第一步声明我们要写的变量\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\nconstract token{\r\nstring public token_name=\"beaventao\"//币全名\r\nstring public token_symbol=\"bea\"//币简称\r\nuint8 public dot=18;\r\nuint256 public total_token=20000000*(10**uint256(dot))//这里是最小单位\r\naddress public owner;\r\n}\r\n```\r\n\r\n2. 捆绑部分\r\n\r\n   ```\r\n   mapping(address => uint256) public balances;\r\n   mapping(address => mapping(address => uint256)) public allowances;\r\n   ```\r\n\r\n3. 初始化\r\n\r\n   ```\r\n   constructor() {\r\n           owner = msg.sender;\r\n           balances[owner] = total_token;\r\n       }\r\n   ```\r\n\r\n4. 创造事件\r\n\r\n   ```\r\n   event Transfer(address indexed from, address indexed to, uint256 value);\r\n   event Approval(address indexed owner, address indexed spender, uint256 value);\r\n   event Mint(address indexed to, uint256 value);\r\n   event Burn(address indexed from, uint256 value);\r\n   ```\r\n\r\n5. 转账函数\r\n\r\n   ```\r\n    function transfer(address _to, uint256 _value) public returns (bool) {\r\n           require(balances[msg.sender] >= _value, \"Not enough tokens\");\r\n           balances[msg.sender] -= _value;\r\n           balances[_to] += _value;\r\n           emit Transfer(msg.sender, _to, _value);\r\n           return true;\r\n       }\r\n   ```\r\n\r\n6. 授权函数\r\n\r\n   ```\r\n   function approve(address _spender, uint256 _value) public returns (bool) {\r\n           allowances[msg.sender][_spender] = _value;\r\n           emit Approval(msg.sender, _spender, _value);\r\n           return true;\r\n       }\r\n   ```\r\n\r\n   这里解释两点\r\n\r\n   1. 这里使用 “=“  而不是 ”+=”  因为是授权，必须是精确的数值\r\n   2. [msg.sender] [_spender]  上面双重映射的另一个形式。\r\n\r\n7. 授权转账函数\r\n\r\n   ```\r\n     function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {\r\n           require(balances[_from] >= _value, \"Not enough tokens\");\r\n           require(allowances[_from][msg.sender] >= _value, \"Allowance exceeded\");\r\n   \r\n           balances[_from] -= _value;\r\n           balances[_to] += _value;\r\n           allowances[_from][msg.sender] -= _value;\r\n           emit Transfer(_from, _to, _value);\r\n           return true;\r\n       }\r\n   ```\r\n\r\n8. 铸造和销毁函数\r\n\r\n   ```\r\n    function mint(address _to, uint256 _value) public returns (bool) {\r\n           require(msg.sender == owner, \"Only the owner can mint tokens\");\r\n           total_token += _value;\r\n           balances[_to] += _value;\r\n           emit Mint(_to, _value);\r\n           emit Transfer(address(0), _to, _value);\r\n           return true;\r\n       }\r\n   \r\n       function burn(address _from, uint256 _value) public returns (bool) {\r\n           require(msg.sender == owner, \"Only the owner can burn tokens\");\r\n           require(balances[_from] >= _value, \"Not enough tokens to burn\");\r\n           total_token -= _value;\r\n           balances[_from] -= _value;\r\n           emit Burn(_from, _value);\r\n           emit Transfer(_from, address(0), _value);\r\n           return true;\r\n       }\r\n   }\r\n   ```\r\n\r\n   针对address(0)解释\r\n\r\n   1. `address(0)` 表示以太坊地址空间中的一个特定地址，这个地址通常被用来表示“空地址”或“无效地址”。它有助于明确地表示某个操作或状态没有实际关联的地址。\r\n   2. 我理解为源泉地址，如同无尽的水源，我们只是从里面抽了一些水，销毁也就是把水送回去。这个过程只要没到其他人的手里，就不会被滥用，也就是无关系地址\r\n   3. emit的参数数量要与事件对应\r\n\r\n### 代码识别\r\n\r\n下面是个错误代码，通过上面学习你把它改成正确的就算搞懂了\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\ncontract token{\r\n string public token_name=\"beaventao\";\r\n string public token_symbol=\"bea\";\r\n uint8  public dot=18;\r\n uint256 public total_token=20000000*(10**dot);\r\n address public owner;\r\n\r\nmapping (address =>uint256) public balances;\r\nmapping (address=> mapping (address=>uint256)) allowances;\r\n\r\nconstructor(){\r\n owner=msg.sender;\r\n balances[owner]=total_token;\r\n}\r\n\r\n event transfer(address indexed from,address indexed to,uint256 value);\r\n event approval(address indexed from,address indexed to,uint256 value);\r\n event mint(address indexed from,address indexed to,uint256 value);\r\n event burn(address indexed from,address indexed to,uint256 value);\r\n\r\n\r\nfunction transfer(address _to,uint256 _value) public returns(bool){\r\n    require(balances[owner]>=_value,\"not enough token\");\r\n    balances[owner]-=_value;\r\n    balances[_to]+=_value;\r\n    emit transfer(msg.sender, _to,_value);\r\n    return true;\r\n}\r\n\r\nfunction approval(address _spendright, address _to,uint256 _value) public returns(bool){\r\n    require(balances[msg.sender]>=_value,\"error\");\r\n    allowances[msg.sender][_spendright]+=value;\r\n    emit approval(msg.sender, _spendright,_value);\r\n    return true;\r\n}\r\n\r\nfunction transferes(address _from,address _to,uint256 _value) returns (bool){\r\n    require(allowances[msg.sender][_spendright]>=_value,\"not enough money\");\r\n    balances[_to]+=_value;\r\n    balances[msg.sender]-=_value;\r\n    allowances[msg.sender][_spendright]-=_value;\r\n    emit transfer(_from, _to, _value);\r\n    return true;\r\n}\r\n\r\nfunction mint(address _to,uint256 token_num) public returns (bool){\r\n    require(msg.sender,\"you don't have right\");\r\n    total_token+=token_num;\r\n    balances[_to]+=token_num;\r\n    emit mint(_to, token_num);\r\n    emit transfer( _to, token_num);\r\n    return true;\r\n}\r\n\r\nfunction burn(address _to,uint256 token_num) public returns (bool){\r\n    require(msg.sender,\"you don't have right\");\r\n    total_token-=token_num;\r\n    balances[_to]-=token_num;\r\n    emit burn(_to, token_num);\r\n    return true;\r\n}\r\n}\r\n```\r\n\r\n### 标准的erc20\r\n其改变最主要的是对address(0)的检验，以及保持授权金额的同步，保证准确\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\ncontract BaseERC20 {\r\n    string public name = \"BaseERC20\";\r\n    string public symbol = \"BERC20\";\r\n    uint8 public decimals = 18;\r\n    uint256 public totalSupply = 100000000 * (10 ** uint256(decimals));\r\n    address public owner;\r\n\r\n    mapping(address => uint256) balances;\r\n    mapping(address => mapping(address => uint256)) allowances;\r\n\r\n    event Transfer(address indexed from, address indexed to, uint256 value);\r\n    event Approval(address indexed owner, address indexed spender, uint256 value);\r\n\r\n    constructor() {\r\n        owner = msg.sender;\r\n        balances[msg.sender] = totalSupply;\r\n    }\r\n\r\n    function balanceOf(address _owner) public view returns (uint256 balance) {\r\n        return balances[_owner];\r\n    }\r\n\r\n    function transfer(address _to, uint256 _value) public returns (bool success) {\r\n        require(_to != address(0), \"Invalid address\");\r\n        require(balances[msg.sender] >= _value, \"ERC20: transfer amount exceeds balance\");\r\n        \r\n        balances[msg.sender] -= _value;\r\n        balances[_to] += _value;\r\n        \r\n        emit Transfer(msg.sender, _to, _value);\r\n        return true;\r\n    }\r\n\r\n    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {\r\n        require(_from != address(0) && _to != address(0), \"Invalid address\");\r\n        require(balances[_from] >= _value, \"ERC20: transfer amount exceeds balance\");\r\n        require(allowances[_from][msg.sender] >= _value, \"ERC20: transfer amount exceeds allowance\");\r\n\r\n        balances[_from] -= _value;\r\n        balances[_to] += _value;\r\n        allowances[_from][msg.sender] -= _value;\r\n\r\n        emit Transfer(_from, _to, _value);\r\n        return true;\r\n    }\r\n\r\n    function approve(address _spender, uint256 _value) public returns (bool success) {\r\n        require(_spender != address(0), \"Invalid address\");\r\n\r\n        allowances[msg.sender][_spender] = _value;\r\n        emit Approval(msg.sender, _spender, _value);\r\n        return true;\r\n    }\r\n\r\n    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {\r\n        return allowances[_owner][_spender];\r\n    }\r\n}\r\n\r\n```"},"author":{"user":"https://learnblockchain.cn/people/19204","address":"0x0c3743ac31156269ea0ea04bdb1864645017a92b"},"history":"bafkreiaw3tdby2tvhqznawrkq4uj4yxzxz6bbttqex5pbwmv7kbc2kblze","timestamp":1716289419,"version":1}