search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

以太坊手把手發幣教學 - 割韭菜起手式 - Soul & Shell Blog

超簡單以太坊發幣教學 (自己的幣自己發)

幣圈一天,人間一年。在 ICO 的世界裡,笑稱「不管黑幣白幣,能忽悠的就是好幣」。雖然現在已經開始瘋 STO 了,過時的我最近剛好研究了一下 Ethereum 智能合約,今天過氣的教教大家如何在以太坊發弊 ICO

為了跟上時代潮流的尾巴,今天教大家如何自己發行 ETH ERC-20 標準的 Token 代幣。所有教學動作可透過 Chrome 瀏覽器 + MetaMask 錢包即可完成,今年要好野就看這一篇了。

什麼是 ERC-20 標準代幣?

ERC-20 是基於以太坊 (Ethereum) 上發行智能合約的一種標準,智能合約是一段可以在區塊鏈執行的程式碼,這個 ERC-20 標準就是程式裡頭常常使用的 Interface 概念。ERC-20 Interface 定義如下:

1
2
3
4
5
6
7
8
9
10
11
contract ERC20Interface {
    function totalSupply() public view returns (uint);
    function balanceOf(address tokenOwner) public view returns (uint balance);
    function allowance(address tokenOwner, address spender) public view returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);
    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

如果你的智能合約實做了上述的介面,那就可以符合 ERC-20 的規範 (ERC-20官方規範在這裡),大家就知道如何使用你的代幣,讓代幣的流通更方便了。話說現在有 14 萬以上種類的 ERC-20 Token 被發行,我是不相信啦(不相信那麼少,寫這篇文章的時候我就發了 3 種幣了),難道真的大家都有兩億!

如果我有兩億

此外,ERC-20 有一些弊端,比如將 Token 轉帳 (transfer) 到一個智能合約的時候,由於邏輯的關係有可能造成卡死,你的 Token 就進到黑洞了。因此後來延伸 ERC-20 出現了 ERC-223 標準,透過 tokenFallback 函式進行驗證,避免代幣被錯誤使用造成代幣消失的問題。但目前官方 theethereum Wiki 還沒有出現這個標準的相關定義,我們今年還是以 ERC-20 來實做發幣。

於以太坊測試公網進行智能合約發布測試

首先,我們準備好錢包與領取測試用的 ETH。啟動你的 Chrome 先安裝 MetaMask Extension,安裝好後請先註冊一個錢包,接著切換為測試網路,如下圖:

metamask-chang-to-test-network

一開始切換到測試網路,會沒有任何 ETH 可以使用,但是佈署與執行智能合約需要 ETH,你可以從以下連結免費領取一個 ETH 來測試使用:

https://faucet.ropsten.be/

填上你的錢包位置:

get-eth-for-test

然後等一下看看你的 MetaMask 應該就有 1 ETH 可以揮霍了,記住這是測試公網,可別天真的以為可以轉去交易所買賣啊~好的開始是成功的全部,做到這裡已經快要可以割韭菜了~

開始製作 ERC-20 代幣智能合約

再來我們要在測試網路佈署這個空氣幣的智能合約,以太坊智能合約使用 Solidity 語言撰寫,所以我們先來學一下 Solidity 語言.......(誤~我不會啊~)

這裡我們會用到一個叫做 Remix 的以太坊 Web 線上智能合約編譯佈署工具,先連到 https://remix.ethereum.org 然後按下「+」圖示新增一個 .sol 檔案,如下:

eth-remix-online

然後輸入一個酷炫的檔名如下:

remix-add-sol-file

然後貼上官方提供的範例,修改後已經同步放在 GitHub ERC-20.sol 檔案,內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
pragma solidity ^0.5.0;
 
// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
library SafeMath {
    function add(uint a, uint b) internal pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function sub(uint a, uint b) internal pure returns (uint c) {
        require(b <= a);
        c = a - b;
    }
    function mul(uint a, uint b) internal pure returns (uint c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }
    function div(uint a, uint b) internal pure returns (uint c) {
        require(b > 0);
        c = a / b;
    }
}
 
 
// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
    function totalSupply() public view returns (uint);
    function balanceOf(address tokenOwner) public view returns (uint balance);
    function allowance(address tokenOwner, address spender) public view returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);
 
    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
 
 
// ----------------------------------------------------------------------------
// Contract function to receive approval and execute function in one call
//
// Borrowed from MiniMeToken
// ----------------------------------------------------------------------------
contract ApproveAndCallFallBack {
    function receiveApproval(address from, uint256 tokens, address token, bytes memory data) public;
}
 
 
// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
    address public owner;
    address public newOwner;
 
    event OwnershipTransferred(address indexed _from, address indexed _to);
 
    constructor() public {
        owner = msg.sender;
    }
 
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
 
    function transferOwnership(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }
    function acceptOwnership() public {
        require(msg.sender == newOwner);
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
        newOwner = address(0);
    }
}
 
 
// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and a
// fixed supply
// ----------------------------------------------------------------------------
contract AirToken is ERC20Interface, Owned {
    using SafeMath for uint;
 
    string public symbol;
    string public  name;
    uint8 public decimals;
    uint _totalSupply;
 
    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;
 
 
    // ------------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------------
    constructor() public {
        symbol = "AirCoin";
        name = "空氣幣";
        decimals = 3;
        _totalSupply = 200000000 * 10**uint(decimals);
        balances[0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF] = _totalSupply;
        emit Transfer(address(0), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, _totalSupply);
    }
 
 
    // ------------------------------------------------------------------------
    // Total supply
    // ------------------------------------------------------------------------
    function totalSupply() public view returns (uint) {
        return _totalSupply.sub(balances[address(0)]);
    }
 
 
    // ------------------------------------------------------------------------
    // Get the token balance for account `tokenOwner`
    // ------------------------------------------------------------------------
    function balanceOf(address tokenOwner) public view returns (uint balance) {
        return balances[tokenOwner];
    }
 
 
    // ------------------------------------------------------------------------
    // Transfer the balance from token owner's account to `to` account
    // - Owner's account must have sufficient balance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transfer(address to, uint tokens) public returns (bool success) {
        balances[msg.sender] = balances[msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(msg.sender, to, tokens);
        return true;
    }
 
 
    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account
    //
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
    // recommends that there are no checks for the approval double-spend attack
    // as this should be implemented in user interfaces
    // ------------------------------------------------------------------------
    function approve(address spender, uint tokens) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }
 
 
    // ------------------------------------------------------------------------
    // Transfer `tokens` from the `from` account to the `to` account
    //
    // The calling account must already have sufficient tokens approve(...)-d
    // for spending from the `from` account and
    // - From account must have sufficient balance to transfer
    // - Spender must have sufficient allowance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transferFrom(address from, address to, uint tokens) public returns (bool success) {
        balances[from] = balances[from].sub(tokens);
        allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(from, to, tokens);
        return true;
    }
 
 
    // ------------------------------------------------------------------------
    // Returns the amount of tokens approved by the owner that can be
    // transferred to the spender's account
    // ------------------------------------------------------------------------
    function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
        return allowed[tokenOwner][spender];
    }
 
 
    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account. The `spender` contract function
    // `receiveApproval(...)` is then executed
    // ------------------------------------------------------------------------
    function approveAndCall(address spender, uint tokens, bytes memory data) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, address(this), data);
        return true;
    }
 
 
    // ------------------------------------------------------------------------
    // Don't accept ETH
    // ------------------------------------------------------------------------
    function () external payable {
        revert();
    }
 
 
    // ------------------------------------------------------------------------
    // Owner can transfer out any accidentally sent ERC20 tokens
    // ------------------------------------------------------------------------
    function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
        return ERC20Interface(tokenAddress).transfer(owner, tokens);
    }
}

上述合約需要更改的地方很少,只有以下幾點:

1
2
3
4
5
6
7
8
    constructor() public {
        symbol = "AirCoin";
        name = "空氣幣";
        decimals = 3;
        _totalSupply = 200000000 * 10**uint(decimals);
        balances[0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF] = _totalSupply;
        emit Transfer(address(0), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, _totalSupply);
    }

  • symbol: 幣的代號
  • name: 幣的名稱,可以用中文
  • decimals: 小數點位數
  • _totalSupply: 總發行量
  • 0x你的錢包:請務必改成你自己的錢包位置,這樣佈署完成以後才可以進行大灑幣的工作

貼上後按下「Start to compile (Ctrl-S)」按鈕進行編譯,編譯成功畫面如下:

remix-erc20-code

再來切換到 Run 功能,選擇我們要佈署的合約設定如下圖:

  • Environment:設定為「Injected Web3」透過 MetaMask
  • Account:設定為自己的 ETH 帳戶 (預設會自動由 MetaMask 帶入)

run-contract

按下「Deploy」這時你的 MetaMask 回出現確認畫面,按下「CONFIRM」進行佈署,如下:

metamask-contract-deploy-confirm

讓子彈飛一下,我們可以看到交易為 Pending 狀態,需要先等待區塊鏈處理交易,如下:

contract-pending

好囉,點選詳細資料,看一下 Etherscan 的狀態如下:

contract-done

contract-ethscan

交易很順利被包進 Block,接著我們看看帳戶是不是有 Token 了,先複製 Remix 智能合約的 Address,如下:

copy-contract-address

然後到 MetaMask 點選「選單」底下有一個「ADD TOKEN」,進入後選擇「Custom Token」並填上我們剛剛的合約位置,如下:

metamask-add-token

按下「NEXT」畫面會自動帶出餘額數量,然後按下「ADD TOKENS」確認新增:

add-token-confirm

然後在 MetaMask 主畫面就可以看到 2E 空氣幣進帳囉:

token-get

Ethereum 發幣之後

接下來呢?是不是要開始忽悠這個 AirCoin 的價值呢?要 ICO 嗎?別鬧了,這是以太坊測試網路,而且想要 ICO 請必須滿足三大條件:

  • 一份酷炫的白皮書
  • 幾位大神團隊成員
  • 氣派酷炫的發表會

三缺三我看我還是先洗洗睡吧~

為了證明我發幣的決心,我決定下重本 (大概 0.5 鎂) 在以太坊公鏈發行 AirCoin 代幣 (正式官方名稱為空氣幣),一共發行 2 億個 Token (本來要發 10E 但是我改 Code 忘記重新 Compile……. XD),至於 AirCoin 的用途、願景與理想我現在還沒想到,可能還需要點時間。以太坊公網全球限量保證不增發的 AirToken 合約如下:

0x5eb53a54f5f15f03dd98c63ec4cf28b9ef7747d6

air coin release 以太坊發幣

另外如果有人想要這個未來可能會爆漲的 AirCoin 空氣幣 (ETH 正式公網喔),請與我聯繫,如果我還有 Gas 就會發囉,現正免費灑幣中!

其他有想到再補充了,今天先介紹到這裡.......啊掰~

平價童鞋首選



熱門推薦

本文由 toright 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