Skip to main content

众筹

众筹ERC20代币

  1. 用户创建活动。
  2. 用户可以质押,将其代币转移到活动中。
  3. 活动结束后,如果承诺的总金额超过活动目标,活动创建者可以领取资金。
  4. 否则,活动未达到目标,用户可以撤回承诺。

Crowd fund ERC20 token

  1. User creates a campaign.
  2. Users can pledge, transferring their token to a campaign.
  3. After the campaign ends, campaign creator can claim the funds if total amount pledged is more than the campaign goal.
  4. Otherwise, campaign did not reach it's goal, users can withdraw their pledge.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

function transferFrom(address, address, uint) external returns (bool);
}

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 {
// Creator of campaign
address creator;
// Amount of tokens to raise
uint goal;
// Total amount pledged
uint pledged;
// Timestamp of start of campaign
uint32 startAt;
// Timestamp of end of campaign
uint32 endAt;
// True if goal was reached and creator has claimed the tokens.
bool claimed;
}

IERC20 public immutable token;
// Total count of campaigns created.
// It is also used to generate id for new campaigns.
uint public count;
// Mapping from id to Campaign
mapping(uint => Campaign) public campaigns;
// Mapping from campaign id => pledger => amount pledged
mapping(uint => mapping(address => uint)) public pledgedAmount;

constructor(address _token) {
token = IERC20(_token);
}

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");

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

emit Launch(count, msg.sender, _goal, _startAt, _endAt);
}

function cancel(uint _id) external {
Campaign memory campaign = campaigns[_id];
require(campaign.creator == msg.sender, "not creator");
require(block.timestamp < campaign.startAt, "started");

delete campaigns[_id];
emit Cancel(_id);
}

function pledge(uint _id, uint _amount) external {
Campaign storage campaign = campaigns[_id];
require(block.timestamp >= campaign.startAt, "not started");
require(block.timestamp <= campaign.endAt, "ended");

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 {
Campaign storage campaign = campaigns[_id];
require(block.timestamp <= campaign.endAt, "ended");

campaign.pledged -= _amount;
pledgedAmount[_id][msg.sender] -= _amount;
token.transfer(msg.sender, _amount);

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

function claim(uint _id) external {
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 {
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);
}
}