在上一篇章節中,我爲大家介紹瞭如何把智能合約的代碼部署到以太坊測試網絡中。當然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);
}