You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写限制公众仅可免费mint 1枚ERC721 NFT的Solidity函数

该需求完全可实现,以下是具体的合约改造方案和补充建议:

合约层改造方案

核心改造逻辑是移除原函数的管理员调用限制,新增用户领取状态校验,实现每个公开用户仅可领取1枚0价格NFT,用户仅自行承担铸造的gas费用:

  1. 新增hasClaimedFreeNFT映射记录用户领取状态,实现单用户限领1枚
  2. 移除原函数的onlyOwner修饰符,允许公开调用
  3. 简化调用参数,无需传入铸造数量和接收地址,默认给调用者铸造1枚
  4. 新增msg.value校验,确保用户无需支付铸造费用,避免误转资产
  5. 移除不必要的循环逻辑,降低用户调用的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 14:48:03