发行你的数字货币

本文主要介绍代币高级功能的实现。
在上文中,介绍了如何实现一个最基本功能的代币。这个代币系统只有一个功能:实现代币的转移。
本文我们要在上文的基础上增加下列高级功能:
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<minBalanceForAccounts) sell((minBalanceForAccounts-msg.sender.balance)/sellPrice);
        if(_to.balance<minBalanceForAccounts)      _to.send(sell((minBalanceForAccounts-_to.balance)/sellPrice));
        balanceOf[msg.sender] -= _value;                     // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
    }

         /* 货币增发的函数 */
        function mintToken(address target, uint256 mintedAmount) onlyOwner {
            balanceOf[target] += mintedAmount;
            totalSupply += mintedAmount;
            Transfer(0, owner, mintedAmount);
            Transfer(owner, target, mintedAmount);
        }
    /* 冻结账户的函数 */
        function freezeAccount(address target, bool freeze) onlyOwner {
            frozenAccount[target] = freeze;
            FrozenFunds(target, freeze);
        }
        /* 设置代币买卖价格的函数 */
        function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
            sellPrice = newSellPrice;
            buyPrice = newBuyPrice;
        }
         /* 从合约购买货币的函数 */
        function buy() returns (uint amount){
            amount = msg.value / buyPrice;                     // calculates the amount
            if (balanceOf[this] < amount) throw;               // checks if it has enough to sell
            balanceOf[msg.sender] += amount;                   // adds the amount to buyer's balance
            balanceOf[this] -= amount;                         // subtracts amount from seller's balance
            Transfer(this, msg.sender, amount);                // execute an event reflecting the change
            return 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 sell
            balanceOf[this] += amount;                         // adds the amount to owner's balance
            balanceOf[msg.sender] -= amount;                   // subtracts the amount from seller's balance
            revenue = amount * sellPrice;                      // calculate the revenue
            msg.sender.send(revenue);                          // sends ether to the seller
            Transfer(msg.sender, this, amount);                // executes an event reflecting on the change
            return revenue;                                    // ends function and returns
        }

    /* 设置自动补充gas的阈值信息 */
        function setMinBalance(uint minimumBalanceInFinney) onlyOwner {
            minBalanceForAccounts = minimumBalanceInFinney * 1 finney;
        }
}

-------------------------------------我是分割线,不要拷贝我-----------------------------------------------------

接着,我们按照功能分别介绍
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从句,目前没看到有什么用处。

设置代币的管理者,以及转移代币管理者的代码就完成了。

下面对管理者这个功能做实验:
实验内容:
1、建立合约,设置合约的管理者为账号1。
实验成功,实验过程很简单,就不说了。
2、将管理者从账号1转移给账号2.
实验成功。转移成功后可以在代币页面查看,“OWNER”是否已经更改。

2、(高级功能)实现货币增发。
就如同美联储狂印钞票一样,你作为货币的创建者,也可以实现货币增发的功能,可以在原有货币总量以外,增加额外的钞票。(想想都是很激动了)。
可以实现货币增发。通过代码可以实现管理者给特定人员增发代币。这个代币是凭空产生的,这将导致代币总量发生变化。
这个函数可以实现挖矿的功能。当矿工达到一定目标后,管理者可以通过调用函数给矿工转移一定的资金。
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参数都可以在钱包看;
凡是函数都可以在钱包中调用
设计实验:
1、给指定地址增发代币。
功能实现成功,管理者可以增发货币给指定地址。
2、使用费管理者调用增发函数
失败。非管理者无法增发。

3、(高级功能)实现数字货币的黑白名单。
通过设置黑白名单,可以冻结某些账户。资产仍在账户,但是不允许交易。
本文演示的是设置黑名单,即黑名单中的用户不能转账。
冻结账户代码:
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函数跳出。

设置实验:
1、正常情况可交易

实验成功
2、冻结后,不能交易

实验成功
3、只有管理员可以冻结。

实验成功
4、能不能冻结自己

实验成功,可以冻结管理者自己。
5、能不能设置0,设置0是不是就是解锁

实验成功。设置0即解锁。
这个图是代币管理页面,在address中输入地址,即可查看是否冻结,NO代表没有冻结,YES代表冻结。

4、(高级功能)实现代币和其他货币的自动兑换。
你可以在自己的货币中实现代币与其他数字货币的兑换机制。这个很激动人心哦,你可以像银行一样收交易费啦。
实现代币和数字货币兑换的代码
function buy() returns (uint amount){
amount = msg.value / buyPrice; // 这个value是用户输入的购买代币支付的以太币数目。amount是根据汇率算出来的代币数目
if (balanceOf[this] < amount) throw; // checks if it has enough to sell
balanceOf[msg.sender] += amount; // 购买者增加代币
balanceOf[this] -= amount; // 合约减少代币
Transfer(this, msg.sender, amount); // execute an event reflecting the change
return 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 sell
balanceOf[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 change
return 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的交易费。是不是很激动,前提是你要忽悠大家用你的代币。

设计实验:
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上做的一样,合约本身已经没有钱了。代币就失去了价值。目前,还没有机制,可以检测是否还有足够的钱支持代币兑换。
实用的交易系统需要考虑这个问题。至少要有提示。

5、(高级功能)实现gas的自动补充。以太坊中的交易时需要gas汽油(实际上就是eth)。
为了解决某些用户没有ETH,只有代币的情况,可以设计自动补充gas的功能。这个功能将使你的代币更加好用。(用的人越多,收交易费越多,嘿嘿)
以太坊中每一次交易都需要支付一定的交易费用(gas,eth)。在某些案例中,不希望客户去处理eth的事情。
所以可以通过代码实现代币和eth的自动兑换,当用户ETH比较少的时候,自动更换一部分代币,得到足够交易的eth。
对于用户来说,只需处理代币,而不用了解背后的ETH

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<minBalanceForAccounts)
sell((minBalanceForAccounts-msg.sender.balance)/sellPrice);
}
在交易函数中,提前做一个检测,如果账户的eth不够阈值,则交易。

还有一种做法是,发送者检测收款方有没有足够的ETH,如果没有,发送者则兑换一部分自己的代币,将得到的ETH发送给收款方(这种做法就是为收款方服务,收款方不用处理ETH、GAS的事情)。
/* Send coins */
function transfer(address _to, uint256 _value) {
...
if(_to.balance<minBalanceForAccounts)
_to.send(sell((minBalanceForAccounts-_to.balance)/sellPrice));
}
设计实验:
1、账户3给账户1转款,账户3没有eth。检查是否执行了自动兑换。
实验失败。发现错误原因,还没有设置价格。
首先设置价格
1代币=1000000000000000(15个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教程中还实现了挖矿的功能。有兴趣的可以直接看原文。
代币的教程就写到这里,以上的实验我都在自己的电脑上进行了实验。欢迎交流。

猜你喜欢

转载自blog.csdn.net/sportshark/article/details/52518160