基于以太坊私链代币发布

【传智播客.黑马程序员训练营成都中心】

一、前言

​​

1.1 预备知识

(1) 以太坊相关概念 (2) 熟悉智能合约代码编写与部署 (3) 以太坊私链环境搭建 (4) Mist钱包的安装与使用

1.2 环境介绍

(1) win10 (2) Mist钱包 (3) geth ---(version:1.7.2) ---搭建以太坊私链

二、以太坊代币(Token)

​​

2.1 介绍

如果不那么追求精确的定义,代币就是数字货币,比特币、以太币都可以定义代币。而以太坊代币是基于以太坊智能合约编写出来并发行到以太坊虚拟机上的合约数字货币,代币可以代表任何可以交易的东西,如:积分、财产、证书等等。利用以太坊智能合约能够非常轻松实现自己的代币,因为以太坊提供了一个开发代币的ERC20标准。

2.2 标准代币ERC20 Token

ERC20和代币经常一同出现, ERC20是以太坊定义的一个代币标准。 要求我们在实现代币的时必须要遵守的协议,如指定代币名称、总量、实现代币交易函数等,只有支持了协议才能被以太坊钱包支持,这样你的代币才具有交易和流通的能力。目前ERC20存在一些无法解决的问题,但是新的标准ERC223以及出世,但市面上大多数以太坊代币都采用ERC20标准,所以本文也使用ERC20标准实现自己的代码,最后会对ERC20存在的问题给大家稍作解释,那接下来我们就进入正题。

三、代币合约

​​

3.1 ERC20的标准接口

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="false" cid="n19" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">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);
}</pre>

接口代码解释: name() 返回ERC20代币的名字,例如”My test token”。 symbol() 返回代币的简称,例如:MTT,这个也是我们一般在代币交易所看到的名字。 decimals() 返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示。 totalSupply() 返回token的总供应量 balanceOf() 返回某个地址(账户)的账户余额 transfer() 从代币合约的调用者地址上转移value的数量token到的地址to,并且必须触发Transfer事件。 transferFrom() transferFrom方法用于允许合同代理某人转移token。前提是被代理人调用approve方法允许代理人设置操作自己多少token allowance() 被代理人设置代理人操作自己的多少token approve() 更改被代理人设置代理人操作自己的多少token,并且必须触发Approval事件 Transfer事件 代币被转移时触发该事件,记录转账日志 Approval事件 调用approve方法时触发,记录授权日志

注意:以上ERC20标准代币接口方法只是标准,并不是所有方法都需要实现,当然我们还可以根据自己的业务增强自己的代币,比如实现代币管理、代币增发、代币兑换、资产冻结、Gas自动补充等功能的高级代币

3.2 代币合约实现

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="false" cid="n24" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit inherit; background-repeat: inherit inherit;">pragma solidity ^0.4.16;

interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }

