Giá thị trường

BTC Bitcoin
$62,746.1 -0.56%
ETH Ethereum
$1,858.66 -0.89%
SOL Solana
$71.73 -2.30%
BNB BNB Chain
$576.9 -2.14%
XRP XRP Ledger
$1.06 -1.22%
DOGE Dogecoin
$0.0696 -0.51%
ADA Cardano
$0.1733 +1.58%
AVAX Avalanche
$6.31 -2.26%
DOT Polkadot
$0.7750 +0.95%
LINK Chainlink
$8.05 -1.84%

Lịch sự kiện blockchain

{{年份}}
08
04
upgrade Solana Firedancer

Trình xác thực độc lập ra mắt trên mainnet

12
05
halving BCH Halving

Sự kiện giảm một nửa phần thưởng khối

15
04
halving Bitcoin Halving

Phần thưởng khối giảm xuống 3,125 BTC

18
03
unlock Mở khóa token Sui

Phần đội ngũ và nhà đầu tư sớm được giải phóng

22
03
unlock Mở khóa Optimism

Lượng cung lưu hành tăng khoảng 2%

28
03
unlock Mở khóa token Arbitrum

Giải phóng 92 triệu ARB

30
04
upgrade Nâng cấp Celestia Mainnet

Cải thiện hiệu quả lấy mẫu tính khả dụng dữ liệu

10
05
upgrade Nâng cấp Ethereum Pectra

Tăng giới hạn validator và trừu tượng hóa tài khoản

Theo dõi phí Gas

Ethereum 28 Gwei
BNB Chain 3 Gwei
Polygon 42 Gwei
Arbitrum 0.5 Gwei
Optimism 0.3 Gwei

💡 Smart Money

0x7eea...f822
Bot chênh lệch giá
+$2.3M
62%
0x69e6...3a4f
Nhà tạo lập thị trường
+$2.5M
62%
0x208f...a0b2
Nhà tạo lập thị trường
+$4.6M
79%

Công cụ

Tất cả →

Oracle s AI data center ambitions are hitting loan syndication walls soaring capex and a 19 stock drop Here s what it means for investors

Ngô Thủy
GameFi
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/access/Ownable.sol";

