|
| 1 | +/** |
| 2 | + * @authors: [@MerlinEgalite] |
| 3 | + * @reviewers: [] |
| 4 | + * @auditors: [] |
| 5 | + * @bounties: [] |
| 6 | + * @deployments: [] |
| 7 | + */ |
| 8 | +pragma solidity ^0.6.6; |
| 9 | + |
| 10 | +import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol"; |
| 11 | +import "./RNG.sol"; |
| 12 | + |
| 13 | + |
| 14 | +interface IKlerosLiquid { |
| 15 | + function passPhase() external; |
| 16 | +} |
| 17 | + |
| 18 | + |
| 19 | +/** |
| 20 | + * @title Random Number Generator using Chainlink Verifiable Randomness Mechanism on Polygon |
| 21 | + * @author Merlin Egalite - <egalite.merlin@gmail.com> |
| 22 | + * |
| 23 | + * @dev This contract implements the RNG standard and inherits from VRFConsumerBase to use Chainlink Verifiable Randomness Mechanism. |
| 24 | + * @dev It allows to store the random number associated to the requests made. |
| 25 | + * @dev Note that to make requests to Chainlink, the contract needs to be funded with some LINK. |
| 26 | + * @dev Chainlink documentation: https://docs.chain.link/docs/chainlink-vrf/ |
| 27 | + * @dev For SECURITY CONSIDERATIONS, you might also have look to: https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/VRFConsumerBase.sol |
| 28 | + */ |
| 29 | +contract ChainlinkRNG is RNG, VRFConsumerBase { |
| 30 | + |
| 31 | + /* Storage */ |
| 32 | + |
| 33 | + IKlerosLiquid public kleros; // The address of Kleros Liquid. |
| 34 | + bytes32 internal keyHash; // The key hash for the VRF Coordinator. |
| 35 | + uint256 internal fee; // The amount of LINK to send with a request. |
| 36 | + mapping(bytes32 => uint256) public randomNumber; // randomNumber[requestId] is the random number for the requestId, 0 otherwise. |
| 37 | + |
| 38 | + /* Modifier */ |
| 39 | + |
| 40 | + modifier onlyByKleros() { |
| 41 | + require(msg.sender == address(kleros), "ChainlinkRNG: not called by Kleros"); |
| 42 | + _; |
| 43 | + } |
| 44 | + |
| 45 | + /* Constructor */ |
| 46 | + |
| 47 | + /** |
| 48 | + * @dev Constructs the ChainlinkRNG contract. |
| 49 | + * @param _vrfCoordinator The address of VRFCoordinator contract. |
| 50 | + * @param _link The address of LINK token contract. |
| 51 | + * @param _kleros The address of Kleros Liquid's contract. |
| 52 | + * @param _keyHash The key hash for the VRF Coordinator. |
| 53 | + * @param _fee The amount of LINK to send with a request. |
| 54 | + * |
| 55 | + * @dev https://docs.chain.link/docs/link-token-contracts |
| 56 | + */ |
| 57 | + constructor( |
| 58 | + address _vrfCoordinator, |
| 59 | + address _link, |
| 60 | + IKlerosLiquid _kleros, |
| 61 | + bytes32 _keyHash, |
| 62 | + uint256 _fee |
| 63 | + ) |
| 64 | + VRFConsumerBase(_vrfCoordinator, _link) |
| 65 | + public |
| 66 | + { |
| 67 | + keyHash = _keyHash; |
| 68 | + kleros = _kleros; |
| 69 | + fee = _fee; |
| 70 | + } |
| 71 | + |
| 72 | + /* External */ |
| 73 | + |
| 74 | + /** |
| 75 | + * @dev Withdraws all LINK tokens locked in this contract. |
| 76 | + */ |
| 77 | + function withdrawLink() external onlyByKleros { |
| 78 | + require(LINK.transfer(msg.sender, LINK.balanceOf(address(this))), "ChainlinkRNG: unable to transfer LINK tokens"); |
| 79 | + } |
| 80 | + |
| 81 | + /** |
| 82 | + * @dev Changes the `fee` storage variable. |
| 83 | + * @param _newFee The new value for the `fee` storage variable. |
| 84 | + */ |
| 85 | + function changeFee(uint256 _newFee) external onlyByKleros { |
| 86 | + fee = _newFee; |
| 87 | + } |
| 88 | + |
| 89 | + /** |
| 90 | + * @dev Changes the `kleros` storage variable. |
| 91 | + * @param _newKleros The new value for the `kleros` storage variable. |
| 92 | + */ |
| 93 | + function changeKleros(IKlerosLiquid _newKleros) external onlyByKleros { |
| 94 | + kleros = _newKleros; |
| 95 | + } |
| 96 | + |
| 97 | + /** |
| 98 | + * @dev Requests a random number. |
| 99 | + * @dev The _seed parameter is vestigial, and is kept only for API |
| 100 | + * @dev compatibility with older versions. It can't *hurt* to mix in some of |
| 101 | + * @dev your own randomness, here, but it's not necessary because the VRF |
| 102 | + * @dev oracle will mix the hash of the block containing your request into the |
| 103 | + * @dev VRF seed it ultimately uses. |
| 104 | + * @param _seed seed mixed into the input of the VRF. |
| 105 | + * @return requestId unique ID for this request. |
| 106 | + */ |
| 107 | + function requestRN(uint _seed) external onlyByKleros returns (bytes32 requestId) { |
| 108 | + require(LINK.balanceOf(address(this)) >= fee, "ChainlinkRNG: not enough LINK to pay the fee"); |
| 109 | + return requestRandomness(keyHash, fee, _seed); |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + * @dev Gets the random number associated to a `_requestId`. |
| 114 | + * @param _requestId The request Id initially returned by requestRN. |
| 115 | + * @return RN Random Number. If the number is not ready or has not been required it returns 0. |
| 116 | + */ |
| 117 | + function getRN(bytes32 _requestId) external view returns (uint256 RN) { |
| 118 | + return randomNumber[_requestId]; |
| 119 | + } |
| 120 | + |
| 121 | + /* Internal */ |
| 122 | + |
| 123 | + /** |
| 124 | + * @dev Stores the random number given by the VRF Coordinator and calls passPhase function on Kleros Liquid. |
| 125 | + * @dev This is the callback function used by the VRF Coordinator. |
| 126 | + * @param _requestId The request Id initially returned by requestRN. |
| 127 | + * @param _randomness the VRF output. |
| 128 | + */ |
| 129 | + function fulfillRandomness(bytes32 _requestId, uint256 _randomness) internal override { |
| 130 | + randomNumber[_requestId] = _randomness; |
| 131 | + IKlerosLiquid(kleros).passPhase(); |
| 132 | + } |
| 133 | +} |
0 commit comments