├── HodlNFT.sol ├── ReentrancyGuard.sol ├── HodlLottery.sol ├── HodlNFT_flat.sol └── HodlLottery_flat.sol /HodlNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/utils/Strings.sol"; 5 | import "@openzeppelin/contracts/utils/Address.sol"; 6 | import "@openzeppelin/contracts/utils/Counters.sol"; 7 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 8 | import "@openzeppelin/contracts/access/Ownable.sol"; 9 | 10 | contract HodlNFT is ERC721, Ownable { 11 | address private RewardWallet; 12 | 13 | event SetHodlNFTPrice(address addr, uint256 newNFTPrice); 14 | event SetBaseURI(address addr, string newUri); 15 | event SetHodlNFTURI(address addr, string newUri); 16 | event SetRewardWalletAddress(address addr, address rewardWallet); 17 | 18 | using Strings for uint256; 19 | 20 | uint256 private HODL_NFT_PRICE = 10; //HODL token 21 | 22 | using Counters for Counters.Counter; 23 | Counters.Counter private _hodlTokenCounter; 24 | 25 | string private _baseURIExtended; 26 | 27 | string private hodlNFTURI; 28 | 29 | /** 30 | * @dev Throws if called by any account other than the multi-signer. 31 | */ 32 | // modifier onlyMultiSignWallet() { 33 | // require(owner() == _msgSender(), "Multi-signer: caller is not the multi-signer"); 34 | // _; 35 | // } 36 | 37 | constructor() ERC721("HODL NFT","HNFT") { 38 | _baseURIExtended = "https://ipfs.infura.io/"; 39 | } 40 | 41 | function setRewardWalletAddress(address _newRewardWallet) external onlyOwner{ 42 | RewardWallet = _newRewardWallet; 43 | emit SetRewardWalletAddress(msg.sender, _newRewardWallet); 44 | } 45 | 46 | //Set, Get Price Func 47 | function setHodlNFTPrice(uint256 _newNFTValue) external onlyOwner{ 48 | HODL_NFT_PRICE = _newNFTValue; 49 | emit SetHodlNFTPrice(msg.sender, _newNFTValue); 50 | } 51 | 52 | function getHodlNFTPrice() external view returns(uint256){ 53 | return HODL_NFT_PRICE; 54 | } 55 | 56 | function getHodlNFTURI() external view returns(string memory){ 57 | return hodlNFTURI; 58 | } 59 | 60 | function setHodlNFTURI(string memory _hodlNFTURI) external onlyOwner{ 61 | hodlNFTURI = _hodlNFTURI; 62 | emit SetHodlNFTURI(msg.sender, hodlNFTURI); 63 | } 64 | 65 | /** 66 | * @dev Mint NFT by customer 67 | */ 68 | function mintNFT(address sender) external returns (uint256) { 69 | 70 | require( msg.sender == RewardWallet, "you can't mint from other account"); 71 | 72 | // Incrementing ID to create new token 73 | uint256 newHodlNFTID = _hodlTokenCounter.current(); 74 | _hodlTokenCounter.increment(); 75 | 76 | _safeMint(sender, newHodlNFTID); 77 | return newHodlNFTID; 78 | } 79 | 80 | /** 81 | * @dev Return the base URI 82 | */ 83 | function _baseURI() internal override view returns (string memory) { 84 | return _baseURIExtended; 85 | } 86 | 87 | /** 88 | * @dev Set the base URI 89 | */ 90 | function setBaseURI(string memory baseURI_) external onlyOwner() { 91 | _baseURIExtended = baseURI_; 92 | emit SetBaseURI(msg.sender, baseURI_); 93 | } 94 | } -------------------------------------------------------------------------------- /ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) 3 | 4 | pragma solidity 0.8.7; 5 | 6 | /** 7 | * @dev Contract module that helps prevent reentrant calls to a function. 8 | * 9 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 10 | * available, which can be applied to functions to make sure there are no nested 11 | * (reentrant) calls to them. 12 | * 13 | * Note that because there is a single `nonReentrant` guard, functions marked as 14 | * `nonReentrant` may not call one another. This can be worked around by making 15 | * those functions `private`, and then adding `external` `nonReentrant` entry 16 | * points to them. 17 | * 18 | * TIP: If you would like to learn more about reentrancy and alternative ways 19 | * to protect against it, check out our blog post 20 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 21 | */ 22 | abstract contract ReentrancyGuard { 23 | // Booleans are more expensive than uint256 or any type that takes up a full 24 | // word because each write operation emits an extra SLOAD to first read the 25 | // slot's contents, replace the bits taken up by the boolean, and then write 26 | // back. This is the compiler's defense against contract upgrades and 27 | // pointer aliasing, and it cannot be disabled. 28 | 29 | // The values being non-zero value makes deployment a bit more expensive, 30 | // but in exchange the refund on every call to nonReentrant will be lower in 31 | // amount. Since refunds are capped to a percentage of the total 32 | // transaction's gas, it is best to keep them low in cases like this one, to 33 | // increase the likelihood of the full refund coming into effect. 34 | uint256 private constant _NOT_ENTERED = 1; 35 | uint256 private constant _ENTERED = 2; 36 | 37 | uint256 private _status; 38 | uint256 private _statusSelectWinner; 39 | uint256 private _statusGivePriceToWinner; 40 | 41 | constructor() { 42 | _status = _NOT_ENTERED; 43 | _statusSelectWinner = _NOT_ENTERED; 44 | _statusGivePriceToWinner = _NOT_ENTERED; 45 | } 46 | 47 | /** 48 | * @dev Prevents a contract from calling itself, directly or indirectly. 49 | * Calling a `nonReentrant` function from another `nonReentrant` 50 | * function is not supported. It is possible to prevent this from happening 51 | * by making the `nonReentrant` function external, and making it call a 52 | * `private` function that does the actual work. 53 | */ 54 | modifier nonReentrant() { 55 | // On the first call to nonReentrant, _notEntered will be true 56 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 57 | 58 | // Any calls to nonReentrant after this point will fail 59 | _status = _ENTERED; 60 | 61 | _; 62 | 63 | // By storing the original value once again, a refund is triggered (see 64 | // https://eips.ethereum.org/EIPS/eip-2200) 65 | _status = _NOT_ENTERED; 66 | } 67 | 68 | modifier nonReentrantSelectWinner() { 69 | // On the first call to nonReentrant, _notEntered will be true 70 | require(_statusSelectWinner != _ENTERED, "ReentrancyGuard: reentrant call"); 71 | 72 | // Any calls to nonReentrant after this point will fail 73 | _statusSelectWinner = _ENTERED; 74 | 75 | _; 76 | 77 | // By storing the original value once again, a refund is triggered (see 78 | // https://eips.ethereum.org/EIPS/eip-2200) 79 | _statusSelectWinner = _NOT_ENTERED; 80 | } 81 | 82 | modifier nonReentrantGivePriceToWinner() { 83 | // On the first call to nonReentrant, _notEntered will be true 84 | require(_statusGivePriceToWinner != _ENTERED, "ReentrancyGuard: reentrant call"); 85 | 86 | // Any calls to nonReentrant after this point will fail 87 | _statusGivePriceToWinner = _ENTERED; 88 | 89 | _; 90 | 91 | // By storing the original value once again, a refund is triggered (see 92 | // https://eips.ethereum.org/EIPS/eip-2200) 93 | _statusGivePriceToWinner = _NOT_ENTERED; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /HodlLottery.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.7; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | // import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 7 | import "./ReentrancyGuard.sol"; 8 | import "./HodlNFT.sol"; 9 | 10 | contract HodlLottery is Ownable, ReentrancyGuard { 11 | // 2 kinds of lottery 12 | enum LOTTERY_TYPE { 13 | LOTTERY_WEEKLY, 14 | LOTTERY_BI_DAILY 15 | } 16 | 17 | // lottery status 18 | enum LOTTERY_STATUS { 19 | LOTTERY_START, 20 | LOTTERY_CLOSED, 21 | LOTTERY_PICKED 22 | } 23 | 24 | // team funds wallet address 25 | address payable _teamFundsWallet = payable(0xbAB8E9cA493E21d5A3f3e84877Ba514c405be0e1); 26 | 27 | // private seed data for claculating picked number 28 | uint256 private constant MAX_UINT_VALUE = (2**255 - 1 + 2**255); 29 | uint256 private pri_seedValue; 30 | string private pri_seedString; 31 | address private pri_seedAddress; 32 | 33 | // distribution percentage of funds 34 | uint256 constant REWARD_FOR_TEAM_FUND = 1; // 10% goes to team funds 35 | uint256 constant REWARD_FOR_REWARD_POOL = 9; // 90% goes to rewards pool 36 | uint256 constant LOTTERY_FEE = 1; // 10% goes to team funds 37 | 38 | // price of ticket 39 | uint256 PRICE_TICKET_WEEKLY = 1 * 10 ** 17; // 0.1 AVAX 40 | uint256 PRICE_TICKET_BI_DAILY = 3 * 10 ** 16; // 0.03 AVAX 41 | 42 | // lottery loop time 43 | uint256 WEEKLY_LOOP_TIME = 60 * 60 * 24 * 7; // 7 days 44 | uint256 BI_DAILY_LOOP_TIME = 60 * 60 * 24 * 2; // 2 days 45 | 46 | // this is for first lottery 47 | uint256 constant TEMPORARY_TIME = 60 * 60 * 5; // 5 hour 48 | 49 | // when user buy ticket, NFT is minted 50 | HodlNFT public nftContract; 51 | 52 | // this is for get user ticket numbers 53 | struct Ticket_Address { 54 | uint256 timestamp; 55 | uint16 startNumber; 56 | uint16 count; 57 | } 58 | 59 | // return ticket status 60 | struct Ret_Ticket_Status { 61 | LOTTERY_STATUS status; 62 | uint256 totalCount; 63 | uint256 poolAmount; 64 | } 65 | 66 | // there are 2 kinds of lottery 67 | // weekly lottery: per week 68 | // bi-daily lottery: per bi-daily 69 | struct Lottery_Info { 70 | uint256 lotteryID; // lottery id 71 | LOTTERY_STATUS lotteryStatus; // current status of lottery 72 | uint256 lotteryTimeStamp; // lottery time stamp 73 | uint256 poolAmount; // all amount of inputed AVAX 74 | uint16[] ids; // start ids of tickes user bought 75 | uint16 winnerID; 76 | uint256 winnerPrize; 77 | mapping(uint16 => address) members; // address of start id 78 | mapping(uint16 => uint16) ticketsOfMember; // ticket ids of members 79 | } 80 | 81 | // lottery infos of weekly lottery 82 | mapping(uint256 => Lottery_Info) internal allWeeklyLotteryInfos; 83 | 84 | // lottery infos of bi-daily lottery 85 | mapping(uint256 => Lottery_Info) internal allBiDailyLotteryInfos; 86 | 87 | // last available lottery id 88 | uint256 public weeklyLotteryCounter; 89 | uint256 public biDailyLotteryCounter; 90 | 91 | // this is sum of total payout 92 | uint256 public totalMarketcap; 93 | 94 | // invest amount current site was paid 95 | uint256 private totalInvestments; 96 | 97 | // all events 98 | event Received (address from, uint amount); 99 | event Fallback (address from, uint amount); 100 | event SetTeamFundsAddress (address addr); 101 | event SetWeeklyTicketPrice (uint256 price); 102 | event SetBiDailyTicketPrice (uint256 price); 103 | event ChangeLotteryInfo (LOTTERY_TYPE lottery_type, uint256 lottery_id, LOTTERY_STATUS status, uint256 time); 104 | event ClearLotteryInfo (LOTTERY_TYPE lottery_type, uint256 lottery_id); 105 | event CreateNewLotteryInfo (LOTTERY_TYPE lottery_type, uint256 lottery_id, LOTTERY_STATUS status); 106 | event BuyTicket (address addr, LOTTERY_TYPE lottery_type, uint256 lottery_id, uint256 time, uint16 startNo, uint16 count); 107 | event LogAllSeedValueChanged (address addr, uint256 seed1, uint256 seed2, string seed3, address seed4); 108 | event SelectWinner (LOTTERY_TYPE lottery_type, uint256 lottery_id, uint256 time, address addr, uint256 ticketID, uint256 price); 109 | event GivePriceToWinner(LOTTERY_TYPE lottery_type, uint256 lottery_id, address addr, uint256 time, uint256 ticketID, uint256 amount); 110 | event SetWeeklyLoopTime (uint256 loopTime); 111 | event SetBiDailyLoopTime (uint256 loopTime); 112 | event SetTotalInvestment (uint256 loopTime); 113 | event SetLotteryStatus (LOTTERY_TYPE lottery_type, uint256 lottery_id); 114 | event WithdrawAll (address addr, uint256 balance); 115 | 116 | // contructor 117 | constructor ( 118 | uint256 _seedValue, 119 | string memory _seedString, 120 | address _seedAddress, 121 | address _nftContract 122 | ) 123 | { 124 | pri_seedValue = _seedValue; 125 | pri_seedString = _seedString; 126 | pri_seedAddress = _seedAddress; 127 | 128 | weeklyLotteryCounter = 0; 129 | biDailyLotteryCounter = 0; 130 | 131 | nftContract = HodlNFT(_nftContract); 132 | } 133 | 134 | receive() external payable { 135 | emit Received(msg.sender, msg.value); 136 | } 137 | 138 | fallback() external payable { 139 | emit Fallback(msg.sender, msg.value); 140 | } 141 | 142 | function setTeamFundsAddress (address _addr) external onlyOwner { 143 | _teamFundsWallet = payable(_addr); 144 | emit SetTeamFundsAddress (_teamFundsWallet); 145 | } 146 | 147 | function getTeamFundsAddress () external view returns (address) { 148 | return _teamFundsWallet; 149 | } 150 | 151 | function setWeeklyTicketPrice (uint256 _ticketPrice) external onlyOwner { 152 | PRICE_TICKET_WEEKLY = _ticketPrice; 153 | emit SetWeeklyTicketPrice (_ticketPrice); 154 | } 155 | 156 | function getWeeklyTicketPrice () external view returns (uint256) { 157 | return PRICE_TICKET_WEEKLY; 158 | } 159 | 160 | function setBiDailyTicketPrice (uint256 _ticketPrice) external onlyOwner { 161 | PRICE_TICKET_BI_DAILY = _ticketPrice; 162 | emit SetBiDailyTicketPrice (_ticketPrice); 163 | } 164 | 165 | function getBiDailyTicketPrice () external view returns (uint256) { 166 | return PRICE_TICKET_BI_DAILY; 167 | } 168 | 169 | function setWeeklyLoopTime (uint256 _time) external onlyOwner { 170 | WEEKLY_LOOP_TIME = _time; 171 | emit SetWeeklyLoopTime (WEEKLY_LOOP_TIME); 172 | } 173 | 174 | function getWeeklyLoopTime () external view returns (uint256) { 175 | return WEEKLY_LOOP_TIME; 176 | } 177 | 178 | function setBiDailyLoopTime (uint256 _time) external onlyOwner { 179 | BI_DAILY_LOOP_TIME = _time; 180 | emit SetBiDailyLoopTime (BI_DAILY_LOOP_TIME); 181 | } 182 | 183 | function getBiDailyLoopTime () external view returns (uint256) { 184 | return BI_DAILY_LOOP_TIME; 185 | } 186 | 187 | function setTotalInvestment (uint256 _value) external onlyOwner { 188 | totalInvestments = _value; 189 | emit SetTotalInvestment (totalInvestments); 190 | } 191 | 192 | function getTotalInvestment () external view returns (uint256) { 193 | return totalInvestments; 194 | } 195 | 196 | function withdrawAll() external onlyOwner{ 197 | uint256 balance = address(this).balance; 198 | address payable mine = payable(msg.sender); 199 | if(balance > 0) { 200 | mine.transfer(balance); 201 | } 202 | emit WithdrawAll(msg.sender, balance); 203 | } 204 | 205 | // admin can oly change status and timestamp of started lottery 206 | function changeLotteryInfo (LOTTERY_TYPE _lotteryType, uint256 _lotteryID, LOTTERY_STATUS _status, uint256 _timestamp) external onlyOwner { 207 | Lottery_Info storage lottoInfo; 208 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 209 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 210 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 211 | } 212 | else { 213 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 214 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 215 | } 216 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "admin can't change data"); 217 | 218 | lottoInfo.lotteryStatus = _status; 219 | lottoInfo.lotteryTimeStamp = _timestamp; 220 | 221 | emit ChangeLotteryInfo (_lotteryType, _lotteryID, _status, _timestamp); 222 | } 223 | 224 | // admin can remove lottery 225 | function clearLotteryInfo (LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external onlyOwner { 226 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 227 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 228 | delete allWeeklyLotteryInfos[_lotteryID]; 229 | weeklyLotteryCounter --; 230 | } 231 | else { 232 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 233 | delete allBiDailyLotteryInfos[_lotteryID]; 234 | biDailyLotteryCounter --; 235 | } 236 | 237 | emit ClearLotteryInfo (_lotteryType, _lotteryID); 238 | } 239 | 240 | // only owner can create new lottery 241 | function createNewLotteryInfo (LOTTERY_TYPE lottery_type) external onlyOwner { 242 | require (lottery_type <= LOTTERY_TYPE.LOTTERY_BI_DAILY, "This lottery doesn't exist"); 243 | Lottery_Info storage newLottery; 244 | uint256 nLotteryTime = block.timestamp + TEMPORARY_TIME; 245 | uint256 poolAmount = 0; 246 | if (lottery_type == LOTTERY_TYPE.LOTTERY_WEEKLY) { 247 | if (weeklyLotteryCounter > 0) { 248 | require(allWeeklyLotteryInfos[weeklyLotteryCounter - 1].lotteryStatus == LOTTERY_STATUS.LOTTERY_PICKED, "Previous lottery doesn't complete."); 249 | nLotteryTime = allWeeklyLotteryInfos[weeklyLotteryCounter - 1].lotteryTimeStamp + WEEKLY_LOOP_TIME; 250 | 251 | // previous pool amount goes to next lottery 252 | poolAmount = allWeeklyLotteryInfos[weeklyLotteryCounter - 1].poolAmount; 253 | allWeeklyLotteryInfos[weeklyLotteryCounter - 1].poolAmount = 0; 254 | } 255 | newLottery = allWeeklyLotteryInfos[weeklyLotteryCounter]; 256 | newLottery.lotteryID = weeklyLotteryCounter; 257 | weeklyLotteryCounter ++; 258 | } 259 | else { 260 | if (biDailyLotteryCounter > 0) { 261 | require(allBiDailyLotteryInfos[biDailyLotteryCounter - 1].lotteryStatus == LOTTERY_STATUS.LOTTERY_PICKED, "Previous lottery doesn't complete."); 262 | nLotteryTime = allBiDailyLotteryInfos[biDailyLotteryCounter - 1].lotteryTimeStamp + BI_DAILY_LOOP_TIME; 263 | 264 | // previous pool amount goes to next lottery 265 | poolAmount = allBiDailyLotteryInfos[biDailyLotteryCounter - 1].poolAmount; 266 | allBiDailyLotteryInfos[biDailyLotteryCounter - 1].poolAmount = 0; 267 | } 268 | newLottery = allBiDailyLotteryInfos[biDailyLotteryCounter]; 269 | newLottery.lotteryID = biDailyLotteryCounter; 270 | biDailyLotteryCounter ++; 271 | } 272 | newLottery.lotteryStatus = LOTTERY_STATUS.LOTTERY_START; 273 | newLottery.lotteryTimeStamp = nLotteryTime; 274 | newLottery.poolAmount = poolAmount; 275 | newLottery.ids.push(1); 276 | newLottery.members[1] = address(msg.sender); 277 | newLottery.ticketsOfMember[1] = 0; 278 | 279 | emit CreateNewLotteryInfo (lottery_type, newLottery.lotteryID, LOTTERY_STATUS.LOTTERY_START); 280 | } 281 | 282 | // Get remain time of last lottery 283 | function getLotteryRemainTime(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external view returns(uint256) { 284 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 285 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 286 | if (allWeeklyLotteryInfos[_lotteryID].lotteryTimeStamp <= block.timestamp) { 287 | return 0; 288 | } 289 | return allWeeklyLotteryInfos[_lotteryID].lotteryTimeStamp - block.timestamp; 290 | } 291 | else { 292 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 293 | if (allBiDailyLotteryInfos[_lotteryID].lotteryTimeStamp <= block.timestamp) { 294 | return 0; 295 | } 296 | return allBiDailyLotteryInfos[_lotteryID].lotteryTimeStamp - block.timestamp; 297 | } 298 | } 299 | 300 | // set lottery status after lottery time 301 | function setLotteryStatus(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external onlyOwner returns(bool) { 302 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 303 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 304 | require(allWeeklyLotteryInfos[_lotteryID].lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "This Lottery Status is not Start."); 305 | require(allWeeklyLotteryInfos[_lotteryID].ids.length > 1, "User has to buy Ticket"); 306 | if (allWeeklyLotteryInfos[weeklyLotteryCounter - 1].lotteryTimeStamp <= block.timestamp) { 307 | allWeeklyLotteryInfos[_lotteryID].lotteryStatus = LOTTERY_STATUS.LOTTERY_CLOSED; 308 | allWeeklyLotteryInfos[_lotteryID].lotteryTimeStamp = block.timestamp; 309 | } 310 | } 311 | else { 312 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 313 | require(allBiDailyLotteryInfos[_lotteryID].lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "This Lottery Status is not Start."); 314 | require(allBiDailyLotteryInfos[_lotteryID].ids.length > 1, "User has to buy Ticket"); 315 | if (allBiDailyLotteryInfos[biDailyLotteryCounter - 1].lotteryTimeStamp <= block.timestamp) { 316 | allBiDailyLotteryInfos[_lotteryID].lotteryStatus = LOTTERY_STATUS.LOTTERY_CLOSED; 317 | allBiDailyLotteryInfos[_lotteryID].lotteryTimeStamp = block.timestamp; 318 | } 319 | } 320 | 321 | emit SetLotteryStatus (_lotteryType, _lotteryID); 322 | return true; 323 | } 324 | 325 | // get full information of _lotteryID 326 | function getLottoryInfo(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external view returns( 327 | uint256, // startingTimestamp 328 | uint16, // winnerID 329 | address, // winnerAddress 330 | uint256, // PoolAmountInAVAX 331 | uint16, // NumberOfLottoMembers 332 | uint256 // winnerPrize 333 | ) 334 | { 335 | Lottery_Info storage lottoInfo; 336 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 337 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 338 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 339 | } 340 | else { 341 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 342 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 343 | } 344 | uint256 lotteryTimeStamp = lottoInfo.lotteryTimeStamp; 345 | uint16 winnerID = lottoInfo.winnerID; 346 | address winnerAddress = lottoInfo.members[lottoInfo.winnerID]; 347 | uint256 poolAmount = lottoInfo.poolAmount; 348 | uint16 NumberOfLottoMembers = uint16(lottoInfo.ids.length - 1); 349 | uint256 winnerPrize = lottoInfo.winnerPrize; 350 | return ( 351 | lotteryTimeStamp, 352 | winnerID, 353 | winnerAddress, 354 | poolAmount, 355 | NumberOfLottoMembers, 356 | winnerPrize 357 | ); 358 | } 359 | 360 | function buyTicket(LOTTERY_TYPE _lotteryType, uint256 _lotteryID, uint16 _numberOfTickets) external payable { 361 | uint256 payAmount; 362 | Lottery_Info storage lottoInfo; 363 | require(_numberOfTickets > 0, "User has to input ticket number."); 364 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 365 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 366 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 367 | payAmount = PRICE_TICKET_WEEKLY * _numberOfTickets; 368 | } 369 | else { 370 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 371 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 372 | payAmount = PRICE_TICKET_BI_DAILY * _numberOfTickets; 373 | } 374 | require(lottoInfo.lotteryTimeStamp >= block.timestamp, "Time is up"); 375 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "Lottery doesn't start."); 376 | 377 | // pay AVAX for ticket 378 | require(msg.value == payAmount, "no enough balance"); 379 | _teamFundsWallet.transfer(payAmount * REWARD_FOR_TEAM_FUND / 10); 380 | payable(address(this)).transfer(payAmount * REWARD_FOR_REWARD_POOL / 10); 381 | lottoInfo.poolAmount += payAmount * REWARD_FOR_REWARD_POOL / 10; 382 | 383 | // insert data into lottery info 384 | uint16 numTickets = _numberOfTickets; 385 | for (uint i = 0; i < numTickets; i ++) { 386 | nftContract.mintNFT(msg.sender); 387 | } 388 | uint16 lastID = lottoInfo.ids[lottoInfo.ids.length - 1]; 389 | uint16 newID = lastID + lottoInfo.ticketsOfMember[lastID]; 390 | 391 | // first 10 users can get 2 times chance than others in weekly lottery 392 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY && lottoInfo.ids.length <= 10) { 393 | numTickets = _numberOfTickets * 2; 394 | } 395 | 396 | lottoInfo.ids.push(newID); 397 | lottoInfo.members[newID] = address(msg.sender); 398 | lottoInfo.ticketsOfMember[newID] = numTickets; 399 | 400 | // insert blank ticket into lottery address 401 | lastID = lottoInfo.ids[lottoInfo.ids.length - 1]; 402 | uint16 blank_newID = lastID + lottoInfo.ticketsOfMember[lastID]; 403 | 404 | lottoInfo.ids.push(blank_newID); 405 | lottoInfo.members[blank_newID] = address(this); 406 | lottoInfo.ticketsOfMember[blank_newID] = _numberOfTickets; 407 | 408 | emit BuyTicket(msg.sender, _lotteryType, _lotteryID, block.timestamp, newID, numTickets); 409 | } 410 | 411 | // Generate random number base on seed and timestamp. 412 | function randomNumberGenerate(LOTTERY_TYPE _lotteryType) private view returns (uint16) { 413 | // random hash from seed data 414 | uint randomHash = uint(keccak256(abi.encodePacked(pri_seedValue, pri_seedString, pri_seedAddress, 415 | block.timestamp, block.difficulty, block.number))); 416 | 417 | Lottery_Info storage lottoInfo; 418 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 419 | lottoInfo = allWeeklyLotteryInfos[weeklyLotteryCounter - 1]; 420 | } 421 | else { 422 | lottoInfo = allBiDailyLotteryInfos[biDailyLotteryCounter - 1]; 423 | } 424 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_CLOSED, "Lottery doesn't close."); 425 | 426 | // generate random number 427 | uint16 lastID = uint16(lottoInfo.ids.length - 1); 428 | uint16 totalMembers = lottoInfo.ids[lastID] + lottoInfo.ticketsOfMember[lottoInfo.ids[lastID]] - 1; 429 | uint256 maxValue = MAX_UINT_VALUE / totalMembers; 430 | uint16 randomNum = uint16(randomHash / maxValue) + 1; 431 | if (randomNum > totalMembers) { 432 | randomNum = 1; 433 | } 434 | 435 | return randomNum; 436 | } 437 | 438 | // only user can change seed data 439 | function updateSeeds(uint256 _seedValue, string memory _seedString, address _seedAddress ) external onlyOwner returns(bool) { 440 | // seed value check 441 | require(_seedValue != 0 && _seedValue != pri_seedValue, 442 | "The seed value can't be 0 value and can't be the same as the previous one."); 443 | 444 | // seed address check 445 | require(_seedAddress != address(0) && _seedAddress != pri_seedAddress, 446 | "The seed Address can't be 0 Address and can't be the same as the previous one."); 447 | 448 | // seed string check 449 | require(keccak256(abi.encodePacked(_seedString)) != 0 && 450 | keccak256(abi.encodePacked(_seedString)) != keccak256(abi.encodePacked(pri_seedString)), 451 | "The seed String can't be 0 String and can't be the same as the previous one."); 452 | 453 | emit LogAllSeedValueChanged(msg.sender, block.timestamp, _seedValue, _seedString, _seedAddress); 454 | 455 | pri_seedValue = _seedValue; 456 | pri_seedString = _seedString; 457 | pri_seedAddress = _seedAddress; 458 | 459 | return true; 460 | } 461 | 462 | // get winnder id 463 | function selectWinner(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external nonReentrantSelectWinner onlyOwner returns(uint16) { 464 | Lottery_Info storage lottoInfo; 465 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 466 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 467 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 468 | } 469 | else { 470 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 471 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 472 | } 473 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_CLOSED, "This lotteryID does not close."); 474 | require(lottoInfo.ids.length > 1, "user does not exist"); 475 | require(lottoInfo.poolAmount > 1, "Lottery Pool is empty!"); 476 | 477 | uint16 winnerIDKey = randomNumberGenerate(_lotteryType); 478 | 479 | // binary search 480 | /* initialize variables: 481 | low : index of smallest value in current subarray of id array 482 | high: index of largest value in current subarray of id array 483 | mid : average of low and high in current subarray of id array */ 484 | uint256 mid; 485 | 486 | uint256 low = 1; // set initial value for low 487 | uint256 high = lottoInfo.ids.length - 1; // set initial value for high 488 | 489 | /* perform binary search */ 490 | while (low <= high) { 491 | mid = low + (high - low)/2; // update mid 492 | 493 | if ((winnerIDKey >= lottoInfo.ids[mid]) && 494 | (winnerIDKey < lottoInfo.ids[mid] + lottoInfo.ticketsOfMember[lottoInfo.ids[mid]])) { 495 | break; // find winnerID 496 | } 497 | else if (lottoInfo.ids[mid] > winnerIDKey) { // search left subarray for val 498 | high = mid - 1; // update high 499 | } 500 | else if (lottoInfo.ids[mid] < winnerIDKey) { // search right subarray for val 501 | low = mid + 1; // update low 502 | } 503 | } 504 | 505 | // send prize AVAX to winner 506 | address winnerAddress = lottoInfo.members[lottoInfo.ids[mid]]; 507 | uint256 winnerPrize = lottoInfo.poolAmount * (10 - LOTTERY_FEE) / 10; 508 | uint256 feePrize = lottoInfo.poolAmount * LOTTERY_FEE / 10; 509 | if (winnerAddress != address(this)) { 510 | payable(winnerAddress).transfer(winnerPrize); 511 | _teamFundsWallet.transfer(feePrize); 512 | lottoInfo.winnerPrize = winnerPrize; 513 | lottoInfo.poolAmount = 0; 514 | totalMarketcap = totalMarketcap + winnerPrize; 515 | } 516 | lottoInfo.lotteryStatus = LOTTERY_STATUS.LOTTERY_PICKED; 517 | 518 | emit SelectWinner(_lotteryType, _lotteryID, lottoInfo.lotteryTimeStamp, winnerAddress, winnerIDKey, winnerPrize); 519 | return lottoInfo.winnerID; 520 | } 521 | 522 | // get current lottery status of _lotteryID 523 | function getLotteryStatus(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external view returns(Ret_Ticket_Status memory) { 524 | Ret_Ticket_Status memory ret_ticket; 525 | Lottery_Info storage lottoInfo; 526 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 527 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 528 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 529 | ret_ticket.status = allWeeklyLotteryInfos[_lotteryID].lotteryStatus; 530 | ret_ticket.poolAmount = allWeeklyLotteryInfos[_lotteryID].poolAmount; 531 | } 532 | else { 533 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 534 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 535 | ret_ticket.status = allBiDailyLotteryInfos[_lotteryID].lotteryStatus; 536 | ret_ticket.poolAmount = allBiDailyLotteryInfos[_lotteryID].poolAmount; 537 | } 538 | uint16 lastID = lottoInfo.ids[lottoInfo.ids.length - 1]; 539 | ret_ticket.totalCount = lastID + lottoInfo.ticketsOfMember[lastID]; 540 | 541 | return ret_ticket; 542 | } 543 | } -------------------------------------------------------------------------------- /HodlNFT_flat.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // File: @openzeppelin/contracts/utils/Context.sol 3 | 4 | 5 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 6 | 7 | pragma solidity ^0.8.0; 8 | 9 | /** 10 | * @dev Provides information about the current execution context, including the 11 | * sender of the transaction and its data. While these are generally available 12 | * via msg.sender and msg.data, they should not be accessed in such a direct 13 | * manner, since when dealing with meta-transactions the account sending and 14 | * paying for execution may not be the actual sender (as far as an application 15 | * is concerned). 16 | * 17 | * This contract is only required for intermediate, library-like contracts. 18 | */ 19 | abstract contract Context { 20 | function _msgSender() internal view virtual returns (address) { 21 | return msg.sender; 22 | } 23 | 24 | function _msgData() internal view virtual returns (bytes calldata) { 25 | return msg.data; 26 | } 27 | } 28 | 29 | // File: @openzeppelin/contracts/access/Ownable.sol 30 | 31 | 32 | // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) 33 | 34 | pragma solidity ^0.8.0; 35 | 36 | 37 | /** 38 | * @dev Contract module which provides a basic access control mechanism, where 39 | * there is an account (an owner) that can be granted exclusive access to 40 | * specific functions. 41 | * 42 | * By default, the owner account will be the one that deploys the contract. This 43 | * can later be changed with {transferOwnership}. 44 | * 45 | * This module is used through inheritance. It will make available the modifier 46 | * `onlyOwner`, which can be applied to your functions to restrict their use to 47 | * the owner. 48 | */ 49 | abstract contract Ownable is Context { 50 | address private _owner; 51 | 52 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 53 | 54 | /** 55 | * @dev Initializes the contract setting the deployer as the initial owner. 56 | */ 57 | constructor() { 58 | _transferOwnership(_msgSender()); 59 | } 60 | 61 | /** 62 | * @dev Returns the address of the current owner. 63 | */ 64 | function owner() public view virtual returns (address) { 65 | return _owner; 66 | } 67 | 68 | /** 69 | * @dev Throws if called by any account other than the owner. 70 | */ 71 | modifier onlyOwner() { 72 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 73 | _; 74 | } 75 | 76 | /** 77 | * @dev Leaves the contract without owner. It will not be possible to call 78 | * `onlyOwner` functions anymore. Can only be called by the current owner. 79 | * 80 | * NOTE: Renouncing ownership will leave the contract without an owner, 81 | * thereby removing any functionality that is only available to the owner. 82 | */ 83 | function renounceOwnership() public virtual onlyOwner { 84 | _transferOwnership(address(0)); 85 | } 86 | 87 | /** 88 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 89 | * Can only be called by the current owner. 90 | */ 91 | function transferOwnership(address newOwner) public virtual onlyOwner { 92 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 93 | _transferOwnership(newOwner); 94 | } 95 | 96 | /** 97 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 98 | * Internal function without access restriction. 99 | */ 100 | function _transferOwnership(address newOwner) internal virtual { 101 | address oldOwner = _owner; 102 | _owner = newOwner; 103 | emit OwnershipTransferred(oldOwner, newOwner); 104 | } 105 | } 106 | 107 | // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol 108 | 109 | 110 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) 111 | 112 | pragma solidity ^0.8.0; 113 | 114 | /** 115 | * @title ERC721 token receiver interface 116 | * @dev Interface for any contract that wants to support safeTransfers 117 | * from ERC721 asset contracts. 118 | */ 119 | interface IERC721Receiver { 120 | /** 121 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 122 | * by `operator` from `from`, this function is called. 123 | * 124 | * It must return its Solidity selector to confirm the token transfer. 125 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 126 | * 127 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 128 | */ 129 | function onERC721Received( 130 | address operator, 131 | address from, 132 | uint256 tokenId, 133 | bytes calldata data 134 | ) external returns (bytes4); 135 | } 136 | 137 | // File: @openzeppelin/contracts/utils/introspection/IERC165.sol 138 | 139 | 140 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) 141 | 142 | pragma solidity ^0.8.0; 143 | 144 | /** 145 | * @dev Interface of the ERC165 standard, as defined in the 146 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 147 | * 148 | * Implementers can declare support of contract interfaces, which can then be 149 | * queried by others ({ERC165Checker}). 150 | * 151 | * For an implementation, see {ERC165}. 152 | */ 153 | interface IERC165 { 154 | /** 155 | * @dev Returns true if this contract implements the interface defined by 156 | * `interfaceId`. See the corresponding 157 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 158 | * to learn more about how these ids are created. 159 | * 160 | * This function call must use less than 30 000 gas. 161 | */ 162 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 163 | } 164 | 165 | // File: @openzeppelin/contracts/utils/introspection/ERC165.sol 166 | 167 | 168 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) 169 | 170 | pragma solidity ^0.8.0; 171 | 172 | 173 | /** 174 | * @dev Implementation of the {IERC165} interface. 175 | * 176 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 177 | * for the additional interface id that will be supported. For example: 178 | * 179 | * ```solidity 180 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 181 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 182 | * } 183 | * ``` 184 | * 185 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 186 | */ 187 | abstract contract ERC165 is IERC165 { 188 | /** 189 | * @dev See {IERC165-supportsInterface}. 190 | */ 191 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 192 | return interfaceId == type(IERC165).interfaceId; 193 | } 194 | } 195 | 196 | // File: @openzeppelin/contracts/token/ERC721/IERC721.sol 197 | 198 | 199 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) 200 | 201 | pragma solidity ^0.8.0; 202 | 203 | 204 | /** 205 | * @dev Required interface of an ERC721 compliant contract. 206 | */ 207 | interface IERC721 is IERC165 { 208 | /** 209 | * @dev Emitted when `tokenId` token is transferred from `from` to `to`. 210 | */ 211 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 212 | 213 | /** 214 | * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. 215 | */ 216 | event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 217 | 218 | /** 219 | * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. 220 | */ 221 | event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 222 | 223 | /** 224 | * @dev Returns the number of tokens in ``owner``'s account. 225 | */ 226 | function balanceOf(address owner) external view returns (uint256 balance); 227 | 228 | /** 229 | * @dev Returns the owner of the `tokenId` token. 230 | * 231 | * Requirements: 232 | * 233 | * - `tokenId` must exist. 234 | */ 235 | function ownerOf(uint256 tokenId) external view returns (address owner); 236 | 237 | /** 238 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 239 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 240 | * 241 | * Requirements: 242 | * 243 | * - `from` cannot be the zero address. 244 | * - `to` cannot be the zero address. 245 | * - `tokenId` token must exist and be owned by `from`. 246 | * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. 247 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 248 | * 249 | * Emits a {Transfer} event. 250 | */ 251 | function safeTransferFrom( 252 | address from, 253 | address to, 254 | uint256 tokenId 255 | ) external; 256 | 257 | /** 258 | * @dev Transfers `tokenId` token from `from` to `to`. 259 | * 260 | * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. 261 | * 262 | * Requirements: 263 | * 264 | * - `from` cannot be the zero address. 265 | * - `to` cannot be the zero address. 266 | * - `tokenId` token must be owned by `from`. 267 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 268 | * 269 | * Emits a {Transfer} event. 270 | */ 271 | function transferFrom( 272 | address from, 273 | address to, 274 | uint256 tokenId 275 | ) external; 276 | 277 | /** 278 | * @dev Gives permission to `to` to transfer `tokenId` token to another account. 279 | * The approval is cleared when the token is transferred. 280 | * 281 | * Only a single account can be approved at a time, so approving the zero address clears previous approvals. 282 | * 283 | * Requirements: 284 | * 285 | * - The caller must own the token or be an approved operator. 286 | * - `tokenId` must exist. 287 | * 288 | * Emits an {Approval} event. 289 | */ 290 | function approve(address to, uint256 tokenId) external; 291 | 292 | /** 293 | * @dev Returns the account approved for `tokenId` token. 294 | * 295 | * Requirements: 296 | * 297 | * - `tokenId` must exist. 298 | */ 299 | function getApproved(uint256 tokenId) external view returns (address operator); 300 | 301 | /** 302 | * @dev Approve or remove `operator` as an operator for the caller. 303 | * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. 304 | * 305 | * Requirements: 306 | * 307 | * - The `operator` cannot be the caller. 308 | * 309 | * Emits an {ApprovalForAll} event. 310 | */ 311 | function setApprovalForAll(address operator, bool _approved) external; 312 | 313 | /** 314 | * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. 315 | * 316 | * See {setApprovalForAll} 317 | */ 318 | function isApprovedForAll(address owner, address operator) external view returns (bool); 319 | 320 | /** 321 | * @dev Safely transfers `tokenId` token from `from` to `to`. 322 | * 323 | * Requirements: 324 | * 325 | * - `from` cannot be the zero address. 326 | * - `to` cannot be the zero address. 327 | * - `tokenId` token must exist and be owned by `from`. 328 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 329 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 330 | * 331 | * Emits a {Transfer} event. 332 | */ 333 | function safeTransferFrom( 334 | address from, 335 | address to, 336 | uint256 tokenId, 337 | bytes calldata data 338 | ) external; 339 | } 340 | 341 | // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol 342 | 343 | 344 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) 345 | 346 | pragma solidity ^0.8.0; 347 | 348 | 349 | /** 350 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 351 | * @dev See https://eips.ethereum.org/EIPS/eip-721 352 | */ 353 | interface IERC721Metadata is IERC721 { 354 | /** 355 | * @dev Returns the token collection name. 356 | */ 357 | function name() external view returns (string memory); 358 | 359 | /** 360 | * @dev Returns the token collection symbol. 361 | */ 362 | function symbol() external view returns (string memory); 363 | 364 | /** 365 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 366 | */ 367 | function tokenURI(uint256 tokenId) external view returns (string memory); 368 | } 369 | 370 | // File: @openzeppelin/contracts/utils/Counters.sol 371 | 372 | 373 | // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) 374 | 375 | pragma solidity ^0.8.0; 376 | 377 | /** 378 | * @title Counters 379 | * @author Matt Condon (@shrugs) 380 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 381 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 382 | * 383 | * Include with `using Counters for Counters.Counter;` 384 | */ 385 | library Counters { 386 | struct Counter { 387 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 388 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 389 | // this feature: see https://github.com/ethereum/solidity/issues/4637 390 | uint256 _value; // default: 0 391 | } 392 | 393 | function current(Counter storage counter) internal view returns (uint256) { 394 | return counter._value; 395 | } 396 | 397 | function increment(Counter storage counter) internal { 398 | unchecked { 399 | counter._value += 1; 400 | } 401 | } 402 | 403 | function decrement(Counter storage counter) internal { 404 | uint256 value = counter._value; 405 | require(value > 0, "Counter: decrement overflow"); 406 | unchecked { 407 | counter._value = value - 1; 408 | } 409 | } 410 | 411 | function reset(Counter storage counter) internal { 412 | counter._value = 0; 413 | } 414 | } 415 | 416 | // File: @openzeppelin/contracts/utils/Address.sol 417 | 418 | 419 | // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) 420 | 421 | pragma solidity ^0.8.1; 422 | 423 | /** 424 | * @dev Collection of functions related to the address type 425 | */ 426 | library Address { 427 | /** 428 | * @dev Returns true if `account` is a contract. 429 | * 430 | * [IMPORTANT] 431 | * ==== 432 | * It is unsafe to assume that an address for which this function returns 433 | * false is an externally-owned account (EOA) and not a contract. 434 | * 435 | * Among others, `isContract` will return false for the following 436 | * types of addresses: 437 | * 438 | * - an externally-owned account 439 | * - a contract in construction 440 | * - an address where a contract will be created 441 | * - an address where a contract lived, but was destroyed 442 | * ==== 443 | * 444 | * [IMPORTANT] 445 | * ==== 446 | * You shouldn't rely on `isContract` to protect against flash loan attacks! 447 | * 448 | * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets 449 | * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract 450 | * constructor. 451 | * ==== 452 | */ 453 | function isContract(address account) internal view returns (bool) { 454 | // This method relies on extcodesize/address.code.length, which returns 0 455 | // for contracts in construction, since the code is only stored at the end 456 | // of the constructor execution. 457 | 458 | return account.code.length > 0; 459 | } 460 | 461 | /** 462 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 463 | * `recipient`, forwarding all available gas and reverting on errors. 464 | * 465 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 466 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 467 | * imposed by `transfer`, making them unable to receive funds via 468 | * `transfer`. {sendValue} removes this limitation. 469 | * 470 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 471 | * 472 | * IMPORTANT: because control is transferred to `recipient`, care must be 473 | * taken to not create reentrancy vulnerabilities. Consider using 474 | * {ReentrancyGuard} or the 475 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 476 | */ 477 | function sendValue(address payable recipient, uint256 amount) internal { 478 | require(address(this).balance >= amount, "Address: insufficient balance"); 479 | 480 | (bool success, ) = recipient.call{value: amount}(""); 481 | require(success, "Address: unable to send value, recipient may have reverted"); 482 | } 483 | 484 | /** 485 | * @dev Performs a Solidity function call using a low level `call`. A 486 | * plain `call` is an unsafe replacement for a function call: use this 487 | * function instead. 488 | * 489 | * If `target` reverts with a revert reason, it is bubbled up by this 490 | * function (like regular Solidity function calls). 491 | * 492 | * Returns the raw returned data. To convert to the expected return value, 493 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 494 | * 495 | * Requirements: 496 | * 497 | * - `target` must be a contract. 498 | * - calling `target` with `data` must not revert. 499 | * 500 | * _Available since v3.1._ 501 | */ 502 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 503 | return functionCall(target, data, "Address: low-level call failed"); 504 | } 505 | 506 | /** 507 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 508 | * `errorMessage` as a fallback revert reason when `target` reverts. 509 | * 510 | * _Available since v3.1._ 511 | */ 512 | function functionCall( 513 | address target, 514 | bytes memory data, 515 | string memory errorMessage 516 | ) internal returns (bytes memory) { 517 | return functionCallWithValue(target, data, 0, errorMessage); 518 | } 519 | 520 | /** 521 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 522 | * but also transferring `value` wei to `target`. 523 | * 524 | * Requirements: 525 | * 526 | * - the calling contract must have an ETH balance of at least `value`. 527 | * - the called Solidity function must be `payable`. 528 | * 529 | * _Available since v3.1._ 530 | */ 531 | function functionCallWithValue( 532 | address target, 533 | bytes memory data, 534 | uint256 value 535 | ) internal returns (bytes memory) { 536 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 537 | } 538 | 539 | /** 540 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 541 | * with `errorMessage` as a fallback revert reason when `target` reverts. 542 | * 543 | * _Available since v3.1._ 544 | */ 545 | function functionCallWithValue( 546 | address target, 547 | bytes memory data, 548 | uint256 value, 549 | string memory errorMessage 550 | ) internal returns (bytes memory) { 551 | require(address(this).balance >= value, "Address: insufficient balance for call"); 552 | require(isContract(target), "Address: call to non-contract"); 553 | 554 | (bool success, bytes memory returndata) = target.call{value: value}(data); 555 | return verifyCallResult(success, returndata, errorMessage); 556 | } 557 | 558 | /** 559 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 560 | * but performing a static call. 561 | * 562 | * _Available since v3.3._ 563 | */ 564 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 565 | return functionStaticCall(target, data, "Address: low-level static call failed"); 566 | } 567 | 568 | /** 569 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 570 | * but performing a static call. 571 | * 572 | * _Available since v3.3._ 573 | */ 574 | function functionStaticCall( 575 | address target, 576 | bytes memory data, 577 | string memory errorMessage 578 | ) internal view returns (bytes memory) { 579 | require(isContract(target), "Address: static call to non-contract"); 580 | 581 | (bool success, bytes memory returndata) = target.staticcall(data); 582 | return verifyCallResult(success, returndata, errorMessage); 583 | } 584 | 585 | /** 586 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 587 | * but performing a delegate call. 588 | * 589 | * _Available since v3.4._ 590 | */ 591 | function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { 592 | return functionDelegateCall(target, data, "Address: low-level delegate call failed"); 593 | } 594 | 595 | /** 596 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 597 | * but performing a delegate call. 598 | * 599 | * _Available since v3.4._ 600 | */ 601 | function functionDelegateCall( 602 | address target, 603 | bytes memory data, 604 | string memory errorMessage 605 | ) internal returns (bytes memory) { 606 | require(isContract(target), "Address: delegate call to non-contract"); 607 | 608 | (bool success, bytes memory returndata) = target.delegatecall(data); 609 | return verifyCallResult(success, returndata, errorMessage); 610 | } 611 | 612 | /** 613 | * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the 614 | * revert reason using the provided one. 615 | * 616 | * _Available since v4.3._ 617 | */ 618 | function verifyCallResult( 619 | bool success, 620 | bytes memory returndata, 621 | string memory errorMessage 622 | ) internal pure returns (bytes memory) { 623 | if (success) { 624 | return returndata; 625 | } else { 626 | // Look for revert reason and bubble it up if present 627 | if (returndata.length > 0) { 628 | // The easiest way to bubble the revert reason is using memory via assembly 629 | 630 | assembly { 631 | let returndata_size := mload(returndata) 632 | revert(add(32, returndata), returndata_size) 633 | } 634 | } else { 635 | revert(errorMessage); 636 | } 637 | } 638 | } 639 | } 640 | 641 | // File: @openzeppelin/contracts/utils/Strings.sol 642 | 643 | 644 | // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) 645 | 646 | pragma solidity ^0.8.0; 647 | 648 | /** 649 | * @dev String operations. 650 | */ 651 | library Strings { 652 | bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; 653 | 654 | /** 655 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 656 | */ 657 | function toString(uint256 value) internal pure returns (string memory) { 658 | // Inspired by OraclizeAPI's implementation - MIT licence 659 | // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 660 | 661 | if (value == 0) { 662 | return "0"; 663 | } 664 | uint256 temp = value; 665 | uint256 digits; 666 | while (temp != 0) { 667 | digits++; 668 | temp /= 10; 669 | } 670 | bytes memory buffer = new bytes(digits); 671 | while (value != 0) { 672 | digits -= 1; 673 | buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); 674 | value /= 10; 675 | } 676 | return string(buffer); 677 | } 678 | 679 | /** 680 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 681 | */ 682 | function toHexString(uint256 value) internal pure returns (string memory) { 683 | if (value == 0) { 684 | return "0x00"; 685 | } 686 | uint256 temp = value; 687 | uint256 length = 0; 688 | while (temp != 0) { 689 | length++; 690 | temp >>= 8; 691 | } 692 | return toHexString(value, length); 693 | } 694 | 695 | /** 696 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 697 | */ 698 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 699 | bytes memory buffer = new bytes(2 * length + 2); 700 | buffer[0] = "0"; 701 | buffer[1] = "x"; 702 | for (uint256 i = 2 * length + 1; i > 1; --i) { 703 | buffer[i] = _HEX_SYMBOLS[value & 0xf]; 704 | value >>= 4; 705 | } 706 | require(value == 0, "Strings: hex length insufficient"); 707 | return string(buffer); 708 | } 709 | } 710 | 711 | // File: @openzeppelin/contracts/token/ERC721/ERC721.sol 712 | 713 | 714 | // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/ERC721.sol) 715 | 716 | pragma solidity ^0.8.0; 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | /** 726 | * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including 727 | * the Metadata extension, but not including the Enumerable extension, which is available separately as 728 | * {ERC721Enumerable}. 729 | */ 730 | contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { 731 | using Address for address; 732 | using Strings for uint256; 733 | 734 | // Token name 735 | string private _name; 736 | 737 | // Token symbol 738 | string private _symbol; 739 | 740 | // Mapping from token ID to owner address 741 | mapping(uint256 => address) private _owners; 742 | 743 | // Mapping owner address to token count 744 | mapping(address => uint256) private _balances; 745 | 746 | // Mapping from token ID to approved address 747 | mapping(uint256 => address) private _tokenApprovals; 748 | 749 | // Mapping from owner to operator approvals 750 | mapping(address => mapping(address => bool)) private _operatorApprovals; 751 | 752 | /** 753 | * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. 754 | */ 755 | constructor(string memory name_, string memory symbol_) { 756 | _name = name_; 757 | _symbol = symbol_; 758 | } 759 | 760 | /** 761 | * @dev See {IERC165-supportsInterface}. 762 | */ 763 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { 764 | return 765 | interfaceId == type(IERC721).interfaceId || 766 | interfaceId == type(IERC721Metadata).interfaceId || 767 | super.supportsInterface(interfaceId); 768 | } 769 | 770 | /** 771 | * @dev See {IERC721-balanceOf}. 772 | */ 773 | function balanceOf(address owner) public view virtual override returns (uint256) { 774 | require(owner != address(0), "ERC721: balance query for the zero address"); 775 | return _balances[owner]; 776 | } 777 | 778 | /** 779 | * @dev See {IERC721-ownerOf}. 780 | */ 781 | function ownerOf(uint256 tokenId) public view virtual override returns (address) { 782 | address owner = _owners[tokenId]; 783 | require(owner != address(0), "ERC721: owner query for nonexistent token"); 784 | return owner; 785 | } 786 | 787 | /** 788 | * @dev See {IERC721Metadata-name}. 789 | */ 790 | function name() public view virtual override returns (string memory) { 791 | return _name; 792 | } 793 | 794 | /** 795 | * @dev See {IERC721Metadata-symbol}. 796 | */ 797 | function symbol() public view virtual override returns (string memory) { 798 | return _symbol; 799 | } 800 | 801 | /** 802 | * @dev See {IERC721Metadata-tokenURI}. 803 | */ 804 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 805 | require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); 806 | 807 | string memory baseURI = _baseURI(); 808 | return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; 809 | } 810 | 811 | /** 812 | * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each 813 | * token will be the concatenation of the `baseURI` and the `tokenId`. Empty 814 | * by default, can be overriden in child contracts. 815 | */ 816 | function _baseURI() internal view virtual returns (string memory) { 817 | return ""; 818 | } 819 | 820 | /** 821 | * @dev See {IERC721-approve}. 822 | */ 823 | function approve(address to, uint256 tokenId) public virtual override { 824 | address owner = ERC721.ownerOf(tokenId); 825 | require(to != owner, "ERC721: approval to current owner"); 826 | 827 | require( 828 | _msgSender() == owner || isApprovedForAll(owner, _msgSender()), 829 | "ERC721: approve caller is not owner nor approved for all" 830 | ); 831 | 832 | _approve(to, tokenId); 833 | } 834 | 835 | /** 836 | * @dev See {IERC721-getApproved}. 837 | */ 838 | function getApproved(uint256 tokenId) public view virtual override returns (address) { 839 | require(_exists(tokenId), "ERC721: approved query for nonexistent token"); 840 | 841 | return _tokenApprovals[tokenId]; 842 | } 843 | 844 | /** 845 | * @dev See {IERC721-setApprovalForAll}. 846 | */ 847 | function setApprovalForAll(address operator, bool approved) public virtual override { 848 | _setApprovalForAll(_msgSender(), operator, approved); 849 | } 850 | 851 | /** 852 | * @dev See {IERC721-isApprovedForAll}. 853 | */ 854 | function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { 855 | return _operatorApprovals[owner][operator]; 856 | } 857 | 858 | /** 859 | * @dev See {IERC721-transferFrom}. 860 | */ 861 | function transferFrom( 862 | address from, 863 | address to, 864 | uint256 tokenId 865 | ) public virtual override { 866 | //solhint-disable-next-line max-line-length 867 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 868 | 869 | _transfer(from, to, tokenId); 870 | } 871 | 872 | /** 873 | * @dev See {IERC721-safeTransferFrom}. 874 | */ 875 | function safeTransferFrom( 876 | address from, 877 | address to, 878 | uint256 tokenId 879 | ) public virtual override { 880 | safeTransferFrom(from, to, tokenId, ""); 881 | } 882 | 883 | /** 884 | * @dev See {IERC721-safeTransferFrom}. 885 | */ 886 | function safeTransferFrom( 887 | address from, 888 | address to, 889 | uint256 tokenId, 890 | bytes memory _data 891 | ) public virtual override { 892 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 893 | _safeTransfer(from, to, tokenId, _data); 894 | } 895 | 896 | /** 897 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 898 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 899 | * 900 | * `_data` is additional data, it has no specified format and it is sent in call to `to`. 901 | * 902 | * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. 903 | * implement alternative mechanisms to perform token transfer, such as signature-based. 904 | * 905 | * Requirements: 906 | * 907 | * - `from` cannot be the zero address. 908 | * - `to` cannot be the zero address. 909 | * - `tokenId` token must exist and be owned by `from`. 910 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 911 | * 912 | * Emits a {Transfer} event. 913 | */ 914 | function _safeTransfer( 915 | address from, 916 | address to, 917 | uint256 tokenId, 918 | bytes memory _data 919 | ) internal virtual { 920 | _transfer(from, to, tokenId); 921 | require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); 922 | } 923 | 924 | /** 925 | * @dev Returns whether `tokenId` exists. 926 | * 927 | * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. 928 | * 929 | * Tokens start existing when they are minted (`_mint`), 930 | * and stop existing when they are burned (`_burn`). 931 | */ 932 | function _exists(uint256 tokenId) internal view virtual returns (bool) { 933 | return _owners[tokenId] != address(0); 934 | } 935 | 936 | /** 937 | * @dev Returns whether `spender` is allowed to manage `tokenId`. 938 | * 939 | * Requirements: 940 | * 941 | * - `tokenId` must exist. 942 | */ 943 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { 944 | require(_exists(tokenId), "ERC721: operator query for nonexistent token"); 945 | address owner = ERC721.ownerOf(tokenId); 946 | return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); 947 | } 948 | 949 | /** 950 | * @dev Safely mints `tokenId` and transfers it to `to`. 951 | * 952 | * Requirements: 953 | * 954 | * - `tokenId` must not exist. 955 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 956 | * 957 | * Emits a {Transfer} event. 958 | */ 959 | function _safeMint(address to, uint256 tokenId) internal virtual { 960 | _safeMint(to, tokenId, ""); 961 | } 962 | 963 | /** 964 | * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is 965 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 966 | */ 967 | function _safeMint( 968 | address to, 969 | uint256 tokenId, 970 | bytes memory _data 971 | ) internal virtual { 972 | _mint(to, tokenId); 973 | require( 974 | _checkOnERC721Received(address(0), to, tokenId, _data), 975 | "ERC721: transfer to non ERC721Receiver implementer" 976 | ); 977 | } 978 | 979 | /** 980 | * @dev Mints `tokenId` and transfers it to `to`. 981 | * 982 | * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible 983 | * 984 | * Requirements: 985 | * 986 | * - `tokenId` must not exist. 987 | * - `to` cannot be the zero address. 988 | * 989 | * Emits a {Transfer} event. 990 | */ 991 | function _mint(address to, uint256 tokenId) internal virtual { 992 | require(to != address(0), "ERC721: mint to the zero address"); 993 | require(!_exists(tokenId), "ERC721: token already minted"); 994 | 995 | _beforeTokenTransfer(address(0), to, tokenId); 996 | 997 | _balances[to] += 1; 998 | _owners[tokenId] = to; 999 | 1000 | emit Transfer(address(0), to, tokenId); 1001 | 1002 | _afterTokenTransfer(address(0), to, tokenId); 1003 | } 1004 | 1005 | /** 1006 | * @dev Destroys `tokenId`. 1007 | * The approval is cleared when the token is burned. 1008 | * 1009 | * Requirements: 1010 | * 1011 | * - `tokenId` must exist. 1012 | * 1013 | * Emits a {Transfer} event. 1014 | */ 1015 | function _burn(uint256 tokenId) internal virtual { 1016 | address owner = ERC721.ownerOf(tokenId); 1017 | 1018 | _beforeTokenTransfer(owner, address(0), tokenId); 1019 | 1020 | // Clear approvals 1021 | _approve(address(0), tokenId); 1022 | 1023 | _balances[owner] -= 1; 1024 | delete _owners[tokenId]; 1025 | 1026 | emit Transfer(owner, address(0), tokenId); 1027 | 1028 | _afterTokenTransfer(owner, address(0), tokenId); 1029 | } 1030 | 1031 | /** 1032 | * @dev Transfers `tokenId` from `from` to `to`. 1033 | * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. 1034 | * 1035 | * Requirements: 1036 | * 1037 | * - `to` cannot be the zero address. 1038 | * - `tokenId` token must be owned by `from`. 1039 | * 1040 | * Emits a {Transfer} event. 1041 | */ 1042 | function _transfer( 1043 | address from, 1044 | address to, 1045 | uint256 tokenId 1046 | ) internal virtual { 1047 | require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); 1048 | require(to != address(0), "ERC721: transfer to the zero address"); 1049 | 1050 | _beforeTokenTransfer(from, to, tokenId); 1051 | 1052 | // Clear approvals from the previous owner 1053 | _approve(address(0), tokenId); 1054 | 1055 | _balances[from] -= 1; 1056 | _balances[to] += 1; 1057 | _owners[tokenId] = to; 1058 | 1059 | emit Transfer(from, to, tokenId); 1060 | 1061 | _afterTokenTransfer(from, to, tokenId); 1062 | } 1063 | 1064 | /** 1065 | * @dev Approve `to` to operate on `tokenId` 1066 | * 1067 | * Emits a {Approval} event. 1068 | */ 1069 | function _approve(address to, uint256 tokenId) internal virtual { 1070 | _tokenApprovals[tokenId] = to; 1071 | emit Approval(ERC721.ownerOf(tokenId), to, tokenId); 1072 | } 1073 | 1074 | /** 1075 | * @dev Approve `operator` to operate on all of `owner` tokens 1076 | * 1077 | * Emits a {ApprovalForAll} event. 1078 | */ 1079 | function _setApprovalForAll( 1080 | address owner, 1081 | address operator, 1082 | bool approved 1083 | ) internal virtual { 1084 | require(owner != operator, "ERC721: approve to caller"); 1085 | _operatorApprovals[owner][operator] = approved; 1086 | emit ApprovalForAll(owner, operator, approved); 1087 | } 1088 | 1089 | /** 1090 | * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. 1091 | * The call is not executed if the target address is not a contract. 1092 | * 1093 | * @param from address representing the previous owner of the given token ID 1094 | * @param to target address that will receive the tokens 1095 | * @param tokenId uint256 ID of the token to be transferred 1096 | * @param _data bytes optional data to send along with the call 1097 | * @return bool whether the call correctly returned the expected magic value 1098 | */ 1099 | function _checkOnERC721Received( 1100 | address from, 1101 | address to, 1102 | uint256 tokenId, 1103 | bytes memory _data 1104 | ) private returns (bool) { 1105 | if (to.isContract()) { 1106 | try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { 1107 | return retval == IERC721Receiver.onERC721Received.selector; 1108 | } catch (bytes memory reason) { 1109 | if (reason.length == 0) { 1110 | revert("ERC721: transfer to non ERC721Receiver implementer"); 1111 | } else { 1112 | assembly { 1113 | revert(add(32, reason), mload(reason)) 1114 | } 1115 | } 1116 | } 1117 | } else { 1118 | return true; 1119 | } 1120 | } 1121 | 1122 | /** 1123 | * @dev Hook that is called before any token transfer. This includes minting 1124 | * and burning. 1125 | * 1126 | * Calling conditions: 1127 | * 1128 | * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be 1129 | * transferred to `to`. 1130 | * - When `from` is zero, `tokenId` will be minted for `to`. 1131 | * - When `to` is zero, ``from``'s `tokenId` will be burned. 1132 | * - `from` and `to` are never both zero. 1133 | * 1134 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 1135 | */ 1136 | function _beforeTokenTransfer( 1137 | address from, 1138 | address to, 1139 | uint256 tokenId 1140 | ) internal virtual {} 1141 | 1142 | /** 1143 | * @dev Hook that is called after any transfer of tokens. This includes 1144 | * minting and burning. 1145 | * 1146 | * Calling conditions: 1147 | * 1148 | * - when `from` and `to` are both non-zero. 1149 | * - `from` and `to` are never both zero. 1150 | * 1151 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 1152 | */ 1153 | function _afterTokenTransfer( 1154 | address from, 1155 | address to, 1156 | uint256 tokenId 1157 | ) internal virtual {} 1158 | } 1159 | 1160 | // File: artifacts/HodlNFT.sol 1161 | 1162 | 1163 | pragma solidity ^0.8.7; 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | contract HodlNFT is ERC721, Ownable { 1171 | address private RewardWallet; 1172 | 1173 | event SetHodlNFTPrice(address addr, uint256 newNFTPrice); 1174 | event SetBaseURI(address addr, string newUri); 1175 | event SetHodlNFTURI(address addr, string newUri); 1176 | event SetRewardWalletAddress(address addr, address rewardWallet); 1177 | 1178 | using Strings for uint256; 1179 | 1180 | uint256 private HODL_NFT_PRICE = 10; //HODL token 1181 | 1182 | using Counters for Counters.Counter; 1183 | Counters.Counter private _hodlTokenCounter; 1184 | 1185 | string private _baseURIExtended; 1186 | 1187 | string private hodlNFTURI; 1188 | 1189 | /** 1190 | * @dev Throws if called by any account other than the multi-signer. 1191 | */ 1192 | // modifier onlyMultiSignWallet() { 1193 | // require(owner() == _msgSender(), "Multi-signer: caller is not the multi-signer"); 1194 | // _; 1195 | // } 1196 | 1197 | constructor() ERC721("HODL NFT","HNFT") { 1198 | _baseURIExtended = "https://ipfs.infura.io/"; 1199 | } 1200 | 1201 | function setRewardWalletAddress(address _newRewardWallet) external onlyOwner{ 1202 | RewardWallet = _newRewardWallet; 1203 | emit SetRewardWalletAddress(msg.sender, _newRewardWallet); 1204 | } 1205 | 1206 | //Set, Get Price Func 1207 | function setHodlNFTPrice(uint256 _newNFTValue) external onlyOwner{ 1208 | HODL_NFT_PRICE = _newNFTValue; 1209 | emit SetHodlNFTPrice(msg.sender, _newNFTValue); 1210 | } 1211 | 1212 | function getHodlNFTPrice() external view returns(uint256){ 1213 | return HODL_NFT_PRICE; 1214 | } 1215 | 1216 | function getHodlNFTURI() external view returns(string memory){ 1217 | return hodlNFTURI; 1218 | } 1219 | 1220 | function setHodlNFTURI(string memory _hodlNFTURI) external onlyOwner{ 1221 | hodlNFTURI = _hodlNFTURI; 1222 | emit SetHodlNFTURI(msg.sender, hodlNFTURI); 1223 | } 1224 | 1225 | /** 1226 | * @dev Mint NFT by customer 1227 | */ 1228 | function mintNFT(address sender) external returns (uint256) { 1229 | 1230 | require( msg.sender == RewardWallet, "you can't mint from other account"); 1231 | 1232 | // Incrementing ID to create new token 1233 | uint256 newHodlNFTID = _hodlTokenCounter.current(); 1234 | _hodlTokenCounter.increment(); 1235 | 1236 | _safeMint(sender, newHodlNFTID); 1237 | return newHodlNFTID; 1238 | } 1239 | 1240 | /** 1241 | * @dev Return the base URI 1242 | */ 1243 | function _baseURI() internal override view returns (string memory) { 1244 | return _baseURIExtended; 1245 | } 1246 | 1247 | /** 1248 | * @dev Set the base URI 1249 | */ 1250 | function setBaseURI(string memory baseURI_) external onlyOwner() { 1251 | _baseURIExtended = baseURI_; 1252 | emit SetBaseURI(msg.sender, baseURI_); 1253 | } 1254 | } -------------------------------------------------------------------------------- /HodlLottery_flat.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol 3 | 4 | 5 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) 6 | 7 | pragma solidity ^0.8.0; 8 | 9 | /** 10 | * @title ERC721 token receiver interface 11 | * @dev Interface for any contract that wants to support safeTransfers 12 | * from ERC721 asset contracts. 13 | */ 14 | interface IERC721Receiver { 15 | /** 16 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 17 | * by `operator` from `from`, this function is called. 18 | * 19 | * It must return its Solidity selector to confirm the token transfer. 20 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 21 | * 22 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 23 | */ 24 | function onERC721Received( 25 | address operator, 26 | address from, 27 | uint256 tokenId, 28 | bytes calldata data 29 | ) external returns (bytes4); 30 | } 31 | 32 | // File: @openzeppelin/contracts/utils/introspection/IERC165.sol 33 | 34 | 35 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) 36 | 37 | pragma solidity ^0.8.0; 38 | 39 | /** 40 | * @dev Interface of the ERC165 standard, as defined in the 41 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 42 | * 43 | * Implementers can declare support of contract interfaces, which can then be 44 | * queried by others ({ERC165Checker}). 45 | * 46 | * For an implementation, see {ERC165}. 47 | */ 48 | interface IERC165 { 49 | /** 50 | * @dev Returns true if this contract implements the interface defined by 51 | * `interfaceId`. See the corresponding 52 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 53 | * to learn more about how these ids are created. 54 | * 55 | * This function call must use less than 30 000 gas. 56 | */ 57 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 58 | } 59 | 60 | // File: @openzeppelin/contracts/utils/introspection/ERC165.sol 61 | 62 | 63 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) 64 | 65 | pragma solidity ^0.8.0; 66 | 67 | 68 | /** 69 | * @dev Implementation of the {IERC165} interface. 70 | * 71 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 72 | * for the additional interface id that will be supported. For example: 73 | * 74 | * ```solidity 75 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 76 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 77 | * } 78 | * ``` 79 | * 80 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 81 | */ 82 | abstract contract ERC165 is IERC165 { 83 | /** 84 | * @dev See {IERC165-supportsInterface}. 85 | */ 86 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 87 | return interfaceId == type(IERC165).interfaceId; 88 | } 89 | } 90 | 91 | // File: @openzeppelin/contracts/token/ERC721/IERC721.sol 92 | 93 | 94 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) 95 | 96 | pragma solidity ^0.8.0; 97 | 98 | 99 | /** 100 | * @dev Required interface of an ERC721 compliant contract. 101 | */ 102 | interface IERC721 is IERC165 { 103 | /** 104 | * @dev Emitted when `tokenId` token is transferred from `from` to `to`. 105 | */ 106 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 107 | 108 | /** 109 | * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. 110 | */ 111 | event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 112 | 113 | /** 114 | * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. 115 | */ 116 | event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 117 | 118 | /** 119 | * @dev Returns the number of tokens in ``owner``'s account. 120 | */ 121 | function balanceOf(address owner) external view returns (uint256 balance); 122 | 123 | /** 124 | * @dev Returns the owner of the `tokenId` token. 125 | * 126 | * Requirements: 127 | * 128 | * - `tokenId` must exist. 129 | */ 130 | function ownerOf(uint256 tokenId) external view returns (address owner); 131 | 132 | /** 133 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 134 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 135 | * 136 | * Requirements: 137 | * 138 | * - `from` cannot be the zero address. 139 | * - `to` cannot be the zero address. 140 | * - `tokenId` token must exist and be owned by `from`. 141 | * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. 142 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 143 | * 144 | * Emits a {Transfer} event. 145 | */ 146 | function safeTransferFrom( 147 | address from, 148 | address to, 149 | uint256 tokenId 150 | ) external; 151 | 152 | /** 153 | * @dev Transfers `tokenId` token from `from` to `to`. 154 | * 155 | * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. 156 | * 157 | * Requirements: 158 | * 159 | * - `from` cannot be the zero address. 160 | * - `to` cannot be the zero address. 161 | * - `tokenId` token must be owned by `from`. 162 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 163 | * 164 | * Emits a {Transfer} event. 165 | */ 166 | function transferFrom( 167 | address from, 168 | address to, 169 | uint256 tokenId 170 | ) external; 171 | 172 | /** 173 | * @dev Gives permission to `to` to transfer `tokenId` token to another account. 174 | * The approval is cleared when the token is transferred. 175 | * 176 | * Only a single account can be approved at a time, so approving the zero address clears previous approvals. 177 | * 178 | * Requirements: 179 | * 180 | * - The caller must own the token or be an approved operator. 181 | * - `tokenId` must exist. 182 | * 183 | * Emits an {Approval} event. 184 | */ 185 | function approve(address to, uint256 tokenId) external; 186 | 187 | /** 188 | * @dev Returns the account approved for `tokenId` token. 189 | * 190 | * Requirements: 191 | * 192 | * - `tokenId` must exist. 193 | */ 194 | function getApproved(uint256 tokenId) external view returns (address operator); 195 | 196 | /** 197 | * @dev Approve or remove `operator` as an operator for the caller. 198 | * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. 199 | * 200 | * Requirements: 201 | * 202 | * - The `operator` cannot be the caller. 203 | * 204 | * Emits an {ApprovalForAll} event. 205 | */ 206 | function setApprovalForAll(address operator, bool _approved) external; 207 | 208 | /** 209 | * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. 210 | * 211 | * See {setApprovalForAll} 212 | */ 213 | function isApprovedForAll(address owner, address operator) external view returns (bool); 214 | 215 | /** 216 | * @dev Safely transfers `tokenId` token from `from` to `to`. 217 | * 218 | * Requirements: 219 | * 220 | * - `from` cannot be the zero address. 221 | * - `to` cannot be the zero address. 222 | * - `tokenId` token must exist and be owned by `from`. 223 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 224 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 225 | * 226 | * Emits a {Transfer} event. 227 | */ 228 | function safeTransferFrom( 229 | address from, 230 | address to, 231 | uint256 tokenId, 232 | bytes calldata data 233 | ) external; 234 | } 235 | 236 | // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol 237 | 238 | 239 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) 240 | 241 | pragma solidity ^0.8.0; 242 | 243 | 244 | /** 245 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 246 | * @dev See https://eips.ethereum.org/EIPS/eip-721 247 | */ 248 | interface IERC721Metadata is IERC721 { 249 | /** 250 | * @dev Returns the token collection name. 251 | */ 252 | function name() external view returns (string memory); 253 | 254 | /** 255 | * @dev Returns the token collection symbol. 256 | */ 257 | function symbol() external view returns (string memory); 258 | 259 | /** 260 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 261 | */ 262 | function tokenURI(uint256 tokenId) external view returns (string memory); 263 | } 264 | 265 | // File: @openzeppelin/contracts/utils/Counters.sol 266 | 267 | 268 | // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) 269 | 270 | pragma solidity ^0.8.0; 271 | 272 | /** 273 | * @title Counters 274 | * @author Matt Condon (@shrugs) 275 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 276 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 277 | * 278 | * Include with `using Counters for Counters.Counter;` 279 | */ 280 | library Counters { 281 | struct Counter { 282 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 283 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 284 | // this feature: see https://github.com/ethereum/solidity/issues/4637 285 | uint256 _value; // default: 0 286 | } 287 | 288 | function current(Counter storage counter) internal view returns (uint256) { 289 | return counter._value; 290 | } 291 | 292 | function increment(Counter storage counter) internal { 293 | unchecked { 294 | counter._value += 1; 295 | } 296 | } 297 | 298 | function decrement(Counter storage counter) internal { 299 | uint256 value = counter._value; 300 | require(value > 0, "Counter: decrement overflow"); 301 | unchecked { 302 | counter._value = value - 1; 303 | } 304 | } 305 | 306 | function reset(Counter storage counter) internal { 307 | counter._value = 0; 308 | } 309 | } 310 | 311 | // File: @openzeppelin/contracts/utils/Address.sol 312 | 313 | 314 | // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) 315 | 316 | pragma solidity ^0.8.1; 317 | 318 | /** 319 | * @dev Collection of functions related to the address type 320 | */ 321 | library Address { 322 | /** 323 | * @dev Returns true if `account` is a contract. 324 | * 325 | * [IMPORTANT] 326 | * ==== 327 | * It is unsafe to assume that an address for which this function returns 328 | * false is an externally-owned account (EOA) and not a contract. 329 | * 330 | * Among others, `isContract` will return false for the following 331 | * types of addresses: 332 | * 333 | * - an externally-owned account 334 | * - a contract in construction 335 | * - an address where a contract will be created 336 | * - an address where a contract lived, but was destroyed 337 | * ==== 338 | * 339 | * [IMPORTANT] 340 | * ==== 341 | * You shouldn't rely on `isContract` to protect against flash loan attacks! 342 | * 343 | * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets 344 | * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract 345 | * constructor. 346 | * ==== 347 | */ 348 | function isContract(address account) internal view returns (bool) { 349 | // This method relies on extcodesize/address.code.length, which returns 0 350 | // for contracts in construction, since the code is only stored at the end 351 | // of the constructor execution. 352 | 353 | return account.code.length > 0; 354 | } 355 | 356 | /** 357 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 358 | * `recipient`, forwarding all available gas and reverting on errors. 359 | * 360 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 361 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 362 | * imposed by `transfer`, making them unable to receive funds via 363 | * `transfer`. {sendValue} removes this limitation. 364 | * 365 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 366 | * 367 | * IMPORTANT: because control is transferred to `recipient`, care must be 368 | * taken to not create reentrancy vulnerabilities. Consider using 369 | * {ReentrancyGuard} or the 370 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 371 | */ 372 | function sendValue(address payable recipient, uint256 amount) internal { 373 | require(address(this).balance >= amount, "Address: insufficient balance"); 374 | 375 | (bool success, ) = recipient.call{value: amount}(""); 376 | require(success, "Address: unable to send value, recipient may have reverted"); 377 | } 378 | 379 | /** 380 | * @dev Performs a Solidity function call using a low level `call`. A 381 | * plain `call` is an unsafe replacement for a function call: use this 382 | * function instead. 383 | * 384 | * If `target` reverts with a revert reason, it is bubbled up by this 385 | * function (like regular Solidity function calls). 386 | * 387 | * Returns the raw returned data. To convert to the expected return value, 388 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 389 | * 390 | * Requirements: 391 | * 392 | * - `target` must be a contract. 393 | * - calling `target` with `data` must not revert. 394 | * 395 | * _Available since v3.1._ 396 | */ 397 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 398 | return functionCall(target, data, "Address: low-level call failed"); 399 | } 400 | 401 | /** 402 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 403 | * `errorMessage` as a fallback revert reason when `target` reverts. 404 | * 405 | * _Available since v3.1._ 406 | */ 407 | function functionCall( 408 | address target, 409 | bytes memory data, 410 | string memory errorMessage 411 | ) internal returns (bytes memory) { 412 | return functionCallWithValue(target, data, 0, errorMessage); 413 | } 414 | 415 | /** 416 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 417 | * but also transferring `value` wei to `target`. 418 | * 419 | * Requirements: 420 | * 421 | * - the calling contract must have an ETH balance of at least `value`. 422 | * - the called Solidity function must be `payable`. 423 | * 424 | * _Available since v3.1._ 425 | */ 426 | function functionCallWithValue( 427 | address target, 428 | bytes memory data, 429 | uint256 value 430 | ) internal returns (bytes memory) { 431 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 432 | } 433 | 434 | /** 435 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 436 | * with `errorMessage` as a fallback revert reason when `target` reverts. 437 | * 438 | * _Available since v3.1._ 439 | */ 440 | function functionCallWithValue( 441 | address target, 442 | bytes memory data, 443 | uint256 value, 444 | string memory errorMessage 445 | ) internal returns (bytes memory) { 446 | require(address(this).balance >= value, "Address: insufficient balance for call"); 447 | require(isContract(target), "Address: call to non-contract"); 448 | 449 | (bool success, bytes memory returndata) = target.call{value: value}(data); 450 | return verifyCallResult(success, returndata, errorMessage); 451 | } 452 | 453 | /** 454 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 455 | * but performing a static call. 456 | * 457 | * _Available since v3.3._ 458 | */ 459 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 460 | return functionStaticCall(target, data, "Address: low-level static call failed"); 461 | } 462 | 463 | /** 464 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 465 | * but performing a static call. 466 | * 467 | * _Available since v3.3._ 468 | */ 469 | function functionStaticCall( 470 | address target, 471 | bytes memory data, 472 | string memory errorMessage 473 | ) internal view returns (bytes memory) { 474 | require(isContract(target), "Address: static call to non-contract"); 475 | 476 | (bool success, bytes memory returndata) = target.staticcall(data); 477 | return verifyCallResult(success, returndata, errorMessage); 478 | } 479 | 480 | /** 481 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 482 | * but performing a delegate call. 483 | * 484 | * _Available since v3.4._ 485 | */ 486 | function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { 487 | return functionDelegateCall(target, data, "Address: low-level delegate call failed"); 488 | } 489 | 490 | /** 491 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 492 | * but performing a delegate call. 493 | * 494 | * _Available since v3.4._ 495 | */ 496 | function functionDelegateCall( 497 | address target, 498 | bytes memory data, 499 | string memory errorMessage 500 | ) internal returns (bytes memory) { 501 | require(isContract(target), "Address: delegate call to non-contract"); 502 | 503 | (bool success, bytes memory returndata) = target.delegatecall(data); 504 | return verifyCallResult(success, returndata, errorMessage); 505 | } 506 | 507 | /** 508 | * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the 509 | * revert reason using the provided one. 510 | * 511 | * _Available since v4.3._ 512 | */ 513 | function verifyCallResult( 514 | bool success, 515 | bytes memory returndata, 516 | string memory errorMessage 517 | ) internal pure returns (bytes memory) { 518 | if (success) { 519 | return returndata; 520 | } else { 521 | // Look for revert reason and bubble it up if present 522 | if (returndata.length > 0) { 523 | // The easiest way to bubble the revert reason is using memory via assembly 524 | 525 | assembly { 526 | let returndata_size := mload(returndata) 527 | revert(add(32, returndata), returndata_size) 528 | } 529 | } else { 530 | revert(errorMessage); 531 | } 532 | } 533 | } 534 | } 535 | 536 | // File: @openzeppelin/contracts/utils/Strings.sol 537 | 538 | 539 | // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) 540 | 541 | pragma solidity ^0.8.0; 542 | 543 | /** 544 | * @dev String operations. 545 | */ 546 | library Strings { 547 | bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; 548 | 549 | /** 550 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 551 | */ 552 | function toString(uint256 value) internal pure returns (string memory) { 553 | // Inspired by OraclizeAPI's implementation - MIT licence 554 | // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 555 | 556 | if (value == 0) { 557 | return "0"; 558 | } 559 | uint256 temp = value; 560 | uint256 digits; 561 | while (temp != 0) { 562 | digits++; 563 | temp /= 10; 564 | } 565 | bytes memory buffer = new bytes(digits); 566 | while (value != 0) { 567 | digits -= 1; 568 | buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); 569 | value /= 10; 570 | } 571 | return string(buffer); 572 | } 573 | 574 | /** 575 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 576 | */ 577 | function toHexString(uint256 value) internal pure returns (string memory) { 578 | if (value == 0) { 579 | return "0x00"; 580 | } 581 | uint256 temp = value; 582 | uint256 length = 0; 583 | while (temp != 0) { 584 | length++; 585 | temp >>= 8; 586 | } 587 | return toHexString(value, length); 588 | } 589 | 590 | /** 591 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 592 | */ 593 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 594 | bytes memory buffer = new bytes(2 * length + 2); 595 | buffer[0] = "0"; 596 | buffer[1] = "x"; 597 | for (uint256 i = 2 * length + 1; i > 1; --i) { 598 | buffer[i] = _HEX_SYMBOLS[value & 0xf]; 599 | value >>= 4; 600 | } 601 | require(value == 0, "Strings: hex length insufficient"); 602 | return string(buffer); 603 | } 604 | } 605 | 606 | // File: artifacts/ReentrancyGuard.sol 607 | 608 | 609 | // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) 610 | 611 | pragma solidity 0.8.7; 612 | 613 | /** 614 | * @dev Contract module that helps prevent reentrant calls to a function. 615 | * 616 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 617 | * available, which can be applied to functions to make sure there are no nested 618 | * (reentrant) calls to them. 619 | * 620 | * Note that because there is a single `nonReentrant` guard, functions marked as 621 | * `nonReentrant` may not call one another. This can be worked around by making 622 | * those functions `private`, and then adding `external` `nonReentrant` entry 623 | * points to them. 624 | * 625 | * TIP: If you would like to learn more about reentrancy and alternative ways 626 | * to protect against it, check out our blog post 627 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 628 | */ 629 | abstract contract ReentrancyGuard { 630 | // Booleans are more expensive than uint256 or any type that takes up a full 631 | // word because each write operation emits an extra SLOAD to first read the 632 | // slot's contents, replace the bits taken up by the boolean, and then write 633 | // back. This is the compiler's defense against contract upgrades and 634 | // pointer aliasing, and it cannot be disabled. 635 | 636 | // The values being non-zero value makes deployment a bit more expensive, 637 | // but in exchange the refund on every call to nonReentrant will be lower in 638 | // amount. Since refunds are capped to a percentage of the total 639 | // transaction's gas, it is best to keep them low in cases like this one, to 640 | // increase the likelihood of the full refund coming into effect. 641 | uint256 private constant _NOT_ENTERED = 1; 642 | uint256 private constant _ENTERED = 2; 643 | 644 | uint256 private _status; 645 | uint256 private _statusSelectWinner; 646 | uint256 private _statusGivePriceToWinner; 647 | 648 | constructor() { 649 | _status = _NOT_ENTERED; 650 | _statusSelectWinner = _NOT_ENTERED; 651 | _statusGivePriceToWinner = _NOT_ENTERED; 652 | } 653 | 654 | /** 655 | * @dev Prevents a contract from calling itself, directly or indirectly. 656 | * Calling a `nonReentrant` function from another `nonReentrant` 657 | * function is not supported. It is possible to prevent this from happening 658 | * by making the `nonReentrant` function external, and making it call a 659 | * `private` function that does the actual work. 660 | */ 661 | modifier nonReentrant() { 662 | // On the first call to nonReentrant, _notEntered will be true 663 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 664 | 665 | // Any calls to nonReentrant after this point will fail 666 | _status = _ENTERED; 667 | 668 | _; 669 | 670 | // By storing the original value once again, a refund is triggered (see 671 | // https://eips.ethereum.org/EIPS/eip-2200) 672 | _status = _NOT_ENTERED; 673 | } 674 | 675 | modifier nonReentrantSelectWinner() { 676 | // On the first call to nonReentrant, _notEntered will be true 677 | require(_statusSelectWinner != _ENTERED, "ReentrancyGuard: reentrant call"); 678 | 679 | // Any calls to nonReentrant after this point will fail 680 | _statusSelectWinner = _ENTERED; 681 | 682 | _; 683 | 684 | // By storing the original value once again, a refund is triggered (see 685 | // https://eips.ethereum.org/EIPS/eip-2200) 686 | _statusSelectWinner = _NOT_ENTERED; 687 | } 688 | 689 | modifier nonReentrantGivePriceToWinner() { 690 | // On the first call to nonReentrant, _notEntered will be true 691 | require(_statusGivePriceToWinner != _ENTERED, "ReentrancyGuard: reentrant call"); 692 | 693 | // Any calls to nonReentrant after this point will fail 694 | _statusGivePriceToWinner = _ENTERED; 695 | 696 | _; 697 | 698 | // By storing the original value once again, a refund is triggered (see 699 | // https://eips.ethereum.org/EIPS/eip-2200) 700 | _statusGivePriceToWinner = _NOT_ENTERED; 701 | } 702 | } 703 | 704 | // File: @openzeppelin/contracts/utils/Context.sol 705 | 706 | 707 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 708 | 709 | pragma solidity ^0.8.0; 710 | 711 | /** 712 | * @dev Provides information about the current execution context, including the 713 | * sender of the transaction and its data. While these are generally available 714 | * via msg.sender and msg.data, they should not be accessed in such a direct 715 | * manner, since when dealing with meta-transactions the account sending and 716 | * paying for execution may not be the actual sender (as far as an application 717 | * is concerned). 718 | * 719 | * This contract is only required for intermediate, library-like contracts. 720 | */ 721 | abstract contract Context { 722 | function _msgSender() internal view virtual returns (address) { 723 | return msg.sender; 724 | } 725 | 726 | function _msgData() internal view virtual returns (bytes calldata) { 727 | return msg.data; 728 | } 729 | } 730 | 731 | // File: @openzeppelin/contracts/token/ERC721/ERC721.sol 732 | 733 | 734 | // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/ERC721.sol) 735 | 736 | pragma solidity ^0.8.0; 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | /** 746 | * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including 747 | * the Metadata extension, but not including the Enumerable extension, which is available separately as 748 | * {ERC721Enumerable}. 749 | */ 750 | contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { 751 | using Address for address; 752 | using Strings for uint256; 753 | 754 | // Token name 755 | string private _name; 756 | 757 | // Token symbol 758 | string private _symbol; 759 | 760 | // Mapping from token ID to owner address 761 | mapping(uint256 => address) private _owners; 762 | 763 | // Mapping owner address to token count 764 | mapping(address => uint256) private _balances; 765 | 766 | // Mapping from token ID to approved address 767 | mapping(uint256 => address) private _tokenApprovals; 768 | 769 | // Mapping from owner to operator approvals 770 | mapping(address => mapping(address => bool)) private _operatorApprovals; 771 | 772 | /** 773 | * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. 774 | */ 775 | constructor(string memory name_, string memory symbol_) { 776 | _name = name_; 777 | _symbol = symbol_; 778 | } 779 | 780 | /** 781 | * @dev See {IERC165-supportsInterface}. 782 | */ 783 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { 784 | return 785 | interfaceId == type(IERC721).interfaceId || 786 | interfaceId == type(IERC721Metadata).interfaceId || 787 | super.supportsInterface(interfaceId); 788 | } 789 | 790 | /** 791 | * @dev See {IERC721-balanceOf}. 792 | */ 793 | function balanceOf(address owner) public view virtual override returns (uint256) { 794 | require(owner != address(0), "ERC721: balance query for the zero address"); 795 | return _balances[owner]; 796 | } 797 | 798 | /** 799 | * @dev See {IERC721-ownerOf}. 800 | */ 801 | function ownerOf(uint256 tokenId) public view virtual override returns (address) { 802 | address owner = _owners[tokenId]; 803 | require(owner != address(0), "ERC721: owner query for nonexistent token"); 804 | return owner; 805 | } 806 | 807 | /** 808 | * @dev See {IERC721Metadata-name}. 809 | */ 810 | function name() public view virtual override returns (string memory) { 811 | return _name; 812 | } 813 | 814 | /** 815 | * @dev See {IERC721Metadata-symbol}. 816 | */ 817 | function symbol() public view virtual override returns (string memory) { 818 | return _symbol; 819 | } 820 | 821 | /** 822 | * @dev See {IERC721Metadata-tokenURI}. 823 | */ 824 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 825 | require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); 826 | 827 | string memory baseURI = _baseURI(); 828 | return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; 829 | } 830 | 831 | /** 832 | * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each 833 | * token will be the concatenation of the `baseURI` and the `tokenId`. Empty 834 | * by default, can be overriden in child contracts. 835 | */ 836 | function _baseURI() internal view virtual returns (string memory) { 837 | return ""; 838 | } 839 | 840 | /** 841 | * @dev See {IERC721-approve}. 842 | */ 843 | function approve(address to, uint256 tokenId) public virtual override { 844 | address owner = ERC721.ownerOf(tokenId); 845 | require(to != owner, "ERC721: approval to current owner"); 846 | 847 | require( 848 | _msgSender() == owner || isApprovedForAll(owner, _msgSender()), 849 | "ERC721: approve caller is not owner nor approved for all" 850 | ); 851 | 852 | _approve(to, tokenId); 853 | } 854 | 855 | /** 856 | * @dev See {IERC721-getApproved}. 857 | */ 858 | function getApproved(uint256 tokenId) public view virtual override returns (address) { 859 | require(_exists(tokenId), "ERC721: approved query for nonexistent token"); 860 | 861 | return _tokenApprovals[tokenId]; 862 | } 863 | 864 | /** 865 | * @dev See {IERC721-setApprovalForAll}. 866 | */ 867 | function setApprovalForAll(address operator, bool approved) public virtual override { 868 | _setApprovalForAll(_msgSender(), operator, approved); 869 | } 870 | 871 | /** 872 | * @dev See {IERC721-isApprovedForAll}. 873 | */ 874 | function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { 875 | return _operatorApprovals[owner][operator]; 876 | } 877 | 878 | /** 879 | * @dev See {IERC721-transferFrom}. 880 | */ 881 | function transferFrom( 882 | address from, 883 | address to, 884 | uint256 tokenId 885 | ) public virtual override { 886 | //solhint-disable-next-line max-line-length 887 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 888 | 889 | _transfer(from, to, tokenId); 890 | } 891 | 892 | /** 893 | * @dev See {IERC721-safeTransferFrom}. 894 | */ 895 | function safeTransferFrom( 896 | address from, 897 | address to, 898 | uint256 tokenId 899 | ) public virtual override { 900 | safeTransferFrom(from, to, tokenId, ""); 901 | } 902 | 903 | /** 904 | * @dev See {IERC721-safeTransferFrom}. 905 | */ 906 | function safeTransferFrom( 907 | address from, 908 | address to, 909 | uint256 tokenId, 910 | bytes memory _data 911 | ) public virtual override { 912 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 913 | _safeTransfer(from, to, tokenId, _data); 914 | } 915 | 916 | /** 917 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 918 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 919 | * 920 | * `_data` is additional data, it has no specified format and it is sent in call to `to`. 921 | * 922 | * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. 923 | * implement alternative mechanisms to perform token transfer, such as signature-based. 924 | * 925 | * Requirements: 926 | * 927 | * - `from` cannot be the zero address. 928 | * - `to` cannot be the zero address. 929 | * - `tokenId` token must exist and be owned by `from`. 930 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 931 | * 932 | * Emits a {Transfer} event. 933 | */ 934 | function _safeTransfer( 935 | address from, 936 | address to, 937 | uint256 tokenId, 938 | bytes memory _data 939 | ) internal virtual { 940 | _transfer(from, to, tokenId); 941 | require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); 942 | } 943 | 944 | /** 945 | * @dev Returns whether `tokenId` exists. 946 | * 947 | * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. 948 | * 949 | * Tokens start existing when they are minted (`_mint`), 950 | * and stop existing when they are burned (`_burn`). 951 | */ 952 | function _exists(uint256 tokenId) internal view virtual returns (bool) { 953 | return _owners[tokenId] != address(0); 954 | } 955 | 956 | /** 957 | * @dev Returns whether `spender` is allowed to manage `tokenId`. 958 | * 959 | * Requirements: 960 | * 961 | * - `tokenId` must exist. 962 | */ 963 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { 964 | require(_exists(tokenId), "ERC721: operator query for nonexistent token"); 965 | address owner = ERC721.ownerOf(tokenId); 966 | return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); 967 | } 968 | 969 | /** 970 | * @dev Safely mints `tokenId` and transfers it to `to`. 971 | * 972 | * Requirements: 973 | * 974 | * - `tokenId` must not exist. 975 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 976 | * 977 | * Emits a {Transfer} event. 978 | */ 979 | function _safeMint(address to, uint256 tokenId) internal virtual { 980 | _safeMint(to, tokenId, ""); 981 | } 982 | 983 | /** 984 | * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is 985 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 986 | */ 987 | function _safeMint( 988 | address to, 989 | uint256 tokenId, 990 | bytes memory _data 991 | ) internal virtual { 992 | _mint(to, tokenId); 993 | require( 994 | _checkOnERC721Received(address(0), to, tokenId, _data), 995 | "ERC721: transfer to non ERC721Receiver implementer" 996 | ); 997 | } 998 | 999 | /** 1000 | * @dev Mints `tokenId` and transfers it to `to`. 1001 | * 1002 | * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible 1003 | * 1004 | * Requirements: 1005 | * 1006 | * - `tokenId` must not exist. 1007 | * - `to` cannot be the zero address. 1008 | * 1009 | * Emits a {Transfer} event. 1010 | */ 1011 | function _mint(address to, uint256 tokenId) internal virtual { 1012 | require(to != address(0), "ERC721: mint to the zero address"); 1013 | require(!_exists(tokenId), "ERC721: token already minted"); 1014 | 1015 | _beforeTokenTransfer(address(0), to, tokenId); 1016 | 1017 | _balances[to] += 1; 1018 | _owners[tokenId] = to; 1019 | 1020 | emit Transfer(address(0), to, tokenId); 1021 | 1022 | _afterTokenTransfer(address(0), to, tokenId); 1023 | } 1024 | 1025 | /** 1026 | * @dev Destroys `tokenId`. 1027 | * The approval is cleared when the token is burned. 1028 | * 1029 | * Requirements: 1030 | * 1031 | * - `tokenId` must exist. 1032 | * 1033 | * Emits a {Transfer} event. 1034 | */ 1035 | function _burn(uint256 tokenId) internal virtual { 1036 | address owner = ERC721.ownerOf(tokenId); 1037 | 1038 | _beforeTokenTransfer(owner, address(0), tokenId); 1039 | 1040 | // Clear approvals 1041 | _approve(address(0), tokenId); 1042 | 1043 | _balances[owner] -= 1; 1044 | delete _owners[tokenId]; 1045 | 1046 | emit Transfer(owner, address(0), tokenId); 1047 | 1048 | _afterTokenTransfer(owner, address(0), tokenId); 1049 | } 1050 | 1051 | /** 1052 | * @dev Transfers `tokenId` from `from` to `to`. 1053 | * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. 1054 | * 1055 | * Requirements: 1056 | * 1057 | * - `to` cannot be the zero address. 1058 | * - `tokenId` token must be owned by `from`. 1059 | * 1060 | * Emits a {Transfer} event. 1061 | */ 1062 | function _transfer( 1063 | address from, 1064 | address to, 1065 | uint256 tokenId 1066 | ) internal virtual { 1067 | require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); 1068 | require(to != address(0), "ERC721: transfer to the zero address"); 1069 | 1070 | _beforeTokenTransfer(from, to, tokenId); 1071 | 1072 | // Clear approvals from the previous owner 1073 | _approve(address(0), tokenId); 1074 | 1075 | _balances[from] -= 1; 1076 | _balances[to] += 1; 1077 | _owners[tokenId] = to; 1078 | 1079 | emit Transfer(from, to, tokenId); 1080 | 1081 | _afterTokenTransfer(from, to, tokenId); 1082 | } 1083 | 1084 | /** 1085 | * @dev Approve `to` to operate on `tokenId` 1086 | * 1087 | * Emits a {Approval} event. 1088 | */ 1089 | function _approve(address to, uint256 tokenId) internal virtual { 1090 | _tokenApprovals[tokenId] = to; 1091 | emit Approval(ERC721.ownerOf(tokenId), to, tokenId); 1092 | } 1093 | 1094 | /** 1095 | * @dev Approve `operator` to operate on all of `owner` tokens 1096 | * 1097 | * Emits a {ApprovalForAll} event. 1098 | */ 1099 | function _setApprovalForAll( 1100 | address owner, 1101 | address operator, 1102 | bool approved 1103 | ) internal virtual { 1104 | require(owner != operator, "ERC721: approve to caller"); 1105 | _operatorApprovals[owner][operator] = approved; 1106 | emit ApprovalForAll(owner, operator, approved); 1107 | } 1108 | 1109 | /** 1110 | * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. 1111 | * The call is not executed if the target address is not a contract. 1112 | * 1113 | * @param from address representing the previous owner of the given token ID 1114 | * @param to target address that will receive the tokens 1115 | * @param tokenId uint256 ID of the token to be transferred 1116 | * @param _data bytes optional data to send along with the call 1117 | * @return bool whether the call correctly returned the expected magic value 1118 | */ 1119 | function _checkOnERC721Received( 1120 | address from, 1121 | address to, 1122 | uint256 tokenId, 1123 | bytes memory _data 1124 | ) private returns (bool) { 1125 | if (to.isContract()) { 1126 | try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { 1127 | return retval == IERC721Receiver.onERC721Received.selector; 1128 | } catch (bytes memory reason) { 1129 | if (reason.length == 0) { 1130 | revert("ERC721: transfer to non ERC721Receiver implementer"); 1131 | } else { 1132 | assembly { 1133 | revert(add(32, reason), mload(reason)) 1134 | } 1135 | } 1136 | } 1137 | } else { 1138 | return true; 1139 | } 1140 | } 1141 | 1142 | /** 1143 | * @dev Hook that is called before any token transfer. This includes minting 1144 | * and burning. 1145 | * 1146 | * Calling conditions: 1147 | * 1148 | * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be 1149 | * transferred to `to`. 1150 | * - When `from` is zero, `tokenId` will be minted for `to`. 1151 | * - When `to` is zero, ``from``'s `tokenId` will be burned. 1152 | * - `from` and `to` are never both zero. 1153 | * 1154 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 1155 | */ 1156 | function _beforeTokenTransfer( 1157 | address from, 1158 | address to, 1159 | uint256 tokenId 1160 | ) internal virtual {} 1161 | 1162 | /** 1163 | * @dev Hook that is called after any transfer of tokens. This includes 1164 | * minting and burning. 1165 | * 1166 | * Calling conditions: 1167 | * 1168 | * - when `from` and `to` are both non-zero. 1169 | * - `from` and `to` are never both zero. 1170 | * 1171 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 1172 | */ 1173 | function _afterTokenTransfer( 1174 | address from, 1175 | address to, 1176 | uint256 tokenId 1177 | ) internal virtual {} 1178 | } 1179 | 1180 | // File: @openzeppelin/contracts/access/Ownable.sol 1181 | 1182 | 1183 | // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) 1184 | 1185 | pragma solidity ^0.8.0; 1186 | 1187 | 1188 | /** 1189 | * @dev Contract module which provides a basic access control mechanism, where 1190 | * there is an account (an owner) that can be granted exclusive access to 1191 | * specific functions. 1192 | * 1193 | * By default, the owner account will be the one that deploys the contract. This 1194 | * can later be changed with {transferOwnership}. 1195 | * 1196 | * This module is used through inheritance. It will make available the modifier 1197 | * `onlyOwner`, which can be applied to your functions to restrict their use to 1198 | * the owner. 1199 | */ 1200 | abstract contract Ownable is Context { 1201 | address private _owner; 1202 | 1203 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 1204 | 1205 | /** 1206 | * @dev Initializes the contract setting the deployer as the initial owner. 1207 | */ 1208 | constructor() { 1209 | _transferOwnership(_msgSender()); 1210 | } 1211 | 1212 | /** 1213 | * @dev Returns the address of the current owner. 1214 | */ 1215 | function owner() public view virtual returns (address) { 1216 | return _owner; 1217 | } 1218 | 1219 | /** 1220 | * @dev Throws if called by any account other than the owner. 1221 | */ 1222 | modifier onlyOwner() { 1223 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 1224 | _; 1225 | } 1226 | 1227 | /** 1228 | * @dev Leaves the contract without owner. It will not be possible to call 1229 | * `onlyOwner` functions anymore. Can only be called by the current owner. 1230 | * 1231 | * NOTE: Renouncing ownership will leave the contract without an owner, 1232 | * thereby removing any functionality that is only available to the owner. 1233 | */ 1234 | function renounceOwnership() public virtual onlyOwner { 1235 | _transferOwnership(address(0)); 1236 | } 1237 | 1238 | /** 1239 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 1240 | * Can only be called by the current owner. 1241 | */ 1242 | function transferOwnership(address newOwner) public virtual onlyOwner { 1243 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 1244 | _transferOwnership(newOwner); 1245 | } 1246 | 1247 | /** 1248 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 1249 | * Internal function without access restriction. 1250 | */ 1251 | function _transferOwnership(address newOwner) internal virtual { 1252 | address oldOwner = _owner; 1253 | _owner = newOwner; 1254 | emit OwnershipTransferred(oldOwner, newOwner); 1255 | } 1256 | } 1257 | 1258 | // File: artifacts/HodlNFT.sol 1259 | 1260 | 1261 | pragma solidity ^0.8.7; 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | contract HodlNFT is ERC721, Ownable { 1269 | address private RewardWallet; 1270 | 1271 | event SetHodlNFTPrice(address addr, uint256 newNFTPrice); 1272 | event SetBaseURI(address addr, string newUri); 1273 | event SetHodlNFTURI(address addr, string newUri); 1274 | event SetRewardWalletAddress(address addr, address rewardWallet); 1275 | 1276 | using Strings for uint256; 1277 | 1278 | uint256 private HODL_NFT_PRICE = 10; //HODL token 1279 | 1280 | using Counters for Counters.Counter; 1281 | Counters.Counter private _hodlTokenCounter; 1282 | 1283 | string private _baseURIExtended; 1284 | 1285 | string private hodlNFTURI; 1286 | 1287 | /** 1288 | * @dev Throws if called by any account other than the multi-signer. 1289 | */ 1290 | // modifier onlyMultiSignWallet() { 1291 | // require(owner() == _msgSender(), "Multi-signer: caller is not the multi-signer"); 1292 | // _; 1293 | // } 1294 | 1295 | constructor() ERC721("HODL NFT","HNFT") { 1296 | _baseURIExtended = "https://ipfs.infura.io/"; 1297 | } 1298 | 1299 | function setRewardWalletAddress(address _newRewardWallet) external onlyOwner{ 1300 | RewardWallet = _newRewardWallet; 1301 | emit SetRewardWalletAddress(msg.sender, _newRewardWallet); 1302 | } 1303 | 1304 | //Set, Get Price Func 1305 | function setHodlNFTPrice(uint256 _newNFTValue) external onlyOwner{ 1306 | HODL_NFT_PRICE = _newNFTValue; 1307 | emit SetHodlNFTPrice(msg.sender, _newNFTValue); 1308 | } 1309 | 1310 | function getHodlNFTPrice() external view returns(uint256){ 1311 | return HODL_NFT_PRICE; 1312 | } 1313 | 1314 | function getHodlNFTURI() external view returns(string memory){ 1315 | return hodlNFTURI; 1316 | } 1317 | 1318 | function setHodlNFTURI(string memory _hodlNFTURI) external onlyOwner{ 1319 | hodlNFTURI = _hodlNFTURI; 1320 | emit SetHodlNFTURI(msg.sender, hodlNFTURI); 1321 | } 1322 | 1323 | /** 1324 | * @dev Mint NFT by customer 1325 | */ 1326 | function mintNFT(address sender) external returns (uint256) { 1327 | 1328 | require( msg.sender == RewardWallet, "you can't mint from other account"); 1329 | 1330 | // Incrementing ID to create new token 1331 | uint256 newHodlNFTID = _hodlTokenCounter.current(); 1332 | _hodlTokenCounter.increment(); 1333 | 1334 | _safeMint(sender, newHodlNFTID); 1335 | return newHodlNFTID; 1336 | } 1337 | 1338 | /** 1339 | * @dev Return the base URI 1340 | */ 1341 | function _baseURI() internal override view returns (string memory) { 1342 | return _baseURIExtended; 1343 | } 1344 | 1345 | /** 1346 | * @dev Set the base URI 1347 | */ 1348 | function setBaseURI(string memory baseURI_) external onlyOwner() { 1349 | _baseURIExtended = baseURI_; 1350 | emit SetBaseURI(msg.sender, baseURI_); 1351 | } 1352 | } 1353 | // File: artifacts/HodlLottery.sol 1354 | 1355 | pragma solidity 0.8.7; 1356 | pragma experimental ABIEncoderV2; 1357 | 1358 | // import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 1359 | 1360 | 1361 | 1362 | contract HodlLottery is Ownable, ReentrancyGuard { 1363 | // 2 kinds of lottery 1364 | enum LOTTERY_TYPE { 1365 | LOTTERY_WEEKLY, 1366 | LOTTERY_BI_DAILY 1367 | } 1368 | 1369 | // lottery status 1370 | enum LOTTERY_STATUS { 1371 | LOTTERY_START, 1372 | LOTTERY_CLOSED, 1373 | LOTTERY_PICKED 1374 | } 1375 | 1376 | // team funds wallet address 1377 | address payable _teamFundsWallet = payable(0xbAB8E9cA493E21d5A3f3e84877Ba514c405be0e1); 1378 | 1379 | // private seed data for claculating picked number 1380 | uint256 private constant MAX_UINT_VALUE = (2**255 - 1 + 2**255); 1381 | uint256 private pri_seedValue; 1382 | string private pri_seedString; 1383 | address private pri_seedAddress; 1384 | 1385 | // distribution percentage of funds 1386 | uint256 constant REWARD_FOR_TEAM_FUND = 1; // 10% goes to team funds 1387 | uint256 constant REWARD_FOR_REWARD_POOL = 9; // 90% goes to rewards pool 1388 | uint256 constant LOTTERY_FEE = 1; // 10% goes to team funds 1389 | 1390 | // price of ticket 1391 | uint256 PRICE_TICKET_WEEKLY = 1 * 10 ** 17; // 0.1 AVAX 1392 | uint256 PRICE_TICKET_BI_DAILY = 3 * 10 ** 16; // 0.03 AVAX 1393 | 1394 | // lottery loop time 1395 | uint256 WEEKLY_LOOP_TIME = 60 * 60 * 24 * 7; // 7 days 1396 | uint256 BI_DAILY_LOOP_TIME = 60 * 60 * 24 * 2; // 2 days 1397 | 1398 | // this is for first lottery 1399 | uint256 constant TEMPORARY_TIME = 60 * 60 * 5; // 5 hour 1400 | 1401 | // when user buy ticket, NFT is minted 1402 | HodlNFT public nftContract; 1403 | 1404 | // this is for get user ticket numbers 1405 | struct Ticket_Address { 1406 | uint256 timestamp; 1407 | uint16 startNumber; 1408 | uint16 count; 1409 | } 1410 | 1411 | // return ticket status 1412 | struct Ret_Ticket_Status { 1413 | LOTTERY_STATUS status; 1414 | uint256 totalCount; 1415 | uint256 poolAmount; 1416 | } 1417 | 1418 | // there are 2 kinds of lottery 1419 | // weekly lottery: per week 1420 | // bi-daily lottery: per bi-daily 1421 | struct Lottery_Info { 1422 | uint256 lotteryID; // lottery id 1423 | LOTTERY_STATUS lotteryStatus; // current status of lottery 1424 | uint256 lotteryTimeStamp; // lottery time stamp 1425 | uint256 poolAmount; // all amount of inputed AVAX 1426 | uint16[] ids; // start ids of tickes user bought 1427 | uint16 winnerID; 1428 | uint256 winnerPrize; 1429 | mapping(uint16 => address) members; // address of start id 1430 | mapping(uint16 => uint16) ticketsOfMember; // ticket ids of members 1431 | } 1432 | 1433 | // lottery infos of weekly lottery 1434 | mapping(uint256 => Lottery_Info) internal allWeeklyLotteryInfos; 1435 | 1436 | // lottery infos of bi-daily lottery 1437 | mapping(uint256 => Lottery_Info) internal allBiDailyLotteryInfos; 1438 | 1439 | // last available lottery id 1440 | uint256 public weeklyLotteryCounter; 1441 | uint256 public biDailyLotteryCounter; 1442 | 1443 | // this is sum of total payout 1444 | uint256 public totalMarketcap; 1445 | 1446 | // invest amount current site was paid 1447 | uint256 private totalInvestments; 1448 | 1449 | // all events 1450 | event Received (address from, uint amount); 1451 | event Fallback (address from, uint amount); 1452 | event SetTeamFundsAddress (address addr); 1453 | event SetWeeklyTicketPrice (uint256 price); 1454 | event SetBiDailyTicketPrice (uint256 price); 1455 | event ChangeLotteryInfo (LOTTERY_TYPE lottery_type, uint256 lottery_id, LOTTERY_STATUS status, uint256 time); 1456 | event ClearLotteryInfo (LOTTERY_TYPE lottery_type, uint256 lottery_id); 1457 | event CreateNewLotteryInfo (LOTTERY_TYPE lottery_type, uint256 lottery_id, LOTTERY_STATUS status); 1458 | event BuyTicket (address addr, LOTTERY_TYPE lottery_type, uint256 lottery_id, uint256 time, uint16 startNo, uint16 count); 1459 | event LogAllSeedValueChanged (address addr, uint256 seed1, uint256 seed2, string seed3, address seed4); 1460 | event SelectWinner (LOTTERY_TYPE lottery_type, uint256 lottery_id, uint256 time, address addr, uint256 ticketID, uint256 price); 1461 | event GivePriceToWinner(LOTTERY_TYPE lottery_type, uint256 lottery_id, address addr, uint256 time, uint256 ticketID, uint256 amount); 1462 | event SetWeeklyLoopTime (uint256 loopTime); 1463 | event SetBiDailyLoopTime (uint256 loopTime); 1464 | event SetTotalInvestment (uint256 loopTime); 1465 | event SetLotteryStatus (LOTTERY_TYPE lottery_type, uint256 lottery_id); 1466 | event WithdrawAll (address addr, uint256 balance); 1467 | 1468 | // contructor 1469 | constructor ( 1470 | uint256 _seedValue, 1471 | string memory _seedString, 1472 | address _seedAddress, 1473 | address _nftContract 1474 | ) 1475 | { 1476 | pri_seedValue = _seedValue; 1477 | pri_seedString = _seedString; 1478 | pri_seedAddress = _seedAddress; 1479 | 1480 | weeklyLotteryCounter = 0; 1481 | biDailyLotteryCounter = 0; 1482 | 1483 | nftContract = HodlNFT(_nftContract); 1484 | } 1485 | 1486 | receive() external payable { 1487 | emit Received(msg.sender, msg.value); 1488 | } 1489 | 1490 | fallback() external payable { 1491 | emit Fallback(msg.sender, msg.value); 1492 | } 1493 | 1494 | function setTeamFundsAddress (address _addr) external onlyOwner { 1495 | _teamFundsWallet = payable(_addr); 1496 | emit SetTeamFundsAddress (_teamFundsWallet); 1497 | } 1498 | 1499 | function getTeamFundsAddress () external view returns (address) { 1500 | return _teamFundsWallet; 1501 | } 1502 | 1503 | function setWeeklyTicketPrice (uint256 _ticketPrice) external onlyOwner { 1504 | PRICE_TICKET_WEEKLY = _ticketPrice; 1505 | emit SetWeeklyTicketPrice (_ticketPrice); 1506 | } 1507 | 1508 | function getWeeklyTicketPrice () external view returns (uint256) { 1509 | return PRICE_TICKET_WEEKLY; 1510 | } 1511 | 1512 | function setBiDailyTicketPrice (uint256 _ticketPrice) external onlyOwner { 1513 | PRICE_TICKET_BI_DAILY = _ticketPrice; 1514 | emit SetBiDailyTicketPrice (_ticketPrice); 1515 | } 1516 | 1517 | function getBiDailyTicketPrice () external view returns (uint256) { 1518 | return PRICE_TICKET_BI_DAILY; 1519 | } 1520 | 1521 | function setWeeklyLoopTime (uint256 _time) external onlyOwner { 1522 | WEEKLY_LOOP_TIME = _time; 1523 | emit SetWeeklyLoopTime (WEEKLY_LOOP_TIME); 1524 | } 1525 | 1526 | function getWeeklyLoopTime () external view returns (uint256) { 1527 | return WEEKLY_LOOP_TIME; 1528 | } 1529 | 1530 | function setBiDailyLoopTime (uint256 _time) external onlyOwner { 1531 | BI_DAILY_LOOP_TIME = _time; 1532 | emit SetBiDailyLoopTime (BI_DAILY_LOOP_TIME); 1533 | } 1534 | 1535 | function getBiDailyLoopTime () external view returns (uint256) { 1536 | return BI_DAILY_LOOP_TIME; 1537 | } 1538 | 1539 | function setTotalInvestment (uint256 _value) external onlyOwner { 1540 | totalInvestments = _value; 1541 | emit SetTotalInvestment (totalInvestments); 1542 | } 1543 | 1544 | function getTotalInvestment () external view returns (uint256) { 1545 | return totalInvestments; 1546 | } 1547 | 1548 | function withdrawAll() external onlyOwner{ 1549 | uint256 balance = address(this).balance; 1550 | address payable mine = payable(msg.sender); 1551 | if(balance > 0) { 1552 | mine.transfer(balance); 1553 | } 1554 | emit WithdrawAll(msg.sender, balance); 1555 | } 1556 | 1557 | // admin can oly change status and timestamp of started lottery 1558 | function changeLotteryInfo (LOTTERY_TYPE _lotteryType, uint256 _lotteryID, LOTTERY_STATUS _status, uint256 _timestamp) external onlyOwner { 1559 | Lottery_Info storage lottoInfo; 1560 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1561 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1562 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 1563 | } 1564 | else { 1565 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1566 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 1567 | } 1568 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "admin can't change data"); 1569 | 1570 | lottoInfo.lotteryStatus = _status; 1571 | lottoInfo.lotteryTimeStamp = _timestamp; 1572 | 1573 | emit ChangeLotteryInfo (_lotteryType, _lotteryID, _status, _timestamp); 1574 | } 1575 | 1576 | // admin can remove lottery 1577 | function clearLotteryInfo (LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external onlyOwner { 1578 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1579 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1580 | delete allWeeklyLotteryInfos[_lotteryID]; 1581 | weeklyLotteryCounter --; 1582 | } 1583 | else { 1584 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1585 | delete allBiDailyLotteryInfos[_lotteryID]; 1586 | biDailyLotteryCounter --; 1587 | } 1588 | 1589 | emit ClearLotteryInfo (_lotteryType, _lotteryID); 1590 | } 1591 | 1592 | // only owner can create new lottery 1593 | function createNewLotteryInfo (LOTTERY_TYPE lottery_type) external onlyOwner { 1594 | require (lottery_type <= LOTTERY_TYPE.LOTTERY_BI_DAILY, "This lottery doesn't exist"); 1595 | Lottery_Info storage newLottery; 1596 | uint256 nLotteryTime = block.timestamp + TEMPORARY_TIME; 1597 | uint256 poolAmount = 0; 1598 | if (lottery_type == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1599 | if (weeklyLotteryCounter > 0) { 1600 | require(allWeeklyLotteryInfos[weeklyLotteryCounter - 1].lotteryStatus == LOTTERY_STATUS.LOTTERY_PICKED, "Previous lottery doesn't complete."); 1601 | nLotteryTime = allWeeklyLotteryInfos[weeklyLotteryCounter - 1].lotteryTimeStamp + WEEKLY_LOOP_TIME; 1602 | 1603 | // previous pool amount goes to next lottery 1604 | poolAmount = allWeeklyLotteryInfos[weeklyLotteryCounter - 1].poolAmount; 1605 | allWeeklyLotteryInfos[weeklyLotteryCounter - 1].poolAmount = 0; 1606 | } 1607 | newLottery = allWeeklyLotteryInfos[weeklyLotteryCounter]; 1608 | newLottery.lotteryID = weeklyLotteryCounter; 1609 | weeklyLotteryCounter ++; 1610 | } 1611 | else { 1612 | if (biDailyLotteryCounter > 0) { 1613 | require(allBiDailyLotteryInfos[biDailyLotteryCounter - 1].lotteryStatus == LOTTERY_STATUS.LOTTERY_PICKED, "Previous lottery doesn't complete."); 1614 | nLotteryTime = allBiDailyLotteryInfos[biDailyLotteryCounter - 1].lotteryTimeStamp + BI_DAILY_LOOP_TIME; 1615 | 1616 | // previous pool amount goes to next lottery 1617 | poolAmount = allBiDailyLotteryInfos[biDailyLotteryCounter - 1].poolAmount; 1618 | allBiDailyLotteryInfos[biDailyLotteryCounter - 1].poolAmount = 0; 1619 | } 1620 | newLottery = allBiDailyLotteryInfos[biDailyLotteryCounter]; 1621 | newLottery.lotteryID = biDailyLotteryCounter; 1622 | biDailyLotteryCounter ++; 1623 | } 1624 | newLottery.lotteryStatus = LOTTERY_STATUS.LOTTERY_START; 1625 | newLottery.lotteryTimeStamp = nLotteryTime; 1626 | newLottery.poolAmount = poolAmount; 1627 | newLottery.ids.push(1); 1628 | newLottery.members[1] = address(msg.sender); 1629 | newLottery.ticketsOfMember[1] = 0; 1630 | 1631 | emit CreateNewLotteryInfo (lottery_type, newLottery.lotteryID, LOTTERY_STATUS.LOTTERY_START); 1632 | } 1633 | 1634 | // Get remain time of last lottery 1635 | function getLotteryRemainTime(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external view returns(uint256) { 1636 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1637 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1638 | if (allWeeklyLotteryInfos[_lotteryID].lotteryTimeStamp <= block.timestamp) { 1639 | return 0; 1640 | } 1641 | return allWeeklyLotteryInfos[_lotteryID].lotteryTimeStamp - block.timestamp; 1642 | } 1643 | else { 1644 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1645 | if (allBiDailyLotteryInfos[_lotteryID].lotteryTimeStamp <= block.timestamp) { 1646 | return 0; 1647 | } 1648 | return allBiDailyLotteryInfos[_lotteryID].lotteryTimeStamp - block.timestamp; 1649 | } 1650 | } 1651 | 1652 | // set lottery status after lottery time 1653 | function setLotteryStatus(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external onlyOwner returns(bool) { 1654 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1655 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1656 | require(allWeeklyLotteryInfos[_lotteryID].lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "This Lottery Status is not Start."); 1657 | require(allWeeklyLotteryInfos[_lotteryID].ids.length > 1, "User has to buy Ticket"); 1658 | if (allWeeklyLotteryInfos[weeklyLotteryCounter - 1].lotteryTimeStamp <= block.timestamp) { 1659 | allWeeklyLotteryInfos[_lotteryID].lotteryStatus = LOTTERY_STATUS.LOTTERY_CLOSED; 1660 | allWeeklyLotteryInfos[_lotteryID].lotteryTimeStamp = block.timestamp; 1661 | } 1662 | } 1663 | else { 1664 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1665 | require(allBiDailyLotteryInfos[_lotteryID].lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "This Lottery Status is not Start."); 1666 | require(allBiDailyLotteryInfos[_lotteryID].ids.length > 1, "User has to buy Ticket"); 1667 | if (allBiDailyLotteryInfos[biDailyLotteryCounter - 1].lotteryTimeStamp <= block.timestamp) { 1668 | allBiDailyLotteryInfos[_lotteryID].lotteryStatus = LOTTERY_STATUS.LOTTERY_CLOSED; 1669 | allBiDailyLotteryInfos[_lotteryID].lotteryTimeStamp = block.timestamp; 1670 | } 1671 | } 1672 | 1673 | emit SetLotteryStatus (_lotteryType, _lotteryID); 1674 | return true; 1675 | } 1676 | 1677 | // get full information of _lotteryID 1678 | function getLottoryInfo(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external view returns( 1679 | uint256, // startingTimestamp 1680 | uint16, // winnerID 1681 | address, // winnerAddress 1682 | uint256, // PoolAmountInAVAX 1683 | uint16, // NumberOfLottoMembers 1684 | uint256 // winnerPrize 1685 | ) 1686 | { 1687 | Lottery_Info storage lottoInfo; 1688 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1689 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1690 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 1691 | } 1692 | else { 1693 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1694 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 1695 | } 1696 | uint256 lotteryTimeStamp = lottoInfo.lotteryTimeStamp; 1697 | uint16 winnerID = lottoInfo.winnerID; 1698 | address winnerAddress = lottoInfo.members[lottoInfo.winnerID]; 1699 | uint256 poolAmount = lottoInfo.poolAmount; 1700 | uint16 NumberOfLottoMembers = uint16(lottoInfo.ids.length - 1); 1701 | uint256 winnerPrize = lottoInfo.winnerPrize; 1702 | return ( 1703 | lotteryTimeStamp, 1704 | winnerID, 1705 | winnerAddress, 1706 | poolAmount, 1707 | NumberOfLottoMembers, 1708 | winnerPrize 1709 | ); 1710 | } 1711 | 1712 | function buyTicket(LOTTERY_TYPE _lotteryType, uint256 _lotteryID, uint16 _numberOfTickets) external payable { 1713 | uint256 payAmount; 1714 | Lottery_Info storage lottoInfo; 1715 | require(_numberOfTickets > 0, "User has to input ticket number."); 1716 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1717 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1718 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 1719 | payAmount = PRICE_TICKET_WEEKLY * _numberOfTickets; 1720 | } 1721 | else { 1722 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1723 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 1724 | payAmount = PRICE_TICKET_BI_DAILY * _numberOfTickets; 1725 | } 1726 | require(lottoInfo.lotteryTimeStamp >= block.timestamp, "Time is up"); 1727 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_START, "Lottery doesn't start."); 1728 | 1729 | // pay AVAX for ticket 1730 | require(msg.value == payAmount, "no enough balance"); 1731 | _teamFundsWallet.transfer(payAmount * REWARD_FOR_TEAM_FUND / 10); 1732 | payable(address(this)).transfer(payAmount * REWARD_FOR_REWARD_POOL / 10); 1733 | lottoInfo.poolAmount += payAmount * REWARD_FOR_REWARD_POOL / 10; 1734 | 1735 | // insert data into lottery info 1736 | uint16 numTickets = _numberOfTickets; 1737 | for (uint i = 0; i < numTickets; i ++) { 1738 | nftContract.mintNFT(msg.sender); 1739 | } 1740 | uint16 lastID = lottoInfo.ids[lottoInfo.ids.length - 1]; 1741 | uint16 newID = lastID + lottoInfo.ticketsOfMember[lastID]; 1742 | 1743 | // first 10 users can get 2 times chance than others in weekly lottery 1744 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY && lottoInfo.ids.length <= 10) { 1745 | numTickets = _numberOfTickets * 2; 1746 | } 1747 | 1748 | lottoInfo.ids.push(newID); 1749 | lottoInfo.members[newID] = address(msg.sender); 1750 | lottoInfo.ticketsOfMember[newID] = numTickets; 1751 | 1752 | // insert blank ticket into lottery address 1753 | lastID = lottoInfo.ids[lottoInfo.ids.length - 1]; 1754 | uint16 blank_newID = lastID + lottoInfo.ticketsOfMember[lastID]; 1755 | 1756 | lottoInfo.ids.push(blank_newID); 1757 | lottoInfo.members[blank_newID] = address(this); 1758 | lottoInfo.ticketsOfMember[blank_newID] = _numberOfTickets; 1759 | 1760 | emit BuyTicket(msg.sender, _lotteryType, _lotteryID, block.timestamp, newID, numTickets); 1761 | } 1762 | 1763 | // Generate random number base on seed and timestamp. 1764 | function randomNumberGenerate(LOTTERY_TYPE _lotteryType) private view returns (uint16) { 1765 | // random hash from seed data 1766 | uint randomHash = uint(keccak256(abi.encodePacked(pri_seedValue, pri_seedString, pri_seedAddress, 1767 | block.timestamp, block.difficulty, block.number))); 1768 | 1769 | Lottery_Info storage lottoInfo; 1770 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1771 | lottoInfo = allWeeklyLotteryInfos[weeklyLotteryCounter - 1]; 1772 | } 1773 | else { 1774 | lottoInfo = allBiDailyLotteryInfos[biDailyLotteryCounter - 1]; 1775 | } 1776 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_CLOSED, "Lottery doesn't close."); 1777 | 1778 | // generate random number 1779 | uint16 lastID = uint16(lottoInfo.ids.length - 1); 1780 | uint16 totalMembers = lottoInfo.ids[lastID] + lottoInfo.ticketsOfMember[lottoInfo.ids[lastID]] - 1; 1781 | uint256 maxValue = MAX_UINT_VALUE / totalMembers; 1782 | uint16 randomNum = uint16(randomHash / maxValue) + 1; 1783 | if (randomNum > totalMembers) { 1784 | randomNum = 1; 1785 | } 1786 | 1787 | return randomNum; 1788 | } 1789 | 1790 | // only user can change seed data 1791 | function updateSeeds(uint256 _seedValue, string memory _seedString, address _seedAddress ) external onlyOwner returns(bool) { 1792 | // seed value check 1793 | require(_seedValue != 0 && _seedValue != pri_seedValue, 1794 | "The seed value can't be 0 value and can't be the same as the previous one."); 1795 | 1796 | // seed address check 1797 | require(_seedAddress != address(0) && _seedAddress != pri_seedAddress, 1798 | "The seed Address can't be 0 Address and can't be the same as the previous one."); 1799 | 1800 | // seed string check 1801 | require(keccak256(abi.encodePacked(_seedString)) != 0 && 1802 | keccak256(abi.encodePacked(_seedString)) != keccak256(abi.encodePacked(pri_seedString)), 1803 | "The seed String can't be 0 String and can't be the same as the previous one."); 1804 | 1805 | emit LogAllSeedValueChanged(msg.sender, block.timestamp, _seedValue, _seedString, _seedAddress); 1806 | 1807 | pri_seedValue = _seedValue; 1808 | pri_seedString = _seedString; 1809 | pri_seedAddress = _seedAddress; 1810 | 1811 | return true; 1812 | } 1813 | 1814 | // get winnder id 1815 | function selectWinner(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external nonReentrantSelectWinner onlyOwner returns(uint16) { 1816 | Lottery_Info storage lottoInfo; 1817 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1818 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1819 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 1820 | } 1821 | else { 1822 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1823 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 1824 | } 1825 | require(lottoInfo.lotteryStatus == LOTTERY_STATUS.LOTTERY_CLOSED, "This lotteryID does not close."); 1826 | require(lottoInfo.ids.length > 1, "user does not exist"); 1827 | require(lottoInfo.poolAmount > 1, "Lottery Pool is empty!"); 1828 | 1829 | uint16 winnerIDKey = randomNumberGenerate(_lotteryType); 1830 | 1831 | // binary search 1832 | /* initialize variables: 1833 | low : index of smallest value in current subarray of id array 1834 | high: index of largest value in current subarray of id array 1835 | mid : average of low and high in current subarray of id array */ 1836 | uint256 mid; 1837 | 1838 | uint256 low = 1; // set initial value for low 1839 | uint256 high = lottoInfo.ids.length - 1; // set initial value for high 1840 | 1841 | /* perform binary search */ 1842 | while (low <= high) { 1843 | mid = low + (high - low)/2; // update mid 1844 | 1845 | if ((winnerIDKey >= lottoInfo.ids[mid]) && 1846 | (winnerIDKey < lottoInfo.ids[mid] + lottoInfo.ticketsOfMember[lottoInfo.ids[mid]])) { 1847 | break; // find winnerID 1848 | } 1849 | else if (lottoInfo.ids[mid] > winnerIDKey) { // search left subarray for val 1850 | high = mid - 1; // update high 1851 | } 1852 | else if (lottoInfo.ids[mid] < winnerIDKey) { // search right subarray for val 1853 | low = mid + 1; // update low 1854 | } 1855 | } 1856 | 1857 | // send prize AVAX to winner 1858 | address winnerAddress = lottoInfo.members[lottoInfo.ids[mid]]; 1859 | uint256 winnerPrize = lottoInfo.poolAmount * (10 - LOTTERY_FEE) / 10; 1860 | uint256 feePrize = lottoInfo.poolAmount * LOTTERY_FEE / 10; 1861 | if (winnerAddress != address(this)) { 1862 | payable(winnerAddress).transfer(winnerPrize); 1863 | _teamFundsWallet.transfer(feePrize); 1864 | lottoInfo.winnerPrize = winnerPrize; 1865 | lottoInfo.poolAmount = 0; 1866 | totalMarketcap = totalMarketcap + winnerPrize; 1867 | } 1868 | lottoInfo.lotteryStatus = LOTTERY_STATUS.LOTTERY_PICKED; 1869 | 1870 | emit SelectWinner(_lotteryType, _lotteryID, lottoInfo.lotteryTimeStamp, winnerAddress, winnerIDKey, winnerPrize); 1871 | return lottoInfo.winnerID; 1872 | } 1873 | 1874 | // get current lottery status of _lotteryID 1875 | function getLotteryStatus(LOTTERY_TYPE _lotteryType, uint256 _lotteryID) external view returns(Ret_Ticket_Status memory) { 1876 | Ret_Ticket_Status memory ret_ticket; 1877 | Lottery_Info storage lottoInfo; 1878 | if (_lotteryType == LOTTERY_TYPE.LOTTERY_WEEKLY) { 1879 | require(_lotteryID < weeklyLotteryCounter, "This lotteryID does not exist."); 1880 | lottoInfo = allWeeklyLotteryInfos[_lotteryID]; 1881 | ret_ticket.status = allWeeklyLotteryInfos[_lotteryID].lotteryStatus; 1882 | ret_ticket.poolAmount = allWeeklyLotteryInfos[_lotteryID].poolAmount; 1883 | } 1884 | else { 1885 | require(_lotteryID < biDailyLotteryCounter, "This lotteryID does not exist."); 1886 | lottoInfo = allBiDailyLotteryInfos[_lotteryID]; 1887 | ret_ticket.status = allBiDailyLotteryInfos[_lotteryID].lotteryStatus; 1888 | ret_ticket.poolAmount = allBiDailyLotteryInfos[_lotteryID].poolAmount; 1889 | } 1890 | uint16 lastID = lottoInfo.ids[lottoInfo.ids.length - 1]; 1891 | ret_ticket.totalCount = lastID + lottoInfo.ticketsOfMember[lastID]; 1892 | 1893 | return ret_ticket; 1894 | } 1895 | } --------------------------------------------------------------------------------