博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
众筹智能合约实现代码
阅读量:7071 次
发布时间:2019-06-28

本文共 4507 字,大约阅读时间需要 15 分钟。

hot3.png

实现一个好的idea常常需要付出巨大的努力,并且需要大量的资金。我们可以寻求用户捐赠,或者寻求投资机构投资,但这往往很难。 区块链提供了一种众筹的新形式——众筹。募资人通过众筹合约设定好众筹目标,以及完成时间,设定不同众筹结果所对应的操作(例如目标失败退回全款、目标成功时受益人获得加密代币或ETH)。由于区块链不可篡改的特性,众筹合约会是一个非常吻合的应用场景。在本文中,我们将使用以太坊solidity来实现一个用于众筹的智能合约,并给出最终实现的solidity全部代码。

代币和分布自治组织

这个例子中我们将通过解决两个重要的问题进行更好的众筹:

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

区块链出现之前的众筹项目一般缺少流动性,投资人一旦错过众筹截止时间将无法参与众筹;一旦参与众筹,投资人也不能中途退出。智能合约通过发行代币的形式来记录投资额,并提供了类似股票市场的流动性。投资人可以选择交易或者继续持有。项目成功后投资者可以使用代币交换实物或者产品服务。项目失败的话投资者可以按照原先的约定退出,并且继续持有代币以表纪念。

同样,当前众筹项目也存在资金去向不明的问题。在这个项目中,我们使用DAO(分布式自治组织)记录每一笔资金去向。

合约代码

先放上代码,然后再一步步解读。

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的定义在代码开头: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语句先判断众筹是否结束,如果众筹已经结束,钱将退回给主叫方,避免主叫方出现不必要的损失。

部署通过之后可以用自己的测试账户向合约地址转账,这样就可以参与众筹了。

众筹成功后,如果继续往合约地址转账,钱将会退回你的账户。

转载于:https://my.oschina.net/u/3790537/blog/1808769

你可能感兴趣的文章
333333333333333333
查看>>
我的友情链接
查看>>
oracle 知识点
查看>>
我的友情链接
查看>>
使用摩客原型托管,3分钟搞定原型发布分享预览
查看>>
VMware8.0安装RedHat Enterprise Linux 6(图文完整安装版)
查看>>
Linux中变量$#,$@,$0,$1,$2,$*,$$,$?的含义
查看>>
如何通过配置来实现IP+MAC+端口绑定功能
查看>>
FileMaker批量生成Word文档,带进度条
查看>>
Install OpenCV 2.4.9 in Ubuntu 14.04, 13.10
查看>>
python的简单入门
查看>>
AndroidStudio——手动打包
查看>>
从Insider计划看Win10的发展
查看>>
关于OSPF协议
查看>>
基于lvs的持久性连接
查看>>
Highly Available L7 Load Balancing for Exchange 2013 with HAProxy – Par
查看>>
linux 如何查看电脑硬件信息
查看>>
Ciscodk——MB2-700变题了
查看>>
Linux手动启动、停止多个服务用的shell脚本
查看>>
centos下MySQL主从服务器设置
查看>>