一、意义:
在上一节课中,我们已经能基于以太坊智能合约做一些简单的Dapp应用了,但在真正生成环境中,这些知识远远不够。为了更好的掌握这部分知识,在这一节中,我们通过一个新项目(众筹)来加强和学习新的知识点。废话不多说,我们言归正传。
项目简介:
众筹是指用团购+预购的形式,向网友募集项目资金的模式。众筹利用互联网和SNS传播的特性,让小企业、艺术家或个人对公众展示他们的创意,争取大家的关注和支持,进而获得所需要的资金援助。在传统众筹项目中,资金难以监管、追溯。参与方是拥有很大风险,因为项目方可以融资后拿钱跑路。通过前几节课的学习,我们知道区块链就是一个超级数据库,不可修改,可追溯。所以我们考虑在技术上通过区块链改进众筹项目。
---------------------------------------------------------------------------------------------------------------------------------------
如果您改进了代码或者想对照代码学习,请访问我的Github。
如果您有问题想要讨论。请加我微信:laughing_jk(加我,请备注来源,谢谢)
众筹项目源码:https://github.com/lsy-zhaoshuaiji/FundingFactory
---------------------------------------------------------------------------------------------------------------------------------------
二、需求分析:
1.每个用户都能参与项目和发布项目
2.众筹总金额等于基本筹金乘以份数,每份众筹金一样。
3.项目方可设置一个时间段和份数值,若在某个时间段众筹份数小于某个值,则代表众筹失败,进行合约退款。
4.项目方提出一个花费请求,每个人都有投票的权利,投票后结果不可更改,不可逆。
5.项目方提出一个花费请求,1/2参与人投票赞成票,则代表通过协议。若少于1/2,则不可花费该资金。
6.花费请求通过后,可以手动向某个特点地址进行付款。
三、概要设计
由于该项目中,弱化了项目方的权利,且产生的数据具有可追溯性,不可修改性,所以我们需要在项目中引入以太坊智能合约。该项目采用(B/S架构),具体设计如下:
1.底层使用ETH智能合约实现该项目的数据存储、 (数据库模块)
2.使用React实现前端与用户的交互 ( 前端模块)
3.使用node.js/web3实现对智能合约的控制和交互 ( 后台模块)
四、详细设计
由于我们设计的是众筹平台,在平台中存在多个众筹项目,一个项目对应着一个合约。所以平台中可能存在多个智能合约。我们把控制多个智能合约的总合约叫做工厂合约(FundingFactorty)。把控制本身项目的合约叫做单例合约(Funding)。
4.1合约编写
4.1.1、思维导图如下图:
4.1.2、单例模式能合约代码
pragma solidity ^0.4.24;
import './fundingFactory.sol';
contract Findding{
address public manager;
string public projectName;
uint256 public targetMoney;
uint256 public supportMoney;
uint256 public endTime;
address [] public Investors;
SupportFundingContract supportFundings;
enum RequestStatus{
Voting,Approving,Completed
}
struct Request{
string purpose;
uint256 cost;
address seller;
uint256 approvedCount;
RequestStatus status;
mapping(address => bool) isVoteMap;
}
Request [] public allRequests;
mapping(address=>bool) public isInverstorMap;
constructor(string _projectName,uint256 _targetMoney,uint256 _supportMoney,uint256 _duration,address _creator,SupportFundingContract _supportFundings) public{
manager=_creator;
projectName=_projectName;
targetMoney=_targetMoney;
supportMoney=_supportMoney;
endTime=block.timestamp+_duration;
supportFundings=_supportFundings;
}
//"大黄蜂",10,5,3600
//"sfsdfsd",5,"0xca35b7d915458ef540ade6068dfe2f44e8fa733c"
modifier OnlyManager(){
require(msg.sender==manager);
_;
}
function getLastTime()public view returns(uint256){
return endTime-block.timestamp;
}
function InverstorCount()public view returns(uint256){
return Investors.length;
}
function getRequestCount()view public returns(uint256){
return allRequests.length;
}
function Invers() payable public {
require(supportMoney*10**18==msg.value);
isInverstorMap[msg.sender]=true;
Investors.push(msg.sender);
supportFundings.setFunding(msg.sender,this);
}
function Refund() OnlyManager public{
for (uint256 i=0;i<Investors.length;i++){
Investors[i].transfer(supportMoney);
}
delete Investors;
}
function createRequest(string _purpose,uint256 _cost,address _seller)OnlyManager public{
Request memory req=Request({
purpose:_purpose,
cost:_cost,
seller:_seller,
approvedCount:0,
status:RequestStatus.Voting
});
allRequests.push(req);
}
function approveRequest(uint256 i)public {
require(isInverstorMap[msg.sender]);
Request storage req=allRequests[i];
require(req.isVoteMap[msg.sender]==false);
req.approvedCount++;
req.isVoteMap[msg.sender]=true;
}
function getRequestIndex(uint256 i) public view returns(string,uint256,address,uint256,RequestStatus){
/*
string purpose;
uint256 cost;
address seller;
uint256 approvedCount;
RequestStatus status;
*/
Request memory req=allRequests[i];
return(req.purpose,req.cost,req.seller,req.approvedCount,req.status);
}
function getBalance() public view returns(uint256){
return address(this).balance;
}
function finalizeRequest(uint256 i) OnlyManager public{
Request storage req=allRequests[i];
require(address(this).balance >= req.cost*10**18);
require(req.approvedCount *2 >=Investors.length);
req.seller.transfer(req.cost*10**18);
req.status=RequestStatus.Completed;
}
}
4.1.3、工厂模式智能合约代码
pragma solidity ^0.4.24;
import './Test.sol';
contract FundingFactory{
address public superManager;
address [] allFundings;
mapping(address=>address[]) public createFundings;
// mapping(address=>address[]) public joinFundings;
SupportFundingContract supportFundings= new SupportFundingContract();
constructor()public{
superManager=msg.sender;
}
function createFunding