如何通過以太坊智能合約來進行眾籌(ICO)

前面我們有兩遍文章寫了如何發行代幣,今天我們講一下如何使用代幣來公開募資,即編寫一個募資合約。

寫在前面

本文所講的代幣是使用以太坊智能合約創建,閱讀本文前,你應該對以太坊、智能合約有所了解,如果你還不了解,建議你先看以太坊是什麼

眾籌

先簡單說下眾籌的概念:一般是這樣的,我一個非常好的想法,但是我沒有錢來做這事,於是我把這個想法發給大家看,說:我做這件事需要5百萬,大家有沒有興趣投些錢,如果大家在30天內投夠了5百萬我就開始做,到時大家都是原始股東,如果募資額不到5百萬,大家投的錢就還給大家。

現在ICO眾籌已經被各路大佬拿來割韭菜而被玩壞了(不管有無達標,都把錢捲走)。

其實區塊鏈技術本事非常適合解決眾籌的信任問題,藉助於智能合約,可以實現當募資額完成時,募資款自動打到指定賬戶,當募資額未完成時,可退款。這個過程不需要看眾籌大佬的人品,不用依靠第三方平台信用擔保。

代幣

傳統的眾籌在參與之後通常不容易交易(參與之後無法轉給其他人),而通過用代幣來參與眾籌,則很容易進行交易,眾籌的參與人可隨時進行買賣,待眾籌項目實施完成的時候,完全根據代幣持有量進行回饋。

舉個例子說明下,大家會更容易理解,有這一個眾籌:A有技術做一個能監測健康的指環,為此向公眾募資200百萬,募資時100塊對應一個代幣,約定在指環上市之後,代幣的持有人可以用一個代幣來兌換一個指環。而指環的研發周期是一年,因此在指環還未上市的一年裡,眾籌的參與人可以隨時交易所持有的代幣。

眾籌智能合約代碼

接下來就看看如何實現一個眾籌智能合約。

pragma solidity ^0.4.16;interface token { function transfer(address receiver, uint amount);}contract Crowdsale { address public beneficiary; // 募資成功後的收款方 uint public fundingGoal; // 募資額度 uint public amountRaised; // 參與數量 uint public deadline; // 募資截止期 uint public price; // token 與以太坊的匯率 , token賣多少錢 token public tokenReward; // 要賣的token mapping(address => uint256) public balanceOf; bool fundingGoalReached = false; // 眾籌是否達到目標 bool crowdsaleClosed = false; // 眾籌是否結束 /** * 事件可以用來跟蹤信息 **/ event GoalReached(address recipient, uint totalAmountRaised); event FundTransfer(address backer, uint amount, bool isContribution); /** * 構造函數, 設置相關屬性 */ function Crowdsale( address ifSuccessfulSendTo, uint fundingGoalInEthers, uint durationInMinutes, uint finneyCostOfEachToken, address addressOfTokenUsedAsReward) { beneficiary = ifSuccessfulSendTo; fundingGoal = fundingGoalInEthers * 1 ether; deadline = now + durationInMinutes * 1 minutes; price = finneyCostOfEachToken * 1 finney; tokenReward = token(addressOfTokenUsedAsReward); // 傳入已發布的 token 合約的地址來創建實例 } /** * 無函數名的Fallback函數, * 在向合約轉賬時,這個函數會被調用 */ function () payable { require(!crowdsaleClosed); uint amount = msg.value; balanceOf[msg.sender] += amount; amountRaised += amount; tokenReward.transfer(msg.sender, amount / price); FundTransfer(msg.sender, amount, true); } /** * 定義函數修改器modifier(作用和Python的裝飾器很相似) * 用於在函數執行前檢查某種前置條件(判斷通過之後才會繼續執行該方法) * _ 表示繼續執行之後的代碼 **/ modifier afterDeadline() { if (now >= deadline) _; } /** * 判斷眾籌是否完成融資目標, 這個方法使用了afterDeadline函數修改器 * */ function checkGoalReached() afterDeadline { if (amountRaised >= fundingGoal) { fundingGoalReached = true; GoalReached(beneficiary, amountRaised); } crowdsaleClosed = true; } /** * 完成融資目標時,融資款發送到收款方 * 未完成融資目標時,執行退款 * */ function safeWithdrawal() afterDeadline { if (!fundingGoalReached) { uint amount = balanceOf[msg.sender]; balanceOf[msg.sender] = 0; if (amount > 0) { if (msg.sender.send(amount)) { FundTransfer(msg.sender, amount, false); } else { balanceOf[msg.sender] = amount; } } } if (fundingGoalReached && beneficiary == msg.sender) { if (beneficiary.send(amountRaised)) { FundTransfer(beneficiary, amountRaised, false); } else { //If we fail to send the funds to beneficiary, unlock funders balance fundingGoalReached = false; } } }}

部署及說明

在部署這個合約之前,我們需要先部署一個代幣合約,請參考一步步教你創建自己的數字貨幣。

  1. 創建眾籌合約我們需要提供一下幾個參數:

    ifSuccessfulSendTo: 募資成功後的收款方(其實這裡可以默認為合約創建者)

    fundingGoalInEthers: 募資額度, 為了方便我們僅募3個ether

    durationInMinutes: 募資時間

    finneyCostOfEachToken 每個代幣的價格, 這裡為了方便使用了單位finney及值為:1 (1 ether = 1000 finney)

    addressOfTokenUsedAsReward: 代幣合約地址。

    如:

本文使用的參數為:

1

  1. 參與人投資的時候實際購買眾籌合約代幣,所有需要先向合約預存代幣,代幣的數量為:募資額度 / 代幣的價格 , 這裡為:3 * 1000/1 = 3000 (當能也可以大於3000)。

    向合約預存代幣可以使用myetherwallet錢包,或在remix中重新載入代幣合約,執行代幣合約tranfer()函數進行代幣轉賬。如使用myetherwallet轉賬如圖:

  1. 參與人投資行為即是向買眾籌合約轉賬,轉賬時,會執行Fallback回退函數(即無名函數)向其賬戶打回相應的代幣。
  2. safeWithdrawl() 可以被參與人或收益人執行,如果融資不達標參與人可收回之前投資款,如果融資達標收益人可以拿到所有的融資款。

擴展

上面是一個很正規的募資合約。接下來講兩個募資合約的擴展,如何實現無限募資合約及割韭菜合約。

這部分內容獨家發布在我的小專欄區塊鏈技術

如果你在學習中遇到問題,歡迎到我的知識星球提問,作為星球成員福利,成員可加入區塊鏈技術付費交流群。

參考文檔

  • Create a crowdsale

深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術博客。


推薦閱讀:

TAG:首次代幣發行ICO | 智能合約 |