1. 程式人生 > 其它 >以太坊·代幣開發詳解

以太坊·代幣開發詳解

本文節選自《Netkiller Blockchain 手札》

Netkiller Blockchain 手札

本文作者最近在找工作,有意向致電 13113668890

Mr. Neo Chan, 陳景峰(BG7NYT)

中國廣東省深圳市龍華新區民治街道溪山美地 518131 +86 13113668890 <[email protected]>

文件始創於2018-02-10

版權 © 2018 Netkiller(Neo Chan). All rights reserved.

版權宣告

轉載請與作者聯絡,轉載時請務必標明文章原始出處和作者資訊及本宣告。

http://www.netkiller.cnhttp://netkiller.github.iohttp://netkiller.sourceforge.net

http://www.netkiller.cn

http://netkiller.github.io

http://netkiller.sourceforge.net

微信訂閱號 netkiller-ebook (微信掃描二維碼)QQ:13721218 請註明“讀者”QQ群:128659835 請註明“讀者”

微信訂閱號 netkiller-ebook (微信掃描二維碼)

QQ:13721218 請註明“讀者”

QQ群:128659835 請註明“讀者”

http://www.netkiller.cn

http://netkiller.github.io

http://netkiller.sourceforge.net

微信訂閱號 netkiller-ebook (微信掃描二維碼)

QQ:13721218 請註明“讀者”

QQ群:128659835 請註明“讀者”

$Data$

內容摘要

這一部關於區塊鏈開發及運維的電子書。

為什麼會寫區塊鏈電子書?因為2018年是區塊鏈年。

這本電子書是否會出版(紙質圖書)? 不會,因為網際網路技術更迭太快,紙質書籍的內容無法實時更新,一本書動輒百元,很快就成為垃圾,你會發現目前市面的上區塊鏈書籍至少是一年前寫的,內容已經過時,很多例子無法正確執行。所以我不會出版,電子書的內容會追逐技術發展,及時跟進軟體版本的升級,做到內容最新,至少是主流。

這本電子書與其他區塊鏈書籍有什麼不同?市面上大部分割槽塊鏈書籍都是用2/3去講區塊鏈原理,只要不到 1/3 的乾貨,乾貨不夠理論來湊,通篇將理論或是大談特談區塊鏈行業,這些內容更多是頭腦風暴,展望區塊鏈,均無法落地實施。本書與那些書籍完全不同,不講理論和原理,面向應用落地,注重例子,均是乾貨。

電子書更新頻率?每天都會有新內容加入,更新頻率最遲不會超過一週,更新內容請關注 https://github.com/netkiller/netkiller.github.io/commits/master

本文采用碎片化寫作,原文會不定期更新,請儘量閱讀原文。

http://www.netkiller.cn/blockchain/index.html

9.4. 建立代幣

https://ethereum.org/token

9.4.1. 合約檔案

pragma solidity ^0.4.16;

interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }

