NO IMAGE

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

寫在前面

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

眾籌

先簡單說下眾籌的概念:一般是這樣的,我一個非常好的想法,但是我沒有錢來做這事,於是我把這個想法發給大家看,說:我做這件事需要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: 代幣合約地址。
    如:

    本文使用的引數為:
"0xc6f9ea59d424733e8e1902c7837ea75e20abfb49",3, 100, 1,"0xad8972e2b583f580fc52f737b98327eb65d08f8c"
  1. 參與人投資的時候實際購買眾籌合約代幣,所有需要先向合約預存代幣,代幣的數量為:募資額度 / 代幣的價格 , 這裡為:3 * 1000/1 = 3000 (當能也可以大於3000)。
    向合約預存代幣可以使用myetherwallet錢包,或在remix中重新載入代幣合約,執行代幣合約tranfer()函式進行代幣轉賬。如使用myetherwallet轉賬如圖:

  2. 參與人投資行為即是向買眾籌合約轉賬,轉賬時,會執行Fallback回退函式(即無名函式)向其賬戶打回相應的代幣。

  3. safeWithdrawl() 可以被參與人或收益人執行,如果融資不達標參與人可收回之前投資款,如果融資達標收益人可以拿到所有的融資款。

擴充套件

上面是一個很正規的募資合約。接下來講兩個募資合約的擴充套件,如何實現無限募資合約及割韭菜合約。
這部分內容獨家釋出在我的小專欄區塊鏈技術

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

參考文件

深入淺出區塊鏈 – 系統學習區塊鏈,打造最好的區塊鏈技術部落格。