



























// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract VSampleToken is ERC20, Ownable { // 规则参数(使用更节省gas的数据类型) uint256 public constant DAILY_CLAIM_AMOUNT = 100 * 10**18; uint8 public constant DAILY_CLAIM_LIMIT = 2; uint256 public constant TOTAL_CLAIM_LIMIT = 1000 * 10**18; uint256 public constant MIN_RESERVE = 100000 * 10**18; uint256 public constant MAX_SUPPLY = 1000000 * 10**18; struct ClaimRecord { uint32 lastClaimDay; uint8 dailyClaimCount; uint96 totalClaimed; } mapping(address => ClaimRecord) public claimRecords; // 事件:成功领取 event Claimed(address indexed user, uint256 amount); constructor() ERC20("VSampleToken", "VST") Ownable(msg.sender) { _mint(address(this), MAX_SUPPLY); } // 统一余额检查逻辑 function _checkReserve() private view { require( balanceOf(address(this)) >= DAILY_CLAIM_AMOUNT + MIN_RESERVE, "Insufficient contract reserve" ); } function claim() external { address user = msg.sender; _checkReserve(); if (user == owner()) { _transfer(address(this), user, DAILY_CLAIM_AMOUNT); return; } ClaimRecord storage record = claimRecords[user]; uint32 currentDay = uint32(block.timestamp / 1 days); // 新的一天重置计数器 if (record.lastClaimDay != currentDay) { record.lastClaimDay = currentDay; record.dailyClaimCount = 0; } require(record.dailyClaimCount < DAILY_CLAIM_LIMIT, "Daily limit reached"); require( record.totalClaimed + DAILY_CLAIM_AMOUNT <= TOTAL_CLAIM_LIMIT, "Total claim limit exceeded" ); // 更新记录(使用安全类型转换) record.dailyClaimCount += 1; record.totalClaimed += uint96(DAILY_CLAIM_AMOUNT); _transfer(address(this), user, DAILY_CLAIM_AMOUNT); emit Claimed(user, DAILY_CLAIM_AMOUNT); } function withdrawRemaining(address to, uint256 amount) external onlyOwner { require( balanceOf(address(this)) - amount >= MIN_RESERVE, "Cannot break reserve requirement" ); _transfer(address(this), to, amount); } function getClaimStatus(address user) external view returns ( bool canClaim, uint8 availableToday, uint256 remainingTotal ) { if (user == owner()) { return ( balanceOf(address(this)) >= DAILY_CLAIM_AMOUNT + MIN_RESERVE, type(uint8).max, type(uint256).max ); } ClaimRecord memory record = claimRecords[user]; uint32 currentDay = uint32(block.timestamp / 1 days); availableToday = record.lastClaimDay == currentDay ? DAILY_CLAIM_LIMIT - record.dailyClaimCount : DAILY_CLAIM_LIMIT; remainingTotal = TOTAL_CLAIM_LIMIT - record.totalClaimed; canClaim = (availableToday > 0) && (remainingTotal >= DAILY_CLAIM_AMOUNT) && (balanceOf(address(this)) >= DAILY_CLAIM_AMOUNT + MIN_RESERVE); } }
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。