contract TokenERC20 {
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = 18;
    // 18 decimals is the strongly suggested default, avoid changing it
    uint256 public totalSupply;

    // This creates an array with all balances
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    // This generates a public event on the blockchain that will notify clients
    event Transfer(address indexed from, address indexed to, uint256 value);

    // This notifies clients about the amount burnt
    event Burn(address indexed from, uint256 value);

    /**
     * Constrctor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    function TokenERC20(
        uint256 initialSupply,
        string tokenName,
        string tokenSymbol
    ) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
        balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
    }

    /**
     * Internal transfer, only can be called by this contract
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // Prevent transfer to 0x0 address. Use burn() instead
        require(_to != 0x0);
        // Check if the sender has enough
        require(balanceOf[_from] >= _value);
        // Check for overflows
        require(balanceOf[_to] + _value > balanceOf[_to]);
        // Save this for an assertion in the future
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        Transfer(_from, _to, _value);
        // Asserts are used to use static analysis to find bugs in your code. They should never fail
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /**
     * Transfer tokens
     *
     * Send `_value` tokens to `_to` from your account
     *
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transfer(address _to, uint256 _value) public {
        _transfer(msg.sender, _to, _value);
    }

    /**
     * Transfer tokens from other address
     *
     * Send `_value` tokens to `_to` on behalf of `_from`
     *
     * @param _from The address of the sender
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    /**
     * Set allowance for other address
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }

    /**
     * Set allowance for other address and notify
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     * @param _extraData some extra information to send to the approved contract
     */
    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;
        }
    }

    /**
     * Destroy tokens
     *
     * Remove `_value` tokens from the system irreversibly
     *
     * @param _value the amount of money to burn
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        Burn(msg.sender, _value);
        return true;
    }

    /**
     * Destroy tokens from other account
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        Burn(_from, _value);
        return true;
    }
}

9.4.2. 部署合約

啟動 Ethereum Wallet,點選 CONTRACTS 按鈕,進入合約管理介面

點選 DEPLOY NEW CONTRACT 按鈕,部署一個新合約

複製貼上合約檔案到 SOLIDITY CONTRACT SOURCE CODE 下方

SELECT CONTRACT TO DEPLOY 列表選擇 “Token ERC 20”

Initial supply 是初始發行貨幣量

Token name 是代幣名稱

Token symbol 是代幣符號

拉動滾動調,找到下方 “DEPLOY”按鈕,點選該按鈕。

輸入賬號密碼,並點選“SEND TRANSACTION” 按鈕。

ERC20代幣建立完成

9.4.3. 代幣轉賬

進入錢包可以看到當前賬號的以太幣數量,在下方還能看到 ERC20 代幣。

點選 SEND 按鈕

填寫 TO 地址 和 代幣 500 個,點選 SEND 按鈕

進入目標賬號檢視餘額。

至此我們完成了,代幣合約部署,實現了賬號對賬號的轉賬。下面我們來講述如何開發。

以太幣開發是指,使用程式實現代幣的轉賬,因為我們不可能使用錢包手工轉賬。讓代幣落地就需要在程式中完成。

通常程式部署在WEB伺服器,例如這樣的場景,使用者在網站上註冊開戶,贈送一定量的代幣獎勵。

這時我們就需要使用WEB3.js(Node) 或者WEB3J (Java API )完成網站或者手機APP訪問以太坊,完成代幣轉賬。

6.10.4. ERC20 Example

通過Web3操作代幣轉賬

fs = require('fs');
const Web3 = require('web3');
const web3 = new Web3('http://localhost:8545');
web3.version
const abi = fs.readFileSync('output/TokenERC20.abi', 'utf-8');

const contractAddress = "0x05A97632C197a0496bc939C4e666c2E03Cb95DD4";
const toAddress = "0x2C687bfF93677D69bd20808a36E4BC2999B4767C";

var coinbase;

web3.eth.getCoinbase().then(function (address){
  coinbase = address;
  console.log(address);
});

const contract = new web3.eth.Contract(JSON.parse(abi), contractAddress, { from: coinbase , gas: 100000});

contract.methods.balanceOf('0x5c18a33DF2cc41a1bedDC91133b8422e89f041B7').call().then(console.log).catch(console.error);
contract.methods.balanceOf('0x2C687bfF93677D69bd20808a36E4BC2999B4767C').call().then(console.log).catch(console.error);

web3.eth.personal.unlockAccount(coinbase, "Netkiller").then(console.log);
contract.methods.transfer('0x2C687bfF93677D69bd20808a36E4BC2999B4767C', 100).send().then(console.log).catch(console.error);

contract.methods.balanceOf('0x2C687bfF93677D69bd20808a36E4BC2999B4767C').call().then(console.log).catch(console.error);

上面的程式碼可是純乾貨,你在網上看到最多的例子就是錢包完成合約,沒有人提供web3程式碼完成同樣的操作。我也翻遍了了網上找不到資料,這是我辛苦琢磨出來的,有不明白之處去我的QQ群裡討論把。

以上例子均使用最新版本

geth 1.8.1

web3.js 1.0.0-beta30

solc Version: 0.4.20

如果上面資料對你有用,打賞地址:http://www.netkiller.cn/home/donations.html