天天看點

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

目錄

Contents [hide]

  • 目錄
  • 1、什麼是 Mist
  • 2、Mist 在哪裡下載下傳?
  • 3、Mist 有哪些依賴?
  • 4、如何安裝 Mist?
    • 4.1、安裝 Mist 依賴工具包
    • 4.2、安裝 Mist
    • 4.3、啟動 Mist,連接配接到 Geth
  • 5、使用 Mist 部署一個簡單的智能合約
  • 6、改善代币
    • 6.1、如何部署
  • 7、進階版的代币功能
    • 7.1、去中心化的管理者
    • 7.2、挖礦
    • 7.3、當機資産
    • 7.4、自動交易
    • 7.5、全部代碼
    • 7.6、使用以太币購買代币
    • 7.7、賣出代币
  • 8、常見問題
    • 8.1、在調試Mist的過程中,建立了很多個合約,如何删除?

1、什麼是 Mist

  

Mist

是以太坊官方的線上錢包管理工具。通過 

Mist

 我們可以很友善的連接配接上我們的私有網絡,進而更好的開發、調試、測試我們的智能合約。既可以連接配接生産網絡、測試網絡,更加可以通過設定參數的方式,連接配接我們自己的私有網絡。

  

Mist

 在通過 

geth.ipc

 檔案連接配接後,就和 

Geth

 所建立的網絡完全契合在一起了,在 

Mist

 上部署的合約,實際上也就是部署在了 

Geth

 網絡上。

Geth

 網絡上建立賬号,也可以在 

Mist

 這個工具上看到。

  通過 

Mist

,我們向大家更詳細的講解了以太坊的核心概念,包括:區塊、Transaction、Gas、賬戶、合約、合約中的構造函數,變量以及方法。

  

2、Mist 在哪裡下載下傳?

  開發版的 

Mist

 在這裡下載下傳:https://github.com/ethereum/mist

  如果要在生産環境上操作,可以直接在以太坊官網下載下傳錢包工具:https://ethereum.org/

  

3、Mist 有哪些依賴?

  需要有以下元件:

  • Node.js 

    v7.x

     (use the prefered installation method for your OS)
  • Meteor javascript app framework
  • Yarn package manager
  • Electron 

    v1.7.9

     cross platform desktop app framework
  • Gulp build and automation system

  

4、如何安裝 Mist?

  在安裝 

Mist

 前,要先安裝依賴的工具包。

  

4.1、安裝 Mist 依賴工具包

➜ /Users/lion >curl https://install.meteor.com/
➜ /Users/lion >brew install yarn
➜ /Users/lion >yarn global add [email protected]
➜ /Users/lion >yarn global add gulp
           
yarn其他平台的安裝方法,可以參考:https://yarnpkg.com/zh-Hans/docs/install

  

4.2、安裝 Mist

➜ /Users/lion/my_project/_eth >git clone https://github.com/ethereum/mist.git
➜ /Users/lion/my_project/_eth >cd mist
➜ /Users/lion/my_project/_eth/mist git:(develop) >git checkout v0.9.2
➜ /Users/lion/my_project/_eth/mist git:(369713b) >yarn
           

  

4.3、啟動 Mist,連接配接到 Geth

  新開一個視窗,用以下指令運作 

Mist

 的背景程式:

➜ /Users/lion/my_project/_eth/mist git:(369713b) >cd interface
➜ /Users/lion/my_project/_eth/mist/interface git:(369713b) >meteor --no-release-check
[[[[[ ~/my_project/_eth/mist/interface ]]]]]

=> Started proxy.
=> Started MongoDB.
=> Started your app.

=> App running at: http://localhost:3000/
=> Client modified -- refreshing
           
第一次運作會慢一些,會啟動proxy、MongoDB等程式,同時下載下傳一些依賴元件

  

  在啟動 

Mist

 之前,我們要先啟動 

Geth

,參考:使用 Go-Ethereum 1.7.2搭建以太坊私有鍊

  我們啟用以太坊私有鍊以後,在 

./chain

 目錄上會建立私有鍊的一些資料,裡面有一個 

geth.ipc

 檔案。

