前面我们有两遍文章写了如何发行代币, 今天我们讲一下如何使用代币来公开募资, 即编写一个募资合约
写在前面
本文所讲的代币是使用以太坊智能合约创建, 阅读本文前, 你应该对以太坊智能合约有所了解, 如果你还不了解, 建议你先看以太坊是什么
众筹
先简单说下众筹的概念: 一般是这样的, 我一个非常好的想法, 但是我没有钱来做这事, 于是我把这个想法发给大家看, 说: 我做这件事需要 5 百万, 大家有没有兴趣投些钱, 如果大家在 30 天内投够了 5 百万我就开始做, 到时大家都是原始股东, 如果募资额不到 5 百万, 大家投的钱就还给大家
现在 ICO 众筹已经被各路大佬拿来割韭菜而被玩坏了(不管有无达标, 都把钱卷走)
其实区块链技术本事非常适合解决众筹的信任问题, 借助于智能合约, 可以实现当募资额完成时, 募资款自动打到指定账户, 当募资额未完成时, 可退款这个过程不需要看众筹大佬的人品, 不用依靠第三方平台信用担保
代币
传统的众筹在参与之后通常不容易交易(参与之后无法转给其他人), 而通过用代币来参与众筹, 则很容易进行交易, 众筹的参与人可随时进行买卖, 待众筹项目实施完成的时候, 完全根据代币持有量进行回馈
举个例子说明下, 大家会更容易理解, 有这一个众筹: A 有技术做一个能监测健康的指环, 为此向公众募资 200 百万, 募资时 100 块对应一个代币, 约定在指环上市之后, 代币的持有人可以用一个代币来兑换一个指环而指环的研发周期是一年, 因此在指环还未上市的一年里, 众筹的参与人可以随时交易所持有的代币
众筹智能合约代码
接下来就看看如何实现一个众筹智能合约
- 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 与以太坊的汇率 , token 卖多少钱
- token public tokenReward; // 要卖的 token
- 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);
- /**
- * 构造函数, 设置相关属性
- */
- function Crowdsale(
- address ifSuccessfulSendTo,
- uint fundingGoalInEthers,
- uint durationInMinutes,
- uint finneyCostOfEachToken,
- address addressOfTokenUsedAsReward) {
- beneficiary = ifSuccessfulSendTo;
- fundingGoal = fundingGoalInEthers * 1 ether;
- deadline = now + durationInMinutes * 1 minutes;
- price = finneyCostOfEachToken * 1 finney;
- tokenReward = token(addressOfTokenUsedAsReward); // 传入已发布的 token 合约的地址来创建实例
- }
- /**
- * 无函数名的 Fallback 函数,
- * 在向合约转账时, 这个函数会被调用
- */
- 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(作用和 Python 的装饰器很相似)
- * 用于在函数执行前检查某种前置条件(判断通过之后才会继续执行该方法)
- * _ 表示继续执行之后的代码
- **/
- modifier afterDeadline() { if (now >= deadline) _; }
- /**
- * 判断众筹是否完成融资目标, 这个方法使用了 afterDeadline 函数修改器
- *
- */
- function checkGoalReached() afterDeadline {
- if (amountRaised >= fundingGoal) {
- fundingGoalReached = true;
- GoalReached(beneficiary, amountRaised);
- }
- crowdsaleClosed = true;
- }
- /**
- * 完成融资目标时, 融资款发送到收款方
- * 未完成融资目标时, 执行退款
- *
- */
- 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;
- }
- }
- }
- }
部署及说明
在部署这个合约之前, 我们需要先部署一个代币合约, 请参考一步步教你创建自己的数字货币
创建众筹合约我们需要提供一下几个参数:
ifSuccessfulSendTo: 募资成功后的收款方(其实这里可以默认为合约创建者)
fundingGoalInEthers: 募资额度, 为了方便我们仅募 3 个 ether
durationInMinutes: 募资时间
finneyCostOfEachToken 每个代币的价格, 这里为了方便使用了单位 finney 及值为: 1 (1 ether = 1000 finney)
addressOfTokenUsedAsReward: 代币合约地址
如:
本文使用的参数为:
"0xc6f9ea59d424733e8e1902c7837ea75e20abfb49",3, 100, 1,"0xad8972e2b583f580fc52f737b98327eb65d08f8c"
参与人投资的时候实际购买众筹合约代币, 所有需要先向合约预存代币, 代币的数量为: 募资额度 / 代币的价格 , 这里为: 3 * 1000/1 = 3000 (当能也可以大于 3000)
向合约预存代币可以使用 myetherwallet 钱包, 或在 remix 中重新加载代币合约, 执行代币合约 tranfer()函数进行代币转账如使用 myetherwallet 转账如图:
参与人投资行为即是向买众筹合约转账, 转账时, 会执行 Fallback 回退函数 (即无名函数) 向其账户打回相应的代币
safeWithdrawl() 可以被参与人或收益人执行, 如果融资不达标参与人可收回之前投资款, 如果融资达标收益人可以拿到所有的融资款
扩展
上面是一个很正规的募资合约接下来讲两个募资合约的扩展, 如何实现无限募资合约及割韭菜合约
这部分内容独家发布在我的小专栏区块链技术
来源: https://www.cnblogs.com/tinyxiong/p/8487348.html