contract TokenERC20 {
string public name; //token的名字
string public symbol;//token的简称
uint8 public decimals = 18; // decimals 可以有的小数点个数,最小的代币单位。18 是建议的默认值
uint256 public totalSupply;//token的总数

// 用mapping保存每个地址对应的余额
mapping (address => uint256) public balanceOf;
// 存储对账号的控制
mapping (address => mapping (address => uint256)) public allowance;

// 事件,用来通知客户端交易发生
event Transfer(address indexed from, address indexed to, uint256 value);

// 事件,用来通知客户端代币被消费
event Burn(address indexed from, uint256 value);

/**

  • 初始化构造
    /
    function TokenERC20(uint256 initialSupply, string tokenName, string tokenSymbol) public {
    totalSupply = initialSupply * 10 ** uint256(decimals); // 供应的份额,份额跟最小的代币单位有关,份额 = 币数 * 10 ** decimals。
    balanceOf[msg.sender] = totalSupply; // 创建者拥有所有的代币
    name = tokenName; // 代币名称
    symbol = tokenSymbol; // 代币符号
    }

    /
    *
  • 代币交易转移的内部实现
    /
    function _transfer(address _from, address _to, uint _value) internal {
    // 确保目标地址不为0x0,因为0x0地址代表销毁
    require(_to != 0x0);
    // 检查发送者余额
    require(balanceOf[_from] >= _value);
    // 确保转移为正数个
    require(balanceOf[_to] + _value > balanceOf[_to]);

    // 以下用来检查交易,
    uint previousBalances = balanceOf[_from] + balanceOf[_to];
    // Subtract from the sender
    balanceOf[_from] -= _value;
    // Add the same to the recipient
    balanceOf[_to] += _value;
    Transfer(_from, _to, _value);

    // 用assert来检查代码逻辑。
    assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /
    *
  • 代币交易转移
  • 从自己(创建交易者)账号发送_value个代币到 _to账号
  • @param _to 接收者地址
  • @param _value 转移数额
    /
    function transfer(address _to, uint256 _value) public {
    _transfer(msg.sender, _to, _value);
    }

    /
    *
  • 账号之间代币交易转移
  • @param _from 发送者地址
  • @param _to 接收者地址
  • @param _value 转移数额
    /
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(_value <= allowance[_from][msg.sender]); // Check allowance
    allowance[_from][msg.sender] -= _value;
    _transfer(_from, _to, _value);
    return true;
    }

    /
    *
  • 设置某个地址(合约)可以创建交易者名义花费的代币数。
  • 允许发送者_spender 花费不多于 _value 个代币
  • @param _spender The address authorized to spend
  • @param _value the max amount they can spend
    /
    function approve(address _spender, uint256 _value) public
    returns (bool success) {
    allowance[msg.sender][_spender] = _value;
    return true;
    }

    /
    *
  • 设置允许一个地址(合约)以我(创建交易者)的名义可最多花费的代币数。
  • @param _spender 被授权的地址(合约)
  • @param _value 最大可花费代币数
  • @param _extraData 发送给合约的附加数据
    /
    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
    public
    returns (bool success) {
    tokenRecipient spender = tokenRecipient(_spender);
    if (approve(_spender, _value)) {
    // 通知合约
    spender.receiveApproval(msg.sender, _value, this, _extraData);
    return true;
    }
    }

    /
    *
  • 销毁我(创建交易者)账户中指定个代币
    /
    function burn(uint256 _value) public returns (bool success) {
    require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
    balanceOf[msg.sender] -= _value; // Subtract from the sender
    totalSupply -= _value; // Updates totalSupply
    Burn(msg.sender, _value);
    return true;
    }

    /
    *
  • 销毁用户账户中指定个代币
  • Remove _value tokens from the system irreversibly on behalf of _from.
  • @param _from the address of the sender
  • @param _value the amount of money to burn
    */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
    require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
    require(_value <= allowance[_from][msg.sender]); // Check allowance
    balanceOf[_from] -= _value; // Subtract from the targeted balance
    allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
    totalSupply -= _value; // Update totalSupply
    Burn(_from, _value);
    return true;
    }
    }</pre>

四、部署

​​

采用以太坊钱包mist+geth私有环境部署

以太坊私链的搭建和mist钱包的安装与使用请自行学习

4.1 启动私链

image

4.2 新建账号

image

4.3 挖矿

挖矿:挖矿可以获得私有链的以太币,因为我们需要部署我们上面写的代币合约就需要消费gas,gas就是相应的以太币。挖矿默认采用第一个账号进行,如下所示

在控制台输入:miner.start() 即可开始挖矿
image

查看余额

image

4.4 打开Mist钱包并连接到私链

image
界面介绍
image

4.5 合约部署

点击【CONTRACTS】进入合约部署界面
image

点击【DEPLOY NEW CONTRACT】开始部署新的合约
image

点击最下面的【DEPLOY】弹出如下窗口(一定要在geth控制台执行miner.start(1)开启挖矿)
image

点击【WALLETS】进入回到主界面
image

五、测试Token

​​

点击【Main account】进入该账号界面

image

点击【Transfer Ether & Tokens】进入转账界面

image

在最下面点击【send】并在弹出框输入密码,待挖矿成功之后如下界面

image

image

当然你还可以在token合约主页面进行相关方法的测试,方法的测试有读者自行完成!

六、ERC20标准代币的问题

ERC20有两种转账方式,一种是收件方为一份合同,这种情况下用户必须使用approve+transferFrom的功能来进行代币转移;而另一种则是收件方为合同外账户(例如,钱包地址)的情况,用户需将代币通过transfer功能转出 。如果用户使用transfer给合同地址转账将导致代币丢失,据了解,以太坊生态中的Golem代币,至今仍有93644.51美元的代币因投资者的无意操作而流失到合同地址内,造成这些代币的永久性丢失。因此ERC223就此诞生,相关介绍请读者自行学习!

七、结尾

本文介绍了基于以太坊私链开发ERC20标准代币合约,并且使用Mist钱包部署,以及简单的转账测试。 区块链技术是目前非常热门的,区块链技术暂时还不成熟,但是相信未来区块链在互联网的地位一定不可小觑,希望本文能够对读者有帮助。相互学习相互探讨不断专研

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

推荐阅读更多精彩内容