/* @title CrowdfundingWithERC20 @notice 基于ERC-20代币的众筹合约,支持项目创建、捐款、退款和取款 @dev 使用OpenZeppelin的SafeERC20防止转账错误,ReentrancyGuard防止重入 */ contract CrowdfundingWithERC20 is ReentrancyGuard, Ownable { using SafeERC20 for IERC20;

// ============ 数据结构 ============

/// @notice 项目状态枚举 enum ProjectState { Active, // 进行中 Successful,// 成功(可提款) Failed, // 失败(可退款) Cancelled // 被项目方取消 }

/// @notice 项目结构 struct Project { address creator; // 项目发起人 string title; // 标题 string description; // 描述 IERC20 token; // 募资代币(ERC-20) uint256 goal; // 目标金额(单位:token decimals) uint256 minRaise; // 最低融资额(可选0,但通常>0) uint256 deadline; // 截止时间戳(秒) uint256 totalRaised; // 已筹集总额 ProjectState state; // 当前状态 uint256 createdAt; // 创建时间 mapping(address => uint256) contributions; // 支持者 -> 捐款数额 address[] supporters; // 所有支持者列表(方便查询) }

// ============ 状态变量 ============

uint256 public projectCounter; // 项目计数器 mapping(uint256 => Project) private _projects; // 项目ID -> 项目

// ============ 事件 ============

event ProjectCreated(uint256 indexed projectId, address indexed creator, string title, uint256 goal, uint256 deadline); event ContributionMade(uint256 indexed projectId, address indexed supporter, uint256 amount); event ProjectFunded(uint256 indexed projectId, uint256 totalRaised); event ProjectFailed(uint256 indexed projectId); event ProjectCancelled(uint256 indexed projectId); event Withdrawn(uint256 indexed projectId, address indexed creator, uint256 amount); event RefundClaimed(uint256 indexed projectId, address indexed supporter, uint256 amount);

// ============ 修饰器 ============

/// @notice 检查项目是否存在 modifier projectExists(uint256 _projectId) { require(_projectId > 0 && _projectId <= projectCounter, "Project does not exist"); _; }

/// @notice 检查项目是否处于活动状态 modifier projectActive(uint256 _projectId) { require(_projects[_projectId].state == ProjectState.Active, "Project is not active"); _; }

/// @notice 仅项目创建者可调用 modifier onlyCreator(uint256 _projectId) { require(msg.sender == _projects[_projectId].creator, "Only project creator"); _; }

// ============ 构造函数 ============

constructor() { // Ownable构造函数默认设置部署者为owner,可根据需求调整 }

// ============ 核心函数 ============

/* @notice 创建新项目 @param _token 募资代币地址 @param _goal 目标金额(需与代币精度一致) @param _minRaise 最低融资额(设为0表示不设下限) @param _deadline 截止时间戳(秒) @param _title 项目标题 @param _description 项目描述 @return 新项目ID / function createProject( IERC20 _token, uint256 _goal, uint256 _minRaise, uint256 _deadline, string calldata _title, string calldata _description ) external returns (uint256) { require(_goal > 0, "Goal must be > 0"); require(_deadline > block.timestamp, "Deadline must be in future"); require(_minRaise <= _goal, "Min raise > goal"); require(bytes(_title).length > 0, "Title required");

projectCounter++; uint256 projectId = projectCounter;

Project storage p = _projects[projectId]; p.creator = msg.sender; p.title = _title; p.description = _description; p.token = _token; p.goal = _goal; p.minRaise = _minRaise; p.deadline = _deadline; p.state = ProjectState.Active; p.createdAt = block.timestamp;

emit ProjectCreated(projectId, msg.sender, _title, _goal, _deadline); return projectId; }

/* @notice 支持目标项目(捐款) @param _projectId 项目ID @param _amount 捐款金额(需大于0) */ function contribute(uint256 _projectId, uint256 _amount) external nonReentrant projectExists(_projectId) projectActive(_projectId) { Project storage p = _projects[_projectId]; require(_amount > 0, "Amount must be > 0"); require(block.timestamp < p.deadline, "Deadline passed"); require(p.state == ProjectState.Active, "Not active");

// 转移代币到合约(先转后记录,防止重入) p.token.safeTransferFrom(msg.sender, address(this), _amount);

// 更新统计 p.totalRaised += _amount; if (p.contributions[msg.sender] == 0) { p.supporters.push(msg.sender); } p.contributions[msg.sender] += _amount;

emit ContributionMade(_projectId, msg.sender, _amount);

// 检查是否已达到目标 if (p.totalRaised >= p.goal) { _setProjectState(_projectId, ProjectState.Successful); emit ProjectFunded(_projectId, p.totalRaised); } }

/* @notice 项目方取款(仅当项目成功时) @param _projectId 项目ID / function withdraw(uint256 _projectId) external nonReentrant projectExists(_projectId) onlyCreator(_projectId) { Project storage p = _projects[_projectId]; require(p.state == ProjectState.Successful, "Project not successful"); require(p.totalRaised > 0, "Nothing to withdraw");

uint256 amount = p.totalRaised; p.totalRaised = 0; // 清零防止重复提取

p.token.safeTransfer(msg.sender, amount); // 状态改为已提款?可以保留Successful或者增加一个新状态Completed,但为了简单,我们保持Successful并清除金额 emit Withdrawn(_projectId, msg.sender, amount); }

/* @notice 支持者领取退款(当项目失败时) @param _projectId 项目ID / function claimRefund(uint256 _projectId) external nonReentrant projectExists(_projectId) { Project storage p = _projects[_projectId]; require(p.state == ProjectState.Failed || p.state == ProjectState.Cancelled, "Not refundable");

uint256 contributed = p.contributions[msg.sender]; require(contributed > 0, "No contribution to refund");

// 清零记录 p.contributions[msg.sender] = 0;

p.token.safeTransfer(msg.sender, contributed); emit RefundClaimed(_projectId, msg.sender, contributed); }

/* @notice 项目方取消项目(仅当项目仍处于活跃状态) @param _projectId 项目ID / function cancelProject(uint256 _projectId) external projectExists(_projectId) onlyCreator(_projectId) projectActive(_projectId) { Project storage p = _projects[_projectId]; // 可限制在截止日期前才能取消?这里允许随时取消 _setProjectState(_projectId, ProjectState.Cancelled); emit ProjectCancelled(_projectId); }

// ============ 内部函数 ============

/* @notice 根据截止日期自动更新项目状态(检查是否失败) @dev 任何人都可以调用,触发失败处理 / function finalizeProject(uint256 _projectId) external projectExists(_projectId) { Project storage p = _projects[_projectId]; require(p.state == ProjectState.Active, "Not active"); require(block.timestamp >= p.deadline, "Deadline not reached");

if (p.totalRaised >= p.minRaise && p.totalRaised < p.goal) { // 虽未达目标但达到最低融资额?根据业务决定:此处设计为未达目标则失败 // 也可以设计为部分成功,但为了简单,我们要求必须达到goal才成功 _setProjectState(_projectId, ProjectState.Failed); emit ProjectFailed(_projectId); } else if (p.totalRaised < p.goal) { _setProjectState(_projectId, ProjectState.Failed); emit ProjectFailed(_projectId); } // 若已达目标,状态已在contribute中更新为Successful,但可能达目标后立即有人调用,会重复?需要检查状态 // 所以这里只处理Active且截止的情况 }

/// @notice 设置项目状态(仅内部调用) function _setProjectState(uint256 _projectId, ProjectState _newState) private { _projects[_projectId].state = _newState; }

// ============ 查询函数 ============

/// @notice 获取项目基本信息(返回多个值) function getProjectInfo(uint256 _projectId) external view projectExists(_projectId) returns ( address creator, string memory title, string memory description, IERC20 token, uint256 goal, uint256 minRaise, uint256 deadline, uint256 totalRaised, ProjectState state, uint256 createdAt ) { Project storage p = _projects[_projectId]; return ( p.creator, p.title, p.description, p.token, p.goal, p.minRaise, p.deadline, p.totalRaised, p.state, p.createdAt ); }

/// @notice 获取支持者捐款额度 function getContribution(uint256 _projectId, address _supporter) external view projectExists(_projectId) returns (uint256) { return _projects[_projectId].contributions[_supporter]; }

/// @notice 获取项目所有支持者地址(用于前端展示) function getSupporters(uint256 _projectId) external view projectExists(_projectId) returns (address[] memory) { return _projects[_projectId].supporters; }

/// @notice 获取项目数量 function getProjectCount() external view returns (uint256) { return projectCounter; }

// ============ 安全辅助 ============

/// @notice 允许合约接收ETH的函数(如果误转ETH,可被owner提出) receive() external payable {}

/// @notice owner提取意外转入的ETH function withdrawETH() external onlyOwner { payable(owner()).transfer(address(this).balance); } } ```

| 功能 | 实现方式 | 安全性考量 | |------|----------|------------| | 项目创建 | 使用计数器生成唯一ID,存储所有参数 | 验证deadline和goal合理性 | | 捐款 | safeTransferFrom 结合 nonReentrant | 先转账后更新状态防止重入 | | 自动成功检测 | 在contribute中检查 totalRaised >= goal 后立即变更状态 | 避免达到目标后继续捐款 | | 退款 | claimRefund 检查状态为Failed或Cancelled | 清零贡献记录防止重复退款 | | 项目方提款 | 仅在Successful状态可用,提款后清零totalRaised | 防止重复提取(状态未改但金额清零) | | 失败触发 | finalizeProject 供任何人调用,根据截止日期后余额判断 | 需检查截止时间已过 |

使用流程示例(基于Remix)

  1. 部署ERC-20代币(如TestToken),给用户一些代币并授权合约
  2. 部署本众筹合约
  3. 用户A调用createProject,传入代币地址、目标1000、截止时间等
  4. 其他用户调用contribute,传入项目ID和金额,并先对众筹合约进行approve
  5. 达到目标后状态自动变为Successful,项目方调用withdraw取款
  6. 若截止日未达目标,任何用户调用finalizeProject,状态变为Failed,支持者调用claimRefund退款

注意事项

  • 代币精度:所有金额需与代币decimals一致
  • Gas消耗:支持者列表supporters数组会无限增长,建议限制项目支持者数量或使用分页查询
  • 状态管理:若项目成功但creator未及时取款,合约中资金安全,但无自动过期机制
  • 最低融资额:代码中minRaise不参与自动成功判断(成功必须达goal),但可用于在finalize中判断是否部分成功?目前设计为严格达到goal才成功,minRaise仅作检查约束

此合约满足基本众筹需求,并利用OpenZeppelin库确保常见安全漏洞防护。

Sợ & Tham

27

Sợ hãi

Tâm lý thị trường

Chỉ số mùa altcoin

44

Mùa Bitcoin

Sự thống trị BTC Mùa altcoin

Vốn hóa thị trường

Tất cả →
# Tiền điện tử Giá
1
Bitcoin BTC
$62,746.1
1
Ethereum ETH
$1,858.66
1
Solana SOL
$71.73
1
BNB Chain BNB
$576.9
1
XRP Ledger XRP
$1.06
1
Dogecoin DOGE
$0.0696
1
Cardano ADA
$0.1733
1
Avalanche AVAX
$6.31
1
Polkadot DOT
$0.7750
1
Chainlink LINK
$8.05

🐋 Theo dõi cá voi

🔵
0x68bd...238d
1 ngày trước
Stake
3,248.18 BTC
🔴
0x500e...fb93
12 phút trước
Chuyển ra
2,934,911 USDT
🔵
0x2e7c...5f92
1 ngày trước
Stake
445,597 USDC