以太坊上建立众筹合约

以太坊应用系列文章:bash

  1. 在以太坊上发行本身的代币
  2. 以太坊代币进阶
  3. 以太坊上建立众筹合约(本篇)
  4. 以太坊上创建去中心自动化组织(DAO);
  5. 以太坊去中心自动化组织(DAO)进阶;

实现一个好的idea经常须要付出巨大的努力,而且须要大量的资金。咱们能够寻求用户捐赠,或者寻求投资机构投资,但这每每很难。对于捐赠,国内的风气不太好,资金去向每每不了了之,捐赠者对于当前的捐赠形式早已失去了信心。而风险投资,对于没有人脉的创业者来讲,很是困难。 区块链提供了一种众筹的新形式——众筹智能合约。募资人经过众筹合约设定好众筹目标,以及完成时间,设定不一样众筹结果所对应的操做(例如目标失败退回全款、目标成功时受益人得到加密代币或ETH)。因为区块链不可篡改的特性,众筹合约会是一个很是吻合的应用场景。微信

代币和分布自治组织

这个例子中咱们将经过解决两个重要的问题进行更好的众筹:网络

  1. 如何管理资金,保证流动性;
  2. 筹集资金后如何花钱。

区块链出现以前的众筹项目通常缺乏流动性,投资人一旦错过众筹截止时间将没法参与众筹;一旦参与众筹,投资人也不能中途退出。智能合约经过发行代币的形式来记录投资额,并提供了相似股票市场的流动性。投资人能够选择交易或者继续持有。项目成功后投资者可使用代币交换实物或者产品服务。项目失败的话投资者能够按照原先的约定退出,而且继续持有代币以表记念。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语句先判断众筹是否结束,若是众筹已经结束,钱将退回给主叫方,避免主叫方出现没必要要的损失。

部署合约 以下图:

  • 在第一个编辑框(if successful,send to)填入你的帐户地址;
  • 众筹目标设置为250个以太币;
  • 若是只是用于测试,结束时间可设置为3到5分钟,若是部署在正式网络,则按本身须要的时间填写;
  • 代币价格能够设置为5;
  • token reward address填入咱们建立的地址;

设置gas,点击deploy便可提交部署。部署经过以后能够用本身的测试帐户向合约地址转帐,这样就能够参与众筹了。

众筹成功后,若是继续往合约地址转帐,钱将会退回你的帐户。

个人公众号贤庭漫步:

或者直接添加我微信:

相关文章
相关标签/搜索