如何编写限制公众仅可免费mint 1枚ERC721 NFT的Solidity函数
该需求完全可实现,以下是具体的合约改造方案和补充建议:
合约层改造方案
核心改造逻辑是移除原函数的管理员调用限制,新增用户领取状态校验,实现每个公开用户仅可领取1枚0价格NFT,用户仅自行承担铸造的gas费用:
- 新增
hasClaimedFreeNFT映射记录用户领取状态,实现单用户限领1枚 - 移除原函数的
onlyOwner修饰符,允许公开调用 - 简化调用参数,无需传入铸造数量和接收地址,默认给调用者铸造1枚
- 新增
msg.value校验,确保用户无需支付铸造费用,避免误转资产 - 移除不必要的循环逻辑,降低用户调用的gas消耗
改造后的完整合约参考:
// 基于Solidity 0.8+ 开发 import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyTestContract is ERC721, ERC721Enumerable, Ownable { bool public preLaunchActive = false; uint256 public maxGiveAway = 3; // 记录用户是否已经领取过免费NFT mapping(address => bool) public hasClaimedFreeNFT; constructor() ERC721("MyTestNFT", "MTN") {} // 公开免费领取入口 function publicClaimFreeNFT() external { require(preLaunchActive, "preLaunchActive state is not active."); require(!hasClaimedFreeNFT[msg.sender], "You have already claimed your free NFT."); require(maxGiveAway > 0, "No more free NFT available."); require(msg.value == 0, "Free mint, no ETH required."); uint256 tokenId = totalSupply(); _safeMint(msg.sender, tokenId); hasClaimedFreeNFT[msg.sender] = true; maxGiveAway -= 1; } // 保留原管理员批量赠送函数,可用于定向发放 function myPreLaunchGiveAway(uint amount, address to) public onlyOwner { require(preLaunchActive, "preLaunchActive state is not active."); require(amount <= maxGiveAway, "No more available."); require(amount > 0, "Amount must be greater than 0."); for (uint i = 0; i < amount; i++) { uint256 tokenId = totalSupply(); _safeMint(to, tokenId); } maxGiveAway -= amount; } // 管理员控制活动开关 function setPreLaunchActive(bool _active) external onlyOwner { preLaunchActive = _active; } // ERC721Enumerable标准重写函数 function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal override(ERC721, ERC721Enumerable) { super._beforeTokenTransfer(from, to, tokenId, batchSize); } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) { return super.supportsInterface(interfaceId); } }
补充优化方案
链上安全优化
- 若需避免机器人批量刷取,可新增签名校验逻辑:后端提前为符合领取条件的用户地址生成专属签名,合约校验签名为官方签发后才允许领取,可灵活控制领取资格,避免非目标用户抢领
- 若免费铸造总量较大,可替换为ERC721A标准开发,进一步降低铸造的gas成本
中心化配套方案
- 前端新增领取前置校验:可要求用户完成手机号验证、官方社交账号关注等活动要求后,才开放领取入口,降低女巫攻击概率
- 后端新增库存监听:实时同步链上剩余免费NFT库存,库存耗尽时自动关闭前端领取入口,避免用户发起无效交易浪费gas
- 数据统计:后端监听链上铸造事件,自动统计领取用户地址、领取时间等数据,方便后续活动复盘
内容的提问来源于stack exchange,提问作者johnDoe
相关产品推荐
相关产品推荐

