使用以太坊智能合约建立代币教程
本文介绍如何利用以太坊智能合约建立自己的代币。
这篇文章来源于以太坊官网中的材料,本文是作者通过阅读材料,亲自试验后写的中文版材料,仅供初学者参考。
本文不是对原文进行完整的翻译,主要是作者消化后整理出来的文档,需要看原文的请直接访问原文地址
https://ethereum.org/token
。
一、什么是代币?
代币是利用以太坊的智能合约编写的数字货币。程序员可以通过编写智能合约代码,创建一种新的数字货币。
你可以实现的功能:
基本功能:
-创建数字货币,设置货币的名称、货币总量、货币图标等基本参数。
-创建货币交易功能。实现货币在不同用户之间的转移。
上面的是基本功能,已经可以实现基本的代表交换,下面是高级功能,可以实现更加复杂的应用。
高级功能:
-创建货币的管理者。虽然区块链是去中心化的,但是可以实现合约的管理者,这在许多应用中是有需求的。
-实现数字货币的黑白名单。通过设置黑白名单,可以冻结某些账户。资产仍在账户,但是不允许交易。
-实现货币增发。就如同美联储狂印钞票一样,你作为货币的创建者,也可以实现货币增发的功能,可以在原有货币总量以外,增加额外的钞票。(想想都是很激动了)
-实现挖矿。比特币、以太币的挖矿机制非常出名,矿工、矿机、矿池等概念大家都很熟悉。你可以在自己的货币中实现挖矿机制,奖励实现挖矿目的的用户一些代币。我目前还没有想到这个功能的用处,但是读这部分的内容有助于理解比特币、以太币的挖矿机制。
-实现代币和其他货币的自动兑换。你可以在自己的货币中实现代币与其他数字货币的兑换机制。这个很激动人心哦,你可以像银行一样收交易费啦。例如,买入代币的价格是1ETH,卖出代笔的价格是0.8ETH,这意味着每个代币的流入流出,你可以收取0.2ETH的交易费。是不是很激动,前提是你要忽悠大家用你的代币。
-实现gas的自动补充。以太坊中的交易时需要gas汽油(实际上就是eth)。为了解决某些用户没有ETH,只有代币的情况,可以设计自动补充gas的功能。这个功能将使你的代币更加好用。(用的人越多,收交易费越多,嘿嘿)
以上就是以太坊官方教程中提到的功能。通过学习这些功能的写法,你将学会基本的智能合约编程方法,能够开发出更加多样化的功能。
接下来,我将介绍如何编程智能合约的代码,实现上述功能。
二、实现代币的基本功能
从简单入手,首先实现一个包含基本功能的代币。只需实现代币定义和交易功能。
实现代币的过程是编写智能合约的代码。智能合约你可以理解为是一种程序,类似于C,C++。不要怕,这种语言很好懂,稍微看看就懂啦。
下面是完整的代码,可以直接部署。
-------------------------------------我是分割线,不要拷贝我-----------------------------------------------
/* contract 类似于C++中的类 */contract MyToken {/* 设置一个数组存储每个账户的代币信息 */mapping (address => uint256) public balanceOf;/* 设置变量 *//* name 代币名称 *//* symbol 代币图标 *//* decimals 代币小数点位数 */string public name;string public symbol;uint8 public decimals;/* event事件,它的作用是提醒客户端发生了这个事件,你会注意到钱包有时候会在右下角弹出信息 */event Transfer(address indexed from, address indexed to, uint256 value);/* 下面这个类似于C++的构造函数,接收用户输入,实现代币的初始化 */function MyToken(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol) {balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokensname = tokenName; // Set the name for display purposessymbol = tokenSymbol; // Set the symbol for display purposesdecimals = decimalUnits; // Amount of decimals for display purposes}/* 代币交易的函数 */function transfer(address _to, uint256 _value) {/* 检查发送方有没有足够的代币 */if (balanceOf[msg.sender] < _value || balanceOf[_to] + _value < balanceOf[_to])throw;/* 交易过程,发送方减去代币,接收方增加代币 */balanceOf[msg.sender] -= _value;balanceOf[_to] += _value;/* 提醒客户端发生了交易事件 */Transfer(msg.sender, _to, _value);}}
-------------------------------------我是分割线,不要拷贝我-----------------------------------------------
下面是部署方式,我使用以太坊钱包mist部署合约。
为了节省资金,我使用以太坊测试网络,测试网络是可以用以太坊钱包挖矿的,挖矿难度不大,我已经挖到20个了。做实验够用了。如果你实在挖不到币的话,请在下方留下你的地址,我可以资助你1个以太币做实验(是测试网络的以太币哦)。
其他方式有很多,这里不讲。我觉得初学者用mist最简单。下面是部署的界面。
这个页面是以太坊钱包“CONTRACTS”页面,点击"DEPLAY NEW CONTRACT"按钮就能看见。
图片的最上面是给合约输入以太币,目前不用设置,保持0即可。图中央的左侧是放置代码的地方,将拷贝的代码粘贴到这里即可。右侧的红圈位置可以选择合约,请点击下拉框选择“My Token”。选择以后,会出现图片上的样子,这里可以输入代币的总数(Initial supply),代币的名称(Token name),代币的小数点数目(Decimal units),代币的符号(Token symbol)。你可以按照图上的来填,也可以试着随便填,理解用途。
填写完成后,点击最下面的“DEPLOY”按钮,如果成功,则在钱包主页面可以看到合约正在等待验证,如果失败,会提示原因,请检查输入。
如果你的网络正常,通常1分钟内合约就验证通过,这是可以在以太坊钱包“CONTRACTS”页面看到我们建立的代币TESTCOIN.
上图标红的就是我建立的代币,点击进入代币的管理页面。
这个图就是我建立的代币的管理页面,这个页面可以查看合约持有的代币数量,每个用户持有的代币数量,执行代币交易等等。
图中左侧可以查看代币的基本信息,名称,小数点位数,符号。
图中左侧标红的位置可以查看指定用户代币的持有数量,只需将指定用户的地址填入红圈中的位置,即可自动显示。
图中右侧是代币的交易函数,可以进行代币交易。
“Select function”,这个选择transfer函数
“To-address”,这个是指接收代币用户的地址
"Value",发送代币数量
“Execute from”,这个地方可以选择发送方的地址。
点击“EXECUTE”按钮,就可以发送。
收到货币的人想要查看代币,只需要在“CONTRACTS”页面的"Watch token"输入对应的代币合约地址即可。
截止到这里,一个具备基本功能的代币就实现了。这个代币可以用于积分管理,简单的交易。
等后续实现更多功能后,可以有更多用途。
三、实现代币的高级功能
接下来,我们要在上文的基础上增加下列高级功能:
1、创建货币的管理者。虽然区块链是去中心化的,但是可以实现合约的管理者,这在许多应用中是有需求的。
2、实现货币增发。就如同美联储狂印钞票一样,你作为货币的创建者,也可以实现货币增发的功能,可以在原有货币总量以外,增加额外的钞票。(想想都是很激动了)
3、实现数字货币的黑白名单。通过设置黑白名单,可以冻结某些账户。资产仍在账户,但是不允许交易。
4、实现代币和其他货币的自动兑换。你可以在自己的货币中实现代币与其他数字货币的兑换机制。这个很激动人心哦,你可以像银行一样收交易费啦。例如,买入代币的价格是1ETH,卖出代笔的价格是0.8ETH,这意味着每个代币的流入流出,你可以收取0.2ETH的交易费。是不是很激动,前提是你要忽悠大家用你的代币。
5、实现gas的自动补充。以太坊中的交易时需要gas汽油(实际上就是eth)。为了解决某些用户没有ETH,只有代币的情况,可以设计自动补充gas的功能。这个功能将使你的代币更加好用。(用的人越多,收交易费越多,嘿嘿)
我介绍的思路是这样的:
首先给出全部的代码,这个代码包含了上述所有功能,可以直接部署。
然后,按照功能分别介绍代码和相关知识。
以下是代码,具备所有的高级功能,可以直接部署在以太坊钱包mist。具体的方法可参考上一篇文章。
-------------------------------------我是分割线,不要拷贝我-----------------------------------------------
/* 建立一个新合约,类似于C++中的类,实现合约管理者的功能 */contract owned { address public owner; function owned() { owner = msg.sender; } modifier onlyOwner { if (msg.sender != owner) throw; _ } /* 管理者的权限可以转移 */ function transferOwnership(address newOwner) onlyOwner { owner = newOwner; }}/* 注意“contract MyToken is owned”,这类似于C++中的派生类的概念 */contract MyToken is owned{ /* Public variables of the token */ string public standard = 'Token 0.1'; string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; uint256 public sellPrice; uint256 public buyPrice; uint minBalanceForAccounts; //threshold amount /* This creates an array with all balances */ mapping (address => uint256) public balanceOf; mapping (address => bool) public frozenAccount; /* This generates a public event on the blockchain that will notify clients */ event Transfer(address indexed from, address indexed to, uint256 value); event FrozenFunds(address target, bool frozen); /* Initializes contract with initial supply tokens to the creator of the contract */ function MyToken( uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol, address centralMinter ) { if(centralMinter != 0 ) owner = msg.sender; balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens totalSupply = initialSupply; // Update total supply name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes decimals = decimalUnits; // Amount of decimals for display purposes } /* 代币转移的函数 */ function transfer(address _to, uint256 _value) { if (frozenAccount[msg.sender]) throw; if (balanceOf[msg.sender] < _value) throw; // Check if the sender has enough if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows if(msg.sender.balance
-------------------------------------我是分割线,不要拷贝我-----------------------------------------------
接着,我们按照功能分别介绍
3.1创建货币的管理者。
虽然区块链是去中心化的,但是可以实现合约的管理者,这在许多应用中是有需求的。可以通过设置,给智能合约添加管理人员。
添加的过程可以利用继承的概念。
3.1.1代码解析
首先定义一个父类
contract owned {address public owner;function owned() {owner = msg.sender;}
上述代码定义一个变量“owner”,这个变量的类型是address,这是用于存储代币的管理者。
owned()类似于C++中的构造函数,功能是给owner赋值。
接下来定义一个modifier(修改标志),可以理解为函数的附属条件。这个条件的内容是假设发送者不是owner(管理者),就跳出。起到一个身份鉴别的作用。
modifier onlyOwner {if (msg.sender != owner) throw;_}
接着定义一个transferOwnership函数,这个函数是用于转移管理者的身份。
function transferOwnership(address newOwner) onlyOwner {owner = newOwner;}
注意,transferOwnership后面跟着 “onlyOwner”。所以这个函数的前提是,发送者必须是owner。
接着修改MyToken.
contract MyToken is owned{
//在mytoken中添加了地址变量centralMinter,这个变量是有输入位置的。
function MyToken(uint256 initialSupply,string tokenName,uint8 decimalUnits,string tokenSymbol,address centralMinter) {if(centraMinter != 0) owner=msg.sender;
上述的if从句,只要输入地址不为0,拥有者就是发送者,所以这里输入什么都没关系。这个if从句,目前没看到有什么用处。
3.1.2代码功能测试
实验内容:
1、建立合约,设置合约的管理者为账号1。
实验成功,实验过程很简单,就不说了。
2、将管理者从账号1转移给账号2.
实验成功。转移成功后可以在代币页面查看,“OWNER”是否已经更改。
3.2实现货币增发
就如同美联储狂印钞票一样,你作为货币的创建者,也可以实现货币增发的功能,可以在原有货币总量以外,增加额外的钞票。(想想都是很激动了)。
可以实现货币增发。通过代码可以实现管理者给特定人员增发代币。这个代币是凭空产生的,这将导致代币总量发生变化。
这个函数可以实现挖矿的功能。当矿工达到一定目标后,管理者可以通过调用函数给矿工转移一定的资金。
3.2.1代码解析
1 function mintToken(address target, uint256 mintedAmount) onlyOwner {2 balanceOf[target] += mintedAmount;3 totalSupply += mintedAmount;4 Transfer(0, owner, mintedAmount);5 Transfer(owner, target, mintedAmount);6 }
第2句代码给指定目标增加代币数量;
第3句代码给代币总量增加相应的数目;
第4句和第5句代码的意义只是提醒客户端发生了这样的交易。
体会:
凡是public参数都可以在钱包看;
凡是函数都可以在钱包中调用
3.2.2代码功能测试
设计实验:
1、给指定地址增发代币。
功能实现成功,管理者可以增发货币给指定地址。
2、使用费管理者调用增发函数
失败。非管理者无法增发。
3.3实现数字货币的黑白名单
通过设置黑白名单,可以冻结某些账户。资产仍在账户,但是不允许交易。
本文演示的是设置黑名单,即黑名单中的用户不能转账。
3.3.1代码解析
mapping (address => bool) public frozenAccount;event FrozenFunds(address target, bool frozen);function freezeAccount(address target, bool freeze) onlyOwner {frozenAccount[target] = freeze;FrozenFunds(target, freeze);}
申请一个数组“freezeAccount”,存储冻结账户的地址和冻结信息
申请一个事件“FrozenFunds”,提醒客户端发生了冻结
建立一个函数“freezeAccount”,设置冻结数组对应位置为freeze,
在transfer中增加冻结代码
function transfer(address _to, uint256 _value)
{ if (frozenAccount[msg.sender]) throw;
假设账户冻结,则transfer函数跳出。
3.3.2代码功能测试
设置实验:
1、正常情况可交易
实验成功
2、冻结后,不能交易
实验成功
3、只有管理员可以冻结。
实验成功
4、能不能冻结自己
实验成功。可以冻结管理者自己。
5、能不能设置0,设置0是不是就是解锁
实验成功。设置0即解锁。
这个图是代币管理页面,在address中输入地址,即可查看是否冻结,NO代表没有冻结,YES代表冻结。
3.4实现代币和其他货币的自动兑换。
你可以在自己的货币中实现代币与其他数字货币的兑换机制。这个很激动人心哦,你可以像银行一样收交易费啦。
实现代币和数字货币兑换的代码
3.4.1代码解析
function buy() returns (uint amount){amount = msg.value / buyPrice; // 这个value是用户输入的购买代币支付的以太币数目。amount是根据汇率算出来的代币数目if (balanceOf[this] < amount) throw; // checks if it has enough to sellbalanceOf[msg.sender] += amount; // 购买者增加代币balanceOf[this] -= amount; // 合约减少代币Transfer(this, msg.sender, amount); // execute an event reflecting the changereturn amount; // ends function and returns}function sell(uint amount) returns (uint revenue){if (balanceOf[msg.sender] < amount ) throw; // checks if the sender has enough to sellbalanceOf[this] += amount; // 合约增加代币balanceOf[msg.sender] -= amount; // 出售者减少代币revenue = amount * sellPrice; // amount是用户数输入的出售代币的数量msg.sender.send(revenue); // 用户获得因为输出代币得到的以太币Transfer(msg.sender, this, amount); // executes an event reflecting on the changereturn revenue; // ends function and returns}
这里的代码实现的是简单的买卖。即合约本身作为中央银行,用户和合约做买卖。用户从合约购买代币,用户向合约出售代币。
注意:这里的代码没有实现检测功能,即可能出现合约没有代币和合约没有以太币,导致交易异常。这个代码没有处理。实际使用时,请自行添加检测代码。
/* 设置代币买卖价格的函数 */
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {sellPrice = newSellPrice;buyPrice = newBuyPrice;}
这个函数是设置代币的汇率。包括购买汇率buyPrice,出售汇率sellPrice。我们在实验时,为了简单,设置buyPrice=sellPrice=0.01ETH。当然这个比例是自由设定的。在实际中,你可以设计买入代币buyPrice的价格是1ETH,卖出代币sellPrice的价格是0.8ETH,这意味着每个代币的流入流出,你可以收取0.2ETH的交易费。是不是很激动,前提是你要忽悠大家用你的代币。
3.4.2代码功能测试
设计实验:
1、调用setPrices函数,设计汇率。
实验成功。注意,智能合约汇率的单位是wei,1个以太币ETH=10的18次方个wei。
我们设计buyPrice=sellPrice=0.01ETH=10000000000000000(10的16次方)
设置价格也是1次交易。每一次价格变动都会写入区块链
2、账号1买入200代币,猜测买入不成功
实验不成功。显示不能买,因为合约没代币,只有eth
3、账号1售出100代币,猜测成功,账号1获得1ETH
实验成功.账号1得到1个代币,出售成功。当前显示gf1合约有100个代币,9个eth。
4、账号2售出800代币,猜测成功,获得8ETH,合约ETH为1
实验成功,账号2得到8个代币,出售成功。当前显示gf1合约有900个代币,1个eth。
5、账号2买入500代币,猜测成功,收取5ETH.
实验成功,账号2得到500个代币,购买成功。当前显示gf1合约有400个代币,6个eth。
6、修改价格,sell 修改为10的17次方。这意味着代币价格升值了。只需50个代币,就能换取5ETH。
实验成功。修改了sell价格。
7、账号1售出60代币,收取6ETH,合约还有0ETH,460个代币。
实验成功。成功交易。当前显示gf1合约有460个代币,0个eth。
sell price 设置为100000000000000000,这意味着账号2可以用60个代币获得6ETH。合约破产了,无力支付剩余的代币。
注意,此时合约以及破产,合约没有以太币ETH,但是用户仍然有代币。合约无法承兑了。
8、账号2售出100代币,猜测不成功。
实验成功。然交易成功,账号2减少100代币,gf1合约增加100代币,但是账号2没得到对应的eth。
猜测,可能的原因是, msg.sender.send(revenue); 这个函数,执行失败。
9、重新设置买卖价格,高价购入代币,看以前的欠款会不会补交。 猜测不会补交。这是一个漏洞,可能通过修改售价。窃取资金。普通用户是没有权限的。
实验成功,确实没有补交,账户1花费5ETH购买50个代币。
11、账号2售出50个代币,获得合约剩余的5个ETH。
实验成功。
以后,如果账户1和账户2再售出代币,将不能得到ETH。
** 注意:这和目前白帽黑客在DAO上做的一样,合约本身已经没有钱了。代币就失去了价值。目前,还没有机制,可以检测是否还有足够的钱支持代币兑换。**
实际的交易系统需要考虑这个问题。至少要有提示。目前的DAO出现了这个问题,DAO中的以太币已经被白猫黑客转移到其他地方。现在如果通过分裂的方式兑换DAO币,会导致得不到以太币。造成资金损失。具体内容请参考
http://ethfans.org/topics/404
。
3.5实现gas的自动补充。以太坊中的交易时需要gas汽油(实际上就是eth)
为了解决某些用户没有ETH,只有代币的情况,可以设计自动补充gas的功能。这个功能将使你的代币更加好用。(用的人越多,收交易费越多,嘿嘿)
以太坊中每一次交易都需要支付一定的交易费用(gas,eth)。在某些案例中,不希望客户去处理eth的事情。
所以可以通过代码实现代币和eth的自动兑换,当用户ETH比较少的时候,自动更换一部分代币,得到足够交易的eth。
对于用户来说,只需处理代币,而不用了解背后的ETH。
3.5.1代码解析
uint minBalanceForAccounts;//注意,这个参数是一个私有变量,意味着钱包里看不见。function setMinBalance(uint minimumBalanceInFinney) onlyOwner {minBalanceForAccounts = minimumBalanceInFinney * 1 finney;}
申请一个变量minBalanceForAccounts,存储自动兑换gas的阈值
创建一个设置阈值的函数
/* Send coins */function transfer(address _to, uint256 _value) {...if(msg.sender.balance
在交易函数中,提前做一个检测,如果账户的eth不够阈值,则交易。
还有一种做法是,发送者检测收款方有没有足够的ETH,如果没有,发送者则兑换一部分自己的代币,将得到的ETH发送给收款方(这种做法就是为收款方服务,收款方不用处理ETH、GAS的事情)。
/* Send coins */function transfer(address _to, uint256 _value) {...if(_to.balance
3.5.2代码功能测试
设计实验:
1、账户3给账户1转款,账户3没有eth。检查是否执行了自动兑换。
实验失败。发现错误原因,还没有设置价格。
首先设置价格
1代币=1000000000000000(16个0)
即使设置了价格,还是不能执行。原因是账户3目前没有ETH,因此不足以支付交易的费用gas。所以,账户3必须拥有足够的ETH来执行交易。
重新设计实验。账户1给账户3转账0.005ETH. 成功
实验成功,账户自动兑换了4个代币,获得0.004个ETH。目前ETH总数是0.006ETH。
2、账户1给账户3转款,检查账户3的变动。前提条件,先将账户3的ETH清0.
实验成功。发现账户兑换了5个代币,发送给账户3。
有意思的是,收款方收到的不是0.005,而是0.0044,应该是扣除了手续费。
截止到这里,所有的高级功能都已经实现了。
以太坊官网的TOKEN教程中还实现了挖矿的功能。有兴趣的可以直接看原文。
代币的教程就写到这里,以上的实验我都在自己的电脑上进行了实验。欢迎交流。
Mount and Blade Bannerlord: Complete Guide, Best Mods, Gameplay Tips & Performance Optimization
Explore Mount and Blade Bannerlord with this ultimate guide featuring gameplay tips, best mods, how ...
DODO Partners with Steer Protocol for Advanced Liquidity Management with AI Precision
This partnership is a strong union that comes together to resolve major problems in DeFi, enhancing ...
Chainlink Price Prediction 2026 Signals Recovery—but Qubetics Presale Growth Steals the Spotlight
Chainlink eyes recovery after a sharp drop, but Qubetics’ fast-growing presale and multi-chain walle...