主页 > imtoken官网下载1.0安卓 > 以太坊众筹智能合约示例

以太坊众筹智能合约示例

imtoken官网下载1.0安卓 2023-12-19 05:09:32

2019年独角兽企业招聘Python工程师标准>>>

hot3.png

学习以太坊智能合约开发的最佳方式是结合具体的应用场景,如投票、众筹、代币发行等,通过实例的实现,边学边练。 在本教程中,我们将使用以太坊solidity实现众筹智能合约,并给出最终solidity实现的全部代码。

如果你想马上开始学习以太坊DApp开发,可以访问汇智网提供的优秀在线互动教程:

实现一个好主意通常需要大量的努力和大量的金钱。 我们可以向用户寻求捐赠,或者向机构投资者寻求投资,但这往往很难。 关于捐款,国内的气氛不是很好,资金的去向往往悬而未决。 捐赠者早已对目前的捐赠形式失去信心。 对于没有人脉的创业者来说,风险投资是非常困难的。 区块链提供了一种新的众筹形式——众筹智能合约。 筹款人通过众筹合约设定众筹目标和完成时间,并设定不同众筹结果对应的操作(如目标失败则全额返还,目标成功则受益人收到加密代币或ETH)。 由于区块链不可篡改的特性,众筹合约将是一个非常合适的应用场景。

代币和 DAO

在这个例子中,我们将解决两个重要的问题以更好地进行众筹:

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

同样以太坊众筹价格,目前的众筹项目也存在资金去向不明的问题。 在这个项目中,我们使用DAO(Distributed Autonomous Organization)来记录每一笔资金的去向。

合约代码

先放代码,再一步步解读。

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。 日期类型的关键字有秒、分、时、日、周、年,以太单位保留的关键字有wei、finney、szabo、ether。 1 芬尼 == 1000 szabo,1 szabo == 10^12 wei。 now也是以太坊保留的关键字,代表当前时间。

接下来我们实例化一个合约:

tokenReward = token(addressOfTokenUsedAsReward);
token的定义在代码开头:
interface token { 
    function transfer(address receiver, uint amount){  }
}

这里我们没有实现代币合约,我们只是告诉编译器我们的代币是一个合约,有一个 transfer() 函数,并且在给定的地址有这个合约。

接下来我们看看合约是如何接收资金的。 相关代码如下:

function () {    
    require(!crowdsaleClosed);
    uint amount = msg.value;
    // ...

这个功能很特别。 它没有名字。 在 solidity 中,我们称其为回退函数。 回退函数没有参数,也没有返回值。 如果合约接收到以太币,则必须显式定义回退函数,否则将引发异常并返回以太币。 接收ether的函数必须有payable关键字,否则会报错。

require语句首先判断众筹是否结束。 如果众筹结束,款项将退还给发起人,避免给发起人造成不必要的损失。

部署通过后,您可以使用自己的测试账户向合约地址转账,即可参与众筹。

众筹成功后以太坊众筹价格,如果您继续向合约地址转账,款项将返还至您的账户。