chainlink - Chainlink VRF - 如何检查 fullfillRandomness 结果是否有效
问题描述
我正在研究智能合约以生成具有一些特定规则的随机卡,我试图使用 Chainlink VRF 生成随机数并实现这样的合约。
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.7.4;
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "../utils/Context.sol";
import "../utils/ReentrancyGuard.sol";
import "../utils/Address.sol";
import "../NFT/CardNFTAccessControls.sol";
import "../NFT/CardNFT.sol";
/**
* @notice Factory contract for NFT handling payments on mint
*/
contract NFTFactory is Context, ReentrancyGuard, VRFConsumerBase {
// using SafeMath for uint256;
using Address for address payable;
struct CardInfo {
uint256 num;
uint256 kind;
uint256 value;
uint256 qty;
}
struct NFTInfo {
uint256 edition;
uint256 cardInfoId;
}
struct RequestNFTConfig {
uint256 limit;
bool kind;
uint256 id;
}
event NFTCreated(
uint256 id,
uint256 num,
uint256 kind,
uint256 edition
);
event RandomReturned(
bytes32 requestId,
uint256 randomness
);
/// @notice chainlink rng request value mapping
mapping(bytes32 => RequestNFTConfig) private requestIds;
/// @notice edition number id
uint256 private editionId;
/// @notice for switching off factory functionality
bool public isPaused;
/// @notice responsible for enforcing mint and admin role
CardNFTAccessControls accessControls;
/// @notice NFT contract
CardNFT cardNFT;
/// @notice platform fee recipient address which will accept all fees and mint price
address payable platformFeeRecipient;
/// @notice keyhash for chainlink rng generator
bytes32 internal keyHash;
/// @notice fee for chainlink rng generator
uint256 internal rngFee;
/// @notice rng generator result
uint256 public randomResult;
/// @notice deck card information for calculation
mapping(uint256 => CardInfo) deckInfo;
/// @notice nft array
mapping(uint256 => NFTInfo) nfts;
modifier whenNotPaused() {
require(!isPaused, "Function is currently paused");
_;
}
constructor(
CardNFTAccessControls _accessControls,
CardNFT _cardNFT,
address payable _platformFeeRecipient
) VRFConsumerBase(
0xa555fC018435bef5A13C6c6870a9d4C11DEC329C,
0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06
) {
require(address(_accessControls) != address(0), "NFTFactory: Invalid Access Controls");
require(address(_cardNFT) != address(0), "NFTFactory: Invalid NFT");
require(_platformFeeRecipient != address(0), "NFTFactory: Invalid platform Fee recipient");
accessControls = _accessControls;
cardNFT = _cardNFT;
platformFeeRecipient = _platformFeeRecipient;
keyHash = 0xcaf3c3727e033261d383b315559476f48034c13b18f8cafed4d871abe5049186;
rngFee = 0.1 * 10 ** 18; // 0.1 LINK
}
/**
@notice create one NFT
@param _limit min or maximum number of card
@param _kind limit kind with lower or higher
@param _price price of NFT mint
@param _amount amount of NFTs to mint
@param _data additional data to leave
*/
function create(uint256 _limit, bool _kind, uint256 _price, uint256 _amount, bytes memory _data) external payable nonReentrant whenNotPaused {
require(_msgSender().isContract() == false, "Factory.create: No contracts are permitted");
require(_msgSender() != address(0), "Factory.create: sender address is ZERO");
uint256 buyPrice = msg.value;
require(buyPrice >= _price, "Factory.create: payment should be same to original price");
// (bool platformTransferSuccess,) = platformFeeRecipient.call{value : buyPrice}("");
// require(platformTransferSuccess, "Factory.mintPayment: Failed to send platform fee");
address creator = _msgSender();
if(_amount > 1) {
uint256[] memory _ids = cardNFT.batchMint(creator, _amount, _data);
require(_amount == _ids.length, "Factory.create: should batch mint same amount of nfts");
for(uint256 i=0; i<_ids.length; i++) {
getRandomNumber(_ids[i], _limit, _kind);
}
} else {
uint256 id = cardNFT.mint(creator, _data);
getRandomNumber(id, _limit, _kind);
}
}
/**
@notice generate actual NFT info
@param _requestId request id for chainlink rng
@param _randomness random number which return from chainlink org
*/
function generateNFTInfo(bytes32 _requestId, uint256 _randomness) private {
RequestNFTConfig storage config = requestIds[_requestId];
uint256 total = getTotalQtyToNumber(config.limit);
bool _kind = config.kind;
uint256 rngResult = 0;
if(_kind) {
rngResult = _randomness * (200000 - total) + total;
} else {
rngResult = _randomness * total;
}
uint256 cardInfoId = getNearestQtyCard(rngResult);
NFTInfo storage nft = nfts[config.id];
uint256 edition = _getNextEditionID();
_incrementEditionId();
nft.edition = edition;
nft.cardInfoId = cardInfoId;
CardInfo storage cardInfo = deckInfo[cardInfoId];
emit NFTCreated(config.id, cardInfo.num, cardInfo.kind, edition);
}
/**
* Requests randomness
*/
function getRandomNumber(uint256 _id, uint256 _limit, bool _kind) private {
require(LINK.balanceOf(address(this)) >= rngFee, "Not enough LINK - fill contract with faucet");
bytes32 requestId = requestRandomness(keyHash, rngFee);
RequestNFTConfig storage config = requestIds[requestId];
config.id = _id;
config.kind = _kind;
config.limit = _limit;
}
/**
* Callback function used by VRF Coordinator
*/
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
emit RandomReturned(requestId, randomness);
generateNFTInfo(requestId, randomness);
}
......
}
我在 BSC 测试网上试过这个,但没有RandomReturned事件日志,也没有更新 generateNFTInfo 函数。此外,我不确定如何在本地测试单元测试而不在本地安装 chainlink-node。有人可以帮我解决这个问题吗?
解决方案
我以为我遇到了同样的问题,但是,我发现根据网络拥塞生成随机数可能需要 2 分钟以上。我正在 Rinkeby 网络中进行测试。
推荐阅读
- css - 如何使用 CSS 对图像进行四舍五入
- algorithm - 使用尾递归在 Scala 中实现 isPrime
- php - 为数据透视表生成控件
- javascript - 将动态 HTML 页面转换为 React/JSX
- python - 如何为不同的区域添加颜色
- python - Python 的 id() 方法提供的内存地址是绝对的还是相对于某个会话的?
- apache-kafka - 生产者和消费者仅在 1 个端口上工作
- javascript - 使用 localStorage 的待办事项列表
- javascript - 如果 React Native 中没有互联网连接,则获取存储数据
- ios - 我需要什么类型的工具来构建一个简单的 react-native 多人纸牌游戏?