以太坊Solidity开发入门(ERC20发币篇)

环境部署

  • 安装 geth(以太坊客户端)
  • 安装 truffle(智能合约开发工具包,用于编译与自动部署)
  • 安装 ganache-cli (简易的本地以太坊测试链服务器)

安装命令

$ brew tap ethereum/ethereum
$ brew install ethereum
$ npm install -g truffle
$ npm install -g ganache-cli

这里只写了mac os的geth安装方法,其他平台的geth安装方法请参考https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum

  • 检测是否安装成功
  • 一切就绪后,会显示各个工具的版本数据。
$ geth version //1.8.19-stable
$ truffle version // Truffle v4.1.14 (core: 4.1.14) 
$ ganache-cli --version //Ganache CLI v6.2.3 (ganache-core: 2.3.1)

项目构建

  • 先新建一个文件夹,用truffle工具初始化,这里会自动下载一些文件,如果网络慢的话,需要等待一下。
$ mkdir erc20
$ cd erc20
$ truffle init
  • 初始化成功后,安装openzeppelin-solidity模组,这是一套开源的智能合约代码,里面已包括了其他大牛帮我们写好了erc20的智能合约。
$ npm install openzeppelin-solidity
  • 在contracts目录下新建MyToken.sol文件,并编辑。
  • 非常简单的,复制粘贴,就把ERC20的智能合约写完了。
  • 其中TMD_TOKEN通证的名字TMD是简称(symbol),18是通证的精度,就是有18位小数的意思。
$ cd contracts
$ touch MyToken.sol
//MyToken.sol
pragma solidity ^0.4.24;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";

contract MyToken is ERC20, ERC20Detailed {
    uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(decimals()));
    constructor () public ERC20Detailed("TMD_TOKEN", "TMD", 18) {
        _mint(msg.sender, INITIAL_SUPPLY);
    }
}
  • 在migrations目录下新建2_deploy_token.js,并编辑
  • 这个文件是对应我们合约的文件,数字2代表第二个开始编译部署。
$ cd migrations
$ touch 2_deploy_token.js
// 2_deploy_token.js
var MyToken = artifacts.require("./MyToken.sol");

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

  • 编辑truffle.js
module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  networks:{
    // 第一个是默认的链接节点,
    development:{
      host:'127.0.0.1',
      port:8545,
      network_id:'*'
    },
    //  rinkeby 测试网络的设置,
    rinkeby: {
      host: "localhost",
      port: 8545,
      // 需要设置一个默认的账号,钱包里可能有多个账号。
      from: "0xBe255696870b84C69F6e2b902177Cf2a2cB57B58",
      network_id: 4,
      gas: 4700000,
    }
  },

  // 编译配置
  solc:{
    optimizer:{
      enabled: true,
      runs: 200
    }
  }
};

启动测试节点

  • ganache-cli会启动一个本地的以太坊网络,里面有10个地址,并且每个地址都是有币的。
  • geth attach链接区块链会开启一个继承了web3.js的js运行环境。
    启动一个新的窗口,连接到区块链,查看一下数据,如果默认地址的钱不够,部署会失败。
$ ganache-cli
$ geth attach http://localhost:8545

// 展示钱包中的地址,在部署的时候,默认会选中第一个。
> eth.accounts

// 查询当前默认账号余额,默认情况下有 100000000000000000000 以太。
> eth.getBalance(eth.accounts[0])

部署erc20到本地私有链

  • 切换到项目目录,也就是和truffle.js在同一层的目录,先把智能合约编译一次,
    编译的时候会读取该配置文件。
  • 编译成功之后会生成一个build/contracts目录,里面包含了一些编译好的合约
  • 编译成功后,查一下erc20的账户余额,确认部署成功。
// 确认一下项目地址。在 ./erc20 目录下
$ pwd

// 如果编译成功,会显示 Writing artifacts to ./build/contracts
$ truffle compile

// --reset参数只是确保每次部署都是新的
// 如果部署成功,会显示Saving successful migration to network...
// 并且显示MyToken: 0x984ed7dfbb2926521c8d31de273295c1def894e4 这个合约的所在地址
$ truffle migrage --reset
  • 在刚才打开的 geth attach 的窗口检测一下部署情况。
// 构建一个简答的abi,只有查询余额与精度
> var abi=[{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"type":"function"}];
> var contract = web3.eth.contract(abi).at(tokenAddress);
// 现在的balance是带了精度了的,需要除以精度,才是正确的数值。
> var balance = contract.balanceOf('0x09d4a5310d25dec940d736872b01be718db5e724');
// 获取精度
> var decimals = contract.decimals()

// 计算实际余额, 返回 10000,与我们设置的一样,说明erc20在私有网络已经部署成功
> balance.div(Math.pow(10, decimals));

部署erc20到公测链(rinkeby)

  • 导入/生成钱包文件到geth客户端中,需要注意的是,测试网和正式网账号是存储在不同目录的,会根据网络参数写入不同的文件。
  • 给账号充值(在rinkeby测试网络上)
  • 我已经有一个含有测试币的地址了,现在只要导入就好。
