您好,登錄后才能下訂單哦!
代幣(Token):
代幣單純從其名字上理解的話,就是一種可以替代通用貨幣起到交換媒介作用的東西,可以是商場積分,可以是游戲幣,也可以是籌碼。但是在區塊鏈中,就不完全是那么回事了,區塊鏈中的代幣或者說Token通常指的是具有流通性的加密數字權益證明,例如比特幣、以太幣等數字貨幣都屬于代幣
從以上定義可以得知代幣的三個要素:
綜上,簡言之代幣的概念大致上就是基于區塊鏈發行的加密貨幣或者其他類似的東西。通常大多數人或團隊在開發區塊鏈項目時,都會考慮發行自己的代幣。在最初的時候,我們要發行自己的加密貨幣得從比特幣的源碼上改造出來。不過現如今通過以太坊平臺,我們能夠很方便的開發并發行自己的代幣,所以本文將介紹如何基于以太坊開發自己的代幣。
本文將使用到兩個工具,分別是Remix和MetaMask,如果對這兩個工具不太了解的話可以參考我另外兩篇文章:
首先我們使用solidity開發一個擁有最基本功能的“代幣”demo,以便了解代幣最基礎的樣子,代碼如下:
pragma solidity ^0.4.20;
contract SimpleToken {
// 保存每個地址所擁有的代幣數量
mapping (address => uint256) public balanceOf;
// 參數為代幣的初始供應量或者說發行數量
constructor (uint256 initSupply) public {
// 創建者擁有所有的代幣
balanceOf[msg.sender] = initSupply;
}
/**
* 轉移代幣
*
* @param _to 接收方的賬戶地址
* @param _value 轉移的代幣數量
*/
function transfer (address _to, uint256 _value) public {
// 發送方的賬戶余額需大于等于轉移的代幣數量
require(balanceOf[msg.sender] >= _value);
// 檢查有沒有發生溢出,因為數量有可能超過uint256可存儲的范圍
require(balanceOf[_to] + _value >= balanceOf[_to]);
// 減少發送方賬戶的代幣數量
balanceOf[msg.sender] -= _value;
// 增加接收方賬戶的代幣數量
balanceOf[_to] += _value;
}
}
1.代碼編寫完成后,在remix上部署合約,首先初始化代幣供應量:
2.查看指定賬戶所擁有的代幣數量:
3.轉移代幣到另一個賬戶地址:
4.此時該賬戶地址的代幣數量就只剩下100了:
在上一小節中,我們實現了一個簡單的代幣,但就因為簡單,所以該代幣是極其不完善的,例如沒有代幣名稱、代幣符號以及無法控制代幣的交易等。
因此以太坊定義了ERC20,ERC20是以太坊定義的一個代幣統一標準,該標準描述了我們在實現代幣時必須要遵守的協議,如指定代幣名稱、總量、實現代幣交易函數等,只有實現了該協議的代幣才能被以太坊錢包支持。
下圖是一個實現了ERC20協議的代幣:
實際上ERC20協議是定義了一組標準接口,該協議使得在以太坊上開發的任何代幣都能被其他應用程序重用,例如錢包到分散的交易所等,如下:
contract ERC20Interface {
// 代幣名稱
string public constant name = "Token Name";
// 代幣符號或者說簡寫
string public constant symbol = "SYM";
// 代幣小數點位數,代幣的最小單位, 18表示我們可以擁有 0.0000000000000000001單位個代幣
uint8 public constant decimals = 18; // 18 is the most common number of decimal places
// 查詢代幣的發行總量
function totalSupply() public constant returns (uint);
// 查詢地址的代幣余額
function balanceOf(address tokenOwner) public constant returns (uint balance);
// 查詢spender允許從tokenOwner上花費的代幣數量
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
// 實現代幣交易,用于從本賬戶給某個地址轉移代幣
function transfer(address to, uint tokens) public returns (bool success);
// 允許spender多次從你的賬戶取款,并且最多可取tokens個,主要用于某些場景下授權委托其他用戶從你的賬戶上花費代幣
function approve(address spender, uint tokens) public returns (bool success);
// 實現代幣用戶之間的交易,從一個地址轉移代幣到另一個地址
function transferFrom(address from, address to, uint tokens) public returns (bool success);
// 代幣交易時觸發的事件,即調用transfer方法時觸發
event Transfer(address indexed from, address indexed to, uint tokens);
// 允許其他用戶從你的賬戶上花費代幣時觸發的事件,即調用approve方法時觸發
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
代碼如下:
pragma solidity ^0.4.20;
// 定義ERC-20標準接口
contract ERC20Interface {
// 代幣名稱
string public name;
// 代幣符號或者說簡寫
string public symbol;
// 代幣小數點位數,代幣的最小單位
uint8 public decimals;
// 代幣的發行總量
uint public totalSupply;
// 實現代幣交易,用于給某個地址轉移代幣
function transfer(address to, uint tokens) public returns (bool success);
// 實現代幣用戶之間的交易,從一個地址轉移代幣到另一個地址
function transferFrom(address from, address to, uint tokens) public returns (bool success);
// 允許spender多次從你的賬戶取款,并且最多可取tokens個,主要用于某些場景下授權委托其他用戶從你的賬戶上花費代幣
function approve(address spender, uint tokens) public returns (bool success);
// 查詢spender允許從tokenOwner上花費的代幣數量
function allowance(address tokenOwner, address spender) public view returns (uint remaining);
// 代幣交易時觸發的事件,即調用transfer方法時觸發
event Transfer(address indexed from, address indexed to, uint tokens);
// 允許其他用戶從你的賬戶上花費代幣時觸發的事件,即調用approve方法時觸發
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
// 實現ERC-20標準接口
contract ERC20Impl is ERC20Interface {
// 存儲每個地址的余額(因為是public的所以會自動生成balanceOf方法)
mapping (address => uint256) public balanceOf;
// 存儲每個地址可操作的地址及其可操作的金額
mapping (address => mapping (address => uint256)) internal allowed;
// 初始化屬性
constructor() public {
name = "Test Token";
symbol = "TEST";
decimals = 18;
totalSupply = 100000000;
// 初始化該代幣的賬戶會擁有所有的代幣
balanceOf[msg.sender] = totalSupply;
}
function transfer(address to, uint tokens) public returns (bool success) {
// 檢驗接收者地址是否合法
require(to != address(0));
// 檢驗發送者賬戶余額是否足夠
require(balanceOf[msg.sender] >= tokens);
// 檢驗是否會發生溢出
require(balanceOf[to] + tokens >= balanceOf[to]);
// 扣除發送者賬戶余額
balanceOf[msg.sender] -= tokens;
// 增加接收者賬戶余額
balanceOf[to] += tokens;
// 觸發相應的事件
emit Transfer(msg.sender, to, tokens);
success = true;
}
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
// 檢驗地址是否合法
require(to != address(0) && from != address(0));
// 檢驗發送者賬戶余額是否足夠
require(balanceOf[from] >= tokens);
// 檢驗操作的金額是否是被允許的
require(allowed[from][msg.sender] <= tokens);
// 檢驗是否會發生溢出
require(balanceOf[to] + tokens >= balanceOf[to]);
// 扣除發送者賬戶余額
balanceOf[from] -= tokens;
// 增加接收者賬戶余額
balanceOf[to] += tokens;
// 觸發相應的事件
emit Transfer(from, to, tokens);
success = true;
}
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
// 觸發相應的事件
emit Approval(msg.sender, spender, tokens);
success = true;
}
function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
return allowed[tokenOwner][spender];
}
}
將以上代碼復制到Remix上,編譯合約代碼:
部署合約:
部署成功:
測試balanceOf方法:
測試transfer方法:
在Remix上測試完基本的方法后,我們通過MetaMask在以太坊的測試網絡上發行我們的代幣。打開MetaMask選擇Ropsten測試網絡,如下:
注:如果你沒有余額請點擊DEPOSIT按鈕,然后再點擊GET ETHER按鈕,會進入一個網站,在該網站中點擊request 1 ether from faucet,可以送一些測試網絡的以太幣給你:
然后到Remix IDE上刷新一下,此時Remix會自動選擇相應的測試網絡,注意MetaMask和Remix需要在同一個瀏覽器上,并且Environment和Account和MetaMask保持一致,如下:
點擊Deploy后,這時MetaMask會彈出一個交易確認框,點CONFIRM:
待合約部署交易確認之后,復制合約地址:
打開Metamask界面,打開菜單(Menu),點ADD TOKEN:
出現如下對話框,選擇Custom Token,然后將合約地址粘貼進去:
點ADD TOKENS:
這時在MetaMask里就可以看到我們創建的代幣了,如下:
接下來我們測試一下代幣的轉賬功能,選擇我們剛剛部署的代幣,點擊SEND:
填寫轉賬的相關信息:
確認轉賬:
成功后會生成相應的交易記錄:
如此一來我們就完成了代幣的創建和部署(正式網絡和測試網絡部署方法一樣),現在已經可以在Etherscan查詢到我們剛剛發行的代幣了:
點擊合約地址可以查看到代幣的詳情:
在上一小節中,我們已經成功在以太坊上發行了我們自己的代幣,但許多同學應該也已經產生了一個疑問,為啥明明代幣中設置了代幣的發行數量,但是發行的數量還是為0呢?其實這也是新手在開發代幣時可能會遇到的一個坑,之所以我們看到發行總量為0是因為代幣的發行總量的整數位表示并不是totalSupply的值,而是totalSupply除以10的decimals次方。
例如我們將decimals設置為8,那么就需要以代幣的發行總量(totalSupply)除以100000000,才能得到其整數。上一小節中合約代碼里設置的decimals值為18,代表代幣使用的小數位為18位,而totalSupply的值為1億,自然計算出來就是小于1的小數,而且還是比較小的小數,MetaMask只顯示3位小數,所以導致在我們看來代幣的發行總量為0。
既然知道是什么原因導致的,那么解決起來就好辦了,修改合約的構造器代幣如下:
// 初始化屬性
constructor() public {
decimals = 18;
totalSupply = 100000000 * 10 ** uint256(decimals);
name = "Test Token";
symbol = "TEST";
// 初始化該代幣的賬戶會擁有所有的代幣
balanceOf[msg.sender] = totalSupply;
}
修改完成后,依舊按照我們上一小節所描述的流程去發行代幣并將代幣添加到MetaMask錢包中。此時該代幣的發行總量就應該是我們期望的值了,如下:
我們也可以嘗試使用代幣進行轉賬:
轉賬成功,該賬戶的余額也正常扣減了:
另一個賬戶也正常收到了這100個代幣:
然后我們再去查看一下代幣詳情:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。