以太坊應用系列文章:bash
- 在以太坊上發行本身的代幣;
- 以太坊代幣進階;
- 以太坊上建立衆籌合約(本篇);
- 以太坊上創建去中心自動化組織(DAO);
- 以太坊去中心自動化組織(DAO)進階;
實現一個好的idea經常須要付出巨大的努力,而且須要大量的資金。咱們能夠尋求用戶捐贈,或者尋求投資機構投資,但這每每很難。對於捐贈,國內的風氣不太好,資金去向每每不了了之,捐贈者對於當前的捐贈形式早已失去了信心。而風險投資,對於沒有人脈的創業者來講,很是困難。 區塊鏈提供了一種衆籌的新形式——衆籌智能合約。募資人經過衆籌合約設定好衆籌目標,以及完成時間,設定不一樣衆籌結果所對應的操做(例如目標失敗退回全款、目標成功時受益人得到加密代幣或ETH)。因爲區塊鏈不可篡改的特性,衆籌合約會是一個很是吻合的應用場景。微信
這個例子中咱們將經過解決兩個重要的問題進行更好的衆籌:網絡
- 如何管理資金,保證流動性;
- 籌集資金後如何花錢。
區塊鏈出現以前的衆籌項目通常缺乏流動性,投資人一旦錯過衆籌截止時間將沒法參與衆籌;一旦參與衆籌,投資人也不能中途退出。智能合約經過發行代幣的形式來記錄投資額,並提供了相似股票市場的流動性。投資人能夠選擇交易或者繼續持有。項目成功後投資者可使用代幣交換實物或者產品服務。項目失敗的話投資者能夠按照原先的約定退出,而且繼續持有代幣以表記念。app
一樣,當前衆籌項目也存在資金去向不明的問題。在這個項目中,咱們使用DAO(分佈式自治組織)記錄每一筆資金去向。分佈式
先放上代碼,而後再一步步解讀。ide
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 public tokenReward;
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);
/**
* Constrctor function
*
* Setup the owner
*/
function Crowdsale(
address ifSuccessfulSendTo,
uint fundingGoalInEthers,
uint durationInMinutes,
uint etherCostOfEachToken,
address addressOfTokenUsedAsReward
) {
beneficiary = ifSuccessfulSendTo;
fundingGoal = fundingGoalInEthers * 1 ether;
deadline = now + durationInMinutes * 1 minutes;
price = etherCostOfEachToken * 1 ether;
tokenReward = token(addressOfTokenUsedAsReward);
}
/**
* Fallback function
*
* The function without name is the default function that is called whenever anyone sends funds to a contract
*/
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 afterDeadline() {
if (now >= deadline) _;
}
/**
* Check if goal was reached
*
* Checks if the goal or time limit has been reached and ends the campaign
*/
function checkGoalReached() afterDeadline {
if (amountRaised >= fundingGoal){
fundingGoalReached = true;
GoalReached(beneficiary, amountRaised);
}
crowdsaleClosed = true;
}
/**
* Withdraw the funds
*
* Checks to see if goal or time limit has been reached, and if so, and the funding goal was reached,
* sends the entire amount to the beneficiary. If goal was not reached, each contributor can withdraw
* the amount they contributed.
*/
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;
}
}
}
}
複製代碼
構造函數中函數
fundingGoal = fundingGoalInEthers * 1 ether;
deadline = now + durationInMinutes * 1 minutes;
複製代碼
ether和minutes是以太坊預留的關鍵字,1 ether == 1000 finney , 2 days == 48 hours。日期類型的關鍵字有seconds,minutes,hours, days,weeks,years,以太幣單位預留的關鍵字有wei,finney,szabo,ether。1 finney == 1000 szabo,1 szabo == 10^12 wei。now也是以太坊預留的關鍵字,表明當前時間。區塊鏈
接下來咱們實例化了一個合約:測試
tokenReward = token(addressOfTokenUsedAsReward);
複製代碼
token的定義在代碼開頭:ui
interface token {
function transfer(address receiver, uint amount){ }
}
複製代碼
這裏咱們並未實現token合約,只是告訴編譯器咱們的token是一個合約,具備一個transfer()函數,而且在給定的地址上有這個合約。
接下來咱們看看合約如何接收資金,相關代碼以下:
function () {
require(!crowdsaleClosed);
uint amount = msg.value;
// ...
複製代碼
這個函數很特別,它沒有名字,在solidity中咱們稱之爲回退函數(Fallback function),回退函數沒有參數,也沒有返回值。若是合約接收ether,則必須明肯定義回退函數,不然會觸發異常,並返回ether。接收ether的函數必須帶有關鍵字payable,不然會報錯。
require語句先判斷衆籌是否結束,若是衆籌已經結束,錢將退回給主叫方,避免主叫方出現沒必要要的損失。
部署合約 以下圖:
設置gas,點擊deploy便可提交部署。部署經過以後能夠用本身的測試帳戶向合約地址轉帳,這樣就能夠參與衆籌了。
衆籌成功後,若是繼續往合約地址轉帳,錢將會退回你的帳戶。
個人公衆號賢庭漫步: