上一篇文章我们介绍了如何在同一台机器上搭建包括两个节点的以太坊私有链网络。本文我们继续使用该网络,介绍如何在以太坊私有链上发行电子代币,本文使用的以太坊私有链钱包是Ethereum Wallet
。
假设有一个山寨需要分两次一共发行1万5千贯山寨币,该山寨币可以在山寨内部各处流通,山寨币的持有者可以随时到山寨的好汉钱庄兑换等值铜钱。基于此背景,我们考虑如何使用以太坊私有链完成如下山寨需求 :
山寨要想在以太坊私有链上发行自己的代币,必须首先要有属于山寨自己的钱包地址,比如说是 :
名称 : ShanZhai
地址 : 0x0C5Ae7c2520b1208d579bCF8b2bF624EdD7a025c
要想在以太坊私有链上开展各项业务,账户里必须有先有以太币,山寨的账户也不例外,以下李逵,武松,孙二娘的账户也不例外。
现在山寨已经准备好了自己的区块链账号,接下来要想发行代币,必须先定义自己的山寨币智能合约:
pragma solidity ^0.4.18;
contract ShanZhaiCoin {
// 发币人地址
address public minter;
// 代币名称
string public coinName="山寨币";
// 代币的单位
string public coinUnit="贯";
// 潜在地为每个被操作的地址创建一个变量 balances,
// 类型为 unit, 用于表示该地址中该代币的余额,初始值为 0,
// 通过该变量 balances, 合约通过该变量获取或者设置某个地址
// 上该代币的余额,
mapping (address => uint) public balances;
// 该智能合约的构造函数,仅在该智能合约创建时被调用,
// 调用时将发币人地址设置成消息的发送者,也就是说,
// 创建该智能合约实例的人会被设置为发币人
constructor() public {
minter = msg.sender;
}
// 发币人发行一定数量的代币
// 可用于初始发行或者后期增发
// 要求调用者地址和最初创建该智能合约的地址必须一致,
// 也就是说,只有该智能合约实例的创建者才能发行/增发该代币
function mint(uint amount) public {
// 要求调用者地址 msg.sender 和 该智能合约实例创建人 minter
// 必须相同, 也就是只有该智能合约实例的创建人才能发行/增发
// 该代币
require(msg.sender == minter);
// 单次发行量不能大于 10的60次方
require(amount < 1e60);
// 往发币人地址上增加指定数量的该代币
balances[minter] += amount;
}
// 从调用者地址往指定地址 receiver 发送指定数量的代币,
// 也就是一般意义上的转账功能
// 从任何地址都可以发起,只要该地址拥有足够的该代币
function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance.");
// 转账发起方账户扣减指定数量代币
balances[msg.sender] -= amount;
// 转账接收方账户增加指定数量代币
balances[receiver] += amount;
}
}
在这个合约中,我们进行了如下信息:
在Ethereum Wallet
中,点击界面右上角的CONTRACTS
进入到合约界面,按照下图提示创建山寨币的智能合约 :
点击部署之后,钱包会提醒输入账户ShanZhai
的密码,输入其密码,点击SEND TRANSACTION
继续即可,如下图所示 :
确保私有链上有矿工正在挖矿,那么在WAllETS
界面下方,你会看到该智能合约实例账户正在被创建,当进度达到12/12
时,山寨币智能合约账户就创建好了。
好了,现在山寨币智能合约账户已经创建了,如下所示 :
名称 : Shan Zhai Coin (根据相应智能合约的名称自动生成)
地址 : 0x0182bB09435a77307D9B1540bDe6f42f9D3d16D3
在上图界面中点击该账户图表即可进入该账户钱包的主界面,如下图所示 :
从此图不难看出,我们在智能合约中定义和创建过程中指定的一些属性,已经在这里显示了出来 :
Minter : ShanZhai (这是我们代币发行者的地址的名称)
Coin name : 山寨币 (这是所发行的代币的名称,在智能合约中已经设定)
Coin unit : 贯 (这是所发行的代币的单位,在智能合约中已经设定)
在Balances
属性下面的Address
输入栏中输入发币人ShanZhai
的地址,下面出现数字0,这表明发币人账户中山寨币的余额为0。这是符合我们预期的一个结果,因为我们尚未发行代币。
在合约账户的右下方,我们选择功能Mint
,设置发行数量Amount
为10000
,指定发行者账号为ShanZhai
,点击EXECUTE
发起发行1万山寨币,如下图所示 :
执行该代币发行事务同样需要消耗发行者账户的以太币,以及需要提供发行者的账户密码,有了这些信息,该发行代币动作和创建该执行合约没什么不同,都是作为一个事务交给底层区块链矿工挖矿完成。
增发代币和初期发行代币有什么不同吗 ?如果从实际业务需求的角度上没有这方面的约束和限制,就可以认为是没有。上面智能合约所定义的山寨币,就可以忽略其不同,所谓增发,就是再执行一次发行山寨币。所以重复上面1.4小节的动作,指定发行数量为5000,即可完成增发任务。增发之后,通过"Balances"方法查询发行人"ShanZhai"的山寨币余额,现在应该是15000贯。如下图所示 :
从上面我们定义山寨币智能合约的代码来看,我们约定了只能由智能合约的创建人来发行代币。那么,上面的智能合约是由"ShanZhai"创建的,其他账号可以用来发行山寨币吗 ?
接下来,我们用李逵的账号试一试,假设李逵的账号是 :
名称 : LiKui
地址 : 0xbd5dd112d243f1D7899708667AE47A1b9AeBe902
这次发行代币过程中我们选择了使用李逵的账号发行山寨币,这是一个不同于山寨币所属智能合约创建者山寨ShanZhai
的一个账号,结果,虽然可以输入密码后将事务发送到区块链处理,但是处理完成之后,李逵的账号中并没有山寨币 :
这正是我们上面智能合约中代币发行逻辑所限制的,只能由智能合约创建者发行代币 :
// 要求调用者地址 msg.sender 和 该智能合约实例创建人 minter
// 必须相同, 也就是只有该智能合约实例的创建人才能发行/增发
// 该代币
require(msg.sender == minter);
山寨币已经发行了,现在山寨要给李逵发年终奖了。山寨之外的世界发奖金比较复杂,扣除各种税,进行各种登记,然后转账。山寨里就比较简单了,在"Shan Zhai Coin"山寨币主界面上,直接转账 :
确保矿工在挖矿,转账事务处理完成后,我们分别看看山寨的账户和李逵的账户 :
因为给李逵发奖金,4000贯已经被所发行的15000贯中扣除了,所以剩下了11000贯。
看来李逵的奖金到账了。
有了钱,李逵要做的第一件事情是还钱,毕竟山寨里都是好汉,好汉的信誉都很重要。现在,李逵要还掉从武松那里借来买牛肉的200贯钱。现在李逵这里有武松的山寨币账号 :
名称 : WuSong
地址 : 0x7dB957E34f634B97E47A632D65C3c520F4E820df
借钱的时候,武松并没有让李逵打什么借条之类的凭据,所以还钱这件事情很简单,李逵只需要转账200贯钱给武松即可。在"Shan Zhai Coin"山寨币主界面上,我们执行这个转账操作:
提交以上转账事务,提供李逵账户的密码,确保矿工在挖矿,转账就能成功。我们来看看该转账完成时的情况。
可以看到,李逵给武松的还钱转账已经完成了。
还完了帐,李逵手里还有钱,现在他要去孙二娘那里打壶酒喝。孙二娘给李逵打了一壶酒,李逵要支付孙二娘20贯酒钱。孙二娘让李逵把山寨币转到自己的这个账号 :
名称 : SunErNiang
地址 : 0xEB851F746ea8693E5776dAe1cdeF80C2c32b8dbC
可以看出,李逵买酒的钱已经转账山寨币给孙二娘了。
过了一段时间,店里的酒卖的差不多了,孙二娘需要到山下进货。山寨币虽然在山寨流通,山下却用不了。孙二娘需要到山寨的好汉钱庄将山寨币兑换成山下能用的铜钱。
要想兑换出铜钱,孙二娘需要先把自己的山寨币转账给好汉钱庄。钱庄让孙二娘把要兑换的山寨币转到这个地址 :
名称 : ShanZhai
地址 : 0x0C5Ae7c2520b1208d579bCF8b2bF624EdD7a025c
孙二娘一看,这不就是山寨最初发行山寨币的那个地址么。没错,好汉钱庄是山寨开的,兑换山寨币的话就需要先将山寨币通过好汉钱庄转回给山寨的山寨币账号。
开始帮孙二娘转账,这段时间一共收了1000贯山寨币,她都需要兑换 :
同样地,需要提供孙二娘账户的密码和矿工挖矿该转账事务才能被处理。处理成功后,看一下转账结果:
转账成功,没有问题,好汉钱庄给了孙二娘1000贯铜钱。孙二娘离开了钱庄。