➜ /Users/lion/my_project/_eth/test >ll chain
total 88
drwxr-xr-x  7 lion  staff    224 Oct 24 12:21 geth
srw-------  1 lion  staff      0 Oct 24 12:24 geth.ipc
-rw-------  1 lion  staff  43213 Oct 24 12:08 history
drwx------  4 lion  staff    128 Oct 22 14:57 keystore
           

  

  在原來的視窗中運作以下指令,用 

Mist

 連接配接我們用 

Geth

 啟動的私有鍊:

➜ /Users/lion/my_project/_eth/mist git:(369713b) >yarn dev:electron --rpc /Users/lion/my_project/_eth/test/chain/geth.ipc
           
如果正常交易以太坊的以太币,可以在官網直接下載下傳以太坊錢包使用:https://ethereum.org/

  

  如果在另一台機器是使用RPC方式運作,也可以使用下面的方法連接配接到 

Geth

➜ /Users/lion/my_project/_eth/mist git:(369713b) >yarn dev:electron --rpc http://localhost:8545
           

  

  運作完以後,會打開一個比較像App的網頁,如下圖:

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題
在之前的文章中我們建立的帳戶,經過 

Mist

 連接配接後,也可以在可視化的界面中看到

  

  在 

Mist

 的界面中,點選發送,可以從一個帳戶位址,向另一個帳戶位址,轉移以太币。

  

5、使用 Mist 部署一個簡單的智能合約

  在 

Mist

 上點選右側的合約。首先要選擇一個帳戶來生成合約,用于支付部署合約的費用,以後是誰調用誰來支付費用。(如果在公有鍊上部署智能合約,需要花費一定的以太币)。

  下面是一個最簡單的合約代碼,主要介紹可以看注釋:  

pragma solidity 0.4.16;

/**
 * @title 基礎版的代币合約
 */
contract token {
    /* 公共變量 */
    string public standard = 'https://mshk.top';

    /*記錄所有餘額的映射*/
    mapping (address => uint256) public balanceOf;

    /* 初始化合約,并且把初始的所有代币都給這合約的建立者
     * @param initialSupply 代币的總數
     */
    function token(uint256 initialSupply) {
        //給指定帳戶初始化代币總量,初始化用于獎勵合約建立者
        balanceOf[msg.sender] = initialSupply;
    }

    /**
     * 私有方法從一個帳戶發送給另一個帳戶代币
     * @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;

      //判斷買、賣雙方的資料是否和轉換前一緻
      assert(balanceOf[_from] + balanceOf[_to] == previousBalances);

    }

    /**
     * 從主帳戶合約調用者發送給别人代币
     * @param  _to address 接受代币的位址
     * @param  _value uint256 接受代币的數量
     */
    function transfer(address _to, uint256 _value) public {
        _transfer(msg.sender, _to, _value);
    }
}
                

  

  接下來我們将上面的合約代碼,通過Mist部署到我們的私有鍊的。

  首先如下圖中,點選

合約

->

部署新合約

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  然後如下面的兩張圖,選擇建立合約的帳戶,将上面的代碼貼到

SOLIDITY合約原始代碼

處,在右側選擇要部署的合約

token

,在

token

的下面

Initial Supply

處,輸入我們要初始化的金額

5000

用于獎勵合約建立者,然後在頁面的最下面,點選部署,的彈出的層中,輸入建立合約這個帳号的密碼,輸入正确以後,合約建立成功。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題
Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  建立一個合約以後,再點選 

Mist

 右側的合約,然後在 

定制化合約

 的下面,可以看到我們剛剛建立的合約 

TOKEN

 ,如下圖:

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題
注意,在合約下面也有一串

0x

開頭的位址,這個就相當于一個錢包的位址。在以太坊中,合約也相當于一個帳戶

  

  點選 

TOKEN

 ,進入到合約裡。在下面的 

Balance Of

 處,輸入剛才建立合約帳戶的位址

0xa18e688326ab13b6147ce3ca2213db143a4ec2ee

,可以看到是有5000個代币在裡面,如下圖:

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  在代币建立的時候,初始值我們設定的是5000,是以隻有建立帳戶的位址有代币,而輸入其他帳戶的位址,如

0xc81896af13449a82f22699311df4ec4b48c07718

,是沒有值的。

  接下來,我們向

0xc81896af13449a82f22699311df4ec4b48c07718

這個帳戶位址,轉入一些代币。點選右側

選擇函數

->選擇

Transfer

,在

_to

中輸入

0xc81896af13449a82f22699311df4ec4b48c07718

