-
Notifications
You must be signed in to change notification settings - Fork 0
/
RandomIpfsNft.sol
138 lines (119 loc) · 4.71 KB
/
RandomIpfsNft.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "hardhat/console.sol";
error RandomIpfsNft__AlreadyInitialized();
error RandomIpfsNft__NeedMoreETHSent();
error RandomIpfsNft__RangeOutOfBounds();
error RandomIpfsNft__TransferFailed();
contract RandomIpfsNft is ERC721URIStorage, VRFConsumerBaseV2, Ownable {
// Types
enum Breed {
PUG,
SHIBA_INU,
ST_BERNARD
}
// Chainlink VRF Variables
VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
uint64 private immutable i_subscriptionId;
bytes32 private immutable i_gasLane;
uint32 private immutable i_callbackGasLimit;
uint16 private constant REQUEST_CONFIRMATIONS = 3;
uint32 private constant NUM_WORDS = 1;
// NFT Variables
uint256 private immutable i_mintFee;
uint256 private s_tokenCounter;
uint256 internal constant MAX_CHANCE_VALUE = 100;
string[] internal s_dogTokenUris;
bool private s_initialized;
// VRF Helpers
mapping(uint256 => address) public s_requestIdToSender;
// Events
event NftRequested(uint256 indexed requestId, address requester);
event NftMinted(Breed breed, address minter);
constructor(
address vrfCoordinatorV2,
uint64 subscriptionId,
bytes32 gasLane, // keyHash
uint256 mintFee,
uint32 callbackGasLimit,
string[3] memory dogTokenUris
) VRFConsumerBaseV2(vrfCoordinatorV2) ERC721("Random IPFS NFT", "RIN") {
i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
i_gasLane = gasLane;
i_subscriptionId = subscriptionId;
i_mintFee = mintFee;
i_callbackGasLimit = callbackGasLimit;
_initializeContract(dogTokenUris);
}
function requestNft() public payable returns (uint256 requestId) {
if (msg.value < i_mintFee) {
revert RandomIpfsNft__NeedMoreETHSent();
}
requestId = i_vrfCoordinator.requestRandomWords(
i_gasLane,
i_subscriptionId,
REQUEST_CONFIRMATIONS,
i_callbackGasLimit,
NUM_WORDS
);
s_requestIdToSender[requestId] = msg.sender;
emit NftRequested(requestId, msg.sender);
}
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
address dogOwner = s_requestIdToSender[requestId];
uint256 newItemId = s_tokenCounter;
s_tokenCounter = s_tokenCounter + 1;
uint256 moddedRng = randomWords[0] % MAX_CHANCE_VALUE;
Breed dogBreed = getBreedFromModdedRng(moddedRng);
_safeMint(dogOwner, newItemId);
_setTokenURI(newItemId, s_dogTokenUris[uint256(dogBreed)]);
emit NftMinted(dogBreed, dogOwner);
}
function getChanceArray() public pure returns (uint256[3] memory) {
return [10, 40, MAX_CHANCE_VALUE];
}
function _initializeContract(string[3] memory dogTokenUris) private {
if (s_initialized) {
revert RandomIpfsNft__AlreadyInitialized();
}
s_dogTokenUris = dogTokenUris;
s_initialized = true;
}
function getBreedFromModdedRng(uint256 moddedRng) public pure returns (Breed) {
uint256 cumulativeSum = 0;
uint256[3] memory chanceArray = getChanceArray();
for (uint256 i = 0; i < chanceArray.length; i++) {
// Pug = 0 - 9 (10%)
// Shiba-inu = 10 - 39 (30%)
// St. Bernard = 40 = 99 (60%)
if (moddedRng >= cumulativeSum && moddedRng < chanceArray[i]) {
return Breed(i);
}
cumulativeSum = chanceArray[i];
}
revert RandomIpfsNft__RangeOutOfBounds();
}
function withdraw() public onlyOwner {
uint256 amount = address(this).balance;
(bool success, ) = payable(msg.sender).call{value: amount}("");
if (!success) {
revert RandomIpfsNft__TransferFailed();
}
}
function getMintFee() public view returns (uint256) {
return i_mintFee;
}
function getDogTokenUris(uint256 index) public view returns (string memory) {
return s_dogTokenUris[index];
}
function getInitialized() public view returns (bool) {
return s_initialized;
}
function getTokenCounter() public view returns (uint256) {
return s_tokenCounter;
}
}