$ vim privatekey.txt
//贴入 056ef7c6a165f877a5aedb3cfe24b2bbcdd6c680d12df9a82092705fc03ce37f

//  --rinkeby 参数说明是rinkeby测试网的文件。如果不带参数则是正式网络
$ geth --rinkeby  account import ./privatekey.txt
// 输入密码 12345678
// 重复密码 12345678
// 展示 Address: {be255696870b84c69f6e2b902177cf2a2cb57b58},表示导入成功
$ rm privatekey.txt

// 查看一下当前客户端有那些地址,be255696870b84c69f6e2b902177cf2a2cb57b58也在其中。
$ geth --rinkeby account list

  • 启动客户端,等待区块信息同步完成,这一步可能会耗费很长时间。
  • 解锁部署账户
$ geth  --rinkeby --rpc --rpcapi db,eth,net,web3,personal  
$ geth attach /Users/tmd/Library/Ethereum/rinkeby/geth.ipc

> personal.unlockAccount('0xbe255696870b84c69f6e2b902177cf2a2cb57b58')
// 输入刚才设置但钱包密码12345678

// 切换窗口
// 部署合约到公测网,该配置在 truffle.js 文件中的rinkeby设置里。
$ truffle migrate --network rinkeby --reset

// 如果部署成功,会显示与本地私有网显示的类似。
// 如果部署不成功,很有可能是客户端还没同步完成,影响部署。

// 切换到 geth attach 窗口

// 在客客户端查询一下自己钱包的余额
> eth.getBalance('0xbe255696870b84c69f6e2b902177cf2a2cb57b58')
// 余额显示为0,但是这个地址在测试网是有钱的,说明我目前的节点同步未完成,无法进行部署,需要等待区块同步结束

通过ether.js部署ERC20

  • ether.js是一个nodejs与以太坊交互的工具,如果不熟悉可以看看我上一篇文章
  • 由于已经通过truffle compile命令编译了合约文件,现在只要读取合约文件中的bytecodeabi部署到区块网络即可,不需要经过等待漫长的客户端区块同步了
$ npm install ether
//ERC20.js
const ethers = require('ethers');
const fs = require('fs');
const util = require('util');
const readFile =util.promisify(fs.readFile);

const provider = ethers.getDefaultProvider('rinkeby');
const mnemonic1 = 'utility opinion husband upset finger side round exhaust arm allow pilot hospital';
const _wallet = ethers.Wallet.fromMnemonic(mnemonic1);
const wallet = _wallet.connect(provider);

const createERC20 = async () => {
  // 读取编译完成的文件。
  const file = await readFile('./erc20/build/contracts/MyToken.json',{encoding: 'utf8'})  ;
  const obj = JSON.parse(file);
  const abi = obj.abi;
  const bytecode= obj.bytecode;
  // console.log(abi);
  // console.log(bytecode);
  let factory = new ethers.ContractFactory(abi, bytecode, wallet);
  let contract = await factory.deploy();
  return contract.deployed()
};
createcreateToken().then(result=>console.log('result: ',result)).catch(err=>console.log('err: ',err));


  • 运行后如果显示一大串信息,并且有交易哈希,则表示运行成功
  • 运行结果中,找到合约地址为0x13f60906DE3758F025cdA95899d3742DC60C24A4

ERC20 转账

  • 转账的时候一定要先读取精度,虽然这个函数不是一定有的,但是大多数erc20都提供了该接口。
const transferERC20 = async () => {
  const file = await readFile('./erc20/build/contracts/MyToken.json',{encoding: 'utf8'})  ;
  const obj = JSON.parse(file);
  const abi = obj.abi;
  const contractAddress = '0x13f60906DE3758F025cdA95899d3742DC60C24A4';
  const contract = new ethers.Contract(contractAddress, abi, provider);
  const decimals = await contract.decimals();
  const name = await contract.name();
  const totalSupply =  await contract.totalSupply();
  const symbol = await contract.symbol();
  console.log('name: ',name);
  console.log('symbol: ',symbol) ;
  console.log('decimals: ',decimals) ;
  console.log('totalSupply: ',ethers.utils.formatUnits(totalSupply, decimals)) ;
  
  // 合约签名
  const contractWithSigner = contract.connect(wallet);
  const amount = '10';
  // 数字序列化
  const numberOfTokens = ethers.utils.parseUnits(amount, decimals);
  // 发起转账
  const tx = await contractWithSigner.transfer('0xbe79D5B66A5D44607F91E312ec5E35b8c92db5bf', numberOfTokens);
  await tx.wait();
  console.log('hash',tx.hash);

  // 查询余额
  const _balance = await contract.balanceOf('0xbe79D5B66A5D44607F91E312ec5E35b8c92db5bf');
  // 数字反序列化
  const balance = ethers.utils.formatUnits(_balance, decimals);
  console.log('balance: ',balance, symbol)

};


transferERC20().catch(console.log);
  • 结果显示余额与symbol,说明转账成功。
  • 因为该合约是部署在公测网上的,可以通过区块浏览器查询到该合约交易历史
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容