[英]Correct way of randomly selecting token Ids from already minted NFTs
我有一個包含1000 個 NFT的 NFT 項目。 作為我項目的一部分,持有 NFT 的用戶將參與抽獎。
我要實現的 function 如下:
Select x 參與抽獎的用戶數。 因此,假設從 1000 個 NFT 中鑄造了500個 NFT ,我希望500 個用戶參與抽獎,我可以選擇任意數量的中獎者。 簡而言之,500 名 NFT 持有者參與抽獎,隨機抽取 10 名 NFT 為獲勝者。
我很幸運地找到了符合我標准的智能合約。
在下面的代碼中, selectWinners()
函數接受一個 uint256 noOfWinners 作為參數,然后為未來的抽獎創建一個日期,並將抽獎加 1。
selectAWinner()
function 循環 x 次 (x = noOfWinners),並隨機選擇獲勝者。
rand()
function 接受隨機地址和隨機數。 我相信這個 function 有助於找到隨機獲勝者。
在下面的代碼中, selectAWinner()
function 生成一個介於 1 到 5000 之間的隨機令牌 id,因為該項目的 maxSupply 是 5000。
我想要的是讓 function 生成介於 1 到 500 之間的隨機令牌 id,因為從 1000 個中鑄造了 500 個 NFT。
我試過的:
在rand()
function 中,我嘗試使用totalSupply
(NFT 鑄造的數量,即 500)而不是maxSupply
。 不幸的是,我遇到了錯誤。
我哪里錯了? 很感謝任何形式的幫助!
function selectWinners(uint256 noOfWinners) public onlyOwner {
require(!paused, "ERROR: Contract is paused");
require(lotteryActive, "ERROR: Lottery not active yet");
require(noOfWinners <= 50, "ERROR: Too many winners selected");
uint256 epochNow = block.timestamp;
uint256 nextLotteryDate = lotteryDates[lotteryDates.length - 1];
require(epochNow >= nextLotteryDate, "ERROR: Cannot draw yet, too early");
for (uint256 i = 0; i < noOfWinners; i++) {
selectAWinner(
0,
epochNow,
msg.sender,
nextLotteryDate,
msg.sender,
0
);
}
lotteryDates.push(epochNow + (epochDay * lotteryIntervalDays));
// increment draw
drawNumber++;
}
function selectAWinner(
uint256 it,
uint256 epochNow,
address sender,
uint256 lotteryDate,
address randomAddr,
uint256 randomNo
) internal {
// Generate random id between 1 - 5000 (corresponds to NFT id)
uint256 winningToken = rand(randomAddr, randomNo);
address winnerAddress = ERC721.ownerOf(winningToken);
uint256 lastWon = _winners[winnerAddress];
bool alreadyWon = (lastWon == lotteryDate);
Winner memory win;
if ((it < 5) && alreadyWon) {
uint256 newIt = it + 1;
return
selectAWinner(
newIt,
epochNow,
sender,
lotteryDate,
winnerAddress,
winningToken
);
} else if ((it >= 5) && alreadyWon) {
return;
} else {
win.date = lotteryDate;
win.winner = winnerAddress;
win.tokenId = winningToken;
winnerLog[drawNumber].push(win);
_winners[winnerAddress] = lotteryDate;
}
return;
}
function rand(address randomAddress, uint256 randomNo) internal view returns (uint256) {
uint256 seed = uint256(
keccak256(
abi.encodePacked(
(block.timestamp - randomNo) +
block.difficulty +
((
uint256(keccak256(abi.encodePacked(block.coinbase)))
) / (block.timestamp)) +
block.gaslimit +
((uint256(keccak256(abi.encodePacked(randomAddress)))) /
(block.timestamp)) +
block.number
)
)
);
return (seed - ((seed / maxSupply) * maxSupply)) + 1;
}
您可能可以通過使用模數 % 運算符來解決這個問題。
https://www.geeksforgeeks.org/solidity-operators/
生成一個隨機數,然后使用與現有 ERC721 NFT 的數量相對應的totalSupply()
的模運算符。 就像是:
uint256 rand = _generateRandomness("rarity") % ERC721.totalSupply();
需要注意的是,如果不使用預言機,在 Solidity 中使用真正的隨機數是不可能的。 最著名和最值得信賴的是 ChainLink 的 RNG。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.