solidity实战练习5——众筹合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IERC20 {
    function transfer(address, uint) external returns (bool);

    function transferFrom( address,  address,uint ) external returns (bool);
}
interface crowdFund{
    function launch( uint _goal,uint32 _startAt,uint32 _endAt ) external;//发起众筹
    function cancel(uint _id) external;//发起者取消众筹
    function pledge(uint _id, uint _amount) external;//用户参与众筹
    function unpledge(uint _id, uint _amount) external ;//用户取消众筹
    function claim(uint _id) external;//众筹成功,发起者可以调走众筹的代币
    function refund(uint _id) external;//众筹失败,用户领取自己的代币
}
contract CrowdFund {
    event Launch(uint id,address indexed creator,uint goal,uint32 startAt,uint32 endAt);
    event Cancel(uint id);
    event Pledge(uint indexed id, address indexed caller, uint amount);
    event Unpledge(uint indexed id, address indexed caller, uint amount);
    event Claim(uint id);
    event Refund(uint id, address indexed caller, uint amount);

    struct Campaign {//这个相当一个类,每次发起一个合约都需要实例化一下这个类
        //确定众筹合约的创建者
        address creator;
        //确定合约众筹的目标
        uint goal;
        //当前众筹合约众筹的总量
        uint pledged;
        // 开始时间
        uint32 startAt;
        //结束时间 
        uint32 endAt;
        //是否完成?
        bool claimed;
    
    }

    IERC20 public immutable token; // 指定token
    uint public count=0;//标记当前合约所含有的众筹合约的个数
    uint record=0;//记录总合约被捐款次数

    mapping(uint => Campaign) public campaigns;// 众筹合约的编号与众筹合约一一对应
    mapping(uint => mapping(address => uint)) public pledgedAmount;//id->个人address->捐款总额
    mapping(uint =>mapping(address=>uint) ) private recordParticipantValue;//ID->address->value
    mapping(uint => mapping(uint=>address)) private participantRecord;//ID->捐款编号->address

    constructor(address _token) {//通过构造函数来确认代币的类型
        token = IERC20(_token);
    }

    modifier isStart(uint _id)//函数修改器,确保被修饰函数需要进行开始检查
    {
        require(block.timestamp >= campaigns[_id].startAt,"not start");
        _;
    }
    modifier isEnd(uint _id)//函数修改器,确保被修饰函数需要进行结束检查
    {
        require(block.timestamp<=campaigns[_id].endAt,"ended");
        _;
    }
    modifier checkId(uint _id){
        require(_id<=count,"your id is wrong");
        _;
    }

    function launch(uint _goal,uint32 _startAt,uint32 _endAt) external {//发起合约的具体定义
        require(_startAt >= block.timestamp, "start at < now");
        require(_endAt > _startAt, "end at < start at");
        require(_endAt <= block.timestamp + 90 days, "end at > max duration");//持续时间默认为90天,通过开始时间来定义结束时间

        campaigns[count] = Campaign({
            creator: msg.sender,
            goal: _goal,
            pledged: 0,
            startAt: _startAt,
            endAt: _endAt,
            claimed: false
        });
        count += 1;
        emit Launch(count, msg.sender, _goal, _startAt, _endAt);
    }

    function cancel(uint _id) external checkId( _id) {//合约发起之后可能由于筹集目标过高,想要删除这次众筹
        Campaign memory campaign = campaigns[_id];
        require(campaign.creator == msg.sender, "not creator");
        
        autoRefund( _id);//调用自动退还功能,被删除合约自动发送所有的代币给参与合约的用户
        delete campaigns[_id];
        emit Cancel(_id);
    }

    function pledge(uint _id, uint _amount) external payable isStart(_id) isEnd(_id) checkId( _id){
        Campaign storage campaign = campaigns[_id];
        require(_amount > 0,"your amount is error");
        require(msg.value==_amount,"money is error");
        participantRecord[_id][record]=msg.sender;
        recordParticipantValue[record][msg.sender]=_amount;
        record+=1;

        campaign.pledged += _amount;
        pledgedAmount[_id][msg.sender] += _amount;
        token.transferFrom(msg.sender, address(this), _amount);

        emit Pledge(_id, msg.sender, _amount);
    }

    function unpledge(uint _id, uint _amount) external isStart(_id) isEnd(_id) checkId( _id){
        require(_amount<=pledgedAmount[_id][msg.sender],"your amount is wrong");
        Campaign storage campaign = campaigns[_id];
         campaign.pledged -= _amount;
        pledgedAmount[_id][msg.sender] -= _amount;
        token.transfer(msg.sender, _amount);

        emit Unpledge(_id, msg.sender, _amount);
    }

    function claim(uint _id) external checkId( _id) {
        Campaign storage campaign = campaigns[_id];
        require(campaign.creator == msg.sender, "not creator");
        require(block.timestamp > campaign.endAt, "not ended");
        require(campaign.pledged >= campaign.goal, "pledged < goal");
        require(!campaign.claimed, "claimed");

        campaign.claimed = true;
        token.transfer(campaign.creator, campaign.pledged);

        emit Claim(_id);
    }

    function refund(uint _id) external isStart(_id) checkId( _id){
        Campaign memory campaign = campaigns[_id];
        require(block.timestamp > campaign.endAt, "not ended");
        require(campaign.pledged < campaign.goal, "pledged >= goal");

        uint bal = pledgedAmount[_id][msg.sender];
        pledgedAmount[_id][msg.sender] = 0;
        token.transfer(msg.sender, bal);

        emit Refund(_id, msg.sender, bal);
    }
    function autoRefund(uint _id)private isStart(_id) checkId( _id){
         Campaign memory campaign  = campaigns[_id];
        for(uint i=0;recordParticipantValue[i][participantRecord[_id][i]]!=0;i++)
        {
        token.transfer(participantRecord[_id][i],recordParticipantValue[i][ participantRecord[_id][i]]);
        pledgedAmount[_id][participantRecord[_id][i]]=0;
        }
        campaign.pledged=0;
        
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值