S Price: $0.513244 (-0.05%)

Contract Diff Checker

Contract Name:
TestVRF

Contract Source Code:

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IGelatoVRFConsumer} from "./IGelatoVRFConsumer.sol";

/// @title GelatoVRFConsumerBase
/// @dev This contract can be inherit by upgradeable smart contracts as well.
/// @dev This contract handles domain separation between consecutive randomness requests
/// The contract has to be implemented by contracts willing to use the gelato VRF system.
/// This base contract enhances the GelatoVRFConsumer by introducing request IDs and
/// ensuring unique random values.
/// for different request IDs by hashing them with the random number provided by drand.
/// For security considerations, refer to the Gelato documentation.
abstract contract GelatoVRFConsumerBase is IGelatoVRFConsumer {
    uint256 private constant _PERIOD = 3;
    uint256 private constant _GENESIS = 1692803367;
    bool[] public requestPending;
    mapping(uint256 => bytes32) public requestedHash;

    /// @notice Returns the address of the dedicated msg.sender.
    /// @dev The operator can be found on the Gelato dashboard after a VRF is deployed.
    /// @return Address of the operator.
    function _operator() internal view virtual returns (address);

    /// @notice User logic to handle the random value received.
    /// @param randomness The random number generated by Gelato VRF.
    /// @param requestId The ID for the randomness request.
    /// @param extraData Additional data from the randomness request.
    function _fulfillRandomness(
        uint256 randomness,
        uint256 requestId,
        bytes memory extraData
    ) internal virtual;

    /// @notice Requests randomness from the Gelato VRF.
    /// @dev The extraData parameter allows for additional data to be passed to
    /// the VRF, which is then forwarded to the callback. This is useful for
    /// request tracking purposes if requestId is not enough.
    /// @param extraData Additional data for the randomness request.
    /// @return requestId The ID for the randomness request.
    function _requestRandomness(
        bytes memory extraData
    ) internal returns (uint256 requestId) {
        requestId = uint256(requestPending.length);
        requestPending.push();
        requestPending[requestId] = true;

        bytes memory data = abi.encode(requestId, extraData);
        uint256 round = _round();

        bytes memory dataWithRound = abi.encode(round, data);
        bytes32 requestHash = keccak256(dataWithRound);

        requestedHash[requestId] = requestHash;

        emit RequestedRandomness(round, data);
    }

    /// @notice Callback function used by Gelato VRF to return the random number.
    /// The randomness is derived by hashing the provided randomness with the request ID.
    /// @param randomness The random number generated by Gelato VRF.
    /// @param dataWithRound Additional data provided by Gelato VRF containing request details.
    function fulfillRandomness(
        uint256 randomness,
        bytes calldata dataWithRound
    ) external {
        require(msg.sender == _operator(), "only operator");

        (, bytes memory data) = abi.decode(dataWithRound, (uint256, bytes));
        (uint256 requestId, bytes memory extraData) = abi.decode(
            data,
            (uint256, bytes)
        );

        bytes32 requestHash = keccak256(dataWithRound);
        bool isValidRequestHash = requestHash == requestedHash[requestId];

        require(requestPending[requestId], "request fulfilled or missing");

        if (isValidRequestHash) {
            randomness = uint(
                keccak256(
                    abi.encode(
                        randomness,
                        address(this),
                        block.chainid,
                        requestId
                    )
                )
            );

            _fulfillRandomness(randomness, requestId, extraData);
            requestPending[requestId] = false;

            delete requestedHash[requestId];
        }

        delete requestedHash[requestId];
    }

    /// @notice Computes and returns the round number of drand to request randomness from.
    function _round() private view returns (uint256 round) {
        // solhint-disable-next-line not-rely-on-time
        uint256 elapsedFromGenesis = block.timestamp - _GENESIS;
        uint256 currentRound = (elapsedFromGenesis / _PERIOD) + 1;

        round = block.chainid == 1 ? currentRound + 4 : currentRound + 1;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title IGelatoVRFConsumer
/// @dev Interface for consuming random number provided by Drand.
/// @notice This interface allows contracts to receive a random number provided by Gelato VRF.
interface IGelatoVRFConsumer {
    /// @notice Event emitted when a randomness request is made.
    /// @param data The round of randomness to request.
    /// @param data Additional data associated with the request.
    event RequestedRandomness(uint256 round, bytes data);

    /// @notice Callback function used by Gelato to return the random number.
    /// @dev The random number is fetched from one among many drand endpoints
    /// and passed back to this function like in a Gelato Web3 Function.
    /// @param randomness The random number generated by drand.
    /// @param data Additional data provided by Gelato VRF or the user, typically unused.
    function fulfillRandomness(
        uint256 randomness,
        bytes calldata data
    ) external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {GelatoVRFConsumerBase} from "contracts/Integrations/Gelato/VRF/GelatoVRFConsumerBase.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

struct RandomnessRequest {
	bool requestSent;
	bool fulfilled;
	uint256 pendingRequestId;
	uint256 latestRandomness;
	uint256 latestRequestId;
}

contract TestVRF is GelatoVRFConsumerBase, Ownable {
	RandomnessRequest public randomnessRequest;

    address private immutable _operatorAddr;

    constructor(address operator) Ownable(msg.sender) {
        _operatorAddr = operator;
    }

    function _fulfillRandomness(
        uint256 randomness,
        uint256 requestId,
        bytes memory
    ) internal override {
		require(randomnessRequest.pendingRequestId == requestId, "requestId not valid");
        randomnessRequest.latestRandomness = randomness;
        randomnessRequest.latestRequestId = requestId;
    }

	function _operator() internal view override returns (address) {
        return _operatorAddr;
    }

    // Simulate

	bool testEnded;
    function testSync() public onlyOwner {
		if (!randomnessRequest.requestSent)
		{
			require(!randomnessRequest.requestSent, "Request already sent");
			randomnessRequest.pendingRequestId = _requestRandomness(abi.encode(0));
			testEnded = true;
		}
		else if (testEnded)
		{
			clearRequest();
			testEnded = false;
		}
    }
	
	bool testActive = true;
	function testSetActive(bool active) public onlyOwner {
		testActive = active;
	}

	function checkExecuteGiveaway() public view returns (bool) {
		return ((testActive && randomnessRequest.fulfilled) || !testActive);
	}

	uint256 public checkReturn;
	function testExecute(uint256 lenght) public onlyOwner {
		checkReturn = 667;
		require (checkExecuteGiveaway(), "Can't execute giveaway");

		uint256 randomIndex = 669;
		if (testActive && randomnessRequest.fulfilled) {
			randomIndex = getRandomIndex(lenght);
			testEnded = false;
			clearRequest();
		}

		if (randomnessRequest.fulfilled)
			return;
		else if (!testEnded)
			checkReturn = randomIndex;
		else
			checkReturn = 0;
	}

    function getRandomIndex(
        uint256 lenght
    ) public view returns (uint256 index) {
        uint256 res = (uint256(keccak256(abi.encodePacked(randomnessRequest.latestRandomness))) %
            lenght);
        return (res);
    }

	function clearRequest() private {
		randomnessRequest.requestSent = false;
		randomnessRequest.fulfilled = false;
		randomnessRequest.pendingRequestId = 0;
		randomnessRequest.latestRandomness = 0;
		randomnessRequest.latestRequestId = 0;
	}

    function getRandomnessRequest() public view returns (RandomnessRequest memory) {
		return randomnessRequest;
	}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):