# 基于以太坊发行的ERC20智能合约代币源码合集 **Repository Path**: ethergo/ether-erc20-token ## Basic Information - **Project Name**: 基于以太坊发行的ERC20智能合约代币源码合集 - **Description**: 收集了431个基于以太坊发行的ERC20代币源码,基本上能找到各种业务模型的ERC20代币业务模型 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 432 - **Forks**: 252 - **Created**: 2020-10-15 - **Last Updated**: 2025-06-10 ## Categories & Tags **Categories**: bitcoin **Tags**: None ## README ## 全网最全ERC20智能合约大全 如果你想在以太坊ETH上发行一个ERC20的代币,你需要了解ERC20代币合约,通读本文以后,你将获得一个比较厉害的技能,希望你能学会。下图是基于ETH发行的ERC20版的USDT,你可以大概了解一下一个基本的ERC20代币的一些信息: [https://cn.etherscan.com/token/0xdac17f958d2ee523a2206206994597c13d831ec7](https://cn.etherscan.com/token/0xdac17f958d2ee523a2206206994597c13d831ec7) ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/152946_dae8db8a_8185976.png "iShot2020-10-15下午03.28.36.png") **什么是ERC20** 可以把ERC20简单理解成以太坊上的一个代币协议,所有基于以太坊开发的代币合约都遵守这个协议。遵守这些协议的代币我们可以认为是标准化的代币,而标准化带来的好处是兼容性好。这些标准化的代币可以被各种以太坊钱包支持,用于不同的平台和项目。说白了,你要是想在以太坊上发行代币融资,必须要遵守ERC20标准。 ERC20的标准接口是这样的: ``` contract ERC20 { function name() constant returns (string name) function symbol() constant returns (string symbol) function decimals() constant returns (uint8 decimals) function totalSupply() constant returns (uint totalSupply); function balanceOf(address _owner) constant returns (uint balance); function transfer(address _to, uint _value) returns (bool success); function transferFrom(address _from, address _to, uint _value) returns (bool success); function approve(address _spender, uint _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint remaining); event Transfer(address indexed _from, address indexed _to, uint _value); event Approval(address indexed _owner, address indexed _spender, uint _value); } ``` 下面对上面的内容做一个简单的解释: **name** > 返回ERC20代币的名字,例如”My test token”。 **symbol** > 返回代币的简称,例如:MTT,这个也是我们一般在代币交易所看到的名字。 **decimals** > 返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示。 **totalSupply** > 返回token的总供应量 **balanceOf** > 返回某个地址(账户)的账户余额 **transfer** > 从代币合约的调用者地址上转移_value的数量token到的地址_to,并且必须触发Transfer事件。 **transferFrom** > 从地址_from发送数量为_value的token到地址_to,必须触发Transfer事件。transferFrom方法用于允许合同代理某人转移token。条件是from账户必须经过了approve。这个后面会举例说明。 **approve** > 允许_spender多次取回您的帐户,最高达_value金额。 如果再次调用此函数,它将以_value覆盖当前的余量。 **allowance** > 返回_spender仍然被允许从_owner提取的金额。 后面三个方法不好理解,这里还需要补充说明一下: approve是授权第三方(比如某个服务合约)从发送者账户转移代币,然后通过 transferFrom() 函数来执行具体的转移操作。 举例说明,如果账户A有1000个ETH,想允许B账户随意调用他的100个ETH,过程如下: ``` 1. A账户按照以下形式调用approve函数approve(B,100) 2. B账户想用这100个ETH中的10个ETH给C账户,调用transferFrom(A, C, 10) 3. 调用allowance(A, B)可以查看B账户还能够调用A账户多少个token ``` **发行ERC20代币步骤** 1. 在 Chrome 插件商店搜索并安装 MetaMask。 > MetaMask是钱包的一种,在chrome浏览器中,安装MetaMask插件即可,安装完成后,右上角会出现一个“狐狸头”的标志,点击该标志,打开钱包,第一步,创建账户,(创建账户只需要输入面密码即可,名称创建后可以随便改,该账户就是一个hash值,如何给自己创建的账户冲以太币呢,你可以通过在交易所买入一些ETH,然后转入即可)创建成功后,记住密码还有产生的几个随机单词(一定要记录下来)。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/153925_0e3a69d5_8185976.jpeg "v2-c7999f3d3e8840f6fa58a9575b8b7a09_b.jpg") 2. 运行后,用它来给我们初始化一个以太坊钱包。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154022_acd9ac97_8185976.jpeg "v2-69055834472658007aab01b0126a58f2_b.jpg") 3. 准备一份ERC20的智能合约源码(仓库里有很多),一个简单的合约如下: ``` pragma solidity ^0.4.12; contract IMigrationContract { function migrate(address addr, uint256 nas) returns (bool success); } contract SafeMath { function safeAdd(uint256 x, uint256 y) internal returns(uint256) { uint256 z = x + y; assert((z >= x) && (z >= y)); return z; } function safeSubtract(uint256 x, uint256 y) internal returns(uint256) { assert(x >= y); uint256 z = x - y; return z; } function safeMult(uint256 x, uint256 y) internal returns(uint256) { uint256 z = x * y; assert((x == 0)||(z/x == y)); return z; } } contract Token { uint256 public totalSupply; function balanceOf(address _owner) constant returns (uint256 balance); function transfer(address _to, uint256 _value) returns (bool success); function transferFrom(address _from, address _to, uint256 _value) returns (bool success); function approve(address _spender, uint256 _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint256 remaining); event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } /* ERC 20 token */ contract StandardToken is Token { function transfer(address _to, uint256 _value) returns (bool success) { if (balances[msg.sender] >= _value && _value > 0) { balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } else { return false; } } function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { balances[_to] += _value; balances[_from] -= _value; allowed[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } else { return false; } } function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } function approve(address _spender, uint256 _value) returns (bool success) { allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) constant returns (uint256 remaining) { return allowed[_owner][_spender]; } mapping (address => uint256) balances; mapping (address => mapping (address => uint256)) allowed; } contract BliBliToken is StandardToken, SafeMath { // metadata string public constant name = "BliBli"; string public constant symbol = "BCoin"; uint256 public constant decimals = 18; string public version = "1.0"; // contracts address public ethFundDeposit; // ETH存放地址 address public newContractAddr; // token更新地址 // crowdsale parameters bool public isFunding; // 状态切换到true uint256 public fundingStartBlock; uint256 public fundingStopBlock; uint256 public currentSupply; // 正在售卖中的tokens数量 uint256 public tokenRaised = 0; // 总的售卖数量token uint256 public tokenMigrated = 0; // 总的已经交易的 token uint256 public tokenExchangeRate = 625; // 625 BILIBILI 兑换 1 ETH // events event AllocateToken(address indexed _to, uint256 _value); // 分配的私有交易token; event IssueToken(address indexed _to, uint256 _value); // 公开发行售卖的token; event IncreaseSupply(uint256 _value); event DecreaseSupply(uint256 _value); event Migrate(address indexed _to, uint256 _value); // 转换 function formatDecimals(uint256 _value) internal returns (uint256 ) { return _value * 10 ** decimals; } // constructor function BliBliToken( address _ethFundDeposit, uint256 _currentSupply) { ethFundDeposit = _ethFundDeposit; isFunding = false; //通过控制预CrowdS ale状态 fundingStartBlock = 0; fundingStopBlock = 0; currentSupply = formatDecimals(_currentSupply); totalSupply = formatDecimals(10000000); balances[msg.sender] = totalSupply; if(currentSupply > totalSupply) throw; } modifier isOwner() { require(msg.sender == ethFundDeposit); _; } /// 设置token汇率 function setTokenExchangeRate(uint256 _tokenExchangeRate) isOwner external { if (_tokenExchangeRate == 0) throw; if (_tokenExchangeRate == tokenExchangeRate) throw; tokenExchangeRate = _tokenExchangeRate; } /// @dev 超发token处理 function increaseSupply (uint256 _value) isOwner external { uint256 value = formatDecimals(_value); if (value + currentSupply > totalSupply) throw; currentSupply = safeAdd(currentSupply, value); IncreaseSupply(value); } /// @dev 被盗token处理 function decreaseSupply (uint256 _value) isOwner external { uint256 value = formatDecimals(_value); if (value + tokenRaised > currentSupply) throw; currentSupply = safeSubtract(currentSupply, value); DecreaseSupply(value); } /// 启动区块检测 异常的处理 function startFunding (uint256 _fundingStartBlock, uint256 _fundingStopBlock) isOwner external { if (isFunding) throw; if (_fundingStartBlock >= _fundingStopBlock) throw; if (block.number >= _fundingStartBlock) throw; fundingStartBlock = _fundingStartBlock; fundingStopBlock = _fundingStopBlock; isFunding = true; } /// 关闭区块异常处理 function stopFunding() isOwner external { if (!isFunding) throw; isFunding = false; } /// 开发了一个新的合同来接收token(或者更新token) function setMigrateContract(address _newContractAddr) isOwner external { if (_newContractAddr == newContractAddr) throw; newContractAddr = _newContractAddr; } /// 设置新的所有者地址 function changeOwner(address _newFundDeposit) isOwner() external { if (_newFundDeposit == address(0x0)) throw; ethFundDeposit = _newFundDeposit; } ///转移token到新的合约 function migrate() external { if(isFunding) throw; if(newContractAddr == address(0x0)) throw; uint256 tokens = balances[msg.sender]; if (tokens == 0) throw; balances[msg.sender] = 0; tokenMigrated = safeAdd(tokenMigrated, tokens); IMigrationContract newContract = IMigrationContract(newContractAddr); if (!newContract.migrate(msg.sender, tokens)) throw; Migrate(msg.sender, tokens); // log it } /// 转账ETH 到BILIBILI团队 function transferETH() isOwner external { if (this.balance == 0) throw; if (!ethFundDeposit.send(this.balance)) throw; } /// 将BILIBILI token分配到预处理地址。 function allocateToken (address _addr, uint256 _eth) isOwner external { if (_eth == 0) throw; if (_addr == address(0x0)) throw; uint256 tokens = safeMult(formatDecimals(_eth), tokenExchangeRate); if (tokens + tokenRaised > currentSupply) throw; tokenRaised = safeAdd(tokenRaised, tokens); balances[_addr] += tokens; AllocateToken(_addr, tokens); // 记录token日志 } /// 购买token function () payable { if (!isFunding) throw; if (msg.value == 0) throw; if (block.number < fundingStartBlock) throw; if (block.number > fundingStopBlock) throw; uint256 tokens = safeMult(msg.value, tokenExchangeRate); if (tokens + tokenRaised > currentSupply) throw; tokenRaised = safeAdd(tokenRaised, tokens); balances[msg.sender] += tokens; IssueToken(msg.sender, tokens); //记录日志 } } ``` 4. 有了智能合约,然后把它发布到以太坊网络中。 我们使用 Remix - Solidity IDE 网站来发布智能合约。MetaMask会把当前账户相关的信息填写到网站上,我们只需要把智能合约的代码粘贴进去,简单的改一下配置就可以了: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154232_47ba4c6b_8185976.jpeg "v2-0571838dabae082d9c6b3901884df1dd_b.jpg") 5. 把网站当前使用的 solidity 编译器版本号改成和文件头一致,把Enable Optimization 去掉。然后切换到 Compile 页面,点击Start Compile。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154306_53b6a01d_8185976.jpeg "v2-d63ea2387ae78db3ba7d38bcf2eb21aa_b.jpg") 6. 在Run页面,点击 Deploy ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154404_db7ce8d8_8185976.jpeg "v2-262feb25fbac6221006fc34b2b4811de_b.jpg") 7. 弹出 MetaMask 确认页面,输入一个 Gas 数量即可,点击Submit。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154436_a8e3ab66_8185976.jpeg "v2-e16742e250cac707a8858a9990be2f1c_b.jpg") 8. 可以看到合约开始部署~ ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154512_0f45c48e_8185976.jpeg "v2-69055834472658007aab01b0126a58f2_b.jpg") 9. 部署完毕后,点击那个合约,会帮你打开一个网站,查看合约详情: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154616_0d40e4ed_8185976.jpeg "v2-2784a05bf1630241ca1fb9ff512715e3_b.jpg") 10. 点击合约地址,会跳转到合约校验发布页面,点击Verify And Publish ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154643_794a9b55_8185976.jpeg "v2-ecce6571b28b905235561fd517cceb8d_b.jpg") 11. 填写好下面信息,同时粘贴代码: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/155014_6105b89c_8185976.jpeg "v2-60377360bc72f4f4f01f631477f6abbe_b.jpg") 12. 拉到最下面,然后确认即可。发布成功后,会看到如下页面: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/155045_3ec4ffa1_8185976.jpeg "v2-34e589f54efe5be1eabae94d56549548_b.jpg") 13. 然后在账户中,就可以看到如下内容了: ![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/155109_749200ca_8185976.jpeg "v2-6b0a5134adccbefd6cac82b22a2e6249_b.jpg") 到此为止,ERC20的合约已经部署完成!