,在

_value

中輸入

500

,然後點選執行,在彈出的層中輸入調用合約帳戶的密碼,确認操作。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題
Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題
我們能夠看到實際調用合約的過程中,會花費一定的

gas

gas

和以太币會根據區塊的算力有一個計算公式,

gas

一般用于獎勵給挖礦者

  

  在 

transfer

 方法中,我們設定了,隻有合約的調用者

msg.sender

才能向指定位址轉移代币。

/**
 * 從主帳戶合約調用者發送給别人代币
 * @param  _to address 接受代币的位址
 * @param  _value uint256 接受代币的數量
 */
function transfer(address _to, uint256 _value) public {
    _transfer(msg.sender, _to, _value);
}
                

  

  這時,再次進入合約,在

Balance Of

處,輸入兩個帳戶的位址,可以看到,餘額都發生的變化,如下圖:

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

6、改善代币

  通過上面的操作,我們已經可以将合約代碼,通過 

Mist

 部署到我們建立的私有鍊中,同樣如果部署到生産環境,隻需要連上以太坊的網絡,同樣的方法也可以将你的合約,部署到生産環境中,不過要根據代碼的大小,花費一些以太币。

  實際使用過程中,交易的過程,需要通知到用戶端,并且記錄到區塊中,我們可以使用

event

事件來指定,如下代碼進行聲明:

//在區塊鍊上建立一個事件,用以通知用戶端
event Transfer(address indexed from, address indexed to, uint256 value);
                

  

  設定一些代币的基本資訊

/* 公共變量 */
string public standard = 'https://mshk.top';
string public name; //代币名稱
string public symbol; //代币符号比如'$'
uint8 public decimals = 18;  //代币機關,展示的小數點後面多少個0,和以太币一樣後面是是18個0
uint256 public totalSupply; //代币總量
                

  

  某些特定的場景中,不允許某個帳戶花費超過指定的上限,避免大額支出,我們可以添加一個 

approve

 方法,來設定一個允許支出最大金額的清單。

mapping (address => mapping (address => uint256)) public allowance;

/**
 * 設定帳戶允許支付的最大金額
 *
 * 一般在智能合約的時候,避免支付過多,造成風險
 *
 * @param _spender 帳戶位址
 * @param _value 金額
 */
function approve(address _spender, uint256 _value) public returns (bool success) {
    allowance[msg.sender][_spender] = _value;
    return true;
}
                

  

  同樣在 

solidity

 中,合約之間也可以互相調用,我們可以增加一個 

approveAndCall

 方法,用于在設定帳戶最大支出金額後,可以做一些其他操作。

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

/**
 * 設定帳戶允許支付的最大金額
 *
 * 一般在智能合約的時候,避免支付過多,造成風險
 *
 * @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;
    }
}
                

  

  我們可以增加一個 

burn

 方法,用于管理者減去指定帳戶的指定金額。進行該方法操作時,通知用戶端記錄到區塊鍊中。

//減去使用者餘額事件
event Burn(address indexed from, uint256 value);  

/**
 * 減少代币調用者的餘額
 *
 * 操作以後是不可逆的
 *
 * @param _value 要删除的數量
 */
function burn(uint256 _value) public returns (bool success) {
    //檢查帳戶餘額是否大于要減去的值
    require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough

    //給指定帳戶減去餘額
    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;
}
                

  

  完整的代碼如下:

pragma solidity 0.4.16;

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


/**
 * @title 基礎版的代币合約
 */
contract token {
    /* 公共變量 */
    string public standard = 'https://mshk.top';
    string public name; //代币名稱
    string public symbol; //代币符号比如'$'
    uint8 public decimals = 18;  //代币機關,展示的小數點後面多少個0,和以太币一樣後面是是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 token(uint256 initialSupply, string tokenName, string tokenSymbol) {

        //初始化總量
        totalSupply = initialSupply * 10 ** uint256(decimals);    //以太币是10^18,後面18個0,是以預設decimals是18

        //給指定帳戶初始化代币總量,初始化用于獎勵合約建立者
        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) returns (bool success) {
        //檢查發送者是否擁有足夠餘額
        require(_value <= allowance[_from][msg.sender]);   // Check allowance

        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);   // Check if the sender has enough

        //給指定帳戶減去餘額
        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;
    }

}
                

  

