Repository navigation
Expand file tree
/
Copy pathRandomGetter.sol
More file actions
135 lines (115 loc) · 4.82 KB
/
Copy pathRandomGetter.sol
File metadata and controls
135 lines (115 loc) · 4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {VRFV2WrapperConsumerBase} from "@chainlink/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IKarrotFactory} from "./interface/IKarrotFactory.sol";
import {IRandomGetter} from "./interface/IRandomGetter.sol";
/**
* @title RandomGetter contract
* @notice RandomGetter gets random numbers for lotteries using chainlink VRF.
* @notice RandomGetter contract must be has enough link token, since we pay a link token for getting a random number.
* @dev We use one RandomGetter contract for all lotteries, avoiding the
* need to send the link token to the balance of each contract separately.
*/
contract RandomGetter is VRFV2WrapperConsumerBase, AccessControl, IRandomGetter {
using SafeERC20 for IERC20;
/// @notice Gas limit for callback fulfillRandomWords function execution.
uint32 constant callbackGasLimit = 100_000;
/// @notice Amount of random numbers that will be received.
uint32 constant numWords = 1;
/// @notice Minimum amount of confirmations during the request.
uint16 constant requestConfirmations = 3; // cannot be lower
/// @notice Address of the KarrotFactory contract.
IKarrotFactory public factory;
/// @inheritdoc IRandomGetter
mapping(address => uint) public requestIds;
/// @inheritdoc IRandomGetter
mapping(uint256 => uint256) public randomNumbersByRequestId;
/// @notice The modifier checks whether the function is called from the lottery contract.
modifier onlyLottery() {
if (!factory.isLottery(msg.sender)) {
revert IncorrectCondition("Only lottery can call this function");
}
_;
}
/**
* @notice Constructor function to initialize the RandomGetter contract.
* @param _link The address of the LINK token contract.
* @param _vrfWrapper The address of the VRF wrapper contract.
* @param _factory The address of the KarrotFactory contract.
* @param _defaultAdmin The address of the admin this contract.
* @dev Reverts if the factory contract does not support their respective interfaces.
*/
constructor(
address _link,
address _vrfWrapper,
address _factory,
address _defaultAdmin
) VRFV2WrapperConsumerBase(_link, _vrfWrapper) {
if (
!IKarrotFactory(_factory).supportsInterface(
type(IKarrotFactory).interfaceId
)
) {
revert InterfaceNotSupported();
}
factory = IKarrotFactory(_factory);
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
}
/// @inheritdoc IRandomGetter
function requestRandomNumber() external onlyLottery returns (uint256) {
if (requestIds[msg.sender] != 0) {
revert IncorrectCondition("Lottery already has random number or request id pending");
}
uint256 requestId = requestRandomness(
callbackGasLimit,
requestConfirmations,
numWords
);
requestIds[msg.sender] = requestId;
emit RequestSent(requestId, numWords);
return requestId;
}
/// @inheritdoc IRandomGetter
function getRandomNumber(uint256 requestId) external view returns (uint256 random) {
random = randomNumbersByRequestId[requestId];
}
/// @inheritdoc IRandomGetter
function getRandomNumber(address lottery) external view returns (uint256 random) {
uint256 requestId = requestIds[lottery];
random = randomNumbersByRequestId[requestId];
}
/// @inheritdoc IRandomGetter
function withdraw(address token, uint256 amount) public onlyRole(DEFAULT_ADMIN_ROLE) {
IERC20(token).safeTransfer(msg.sender, amount);
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
)
public
view
override(AccessControl, IERC165)
returns (bool)
{
return
type(IRandomGetter).interfaceId == interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Fulfills the requested random words.
* @param _requestId The ID of the request.
* @param randomWords The array of random words to fulfill.
* @dev Overrides the internal function in the VRFConsumerBase contract.
*/
function fulfillRandomWords(
uint256 _requestId,
uint256[] memory randomWords
) internal override {
randomNumbersByRequestId[_requestId] = randomWords[0] == 0 ? 1 : randomWords[0];
emit RequestFulfilled(_requestId, randomWords[0]);
}
}