Untitled
unknown
plain_text
4 years ago
11 kB
8
Indexable
/**
*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);
}
}Editor is loading...