主页 > imtoken官网下载1.0安卓 > 以太坊众筹智能合约示例
以太坊众筹智能合约示例
2019年独角兽企业招聘Python工程师标准>>>
学习以太坊智能合约开发的最佳方式是结合具体的应用场景,如投票、众筹、代币发行等,通过实例的实现,边学边练。 在本教程中,我们将使用以太坊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语句首先判断众筹是否结束。 如果众筹结束,款项将退还给发起人,避免给发起人造成不必要的损失。
部署通过后,您可以使用自己的测试账户向合约地址转账,即可参与众筹。
众筹成功后以太坊众筹价格,如果您继续向合约地址转账,款项将返还至您的账户。