基于以太坊發(fā)布屬于自己的數(shù)字貨幣(代幣)完整版
(參考資料來源于網(wǎng)絡(luò)以及各種摸索,其中各種坑)
本文單純從技術(shù)角度詳細(xì)介紹如何基于以太坊ERC20創(chuàng)建代幣的流程(此案例是部署的eth主網(wǎng),非測試案例)
寫在前面
本文所講的代幣是使用以太坊智能合約創(chuàng)建,閱讀本文前,你應(yīng)該對以太坊、智能合約有所了解,如果你還不了解,建議你先看以太坊是什么。
代幣Token
如果不那么追求精確的定義,代幣就是數(shù)字貨幣,比特幣、以太幣就是一個代幣。
利用以太坊的智能合約可以輕松編寫出屬于自己的代幣,代幣可以代表任何可以交易的東西,如:積分、財(cái)產(chǎn)、證書等等。
因此不管是出于商業(yè),還是學(xué)習(xí)很多人想創(chuàng)建一個自己的代幣,先貼一個圖看看創(chuàng)建的代幣是什么樣子。
以我自己發(fā)布的BliBli幣 Bcoin為例
訪問地址 : ?https://etherscan.io/token/0x73c8da697fe5e145f6269c4c852e59a7328f9371
?今天我們就來詳細(xì)講一講怎樣創(chuàng)建一個這樣的代幣。
ERC20 Token
ERC20和代幣一同出現(xiàn), ERC20是以太坊定義的一個代幣標(biāo)準(zhǔn)。是一種發(fā)行代幣合約必須要遵守的協(xié)議,該協(xié)議規(guī)定了幾個參數(shù)——發(fā)行貨幣的名稱,簡稱,發(fā)行量,要支持的函數(shù)等,只有支持了該協(xié)議才會被以太坊所認(rèn)同。
erc20標(biāo)準(zhǔn)代碼如下
// https://github.com/ethereum/EIPs/issues/20
? contract ERC20 {
? ? ? function totalSupply() constant returns (uint totalSupply);
? ? ? function balanceOf(address _owner) constant returns (uint balance);
? ? ? function transfer(address _to, uint _value) returns (bool success);
? ? ? function transferFrom(address _from, address _to, uint _value) returns (bool success);
? ? ? function approve(address _spender, uint _value) returns (bool success);
? ? ? function allowance(address _owner, address _spender) constant returns (uint remaining);
? ? ? event Transfer(address indexed _from, address indexed _to, uint _value);
? ? ? event Approval(address indexed _owner, address indexed _spender, uint _value);
? ? }
totalSupply:? 代表的是代幣發(fā)行總量? ? totalSupply():該方法可以返回代幣的總數(shù)量
name:? 發(fā)行代幣的名稱? ? ? ? ? ? ? ? ? ? ? ?dicimals:? 發(fā)行代幣以后,代幣交易的最小單位
balanceOf(): 該方法返回的是輸入錢包地址后,該錢包的代幣余額
tansferFrom() :從一個地址向另一個地址發(fā)送余額
approve(): 允許_spender從你的賬戶轉(zhuǎn)出_value余額
allowance(): 允許_spender從你的賬戶轉(zhuǎn)出_value的余額,調(diào)用多次會覆蓋可用量。某些DEX功能需要此功能
event Transfer(): ?token轉(zhuǎn)移完成后出發(fā)
event Approval(): ?approve(address _spender, uint256 _value)調(diào)用后觸發(fā)
編寫代幣合約:
pragma solidity ^0.4.12;
contract IMigrationContract {
? ? function migrate(address addr, uint256 nas) returns (bool success);
}
/* 靈感來自于NAS? coin*/
contract SafeMath {
? ? function safeAdd(uint256 x, uint256 y) internal returns(uint256) {
? ? ? ? uint256 z = x + y;
? ? ? ? assert((z >= x) && (z >= y));
? ? ? ? return z;
? ? }
? ? function safeSubtract(uint256 x, uint256 y) internal returns(uint256) {
? ? ? ? assert(x >= y);
? ? ? ? uint256 z = x - y;
? ? ? ? return z;
? ? }
? ? function safeMult(uint256 x, uint256 y) internal returns(uint256) {
? ? ? ? uint256 z = x * y;
? ? ? ? assert((x == 0)||(z/x == y));
? ? ? ? return z;
? ? }
}
contract Token {
? ? uint256 public totalSupply;
? ? function balanceOf(address _owner) constant returns (uint256 balance);
? ? function transfer(address _to, uint256 _value) returns (bool success);
? ? function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
? ? function approve(address _spender, uint256 _value) returns (bool success);
? ? function allowance(address _owner, address _spender) constant returns (uint256 remaining);
? ? event Transfer(address indexed _from, address indexed _to, uint256 _value);
? ? event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
/*? ERC 20 token */
contract StandardToken is Token {
? ? function transfer(address _to, uint256 _value) returns (bool success) {
? ? ? ? if (balances[msg.sender] >= _value && _value > 0) {
? ? ? ? ? ? balances[msg.sender] -= _value;
? ? ? ? ? ? balances[_to] += _value;
? ? ? ? ? ? Transfer(msg.sender, _to, _value);
? ? ? ? ? ? return true;
? ? ? ? } else {
? ? ? ? ? ? return false;
? ? ? ? }
? ? }
? ? function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
? ? ? ? if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
? ? ? ? ? ? balances[_to] += _value;
? ? ? ? ? ? balances[_from] -= _value;
? ? ? ? ? ? allowed[_from][msg.sender] -= _value;
? ? ? ? ? ? Transfer(_from, _to, _value);
? ? ? ? ? ? return true;
? ? ? ? } else {
? ? ? ? ? ? return false;
? ? ? ? }
? ? }
? ? function balanceOf(address _owner) constant returns (uint256 balance) {
? ? ? ? return balances[_owner];
? ? }
? ? function approve(address _spender, uint256 _value) returns (bool success) {
? ? ? ? allowed[msg.sender][_spender] = _value;
? ? ? ? Approval(msg.sender, _spender, _value);
? ? ? ? return true;
? ? }
? ? function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
? ? ? ? return allowed[_owner][_spender];
? ? }
? ? mapping (address => uint256) balances;
? ? mapping (address => mapping (address => uint256)) allowed;
}
contract BliBliToken is StandardToken, SafeMath {
? ? // metadata
? ? string? public constant name = "BliBli";
? ? string? public constant symbol = "BCoin";
? ? uint256 public constant decimals = 18;
? ? string? public version = "1.0";
? ? // contracts
? ? address public ethFundDeposit;? ? ? ? ? // ETH存放地址
? ? address public newContractAddr;? ? ? ? // token更新地址
? ? // crowdsale parameters
? ? bool? ? public isFunding;? ? ? ? ? ? ? ? // 狀態(tài)切換到true
? ? uint256 public fundingStartBlock;
? ? uint256 public fundingStopBlock;
? ? uint256 public currentSupply;? ? ? ? ? // 正在售賣中的tokens數(shù)量
? ? uint256 public tokenRaised = 0;? ? ? ? // 總的售賣數(shù)量token
? ? uint256 public tokenMigrated = 0;? ? // 總的已經(jīng)交易的 token
? ? uint256 public tokenExchangeRate = 625;? ? ? ? ? ? // 625 BILIBILI 兌換 1 ETH
? ? // events
? ? event AllocateToken(address indexed _to, uint256 _value);? // 分配的私有交易token;
? ? event IssueToken(address indexed _to, uint256 _value);? ? ? // 公開發(fā)行售賣的token;
? ? event IncreaseSupply(uint256 _value);
? ? event DecreaseSupply(uint256 _value);
? ? event Migrate(address indexed _to, uint256 _value);
? ? // 轉(zhuǎn)換
? ? function formatDecimals(uint256 _value) internal returns (uint256 ) {
? ? ? ? return _value * 10 ** decimals;
? ? }
? ? // constructor
? ? function BliBliToken(
? ? ? ? address _ethFundDeposit,
? ? ? ? uint256 _currentSupply)
? ? {
? ? ? ? ethFundDeposit = _ethFundDeposit;
? ? ? ? isFunding = false;? ? ? ? ? ? ? ? ? ? ? ? ? //通過控制預(yù)CrowdS ale狀態(tài)
? ? ? ? fundingStartBlock = 0;
? ? ? ? fundingStopBlock = 0;
? ? ? ? currentSupply = formatDecimals(_currentSupply);
? ? ? ? totalSupply = formatDecimals(10000000);
? ? ? ? balances[msg.sender] = totalSupply;
? ? ? ? if(currentSupply > totalSupply) throw;
? ? }
? ? modifier isOwner()? { require(msg.sender == ethFundDeposit); _; }
? ? ///? 設(shè)置token匯率
? ? function setTokenExchangeRate(uint256 _tokenExchangeRate) isOwner external {
? ? ? ? if (_tokenExchangeRate == 0) throw;
? ? ? ? if (_tokenExchangeRate == tokenExchangeRate) throw;
? ? ? ? tokenExchangeRate = _tokenExchangeRate;
? ? }
? ? /// @dev 超發(fā)token處理
? ? function increaseSupply (uint256 _value) isOwner external {
? ? ? ? uint256 value = formatDecimals(_value);
? ? ? ? if (value + currentSupply > totalSupply) throw;
? ? ? ? currentSupply = safeAdd(currentSupply, value);
? ? ? ? IncreaseSupply(value);
? ? }
? ? /// @dev 被盜token處理
? ? function decreaseSupply (uint256 _value) isOwner external {
? ? ? ? uint256 value = formatDecimals(_value);
? ? ? ? if (value + tokenRaised > currentSupply) throw;
? ? ? ? currentSupply = safeSubtract(currentSupply, value);
? ? ? ? DecreaseSupply(value);
? ? }
? ? ///? 啟動區(qū)塊檢測 異常的處理
? ? function startFunding (uint256 _fundingStartBlock, uint256 _fundingStopBlock) isOwner external {
? ? ? ? if (isFunding) throw;
? ? ? ? if (_fundingStartBlock >= _fundingStopBlock) throw;
? ? ? ? if (block.number >= _fundingStartBlock) throw;
? ? ? ? fundingStartBlock = _fundingStartBlock;
? ? ? ? fundingStopBlock = _fundingStopBlock;
? ? ? ? isFunding = true;
? ? }
? ? ///? 關(guān)閉區(qū)塊異常處理
? ? function stopFunding() isOwner external {
? ? ? ? if (!isFunding) throw;
? ? ? ? isFunding = false;
? ? }
? ? /// 開發(fā)了一個新的合同來接收token(或者更新token)
? ? function setMigrateContract(address _newContractAddr) isOwner external {
? ? ? ? if (_newContractAddr == newContractAddr) throw;
? ? ? ? newContractAddr = _newContractAddr;
? ? }
? ? /// 設(shè)置新的所有者地址
? ? function changeOwner(address _newFundDeposit) isOwner() external {
? ? ? ? if (_newFundDeposit == address(0x0)) throw;
? ? ? ? ethFundDeposit = _newFundDeposit;
? ? }
? ? ///轉(zhuǎn)移token到新的合約
? ? function migrate() external {
? ? ? ? if(isFunding) throw;
? ? ? ? if(newContractAddr == address(0x0)) throw;
? ? ? ? uint256 tokens = balances[msg.sender];
? ? ? ? if (tokens == 0) throw;
? ? ? ? balances[msg.sender] = 0;
? ? ? ? tokenMigrated = safeAdd(tokenMigrated, tokens);
? ? ? ? IMigrationContract newContract = IMigrationContract(newContractAddr);
? ? ? ? if (!newContract.migrate(msg.sender, tokens)) throw;
? ? ? ? Migrate(msg.sender, tokens);? ? ? ? ? ? ? // log it
? ? }
? ? /// 轉(zhuǎn)賬ETH 到BILIBILI團(tuán)隊(duì)
? ? function transferETH() isOwner external {
? ? ? ? if (this.balance == 0) throw;
? ? ? ? if (!ethFundDeposit.send(this.balance)) throw;
? ? }
? ? ///? 將BILIBILI token分配到預(yù)處理地址。
? ? function allocateToken (address _addr, uint256 _eth) isOwner external {
? ? ? ? if (_eth == 0) throw;
? ? ? ? if (_addr == address(0x0)) throw;
? ? ? ? uint256 tokens = safeMult(formatDecimals(_eth), tokenExchangeRate);
? ? ? ? if (tokens + tokenRaised > currentSupply) throw;
? ? ? ? tokenRaised = safeAdd(tokenRaised, tokens);
? ? ? ? balances[_addr] += tokens;
? ? ? ? AllocateToken(_addr, tokens);? // 記錄token日志
? ? }
? ? /// 購買token
? ? function () payable {
? ? ? ? if (!isFunding) throw;
? ? ? ? if (msg.value == 0) throw;
? ? ? ? if (block.number < fundingStartBlock) throw;
? ? ? ? if (block.number > fundingStopBlock) throw;
? ? ? ? uint256 tokens = safeMult(msg.value, tokenExchangeRate);
? ? ? ? if (tokens + tokenRaised > currentSupply) throw;
? ? ? ? tokenRaised = safeAdd(tokenRaised, tokens);
? ? ? ? balances[msg.sender] += tokens;
? ? ? ? IssueToken(msg.sender, tokens);? //記錄日志
? ? }
}
以上的代幣合約,是參考以太坊已經(jīng)ICO過,并且產(chǎn)生價值的代幣合約參考而來,完整比且功能強(qiáng)大,此合約創(chuàng)建的代幣,具有“交易”,“轉(zhuǎn)賬”,“異常檢測”,“更改代幣持有人”,“設(shè)置匯率”,“被盜處理”,“超發(fā)代幣”等功能。
(解釋下:在以太坊的世界中,硬通貨就是ETH-以太幣,相當(dāng)于現(xiàn)實(shí)世界中的黃金,我們發(fā)布的代幣,就相當(dāng)于各國發(fā)行的需要 與黃金掛鉤兌換比率的貨幣,國家對貨幣擁有控制權(quán),只要合約功能進(jìn)行擴(kuò)展,創(chuàng)造代幣的人也會對代幣擁有控制權(quán)。)
(對于挖礦的誤解:不少小哥哥小姐姐認(rèn)為挖礦就是挖幣,其實(shí)挖礦是挖區(qū)塊,區(qū)塊是干嘛的,是用來打包交易的,是存儲數(shù)據(jù)的,代幣是不用挖的,當(dāng)你挖到了區(qū)塊,代幣是給你的獎勵,在發(fā)行量一定的情況下,代幣會越來越少,所以挖到區(qū)塊的獎勵會變少。那獎勵少了為什么還要挖礦呢,因?yàn)槟愕娜魏我还P交易都需要記錄,一個區(qū)塊的大小也就幾M,存儲不了那么多交易信息,所以要持續(xù)挖區(qū)塊來記錄你的交易,同時交易的手續(xù)費(fèi),會獎勵給挖出區(qū)塊的人。)
部署合約:
部署合約有多種方式? ? ? 1 geth 編譯代碼 ---部署合約
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2 用ethereum wallet錢包部署合約
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3 最簡單直觀的部署合約方式:??MetaMask和Remix Solidity IDE?部署合約
? ?我們按照?MetaMask和Remix Solidity IDE?來進(jìn)行部署合約。
?1:?創(chuàng)建錢包帳號。MetaMask是錢包的一種,在chrome瀏覽器中,安裝MetaMask插件即可,安裝完成后,右上角會出現(xiàn)一個“狐貍頭”的標(biāo)志,點(diǎn)擊該標(biāo)志,打開錢包,第一步,創(chuàng)建賬戶,(創(chuàng)建賬戶只需要輸入面密碼即可,名稱創(chuàng)建后可以隨便改,該賬戶就是一個hash值,如何給自己創(chuàng)建的賬戶沖以太幣,可以上https://otcbtc.com/sign_up網(wǎng)站,按照操作買以太幣,然后轉(zhuǎn)賬到自己創(chuàng)建的賬戶)創(chuàng)建成功后,記住密碼還有產(chǎn)生的幾個隨機(jī)單詞(一定要記錄下來)。如下:
???2:打開?Remix Solidity IDE?訪問地址:?http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.21+commit.dfe3193c.js? ?界面如下?
3:? 拷貝“編寫代幣合約”后邊的代碼到Remix Solidity IDE中按照如下編譯
4: create 發(fā)布? 如下
5 create后,產(chǎn)生hash值,拷貝hash值,在錢包中添加token
OK,如上所示,第一個屬于你的真正意義上的去中心化數(shù)字貨幣就誕生了。正式網(wǎng)絡(luò)和測試網(wǎng)絡(luò)部署方法一樣,不需要買eth就是了。
如果是測試網(wǎng)絡(luò),如何獲得ETH?? ?進(jìn)入 https://gitter.im/kovan-testnet/faucet? 下方直接發(fā)送你的賬戶地址(hash值)即可,一般五分鐘到賬,會得到五個測試網(wǎng)絡(luò)用的ETH幣。
6(如果部署的是eth主網(wǎng),非測試網(wǎng),執(zhí)行該步驟,測試網(wǎng)絡(luò)可以不理會)
發(fā)布了代幣以后,如果以后進(jìn)行ico,那么需要發(fā)布源碼公開。步驟如下
? ?①? 拷貝部署成功的合約地址(hash),到? https://etherscan.io/? ?右上角搜索hash
? ?②? 按照如下圖進(jìn)行verify AND publish
? ? ? ? ? ?打開如下頁面第一步
? ? ? ? ?打開如下頁面第二部
? ? ? ? ? 打開如下頁面第三部
? ok? 現(xiàn)在的代幣就比較完整了,差ico了
代幣轉(zhuǎn)賬:
? ?1? metamask錢包轉(zhuǎn)賬:? 如下
? ?輸入地址和代幣數(shù)量
2? 網(wǎng)頁錢包轉(zhuǎn)賬:? 如下??https://www.myetherwallet.com/#send-transaction
? ? 登錄賬戶:
? 轉(zhuǎn)賬交易
---------------------
作者:JAVA_HHHH
來源:CSDN
原文:https://blog.csdn.net/JAVA_HHHH/article/details/79771752
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!