如何在 20 分钟内发布一个正式的 ERC20 通证
在这篇教程中，我准备指导你部署你自己的 ERC20 通证到实际的以太坊网络上去。
以太坊 ERC20
在这篇教程中，我准备指导你部署你自己的 ERC20 通证到实际的以太坊网络上去。
![](/data/attachment/album/201807/10/222045hwhg7mp7w766v7dz.jpg)


这段时间以来，以太坊通证很流行。这些通证可以用来代表现实世界的各种价值单位：[黄金](https://digix.global/)、 [谎言](https://www.cnbc.com/2017/08/28/burger-king-russia-cryptocurrency-whoppercoin.html)、 [猫咪](https://www.cryptokitties.co/) 甚至是类似 [公司股票](https://www.investopedia.com/terms/i/initial-coin-offering-ico.asp) 一样的东西。迄今为止，人们已经募集了 [20 亿美元的通证](https://www.forbes.com/sites/chancebarnett/2017/09/23/inside-the-meteoric-rise-of-icos/#57ac46d95670)。那些通证是以 [ERC20](https://theethereum.wiki/w/index.php/ERC20_Token_Standard) 为标准的，人们可以轻松地在钱包之间进行交易。在这篇教程中，我准备指导你部署你自己的 ERC20 通证到真实的以太坊网络上去。


事先准备：


* 一个文本编辑器（[Atom](https://atom.io/) 不错，不过我喜欢 [Vim](http://www.vim.org/)）
* 对命令行和终端（模拟器）有起码的了解。Mac 内置的应用“终端”就很好，不过我喜欢 [iTerm2](https://www.iterm2.com/)
* Chrome 浏览器
* [Node.js 8](https://nodejs.org/)（或更高版本）
* 你的通证的名字。我的准备叫做 HamburgerCoin（汉堡币）


你需要做的第一件事是安装 [MetaMask](https://metamask.io/)。访问 [Metamask 网站](https://metamask.io/) 并点击“Get Chrome Extention”。


Metamask 可以让你通过 Chrome 在以太坊上进行交易。它依靠运行着公开以太坊节点的 [Infura](https://infura.io/) ，所以你不用自己运行以太坊全节点。如果你颇具探索精神，你也可以下载和安装 [Mist](https://github.com/ethereum/mist/releases) 以替代它。运行 Mist 就可以让你运行你自己的以太坊节点。运行自己的节点你就需要将你的计算机与该网络进行同步，这需要不短的时间。从技术上讲这更安全，因为这样你不必信任 Infura 来处理你的交易。Infura 可以忽略你的交易而干预你，但是它并不能偷走你的钱。因为安装 Metamask 比 Mist 更快也更简单，所以我假设你在下面的教程中使用 Metamask。


接着你需要安装 [truffle](http://truffleframework.com/)：



```
 $ npm install -g truffle

```

现在为你自己的新通证创建一个新目录，cd 到其中并初始化你的 truffle 项目。



```
$ mkdir hamburger-coin
$ cd hamburger-coin
$ truffle init

```

很好，你的 truffle 项目已经设置好了！


现在来创建我们的通证。首先我们需要安装 [OpenZepplin](https://github.com/OpenZeppelin) 框架。OpenZepplin 框架包括了大量预先构建好的合约，包括我们要部署的 ERC20 通证合约。


（只需要按下回车接受默认值即可）



```
$ npm init
package name: (hamburger-coin)
version: (1.0.0)
description:
entry point: (truffle.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/masonf/src/hamburger-coin/package.json:

{
  "name": "hamburger-coin",
  "version": "1.0.0",
  "description": "",
  "main": "truffle.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes
$ npm install zeppelin-solidity

```

现在我们可以创建我们的通证合约了。创建一个 `contracts/HamburgerCoin.sol` 文件并加入如下内容：



```
pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/StandardToken.sol";

contract HamburgerCoin is StandardToken {
  string public name = "HamburgerCoin"; 
  string public symbol = "HBC";
  uint public decimals = 2;
  uint public INITIAL_SUPPLY = 10000 * (10 ** decimals);

  function HamburgerCoin() public {
    totalSupply_ = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }
}

```

（LCTT 译注：上述合约内容中指定了合约的名称、符号和供应量。在 ERC20 当中，通证的供应量其实是整数，上述合约中通证的实际供应量是 10000 \* 100 个，出于显示 2 位小数的需求，你在合约浏览器、钱包软件中看到和操作的 1 个通证，实际上在交易中是以 100 个进行的。）


OpenZepplin 的 `StandardToken` 是一个标准的 ERC20 通证。如果你感兴趣，你可以看看它的 [源代码](https://github.com/OpenZeppelin/zeppelin-solidity/tree/master/contracts/token) 以了解是如何工作的。


实际上并不太复杂。该合约有一个 [地址到余额](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/BasicToken.sol#L15) 的映射（LCTT 译注：你可以理解为哈希、关联数组），它也有一个 [允许转账](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol#L17) 的列表。你可以看做是支票。你可以写张支票，但是直到它被兑付前，钱并不会被转账。


如果有人要转走一些资金，你可以在合约上调用 [approve](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol#L48) 方法，设置你要发送的通证数量。这就像是写支票一样。


然后调用 [transferFrom](https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/StandardToken.sol#L26) 会实际进行转账。


我们可以从头写这些合约，但是最好采用经过完备的社区测试的合约。从头写一个 ERC20 通证那就是另外一篇文章了。


试着运行 `compile` 来编译我们的合约：



```
$ truffle compile
Compiling ./contracts/HamburgerCoin.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/ownership/Ownable.sol...
Compiling zeppelin-solidity/contracts/token/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/MintableToken.sol...
Compiling zeppelin-solidity/contracts/token/StandardToken.sol...
Writing artifacts to ./build/contracts Next you'll need to add a migration file which will tell truffle how to deploy your contract.

```

接下来我们需要增加一个 truffle [迁移](http://truffleframework.com/docs/getting_started/migrations)。


创建 `migrations/2_deploy_hamburgercoin.js` 文件并添加如下内容：



```
var HamburgerCoin = artifacts.require("./HamburgerCoin.sol");

module.exports = function(deployer) {
  deployer.deploy(HamburgerCoin);
};

```

现在让我们配置 truffle 以能够使用 Infura 公共节点。如果我们要部署到公共节点，那就需要钱包的私钥。我们可以将该私钥包含在我们的源代码当中，但是如果任何人可以访问你的源代码（和版本库），他就能够偷走我们所有的汉堡币！要避免这种情况，我们会使用 [dotenv](https://github.com/motdotla/dotenv) node.js 模块。（LCTT 译注：dotenv 用于存储机密信息的文件 .env 是以 “.” 开头的，默认不会进入版本库，当然，如果有人能查看你全部的项目文件，你的私钥还是会被泄露。）


让我们安装部署到 Infura 所需的所有模块。



```
npm install --save-dev dotenv truffle-wallet-provider ethereumjs-wallet

```

（LCTT 译注：可能安装过程中会有很多警告，大多应该是属于定义了未使用的变量和方法的编译警告，可以忽略。）


现在编辑 `truffle.js` 并（原样）加入如下内容：



```
require('dotenv').config();
const Web3 = require("web3");
const web3 = new Web3();
const WalletProvider = require("truffle-wallet-provider");
const Wallet = require('ethereumjs-wallet');

var mainNetPrivateKey = Buffer.from(process.env["MAINNET_PRIVATE_KEY"], "hex")
var mainNetWallet = Wallet.fromPrivateKey(mainNetPrivateKey);
var mainNetProvider = new WalletProvider(mainNetWallet, "https://mainnet.infura.io/");

var ropstenPrivateKey = Buffer.from(process.env["ROPSTEN_PRIVATE_KEY"], "hex")
var ropstenWallet = Wallet.fromPrivateKey(ropstenPrivateKey);
var ropstenProvider = new WalletProvider(ropstenWallet, "https://ropsten.infura.io/");


module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8545,
      network_id: "*" // Match any network id
    },
    ropsten: {
      provider: ropstenProvider,
      // You can get the current gasLimit by running
      // truffle deploy --network rinkeby
      // truffle(rinkeby)> web3.eth.getBlock("pending", (error, result) =>
      //   console.log(result.gasLimit))
      gas: 4600000,
      gasPrice: web3.toWei("20", "gwei"),
      network_id: "3",
    },
    mainnet: {
      provider: mainNetProvider,
      gas: 4600000,
      gasPrice: web3.toWei("20", "gwei"),
      network_id: "1",
    }
  }
};

```

（LCTT 译注：原文采用 `new Buffer` 来获取私钥设置，但 node.js 升级后，废弃了 `new Buffer` 这种用法，运行时会发出警告，所以上面我修改为使用 `Buffer.from` 。）


接下来我们从 Metamask 中得到我们的私钥：


1. 点击你的 Chrome 窗口右上角的狐狸图标。
2. 点击 “Account 1” 右侧的省略号。
3. 点击 “Export Private Key”。
4. 输入你的密码。
5. 点击该文字以复制私钥到剪贴板。


然后打开 `.env`文件，并像下面这样贴入你的私钥（对于 Ropsten 测试网和 Mainnet 主网，你的私钥是一样的）：



```
ROPSTEN_PRIVATE_KEY="123YourPrivateKeyHere"
MAINNET_PRIVATE_KEY="123YourPrivateKeyHere"

```

接下来，让我们部署到 Ropsten 以太坊测试网。


以太坊测试网是一个你可以测试合约的地方。此外还有 [Kovan](https://kovan-testnet.github.io/website/) 和 [Rinkeby](https://www.rinkeby.io/) 测试网。我在这个教程中选择 Ropsten 是因为现在很容易得到 Ropsten 的测试 ETH。这些测试网都类似，你可以使用任何一个你喜欢的，但是在此教程当中我假设你在使用 Ropsten。访问 <https://faucet.metamask.io/> 以得到一些测试 ETH。从 faucet 得到一些 ETH 后，你就可以部署了。



```
$ truffle deploy --network ropsten
Compiling ./contracts/HamburgerCoin.sol...
Compiling ./contracts/Migrations.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/token/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/StandardToken.sol...
Writing artifacts to ./build/contracts

Using network 'ropsten'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xc2bbe6bf5a7c7c7312c43d65de4c18c51c4d620d5bf51481ea530411dcebc499
  Migrations: 0xd827b6f93fcb50631edc4cf8e293159f0c056538
Saving successful migration to network...
  ... 0xe6f92402e6ca0b1d615a310751568219f66b9d78b80a37c6d92ca59af26cf475
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying HamburgerCoin...
  ... 0x02c4d47526772dc524851fc2180b338a6b037500ab298fa2f405f01abdee21c4
  HamburgerCoin: 0x973b1a5c753a2d5d3924dfb66028b975e7ccca51
Saving artifacts...

```

在 “Saving aritfacts” 上面的这行即是你的合约的新地址。


复制并黏贴该地址到 [Ropsten Etherscan 搜索框](https://ropsten.etherscan.io/)，你就能看到你新部署的合约。


现在你可以在任何 ERC20 兼容的钱包，如 [Mist](https://github.com/ethereum/mist) 、[MyEtherWallet](https://www.myetherwallet.com/)（LCTT 译注：或 ImToken 这样的手机应用）里面使用你的通证了。


为了这篇教程，我构建了一个名为 [Etherface](http://etherface.io/) 的钱包来做演示。


首先你需要添加你的通证到 Etherface：


1. 访问 <http://etherface.io/> 。
2. 确认你在 Metamask 中选择了 “Ropsten” 网络。
3. 点击 “Tokens”。
4. 点击右上角的加号按钮。
5. 输入上面的合约地址。


如果你有朋友想要一些汉堡币，你现在就可以发送给他们了。如果没有，你也可以在你的两个账号间测试转账：


1. 在 Metamask 中点击 “切换账号”按钮（在右上角），并改变你的账号为 “Account 2”。
2. 点击 “Account 2” 右边的省略号，然后选择 “Copy Address to clipboard”。
3. 切换回 “Account 1”，这很重要！否则交易会失败。
4. 在 Etherface 中你的余额下点击 “Send”。
5. 黏贴 “Account 2” 的地址。
6. 输入你要发送的数量。
7. Metamask 会弹出确认窗口，点击 “Submit”。
8. 等大约 15-30 秒。
9. 你的 “Account 1” 的余额应该会减少，“Account 2” 现在会有了一些汉堡币！


最后，让我们来部署到主网（LCTT 译注：这会花费你真实的 ETH，你可以通过查看前面部署到 Ropsten 的合约信息中了解花费了多少 gas，以相应估计实际要花费多少 ETH）：



```
$ truffle deploy --network mainnet

```

你可以如前面一样加你的通证到 Etherface ，并发送你新打造的通证给你的朋友们了！

