以太坊实现盲盒随机NFT

文章介绍了如何在Solidity中开发ERC721NFT,并特别关注了在以太坊网络上生成随机数的问题。由于Solidity本身无法产生真正的随机数,文章推荐使用Chainlink的VRF服务,这是一个链下生成、链上验证的可验证随机数解决方案。还讨论了本地模拟ChainlinkVRF的方法以及合约的部署流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

一个开源solidity合集仓库
https://github.com/qdwds/smart-contracts
以太坊ERC721全栈开发开NFT合集从入门到项目实战项目
https://learnblockchain.cn/course/31
https://edu.51cto.com/course/33566.html

一起学习吧

我们一起沟通、交流、学习吧!

随机NFT

敲黑板solidity无法创建真正意义上的随机数。以太坊每次调用交互函数都是需要gas的,所以复杂的运算成本较高。除此之外还有每个节点如果计算随机数是不一致的,其他节点是无法验证随机数的正确性的。

所以一般使用随机数使用的是chainlink VEF 可验证的随机数。这里我会先介绍一下区块链随机数可能存在的问题

chainlink 随机数

chainlink VRF随机数是链下创建随机值,交给链上合约验证确定可用才发送给合约地址。

原理:用户调用chainlink请求随机数 > 链下预言机生成随机数 > 链上VRF合约验证是否指定算法生成的随机数 > 发送随机数给合约.

在这里插入图片描述

开发本地mock随机数

在使用chainlink随机数的时候,如果一直和链上交互的话,可能会造成时间上的浪费和测试ETH的浪费,所以我们选择本地mock chainlinkVRF随机数,在本地开发使用,等开发完成之后切到测试网络进行测试。

下载chainlink

npm install @chainlink/contracts

mock合约

<!-- VRFCoordinatorV2Mock.sol -->
pragma solidity ^0.8.4;
import "@chainlink/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol";

获取随机数合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "hardhat/console.sol";
contract VRF is  VRFConsumerBaseV2 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdCounter;
    VRFCoordinatorV2Interface COORDINATOR;

    event RequestSent(uint256 requestId, uint32 numWords);

    uint64 s_subscriptionId;    //  subid
    bytes32 keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;   //  请求最大的gas费
    uint32 callbackGasLimit = 1000000;   //  gas费上线 link
    uint16 requestConfirmations = 3;    //  等待区块
    uint32 numWords = 30;    //  请求多少随机数


    constructor(uint64 subscriptionId, address _mockAddress) VRFConsumerBaseV2(_mockAddress) {
        COORDINATOR = VRFCoordinatorV2Interface(_mockAddress);
        s_subscriptionId = subscriptionId;
    }


    // 请求随机数
    function requestRandomWords()external returns (uint256 requestId){
        requestId = COORDINATOR.requestRandomWords(
            keyHash,
            s_subscriptionId,   //  subID
            requestConfirmations,   //  经过几个区块验证
            callbackGasLimit,
            numWords
        );
        emit RequestSent(requestId, numWords);
        return requestId;
    }
    //  接收到随机值的回调函数,本地模拟的话需要自己调用。链上由chainlink调用
    function fulfillRandomWords(
        uint256 _requestId,
        uint256[] memory _randomWords
    ) internal override {
       for(uint i = 0; i < _randomWords.length; i++){
            console.log(_randomWords[i]);
       }
    }

}

合约部署


import { parseUnits } from "ethers/lib/utils";
import { ethers } from "hardhat";
const baseFee = parseUnits("0.0001");   //  节点调用的费用
const gasPriceLink = parseUnits("1","gwei");   //  节点调用的费用


const vrf = async() =>{
    const Mock = await ethers.getContractFactory("VRFCoordinatorV2Mock");
    const mock = await Mock.deploy(
        baseFee,
        gasPriceLink
    )
    await mock.deployed();

    const tx = await mock.createSubscription();
    const txReceipt:any = await tx.wait(1);
    const subId = txReceipt.events[0].topics[1];

    // 模拟充值link
    await mock.fundSubscription(subId, parseUnits("10000"));

    const VRF = await ethers.getContractFactory("VRF");
    const vrf = await VRF.deploy(subId, mock.address);
    await vrf.deployed();

    await mock.addConsumer(subId, vrf.address);
    console.log(mock.address);
    console.log(vrf.address);
    
    const result = await vrf.requestRandomWords();
    const vrfTx:any = await result.wait(4);

    const requestId = vrfTx.events[1].args[0];

    await mock.fulfillRandomWords(requestId, vrf.address);
}


vrf()
    .catch(err =>{
        console.log(err);
        process.exit(1);
    })

获取链上随机数

chainlink 配置随机数 https://vrf.chain.link/goerli

link 水龙头🚰 https://faucets.chain.link/goerli

随机获取NFT

随机NFT是在指定的范围内,根据随机的值创建NFT

稀有NFT

根据产生的随机数出现的机率来创建随机数。
比如: b级出现的机率是50%;a级出现的机率是30%;s级出现的机率是20%;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值