Untitled

mail@pastecode.io avatar
unknown
plain_text
2 years ago
11 kB
2
Indexable
Never
/**
 *Submitted for verification at BscScan.com on 2021-10-22
*/

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

/*

      ___           ___           ___           ___           ___       ___                    ___           ___           ___                       ___     
     /\  \         /\  \         /\__\         /\  \         /\__\     /\  \                  /\  \         /\  \         /\__\          ___        /\  \    
    /::\  \       /::\  \       /::|  |       /::\  \       /:/  /    /::\  \                /::\  \       /::\  \       /::|  |        /\  \      /::\  \   
   /:/\:\  \     /:/\:\  \     /:|:|  |      /:/\:\  \     /:/  /    /:/\:\  \              /:/\:\  \     /:/\:\  \     /:|:|  |        \:\  \    /:/\:\  \  
  /:/  \:\  \   /::\~\:\  \   /:/|:|  |__   /:/  \:\__\   /:/  /    /::\~\:\  \            /:/  \:\  \   /::\~\:\  \   /:/|:|  |__      /::\__\  /::\~\:\  \ 
 /:/__/ \:\__\ /:/\:\ \:\__\ /:/ |:| /\__\ /:/__/ \:|__| /:/__/    /:/\:\ \:\__\          /:/__/_\:\__\ /:/\:\ \:\__\ /:/ |:| /\__\  __/:/\/__/ /:/\:\ \:\__\
 \:\  \  \/__/ \/__\:\/:/  / \/__|:|/:/  / \:\  \ /:/  / \:\  \    \:\~\:\ \/__/          \:\  /\ \/__/ \:\~\:\ \/__/ \/__|:|/:/  / /\/:/  /    \:\~\:\ \/__/
  \:\  \            \::/  /      |:/:/  /   \:\  /:/  /   \:\  \    \:\ \:\__\             \:\ \:\__\    \:\ \:\__\       |:/:/  /  \::/__/      \:\ \:\__\  
   \:\  \           /:/  /       |::/  /     \:\/:/  /     \:\  \    \:\ \/__/              \:\/:/  /     \:\ \/__/       |::/  /    \:\__\       \:\ \/__/  
    \:\__\         /:/  /        /:/  /       \::/__/       \:\__\    \:\__\                 \::/  /       \:\__\         /:/  /      \/__/        \:\__\    
     \/__/         \/__/         \/__/         ~~            \/__/     \/__/                  \/__/         \/__/         \/__/                     \/__/  
     
                                                                      CG COINFLIP RNG
                                                                   https://candlegenie.io


*/


// CONTEXT
abstract contract Context 
{
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

// OWNABLE
abstract contract Ownable is Context {
    address private _owner;

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


    constructor() {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }


    function owner() public view virtual returns (address) {
        return _owner;
    }


    modifier onlyOwner() {
        require(owner() == _msgSender(), "Caller is not the owner");
        _;
    }

    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }


    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "New owner can not be the ZERO address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// REENTRANCY GUARD
abstract contract ReentrancyGuard 
{
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}


// LINK TOKEN INTERFACE
interface LinkTokenInterface {

  function allowance(
    address owner,
    address spender
  )
    external
    view
    returns (
      uint256 remaining
    );

  function approve(
    address spender,
    uint256 value
  )
    external
    returns (
      bool success
    );

  function balanceOf(
    address owner
  )
    external
    view
    returns (
      uint256 balance
    );

  function decimals()
    external
    view
    returns (
      uint8 decimalPlaces
    );

  function decreaseApproval(
    address spender,
    uint256 addedValue
  )
    external
    returns (
      bool success
    );

  function increaseApproval(
    address spender,
    uint256 subtractedValue
  ) external;

  function name()
    external
    view
    returns (
      string memory tokenName
    );

  function symbol()
    external
    view
    returns (
      string memory tokenSymbol
    );

  function totalSupply()
    external
    view
    returns (
      uint256 totalTokensIssued
    );

  function transfer(
    address to,
    uint256 value
  )
    external
    returns (
      bool success
    );

  function transferAndCall(
    address to,
    uint256 value,
    bytes calldata data
  )
    external
    returns (
      bool success
    );

  function transferFrom(
    address from,
    address to,
    uint256 value
  )
    external
    returns (
      bool success
    );

}

// VRF ID BASE
contract VRFRequestIDBase {

  function makeVRFInputSeed(
    bytes32 _keyHash,
    uint256 _userSeed,
    address _requester,
    uint256 _nonce
  )
    internal
    pure
    returns (
      uint256
    )
  {
    return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)));
  }

  function makeRequestId(
    bytes32 _keyHash,
    uint256 _vRFInputSeed
  )
    internal
    pure
    returns (
      bytes32
    )
  {
    return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed));
  }
}

