文件 1 的 3:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 3:Grail.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
interface InterfaceRainbows {
function burn(address user, uint256 amount) external;
}
contract Grail is Ownable {
struct RaffleEntry {
address user;
uint32 count;
}
InterfaceRainbows public Rainbows;
address[] public winnerList;
uint256 public raffleEntryCost = 20 ether;
uint256 public raffleStartTime = 0;
uint256 public raffleEndTime = 0;
RaffleEntry[] public raffleEntries;
uint256 public totalRaffleEntries;
uint256 public uniqueEntryAddresses;
mapping(address => uint256) public userEntries;
mapping(address => bool) public winners;
event RaffleWinner(address indexed _winner);
mapping(address => bool) public extendedAccess;
modifier raffleEnabled() {
require(raffleStartTime > 0 && block.timestamp > raffleStartTime, "Raffle not started.");
require(raffleEndTime > 0 && block.timestamp <= raffleEndTime, "Raffle has ended.");
_;
}
modifier onlyFromRestricted() {
require(extendedAccess[msg.sender], "Your address does not have permission to use.");
_;
}
constructor() {
extendedAccess[msg.sender] = true;
}
function setAddressAccess(address _noundles, bool _value) public onlyOwner {
extendedAccess[_noundles] = _value;
}
function getAddressAccess(address user) external view returns(bool) {
return extendedAccess[user];
}
function resetRaffle() public onlyFromRestricted {
totalRaffleEntries = 0;
uniqueEntryAddresses = 0;
for(uint i; i < raffleEntries.length; i++) {
address user = raffleEntries[i].user;
userEntries[user] = 0;
winners[user] = false;
}
delete winnerList;
delete raffleEntries;
}
function resetWinners() internal {
for(uint i; i < raffleEntries.length; i++) {
address user = raffleEntries[i].user;
winners[user] = false;
}
delete winnerList;
}
function setRaffleSettings(uint256 _raffleStartTime, uint256 _raffleEndTime, uint256 _raffleEntryCost) public onlyFromRestricted {
raffleStartTime = _raffleStartTime;
raffleEndTime = _raffleEndTime;
raffleEntryCost = _raffleEntryCost;
}
function setAddresses(address _rainbow) external onlyOwner {
Rainbows = InterfaceRainbows(_rainbow);
}
function enterRaffle(uint32 _entryCount) public raffleEnabled {
Rainbows.burn(msg.sender, raffleEntryCost * _entryCount);
raffleEntries.push(RaffleEntry(msg.sender, _entryCount));
totalRaffleEntries += _entryCount;
if(userEntries[msg.sender] == 0) {
uniqueEntryAddresses += 1;
}
userEntries[msg.sender] += _entryCount;
}
function pickWinners(uint256 _winnerCount) public onlyFromRestricted {
require(_winnerCount <= uniqueEntryAddresses, "Can't have more winners than entries");
resetWinners();
uint256 retryCounter = 0;
for(uint256 i = 1; i < (_winnerCount + 1); i += 1) {
uint256 pick = getRandomNumber(i + retryCounter) % totalRaffleEntries;
uint256 runningTotal = 0;
for(uint r; r < raffleEntries.length; r += 1) {
RaffleEntry storage entry = raffleEntries[r];
if(runningTotal <= pick && pick < (runningTotal + entry.count)) {
if(winners[entry.user]) {
i--;
retryCounter += 1;
break;
}
winners[entry.user] = true;
emit RaffleWinner(entry.user);
winnerList.push(entry.user);
break;
}
runningTotal += entry.count;
}
}
}
function pickWinnersView(uint256 _winnerCount) public view returns (address [] memory){
require(_winnerCount <= uniqueEntryAddresses, "Can't have more winners than entries");
address[] memory localWinnerList = new address[](_winnerCount);
uint256 retryCounter = 0;
for(uint256 i = 1; i < (_winnerCount + 1); i += 1) {
uint256 pick = getRandomNumber(i + retryCounter) % totalRaffleEntries;
uint256 runningTotal = 0;
for(uint r; r < raffleEntries.length; r += 1) {
RaffleEntry storage entry = raffleEntries[r];
if(runningTotal <= pick && pick < (runningTotal + entry.count)) {
localWinnerList[i -1] = entry.user;
break;
}
runningTotal += entry.count;
}
}
return localWinnerList;
}
function getRandomNumber(uint256 _arg) public view returns (uint) {
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, _arg)));
}
function getEntryCount(address _arg) public view returns (uint256) {
return userEntries[_arg];
}
function getWinners() public view returns (address[] memory) {
return winnerList;
}
function checkWinners(address _arg) public view returns (bool) {
return winners[_arg];
}
}
文件 3 的 3:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"contracts/Grail.sol": "Grail"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_winner","type":"address"}],"name":"RaffleWinner","type":"event"},{"inputs":[],"name":"Rainbows","outputs":[{"internalType":"contract InterfaceRainbows","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_arg","type":"address"}],"name":"checkWinners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_entryCount","type":"uint32"}],"name":"enterRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"extendedAccess","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getAddressAccess","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_arg","type":"address"}],"name":"getEntryCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_arg","type":"uint256"}],"name":"getRandomNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWinners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_winnerCount","type":"uint256"}],"name":"pickWinners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_winnerCount","type":"uint256"}],"name":"pickWinnersView","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"raffleEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffleEntries","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"count","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"raffleEntryCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"raffleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_noundles","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setAddressAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rainbow","type":"address"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_raffleStartTime","type":"uint256"},{"internalType":"uint256","name":"_raffleEndTime","type":"uint256"},{"internalType":"uint256","name":"_raffleEntryCost","type":"uint256"}],"name":"setRaffleSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalRaffleEntries","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniqueEntryAddresses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userEntries","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"winnerList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"winners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]