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

如何在Solidity的Mint循环中实现1-4951区间不重复随机数功能

Solidity 实现1-4951区间不重复随机mint方案

实现思路

  • 采用优化版Fisher-Yates(费雪-耶茨)洗牌算法,无需提前初始化全量ID数组,大幅节省部署和运行gas
  • 通过mapping记录已置换的ID位置,确保每次抽取的随机ID不会重复
  • 每次成功mint后递增supply,最终supply数值等于已mint的总数量

依赖存储变量

// 存储已置换的ID映射,key为原索引,value为对应分配的tokenId
mapping(uint256 => uint256) private _idMap;
// 当前已mint的总数量
uint256 public supply;
// 最大可mint的ID上限
uint256 public constant MAX_ID = 4951;

修改后的mint逻辑代码

function mint(address _to, uint256 _mintAmount) external {
    // 前置校验:mint数量需大于0,且不能超过剩余可mint额度
    require(_mintAmount > 0 && supply + _mintAmount <= MAX_ID, "Invalid mint amount");

    for (uint256 i = 0; i < _mintAmount; i++) {
        // 计算当前剩余可选的ID总数
        uint256 remaining = MAX_ID - supply;
        // 生成[0, remaining)区间的随机数,本示例为基础实现,生产环境建议替换为可验证随机源
        uint256 rand = uint256(keccak256(abi.encodePacked(block.prevrandao, block.timestamp, _to, i))) % remaining;
        uint256 currentIndex = supply + rand;

        // 读取选中的tokenId,无置换记录时默认取索引+1(适配ID从1开始的规则)
        uint256 tokenId = _idMap[currentIndex] == 0 ? currentIndex + 1 : _idMap[currentIndex];

        // 将当前选中的位置与剩余区间的最后一个位置置换,避免后续重复抽取
        uint256 lastIndex = MAX_ID - 1 - supply;
        _idMap[currentIndex] = _idMap[lastIndex] == 0 ? lastIndex + 1 : _idMap[lastIndex];

        // 执行mint逻辑
        _safeMint(_to, tokenId);
        // 每成功mint一个,supply自增1,最终总增量等于本次mint数量
        supply++;
    }
}

说明

上述实现无需提前初始化1~4951的全量ID数组,仅在mint时写入mapping记录,gas成本和mint数量成正比,适配NFT等常见mint场景。

注意事项

  • 示例中的随机数生成方式仅做功能演示,直接使用区块变量生成的随机数存在被矿工操纵的风险,生产环境如果需要高安全性的随机数,建议接入可验证随机数服务
  • 逻辑原生保证所有抽取的tokenId都是1~4951区间内的不重复数值,supply累计值等于全合约累计mint的总数量

内容的提问来源于stack exchange,提问作者Haidarali Masu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 20:06:05