Skip to main content

众筹合约

众筹合约的基本思路是允许项目发起人启动一个众筹活动,设定目标金额和截止日期。支持者可以向合约发送资金以表示支持。如果在截止日期前达到目标金额,则项目发起人可以领取资金;如果未达到,则支持者可以领回他们的资金。

以下是创建众筹合约的步骤:

  1. 初始化合约:在合约构造函数中设定发起人、目标金额和截止日期。
  2. 接收资金:实现一个函数允许用户向合约发送资金,并记录每个支持者的贡献。
  3. 检查目标达成:在截止日期后,如果达到目标金额,允许项目发起人提取资金。
  4. 退款:如果在截止日期后未达到目标金额,允许支持者提取他们的资金。
  5. 安全考虑:确保处理资金的函数是安全的,避免重入攻击等安全隐患。
  6. 事件日志:为关键活动(如捐款和资金提取)添加事件,以便于在区块链上追踪。

下面是众筹合约的简单实现:

pragma solidity ^0.8.0;

contract Crowdfunding {
// 定义众筹项目的结构体
struct Project {
address payable creator; // 项目创建者
uint goalAmount; // 目标金额
uint currentAmount; // 当前金额
uint deadline; // 截止日期
bool isOpen; // 项目是否开放捐款
mapping(address => uint) contributions; // 记录每个地址的捐款
}

Project public project;

event FundingReceived(address contributor, uint amount, uint currentTotal);
event CreatorPaid(address recipient);

// 构造函数,初始化众筹项目
constructor(uint _goalAmount, uint _duration) {
project.creator = payable(msg.sender);
project.goalAmount = _goalAmount;
project.deadline = block.timestamp + _duration;
project.isOpen = true;
}

// 支持者可以调用这个函数捐款
function contribute() external payable {
require(block.timestamp < project.deadline, "The crowdfunding campaign is closed.");
require(project.isOpen, "The project is not open for funding.");

project.contributions[msg.sender] += msg.value;
project.currentAmount += msg.value;
emit FundingReceived(msg.sender, msg.value, project.currentAmount);
}

// 检查是否达到目标金额并且截止日期已过
function checkGoalReached() public {
require(block.timestamp >= project.deadline, "The crowdfunding campaign is not closed yet.");
if (project.currentAmount >= project.goalAmount) {
project.isOpen = false;
emit CreatorPaid(project.creator);
project.creator.transfer(project.currentAmount);
} else {
project.isOpen = false;
}
}

// 支持者可以调用这个函数退款
function getRefund() public {
require(block.timestamp >= project.deadline, "The crowdfunding campaign is not closed yet.");
require(!project.isOpen, "The project is still open for funding.");
require(project.contributions[msg.sender] > 0, "No contributions to refund.");

uint contributedAmount = project.contributions[msg.sender];
project.contributions[msg.sender] = 0;
payable(msg.sender).transfer(contributedAmount);
}
}

这个合约实现了基本的众筹逻辑。请注意,实际的众筹合约可能需要更复杂的功能和安全措施,例如限制最大捐款额度、处理可能的重入攻击、添加权限管理等。此外,对于生产环境的合约,务必进行充分的测试和安全审计。

为了增加合约的安全性和功能,我们可以添加以下几个特性:

  1. 限制最大捐款额度:为了防止单个支持者贡献过多资金,我们可以设置一个最大捐款额度。

  2. 处理可能的重入攻击:在处理资金的函数中,先更新内部状态,然后再进行资金转移,以避免重入攻击。

  3. 添加权限管理:确保只有项目发起人才能提取资金,并且在项目成功后关闭众筹。

  4. 添加暂停功能:允许项目发起人在紧急情况下暂停众筹活动。

下面是添加了这些特性的众筹合约代码:

pragma solidity ^0.8.0;

contract Crowdfunding {
// 定义众筹项目的结构体
struct Project {
address payable creator; // 项目创建者
uint goalAmount; // 目标金额
uint currentAmount; // 当前金额
uint deadline; // 截止日期
bool isOpen; // 项目是否开放捐款
uint maxContribution; // 最大捐款额度
mapping(address => uint) contributions; // 记录每个地址的捐款
}

Project public project;
bool public paused; // 众筹活动是否被暂停

event FundingReceived(address contributor, uint amount, uint currentTotal);
event CreatorPaid(address recipient);
event RefundIssued(address contributor, uint amount);
event ProjectPaused();
event ProjectResumed();

modifier onlyCreator() {
require(msg.sender == project.creator, "Only the project creator can call this function.");
_;
}

modifier whenNotPaused() {
require(!paused, "The contract is paused.");
_;
}

// 构造函数,初始化众筹项目
constructor(uint _goalAmount, uint _duration, uint _maxContribution) {
project.creator = payable(msg.sender);
project.goalAmount = _goalAmount;
project.deadline = block.timestamp + _duration;
project.isOpen = true;
project.maxContribution = _maxContribution;
paused = false;
}

// 支持者可以调用这个函数捐款
function contribute() external payable whenNotPaused {
require(block.timestamp < project.deadline, "The crowdfunding campaign is closed.");
require(project.isOpen, "The project is not open for funding.");
require(msg.value <= project.maxContribution, "Contribution exceeds the maximum allowed.");

project.contributions[msg.sender] += msg.value;
project.currentAmount += msg.value;
emit FundingReceived(msg.sender, msg.value, project.currentAmount);
}

// 检查是否达到目标金额并且截止日期已过
function checkGoalReached() public onlyCreator {
require(block.timestamp >= project.deadline, "The crowdfunding campaign is not closed yet.");
if (project.currentAmount >= project.goalAmount) {
project.isOpen = false;
emit CreatorPaid(project.creator);
project.creator.transfer(project.currentAmount);
} else {
project.isOpen = false;
}
}

// 支持者可以调用这个函数退款
function getRefund() public whenNotPaused {
require(block.timestamp >= project.deadline, "The crowdfunding campaign is not closed yet.");
require(!project.isOpen, "The project is still open for funding.");
require(project.contributions[msg.sender] > 0, "No contributions to refund.");

uint contributedAmount = project.contributions[msg.sender];
project.contributions[msg.sender] = 0;
payable(msg.sender).transfer(contributedAmount);
emit RefundIssued(msg.sender, contributedAmount);
}

// 项目创建者可以暂停众筹活动
function pauseProject() public onlyCreator {
paused = true;
emit ProjectPaused();
}

// 项目创建者可以恢复众筹活动
function resumeProject() public onlyCreator {
paused = false;
emit ProjectResumed();
}
}

在这个合约中,我们添加了以下功能:

  • paused 状态变量和 whenNotPaused 修饰符用于控制合约的暂停和恢复。
  • 通过 onlyCreator 修饰符确保只有项目发起人可以提取资金和暂停众筹。
  • contribute 函数中添加了检查,确保每次捐款不超过最大捐款额度。
  • 通过在 getRefund 函数中先更新内部状态再发送资金的方式来防止重入攻击。
  • 添加了 pauseProjectresumeProject 函数,允许项目发起人在必要时暂停和恢复众筹活动。

请注意,即使进行了这些改进,合约仍然需要经过彻底的测试和审计,以确保没有安全漏洞。在部署到主网之前,应该在测试网上进行充分的测试。