6.1、如何部署

  如上面的部署中,我們将完整的代碼,貼到 

Mist

 的 

solidity合約原始代碼

 處,在右側選擇 

token

 , 

Initial Supply

 輸入初始金額

5000

Token name

 輸入我們的代币名稱 

陌上花開

 , 

Token symbol

 代币符号我們輸入 

$$

,然後點選 

部署

,輸入部署帳戶的密碼。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  部署合約以後,我們能夠在合約頁面看到剛才建立的合約。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  點選合約名稱,可以看到合約的一些基本資訊,以及合約和操作函數

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  我們能夠在 

Mist

 上方的 

錢包

 中的主帳号這裡看到有個小圖示,說明主帳戶已經有了代币,其他帳戶是沒有這個圖示的

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  點選進入主帳号以後,我們就可以看到主帳戶已經擁有的代币和以太币的數量,因為我們是參考以太币進行設定,最小機關是wei,是以小數點後面有18個0。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  接下來,我們向另一個帳戶發送一些 

陌上花開

 币,點選 

Mist

 上方的發送,輸入發送的帳戶位址,輸入數量 

500

,選擇發送的是 

陌上花開

 币,點選發送,如下圖

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  再次回到錢包中,我們可以看到,另一個帳戶也有了一個代币的圖示,說明代币已經轉入成功。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  現在你擁有了自己的代币,也可以做轉入轉出操作。可以被用于價值交換,或者工作時間追蹤或者其他項目。

  

7、進階版的代币功能

  一般的代币可以不設定管理者,就是所謂的去中心化。實際使用過程中,可能需要給予挖礦等功能,讓别人能夠購買你的代币,那麼我們就需要設定一個帳戶位址做為這個代币合約的管理者。

**
 * owned 是一個管理者
 */
contract owned {
    address public owner;

    /**
     * 初台化構造函數
     */
    function owned() {
        owner = msg.sender;
    }

    /**
     * 判斷目前合約調用者是否是管理者
     */
    modifier onlyOwner {
        require (msg.sender == owner);
        _;
    }

    /**
     * 指派一個新的管理者
     * @param  newOwner address 新的管理者帳戶位址
     */
    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}
                

  

  上面的代碼是一個非常簡單的合約,我們可以在後面的代碼中,使用 

繼承

 來實作後續的功能。

/**
 * @title 進階版代币
 * 增加當機使用者、挖礦、根據指定匯率購買(售出)代币價格的功能
 */
contract MyAdvancedToken is owned{}
                

  在 

MyAdvancedToken

 的所有方法中,可以使用 

owned

 的變量 

owner

和 

modifier onlyOwner

  

7.1、去中心化的管理者

  我們也可以在構造函數中設定是否需要一個去中心化的管理者。

/*初始化合約,并且把初始的所有的令牌都給這合約的建立者
 * @param initialSupply 所有币的總數
 * @param tokenName 代币名稱
 * @param tokenSymbol 代币符号
 * @param centralMinter 是否指定其他帳戶為合約所有者,為0是去中心化
 */
function MyAdvancedToken(
  uint256 initialSupply,
  string tokenName,
  string tokenSymbol,
  address centralMinter
)  {
    //設定合約的管理者
    if(centralMinter != 0 ) owner = centralMinter;
}
                

  

7.2、挖礦

  有的時候需要更多的代币流通,可以增加 

mintToken

 方法,創造更多的代币。

/**
 * 合約擁有者,可以為指定帳戶創造一些代币
 * @param  target address 帳戶位址
 * @param  mintedAmount uint256 增加的金額(機關是wei)
 */
function mintToken(address target, uint256 mintedAmount) onlyOwner {

    //給指定位址增加代币,同時總量也相加
    balanceOf[target] += mintedAmount;
    totalSupply += mintedAmount;
}
                

  

  在方法的最後有一個 

onlyOwner

,說明 

mintToken

 是繼承了 

onlyOwner

方法,會先調用 

modifier onlyOwner

 方法,然後将 

mintToken

 方法的内容,插入到下劃線 

_

 處調用。

  

7.3、當機資産

  有的場景中,某些使用者違反了規定,需要當機/解凍帳戶,不想讓他使用已經擁有的代币.可以增加以下代碼來控制:

//是否當機帳戶的清單
mapping (address => bool) public frozenAccount;