// VRF COSUMER BASE
abstract contract VRFConsumerBase is VRFRequestIDBase {


  function fulfillRandomness(
    bytes32 requestId,
    uint256 randomness
  )
    internal
    virtual;


  uint256 constant private USER_SEED_PLACEHOLDER = 0;

  function requestRandomness(
    bytes32 _keyHash,
    uint256 _fee
  )
    internal
    returns (
      bytes32 requestId
    )
  {
    LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER));
    uint256 vRFSeed  = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]);
    nonces[_keyHash] = nonces[_keyHash] + 1;
    return makeRequestId(_keyHash, vRFSeed);
  }

  LinkTokenInterface immutable internal LINK;
  address immutable private vrfCoordinator;


  mapping(bytes32 /* keyHash */ => uint256 /* nonce */) private nonces;


  constructor(
    address _vrfCoordinator,
    address _link
  ) {
    vrfCoordinator = _vrfCoordinator;
    LINK = LinkTokenInterface(_link);
  }


  function rawFulfillRandomness(
    bytes32 requestId,
    uint256 randomness
  )
    external
  {
    require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
    fulfillRandomness(requestId, randomness);
  }
}

// CGCOINFLIP INTERFACE
abstract contract CandleGenieCoinFlip
{
    enum Position {None, Heads, Tails}
    enum Status {Idle, Flipping , Drop, Refunded}

    struct Bet 
    {
        address user;
        uint256 Index;
        uint256 flipId;
        uint256 flipTimestamp;
        uint256 dropTimestamp;
        uint256 betAmount;
        uint256 paidAmount;
        uint8 rewardMultiplier;
        Position guess;
        Position result;
        Status status;
        bool paid;
        bool vrfUsed;
    }
    
    function getBet(uint256 flipId) external virtual view returns (Bet memory);
    function getUserBetsLength(address user) external virtual view returns (uint256);
    function getUserBetId(address user, uint256 position) external virtual view returns (uint256);
    function getUserBets(address user, uint256 cursor, uint256 size) external virtual view returns (uint256[] memory, Bet[] memory, uint256);
    function Drop(uint256 flipId, int flipResult) external virtual;
    
}

contract CandleGenieCoinFlipRandomSource is VRFConsumerBase, ReentrancyGuard, Ownable 
{
    
    address public gameContractAddress;
    CandleGenieCoinFlip internal gameContract;
    
    bytes32 internal keyHash;
    uint256 internal fee;
    uint256 public flipCount;

    constructor() 
        VRFConsumerBase(
            0x747973a5A2a4Ae1D3a8fDF5479f1514F65Db9C31, // VRF Coordinator
            0x404460C6A5EdE2D891e8297795264fDe62ADBB75  // LINK Token
        )
    {
        keyHash = 0xc251acd21ec4fb7f31bb8868288bfdbaeb4fbfec2df3735ddbd4f7dc8d60103c;
        fee = 0.2 * 10 ** 18; // 0.1 LINK
    }
    
    modifier onlyGameContract() 
    {
        require(msg.sender == gameContractAddress, "Only game contract allowed");
        _;
    }
    
    
    function setFee(uint256 _fee) external onlyOwner {
        fee = _fee;
    }
    
    function setKeyHash(bytes32 _keyHash) external onlyOwner {
        keyHash = _keyHash;
    }
    

    function setGameContract(address _gameContractAddress) external onlyOwner 
    {
        gameContractAddress = _gameContractAddress;
        gameContract = CandleGenieCoinFlip(gameContractAddress);
    }
    
    function FlipWithVRF() external onlyGameContract returns (uint256 requestId) 
    {
        require(keyHash != bytes32(0), "Invalid key hash");
        require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK");
           
        flipCount++;
        return uint256(requestRandomness(keyHash, fee));  
    }

    function FlipWithPSEUDO() external onlyGameContract returns (uint256 requestId) 
    {
        uint256 hash = uint256(keccak256(abi.encodePacked(flipCount + block.timestamp + block.number)));
        flipCount++;
        return hash;
    }


    function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override 
    {
        
        uint256 randomResult =  randomness % 100 + 1;

        int flipResult;
        if (randomResult < 50)
        {
            flipResult = 0;
        }
        else if (randomResult >= 50)
        {
            flipResult = 1;
        } 
        
        // Finalizing Flip
       gameContract.Drop(uint256(requestId), flipResult);   
    }
    
    function fulfillPSEUDO(uint256 requestId) external onlyGameContract
    {

        uint256 randomness = uint256(keccak256(abi.encodePacked(block.timestamp + block.difficulty + ((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (block.timestamp)) + block.gaslimit + ((uint256(keccak256(abi.encodePacked(msg.sender)))) / (block.timestamp)) + block.number)));
        uint256 randomResult =  randomness % 100 + 1;
        
        int flipResult; 
        
        if (randomResult < 50)
        {
            flipResult = 0;
        }
        else if (randomResult >= 50)
        {
            flipResult = 1;
        } 
        pseudoPivot = 1;
        
        // Finalizing Flip
        gameContract.Drop(uint256(requestId), flipResult);   
    }
    
  
}