以太坊 day (6)
一、众筹项目
1.1 众筹规则
-
规定时间内筹得资金则成功,反之失败
-
众筹的钱存放在合约里,发起众筹的人想花费合约中的钱的时候需要提交申请,投资者投票过半,申请才可以通过
-投资者对申请只能投一次票 -
花费申请成功时,可以获得花费的权力
二、众筹合约实现
2.1 字段
- 项目发起人
- 需要资金
- 人均投资
- 持续时间
- 项目名称
pragma solidity ^0.4.26;
contract Funding{
string public pro_name;
uint256 public endtime;
uint256 public need_money;
uint256 public peo_money;
address public launch;
constructor(string pro_name1,uint256 endtime1,uint256 need_money1,uint256 peo_money1) public {
launch = msg.sender;
pro_name = pro_name1;
endtime = block.timestamp + endtime1;
peo_money = peo_money1;
need_money = need_money1;
}
function getName() public view returns (string){
return pro_name;
}
}
2.2 添加投资函数
function invest() public payable{
require(msg.value == 1000);
investors.push(msg.sender);
}
function getContractBalance() public view returns (uint256){
return address(this).balance;
}
function getInvestors() public view returns (address[]){
return investors;
}
2.3 发起人请求花费的结构体定义
enum appliStatue{
//正在进行中,已赞成,已结束
voting, approved, finish
}
struct application{
//花费的请求
string spendReason;
//商家的地址
address seller;
//请求的状态
appliStatue statue;
//赞成的数量
uint256 approve;
//请求花费多少
uint256 cost;
//每个投资者的投资状况
mapping(address=>bool) isVotedMap;
}
2.4 众筹失败,原路退回资金
function refund() public {
require(msg.sender == launch);
for (uint256 i = 0;i < investors.length; i ++){
investors[i].transfer(supportMoney);
}
delete investors;
}
2.5 甲方创建花费请求
//创建花费请求
function createEat(string _spendReason, address _seller,uint256 _cost ) public {
Application memory myRequest = Application({
spendReason : _spendReason,
seller : _seller,
statue : AppliStatue.voting,
approve : 0,
cost :_cost
});
allApplication.push(myRequest);
}
2.6 投资人对花费请求进行投票
//投资人对花费请求进行批准
function voteRequest(uint256 i) public{
//判断投资人是否据有投资资格
require(isVoter[msg.sender] == true);
//这里一定是storage 类型
Application storage app = allApplication[i];
//判断是否已经投过票
require(app.isVotedMap[msg.sender] == false);
app.approve = app.approve+ 1;
app.isVotedMap[msg.sender] == true;
}
2.7 执行花费动作
- 判断投票是否过半
- 判断合约的钱是否大于请求的钱
- 将花费的钱转给商家
- 更新花费申请的状态
//执行花费动作
function startSpend(uint256 i) public{
Application storage app = allApplication[i];
//判断投票是否过半
require(app.approve * 2 > investors.length);
//判断合约的钱是否大于请求的钱
require(address(this).balance > app.cost);
//将花费的钱转给商家
app.seller.transfer(app.cost);
//更新花费申请的状态
app.statue = AppliStatue.finish;
}
2.8 辅助函数
- 权限控制
- 返回投资人数
- 返回申请请求详细信息
- 返回众筹剩余时间
modifier onlyManager(){
//只有投资者才拥有的权限
require(msg.sender == launch);
_;
}
function getInvestNum() public view returns (uint256){
return investors.length;
}
function leftTime() public view returns (uint256){
return endtime - block.timestamp;
}
function detailApplication(uint256 i) public view returns (string, address, uint256, uint256, AppliStatue){
Application storage app = allApplication[i];
return (app.spendReason, app.seller, app.cost, app.approve, app.statue);
}
2.9 怎么快速检验是不是投资人
mapping (address=>bool) isVoter;
三、工厂合约
3.1工厂合约包含的内容
- 所有的合约
address[] - 我参加的众筹合约
mapping(address=>address[]) - 我参与的众筹合约
mapping(address=>address[]) - 平台管理员
//众筹项目工厂管理者
address public FactoryManager;
//所有的众筹项目
address [] public allCrowdFunding;
//用户创建的众筹项目
mapping(address=>address[]) ownCrowdFunding;
//用户参与的众筹项目
mapping(address=>address[]) joinCrowdFunding;
//创建众筹项目
3.2 创建众筹项目
function createCrowdFunding(string pro_name1,uint256 endtime1,uint256 need_money1,uint256 supportMoney1) public {
address funding = new Funding(pro_name1,endtime1,need_money1,supportMoney1);
allCrowdFunding.push(funding);
ownCrowdFunding[msg.sender].push(funding);
}
3.3 辅助函数
function getAllFunding() public view returns(address[]){
return allCrowdFunding;
}
function getAllCreatefunding() public view returns(address[]){
return ownCrowdFunding[msg.sender];
}
function fetAllJoinFunding() public view returns(address[]){
return joinCrowdFunding[msg.sender];
}
3.4 切换用户,创建的合约中的创建人的地址是合约管理者的地址
- 合约创建构造函数
function createCrowdFunding(string pro_name1,uint256 endtime1,uint256 need_money1,uint256 supportMoney1) public {
address funding = new Funding(pro_name1,endtime1,need_money1,supportMoney1,msg.sender);
allCrowdFunding.push(funding);
ownCrowdFunding[msg.sender].push(funding);
}
-合约工厂
constructor(string pro_name1,uint256 endtime1,uint256 need_money1,uint256 supportMoney1, address launch1) public {
//这里的lanch不能是launch=msg.sender,不然会变成合约工场的管理者
launch = launch1;
pro_name = pro_name1;
endtime = block.timestamp + endtime1;
supportMoney = supportMoney1;
need_money = need_money1;
}
3.5 获取投资人参与的所有的众筹
- 合约工厂中的字段
//用户参与的众筹项目
mapping(address=>address[]) joinCrowdFunding;
- 合约中的invest()方法需要将加入的众筹加入上述合约工厂中的joinCrowdFunding字段,但是mapping类型的数据无法通过合约工厂的function createCrowdFundin()函数传递
解决方法:通过中间合约来解决。
3.6 显示用户所有的参与的众筹
- 维护用户参与众筹的合约
pragma solidity ^0.4.26;
//本合约的作用是为了维护一个显示用户参与合约的mapping
contract JoinFundingContract{
mapping(address=>address[]) public joinFunding;
function getJoinFunding(address _user) public view returns (address[]){
return joinFunding[_user];
}
function setJoinFunding(address _user, address _fund) public {
joinFunding[_user].push(_fund);
}
}
- 用户参与众筹时,加入参与众筹mapping
function invest() public payable{
require(msg.value == 1000);
investors.push(msg.sender);
//用map记录具有投资资格的人
isVoter[msg.sender] = true;
//msg.sender:当前用户的地址,this:当前合约的地址
joinFundingContract.setJoinFunding(msg.sender, this);
}
- 查看用户参与的所有的众筹
function getAllJoinFunding() public view returns (address[]){
return joinFundingContract.getJoinFunding(msg.sender);
}