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

如何实现Chainlink VRF功能 铸造NFT时向随机NFT持有人发放铸造费分成

核心问题说明

你当前代码的核心矛盾是Chainlink VRF的请求为异步逻辑,从调用getRandomNumber发起请求到fulfillRandomness收到回调结果,中间需要链下节点运算、上链确认的延迟,不可能在同一次mint交易内拿到随机结果直接完成转账,必须拆分逻辑实现。

调整思路

  • 把「铸造扣取奖励」和「随机选持有人发奖」拆为两个独立步骤:铸造时仅预留对应比例的奖励在合约中,同时发起VRF请求,等VRF回调返回随机数后再执行奖励发放
  • 新增存储结构记录每次VRF请求对应的奖励金额、发起请求时的已发行NFT总量,供回调时直接调用
  • 移除mint函数内的同步转账逻辑,所有奖励转账操作全部放到VRF回调函数中执行

具体代码修改

新增存储变量

// 存储每个VRF请求ID对应的待发放奖励金额
mapping(bytes32 => uint256) public requestIdToReward;
// 存储每个VRF请求ID发起时的已发行NFT总量(即随机抽选的样本池大小)
mapping(bytes32 => uint256) public requestIdToSupply;

修改mint函数

function mint() public payable {
    uint256 supply = totalSupply();
    require(!paused);
    require(supply + 1 <= maxSupply);
    require(msg.value >= cost);

    if (msg.sender != owner()) {
        require(msg.value >= cost);
    }

    _safeMint(msg.sender, supply + 1);

    // 已有存量NFT时才需要发放奖励
    if (supply > 0) {
        // 计算本次待发放的奖励金额
        uint256 reward = ((supply + 1 == 5) || (supply + 1 == 10)) ? address(this).balance * 1 / 100 : msg.value * 10 / 100;
        // 发起VRF请求
        bytes32 requestId = getRandomNumber();
        // 关联本次请求对应的奖励和存量NFT数量
        requestIdToReward[requestId] = reward;
        requestIdToSupply[requestId] = supply;
    } else {
        // 首次铸造无存量持有人,直接请求VRF供下一次铸造发奖使用
        getRandomNumber();
    }
 }

修改fulfillRandomness回调函数

function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
    requestIdToRandomNumber[requestId] = randomness;
    uint256 currentSupply = requestIdToSupply[requestId];
    uint256 reward = requestIdToReward[requestId];
    
    // 仅有效奖励请求执行转账
    if (reward > 0 && currentSupply > 0) {
        // 随机数模存量总量得到选中的tokenId,tokenId从1开始所以结果+1
        uint256 selectedTokenId = (randomness % currentSupply) + 1;
        address payable winner = payable(ownerOf(selectedTokenId));
        (bool success, ) = winner.call{value: reward}("");
        require(success, "Reward transfer failed");
    }
}

注意事项

  • 需提前给合约转入足够的LINK代币支付VRF请求手续费,否则铸造会失败
  • 对公平性要求较高的场景可以使用Chainlink官方的随机数扩展方法避免模运算偏差
  • 可根据需求新增VRF请求失败的兜底逻辑,比如超时未回调允许手动触发重试

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:45:01