//定義一個事件,當有資産被當機的時候,通知正在監聽事件的用戶端
event FrozenFunds(address target, bool frozen);

/**
 * 增加當機帳戶名稱
 *
 * 你可能需要監管功能以便你能控制誰可以/誰不可以使用你建立的代币合約
 *
 * @param  target address 帳戶位址
 * @param  freeze bool    是否當機
 */
function freezeAccount(address target, bool freeze) onlyOwner {
    frozenAccount[target] = freeze;
    FrozenFunds(target, freeze);
}
                

  

7.4、自動交易

  到了現在,代币的功能很完善,大家也相信你的代币是有價值的,但你想要使用以太币 

ether

 或者其他代币來購買,讓代币市場化,可以真實的交易,我們可以設定一個價格

//賣出的匯率,一個代币,可以賣出多少個以太币,機關是wei
uint256 public sellPrice;

//買入的匯率,1個以太币,可以買幾個代币
uint256 public buyPrice;

/**
 * 設定買賣價格
 *
 * 如果你想讓ether(或其他代币)為你的代币進行背書,以便可以市場價自動化買賣代币,我們可以這麼做。如果要使用浮動的價格,也可以在這裡設定
 *
 * @param newSellPrice 新的賣出價格
 * @param newBuyPrice 新的買入價格
 */
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
    sellPrice = newSellPrice;
    buyPrice = newBuyPrice;
}
                

  

  然後增加買、賣的方法,每一次的交易,都會消耗掉一定的 

ether

。在 

Solidity 0.4.0

 之後,要接收 

ether

 的函數都要加一個 

payable

 屬性,如果你開放的合約,需要别人轉錢給你,就需要加 

payable

  下面的方法,不會增加代币,隻是改變調用合約者的代币數量,買、賣的價格機關不是 

ether

,而是 

wei

,這是以太币中最小的機關(就像美元裡的美分,比特币裡的聰)。1 ether = 1000000000000000000 wei。是以使用 

ether

 設定價格的時候,在最後加18個0。

  當建立合約的時候,發送足夠多的 

ether

 作為代币的背書,否則你的合約就是破産的,你的使用者就不能夠賣掉他們的代币。

/**
 * 使用以太币購買代币
 */
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);
}
                

  

7.5、全部代碼

  把所有的特性加上,完整的代碼如下:

pragma solidity 0.4.16;

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

/**
 * owned 是一個管理者
 */
contract owned {
    address public owner;

    /**
     * 初台化構造函數
     */
    function owned() {
        owner = msg.sender;
    }

    /**
     * 判斷目前合約調用者是否是管理者
     */
    modifier onlyOwner {
        require (msg.sender == owner);
        _;
    }

    /**
     * 指派一個新的管理者
     * @param  newOwner address 新的管理者帳戶位址
     */
    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}

/**
 * @title 基礎版的代币合約
 */
contract token {
    /* 公共變量 */
    string public standard = 'https://mshk.top';
    string public name; //代币名稱
    string public symbol; //代币符号比如'$'
    uint8 public decimals = 18;  //代币機關,展示的小數點後面多少個0,和以太币一樣後面是是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 token(uint256 initialSupply, string tokenName, string tokenSymbol) {

        //初始化總量
        totalSupply = initialSupply * 10 ** uint256(decimals);    //以太币是10^18,後面18個0,是以預設decimals是18

        //給指定帳戶初始化代币總量,初始化用于獎勵合約建立者
        //balanceOf[msg.sender] = totalSupply;
        balanceOf[this] = 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) returns (bool success) {
        //檢查發送者是否擁有足夠餘額
        require(_value <= allowance[_from][msg.sender]);   // Check allowance

        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);   // Check if the sender has enough

        //給指定帳戶減去餘額
        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;
    }



    /**
     * 匿名方法,預防有人向這合約發送以太币
     */
    /*function() {
        //return;     // Prevents accidental sending of ether
    }*/
}

/**
 * @title 進階版代币
 * 增加當機使用者、挖礦、根據指定匯率購買(售出)代币價格的功能
 */
