天天看點

建立自己的ERC20加密貨币(可管理、增發、兌換、當機等進階功能的代币)

以太坊官方原文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

建立自己的ERC20加密貨币(可管理、增發、兌換、當機等進階功能的代币)

繼續閱讀