以太坊官方原文ERC20代币标準源碼:https://ethereum.org/token
(注:本文是在原文的基礎上,根據個人的了解,修改部分内容并添加了一些注釋)
pragma solidity ^0.4.16;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
/**
* owned是合約的管理者
*/
contract owned {
address public owner;
/**
* 初台化構造函數
*/
function owned () public {
owner = msg.sender;
}
/**
* 判斷目前合約調用者是否是合約的所有者
*/
modifier onlyOwner {
require (msg.sender == owner);
_;
}
/**
* 合約的所有者指派一個新的管理者
* @param newOwner address 新的管理者帳戶位址
*/
function transferOwnership(address newOwner) onlyOwner public {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
/**
* 基礎代币合約
*/
contract TokenERC20 {
string public name; //發行的代币名稱
string public symbol; //發行的代币符号
uint8 public decimals = 18; //代币機關,展示的小數點後面多少個0。
uint256 public totalSupply; //發行的代币總量
/*記錄所有餘額的映射*/
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
/* 在區塊鍊上建立一個事件,用以通知用戶端*/
//轉帳通知事件
event Transfer(address indexed from, address indexed to, uint256 value);
event Burn(address indexed from, uint256 value); //減去使用者餘額事件
/* 初始化合約,并且把初始的所有代币都給這合約的建立者
* @param initialSupply 代币的總數
* @param tokenName 代币名稱
* @param tokenSymbol 代币符号
*/
function TokenERC20(uint256 initialSupply, string tokenName, string tokenSymbol) public {
//初始化總量
totalSupply = initialSupply * 10 ** uint256(decimals);
//給指定帳戶初始化代币總量,初始化用于獎勵合約建立者
balanceOf[msg.sender] = totalSupply;
name = tokenName;
symbol = tokenSymbol;
}
/**
* 私有方法從一個帳戶發送給另一個帳戶代币
* @param _from address 發送代币的位址
* @param _to address 接受代币的位址
* @param _value uint256 接受代币的數量
*/
function _transfer(address _from, address _to, uint256 _value) internal {
//避免轉帳的位址是0x0
require(_to != 0x0);
//檢查發送者是否擁有足夠餘額
require(balanceOf[_from] >= _value);
//檢查是否溢出
require(balanceOf[_to] + _value > balanceOf[_to]);
//儲存資料用于後面的判斷
uint previousBalances = balanceOf[_from] + balanceOf[_to];
//從發送者減掉發送額
balanceOf[_from] -= _value;
//給接收者加上相同的量
balanceOf[_to] += _value;
//通知任何監聽該交易的用戶端
Transfer(_from, _to, _value);
//判斷買、賣雙方的資料是否和轉換前一緻
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
/**
* 從主帳戶合約調用者發送給别人代币
* @param _to address 接受代币的位址
* @param _value uint256 接受代币的數量
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
/**
* 從某個指定的帳戶中,向另一個帳戶發送代币
* 調用過程,會檢查設定的允許最大交易額
* @param _from address 發送者位址
* @param _to address 接受者位址
* @param _value uint256 要轉移的代币數量
* @return success 是否交易成功
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
//檢查發送者是否擁有足夠餘額
require(_value <= allowance[_from][msg.sender]);
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
/**
* 設定帳戶允許支付的最大金額
* 一般在智能合約的時候,避免支付過多,造成風險
* @param _spender 帳戶位址
* @param _value 金額
*/
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
/**
* 設定帳戶允許支付的最大金額
* 一般在智能合約的時候,避免支付過多,造成風險,加入時間參數,可以在 tokenRecipient 中做其他操作
* @param _spender 帳戶位址
* @param _value 金額
* @param _extraData 操作的時間
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
/**
* 減少代币調用者的餘額
* 操作以後是不可逆的
* @param _value 要删除的數量
*/
function burn(uint256 _value) public returns (bool success) {
//檢查帳戶餘額是否大于要減去的值
require(balanceOf[msg.sender] >= _value);
//給指定帳戶減去餘額
balanceOf[msg.sender] -= _value;
//代币問題做相應扣除
totalSupply -= _value;
Burn(msg.sender, _value);
return true;
}
/**
* 删除帳戶的餘額(含其他帳戶)
* 删除以後是不可逆的
* @param _from 要操作的帳戶位址
* @param _value 要減去的數量
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {
//檢查帳戶餘額是否大于要減去的值
require(balanceOf[_from] >= _value);
//檢查 其他帳戶 的餘額是否夠使用
require(_value <= allowance[_from][msg.sender]);
//減掉代币
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value;
//更新總量
totalSupply -= _value;
Burn(_from, _value);
return true;
}
}
/**
* 代币增發、
* 代币當機、
* 代币自動銷售和購買、
* 進階代币功能
*/
contract MyAdvancedToken is owned, TokenERC20 {
//賣出的匯率,一個代币,可以賣出多少個以太币,機關是wei
uint256 public sellPrice;
//買入的匯率,1個以太币,可以買幾個代币
uint256 public buyPrice;
//是否當機帳戶的清單
mapping (address => bool) public frozenAccount;
//定義一個事件,當有資産被當機的時候,通知正在監聽事件的用戶端
event FrozenFunds(address target, bool frozen);
/*初始化合約,并且把初始的所有的令牌都給這合約的建立者
* @param initialSupply 所有币的總數
* @param tokenName 代币名稱
* @param tokenSymbol 代币符号
*/
function MyAdvancedToken(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) TokenERC20(initialSupply, tokenName, tokenSymbol) public {}
/**
* 私有方法,從指定帳戶轉出餘額
* @param _from address 發送代币的位址
* @param _to address 接受代币的位址
* @param _value uint256 接受代币的數量
*/
function _transfer(address _from, address _to, uint _value) internal {
//避免轉帳的位址是0x0
require (_to != 0x0);
//檢查發送者是否擁有足夠餘額
require (balanceOf[_from] > _value);
//檢查是否溢出
require (balanceOf[_to] + _value > balanceOf[_to]);
//檢查 當機帳戶
require(!frozenAccount[_from]);
require(!frozenAccount[_to]);
//從發送者減掉發送額
balanceOf[_from] -= _value;
//給接收者加上相同的量
balanceOf[_to] += _value;
//通知任何監聽該交易的用戶端
Transfer(_from, _to, _value);
}
/**
* 合約擁有者,可以為指定帳戶創造一些代币
* @param target address 帳戶位址
* @param mintedAmount uint256 增加的金額(機關是wei)
*/
function mintToken(address target, uint256 mintedAmount) onlyOwner public {
//給指定位址增加代币,同時總量也相加
balanceOf[target] += mintedAmount;
totalSupply += mintedAmount;
Transfer(0, this, mintedAmount);
Transfer(this, target, mintedAmount);
}
/**
* 增加當機帳戶名稱
*
* 你可能需要監管功能以便你能控制誰可以/誰不可以使用你建立的代币合約
*
* @param target address 帳戶位址
* @param freeze bool 是否當機
*/
function freezeAccount(address target, bool freeze) onlyOwner public {
frozenAccount[target] = freeze;
FrozenFunds(target, freeze);
}
/**
* 設定買賣價格
*
* 如果你想讓ether(或其他代币)為你的代币進行背書,以便可以市場價自動化買賣代币,我們可以這麼做。如果要使用浮動的價格,也可以在這裡設定
*
* @param newSellPrice 新的賣出價格
* @param newBuyPrice 新的買入價格
*/
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {
sellPrice = newSellPrice;
buyPrice = newBuyPrice;
}
/**
* 使用以太币購買代币
*/
function buy() payable public {
uint amount = msg.value / buyPrice;
_transfer(this, msg.sender, amount);
}
/**
* @dev 賣出代币
* @return 要賣出的數量(機關是wei)
*/
function sell(uint256 amount) public {
//檢查合約的餘額是否充足
require(this.balance >= amount * sellPrice);
_transfer(msg.sender, this, amount);
msg.sender.transfer(amount * sellPrice);
}
}
下一篇文章我們将講到 如何 使用Remix編輯器釋出以太坊ERC20進階代币合約
學如逆水行舟,不進則退。心似平原跑馬,易放難收。全棧工程師是指掌握多種技能,并能利用多種技能獨立完成産品的人。 也叫全端工程師(同時具備前端和背景能力),英文Full Stack engineer。【人工智能】【區塊鍊】【系統/網絡/運維】【雲計算/大資料】【資料庫】【移動開發】【後端開發】【遊戲開發】【UI設計】【微服務】【爬蟲】【Java】【Go】【C++】【PHP】【Python】【Android/IOS】【HTML/CSS】【JavaScript】【Node】。歡迎各位大神萌新一起專研分享技術。。。
歡迎加入 IT全棧工程師技術交流群:593674370