contract MyAdvancedToken is owned, token {

    //賣出的匯率,一個代币,可以賣出多少個以太币,機關是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 代币符号
     * @param centralMinter 是否指定其他帳戶為合約所有者,為0是去中心化
     */
    function MyAdvancedToken(
      uint256 initialSupply,
      string tokenName,
      string tokenSymbol,
      address centralMinter
    ) token (initialSupply, tokenName, tokenSymbol) {

        //設定合約的管理者
        if(centralMinter != 0 ) owner = centralMinter;

        sellPrice = 2;     //設定1個機關的代币(機關是wei),能夠賣出2個以太币
        buyPrice = 4;      //設定1個以太币,可以買0.25個代币
    }


    /**
     * 私有方法,從指定帳戶轉出餘額
     * @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 {

        //給指定位址增加代币,同時總量也相加
        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 {
        frozenAccount[target] = freeze;
        FrozenFunds(target, freeze);
    }

    /**
     * 設定買賣價格
     *
     * 如果你想讓ether(或其他代币)為你的代币進行背書,以便可以市場價自動化買賣代币,我們可以這麼做。如果要使用浮動的價格,也可以在這裡設定
     *
     * @param newSellPrice 新的賣出價格
     * @param newBuyPrice 新的買入價格
     */
    function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
        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);
    }
}
                

  

  參考之前的方法,在 

Mist

 中重新部署合約,貼完代碼後,在右側選擇 

My Advanced Token

Initial Supply

 輸入初始金額5000,

Token name

 輸入我們的代币名稱 

陌上花開A

Token symbol

 代币符号我們輸入 

#

,然後點選部署,輸入部署帳戶的密碼。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  建立成功以後,我們在合約清單頁,可以看到剛才建立的新合約

陌上花開A

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  點選 

Mist

 上面的發送,我們先給帳戶

0xd29adaadf3a40fd0b68c83c222c10d3ea637dce0

轉入100個以太币。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  操作成功以後,我們能夠在錢包頁面看到

Account 4

已經有了

100

以太币。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

7.6、使用以太币購買代币

  接下來,我們進入合約頁面,使用以太币購買 

陌上花開A

 代币,進入合約界面後,我們能夠看到代币上的以太币是 

0 ether

,在右側選擇 

Buy

 方法,

Execut from

 選擇 

Account 4

,在 

Send ether

 輸入 

10

 個以太币,點選 

執行

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  執行成功以後,能夠看到目前頁面自動重新整理,合約中已經有了

10 ether

,代币的總量不變

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  再次回到 

錢包

 頁面,可以看到 

Account 4

 已經從 

100 ether

 變成了 

90 ether

,并且多了一個代币圖示。

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  點選 

Account 4

 帳号進去,可以看到一些詳細資訊,ether的總量是 

89,999081514

而不是 

90

,是因為執行合約的時候,我們會消費一定的 

gas

。我們設定的費率是1:4,是以 

10 ether

,隻可以購買 

2.5

 個 

陌上花開A

 代币,最小機關也是wei,是以是 

2,500000000000000000

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

7.7、賣出代币

  進入合約界面後,我們能夠看到代币上的以太币是 

10 ether

,在右側選擇 

Sell

 方法,在 

Amount

 處輸入 

2000000000000000000

(因為我們剛才購買了2.5個代币,現在賣出2個,賣出的最小機關是wei),

Execut from

 選擇 

Account 4

,點選 

執行

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  執行以後,在代币的詳情頁面,能夠看到從 

10 ether

變成了 

6 ether

,因為剛才 

Account 4

 賣出了 

2

 個 

陌上花開A

 代币,而我們設定的賣價是 

1個代币

 能賣出 

2個以太币

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

  再次回到 

Account 4

 的詳情頁面,能夠看到以太币變成了 

93,998273026

,而 

陌上花開A

 代币的數量,變成了 

0,500000000000000000

Go-Ethereum 結合 Mist 0.9.2 實作代币智能合約的執行個體目錄1、什麼是 Mist2、Mist 在哪裡下載下傳?3、Mist 有哪些依賴?4、如何安裝 Mist?5、使用 Mist 部署一個簡單的智能合約6、改善代币7、進階版的代币功能8、常見問題

  

8、常見問題

8.1、在調試

Mist

的過程中,建立了很多個合約,如何删除?

  In the Ethereum Wallet (Mist) menu, click on Develop -> Toggle Developer Tools -> Wallet UI. Click on the Console tab

CustomContracts.find().fetch().map(
   function(m) { CustomContracts.remove(m._id);}
)
                

繼續閱讀