在上一篇章节中,我为大家介绍了如何把智能合约的代码部署到以太坊测试网络中。当然ERC20的代币功能尚待完善。
代币的高级功能有以下几点:
1.代币增发
2.代币管理
3.账户冻结
4.代币销毁
下面为大家一一介绍这些功能。
一、代币管理
字面意思不难理解,就是把整个代币的相关功能{transfer(),transferFrom() ,approve(),allowance()}等集中交给指定账户(就是部署代码的账户。这里我先把上一章节部署好的合约加载进Remix IDE。
合约链接如下https://ropsten.etherscan.io/token/0x15b2636d3e42d886aca146b0189dd6a8de43aab0
复制合约地址0x15b2636d3e42d886aca146b0189dd6a8de43aab0到remix IDE
下面开始编写高级代币合约,步骤如下
1.新建AdvanceToken.sol文件
2.编写AdvanceToken合约继承StandardToken
3.编写构造函数为StandardToken传入参数。(这里需要注意的是只需要传参给父合约就ok,其它函数在父合约有具体函数体)
代币增发无非就是把totalSupply的数量提高,所以这个实现起来也很容易.代码如下:
pragma solidity ^0.4.24;
import './StandardToken.sol';
contract AdvanceToken is StandardToken{
//构造函数,只需把参数传给父合约,不需要实现体
constructor(string _name) StandardToken(_name) public{
}
function addTotalSupply(uint _value) public returns(bool success){
require(totalSupply<=totalSupply+_value);//整数溢出校验
totalSupply+=_value;
balanceOf[msg.sender]+=_value;//向函数调用者账户新增余额
emit AdditionTotalSupply(_value);触发增发事件
return true;
}
event AdditionTotalSupply(uint _value);//增发事件
}
下面在Javascript VM 部署测试下
现在增发功能已经实现了,但问题出现在于这个函数没有防护,任何人都可以增发,相当于无限通货膨胀。现在比特币那么值钱是因为其可以在交易所与现金互换,而且总发行量2000万是固定的,那么要使得代币有所价值,增发是一定要控制的,于是引出了代币管理的功能。
二、代币管理
所谓的代币管理,无非就是指定一个地址成为代币管理者,就像网吧找个美女网管一样。
新建一个Manager.sol文件,编写一个Manager合约
pragma solidity ^0.4.24;
contract Manager{
address public manager;//用来记录代币管理者的地址
//构造函数,把部署合约的地址记录为代币管理者
constructor() public{
manager=msg.sender ;
}
//函数修饰器
modifier IsManager{
//这里判断记录代币管理者的地址与调用合约的地址是否一致,不一致则回滚交易
require(manager==msg.sender);
_;
}
//更改代笔管理者角色
function changemanager(address newmanager) public IsManager{
manager=newmanager;
}
}
现在部署到Javascript VM看看效果
代币管理的功能已经实现,现在让我们的高级代币去实现这个功能
pragma solidity ^0.4.24;
import './StandardToken.sol';
import './Manager.sol';
contract AdvanceToken is StandardToken,Manager{//继承Manager合约,多继承用“,”隔开
constructor(string _name) StandardToken(_name) public{
}
//用IsManager函数修饰器去修饰增发函数,只允许代笔管理者调用
function addTotalSupply(uint _value) public IsManager returns(bool success) {
require(totalSupply<=totalSupply+_value);
totalSupply+=_value;
balanceOf[msg.sender]+=_value;
emit AdditionTotalSupply(_value);
return true;
}
event AdditionTotalSupply(uint _value);
}
三、账户冻结
字面意思就是账户被冻结,不能交易代币了,但资产还在账户内,”香菇蓝痩- - “。如何去实现这个功能?其实就是在两个转账函数transfer\transferFrom做下控制,去判断账户是否被冻结,同时需要一个mapping去记录账户被冻结情况。
pragma solidity ^0.4.24;
import './StandardToken.sol';
import './Manager.sol';
contract AdvanceToken is StandardToken,Manager{
mapping(address => bool) public isfroze;//记录账户是否被冻结
constructor(string _name) StandardToken(_name) public{
}
function addTotalSupply(uint _value) public IsManager returns(bool success) {
require(totalSupply<=totalSupply+_value);
totalSupply+=_value;
balanceOf[msg.sender]+=_value;
emit AdditionTotalSupply(_value);
return true;
}
event AdditionTotalSupply(uint _value);
//冻结函数,同样需要IsManager修饰,只有代笔管理者能操作
function froze(address _account) IsManager public returns(bool success){
isfroze[_account]=true;//记录此账户被冻结
emit Frozen(_account);//触发冻结事件
return true;
}
//重写转账函数
function transfer(address _to, uint256 _value) public returns (bool success){
require(balanceOf[msg.sender]>=_value);//判断代币持有者余额要大于转账余额
require(balanceOf[_to]<=balanceOf[_to]+_value);//溢出判断。
require(isfroze[msg.sender]==false);//转账之前判断账户是否被冻结
balanceOf[msg.sender]-=_value;//对代币持有者余额做减法
balanceOf[_to]+=_value;//目标地址做加法
emit Transfer(msg.sender,_to,_value);//触发事件
return true;
}
//重写授权转账函数
function transferFrom(address _from, address _to, uint256 _value)public returns (bool success){
//判断转账人是否有足够余额
require(balanceOf[_from]>=_value&&allowed[_from][msg.sender]>=_value);
//整数溢出判断
require(balanceOf[_to]<=balanceOf[_to]+_value);
require(isfroze[_from]==false);//转账之前判断授权账户是否被冻结
balanceOf[_from]-=_value;
balanceOf[_to]+=_value;
allowed[_from][msg.sender]-=_value;
return true;
}
event Frozen(address _account);
}
现在用0xca35b7d915458ef540ade6068dfe2f44e8fa733c这个账户去部署到JavaScript VM,
转账1万个代币到0x14723a09acff6d2a60dcdf7aa4aff308fddc160c这个账户,然后冻结此账户,看看能否交易成功。
账户冻结功能实现,下面来实现最后一个代币销毁功能
四、代币销毁
这个理解为与增发相反的动作,因此也相对简单,完整高级代币代码如下
pragma solidity ^0.4.24;
import './StandardToken.sol';
import './Manager.sol';
contract AdvanceToken is StandardToken,Manager{
mapping(address => bool) public isfroze;//记录账户是否被冻结
//构造函数,只需把参数传给StandardToken父合约,无需实现体
constructor(string _name) StandardToken(_name) public{
}
//代币增发
function addTotalSupply(uint _value) public IsManager returns(bool success) {
require(totalSupply<=totalSupply+_value);//整数溢出校验
totalSupply+=_value;
balanceOf[msg.sender]+=_value;
emit AdditionTotalSupply(_value);
return true;
}
event AdditionTotalSupply(uint _value);//代币增发事件
//代币销毁
function subTotalSupply(uint _value) public IsManager returns(bool success) {
require(totalSupply>=totalSupply-_value);
totalSupply-=_value;
balanceOf[msg.sender]-=_value;
emit SubTotalSupply(_value);
return true;
}
event SubTotalSupply(uint _value);//代币销毁事件
//冻结函数,同样需要IsManager修饰,只有代笔管理者能操作
function froze(address _account) IsManager public returns(bool success){
isfroze[_account]=true;//记录此账户被冻结
emit Frozen(_account);//触发冻结事件
return true;
}
//重写转账函数
function transfer(address _to, uint256 _value) public returns (bool success){
require(balanceOf[msg.sender]>=_value);//判断代币持有者余额要大于转账余额
require(balanceOf[_to]<=balanceOf[_to]+_value);//溢出判断。
require(isfroze[msg.sender]==false);//转账之前判断账户是否被冻结
balanceOf[msg.sender]-=_value;//对代币持有者余额做减法
balanceOf[_to]+=_value;//目标地址做加法
emit Transfer(msg.sender,_to,_value);//触发事件
return true;
}
//重写授权转账函数
function transferFrom(address _from, address _to, uint256 _value)public returns (bool success){
//判断转账人是否有足够余额
require(balanceOf[_from]>=_value&&allowed[_from][msg.sender]>=_value);
//整数溢出判断
require(balanceOf[_to]<=balanceOf[_to]+_value);
require(isfroze[_from]==false);//转账之前判断授权账户是否被冻结
balanceOf[_from]-=_value;
balanceOf[_to]+=_value;
allowed[_from][msg.sender]-=_value;
return true;
}
event Frozen(address _account);
}