// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @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;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;


/**
 * @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.
 *
 * By default, the owner account will be the one that deploys the contract. 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;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @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 {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _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);
    }
}

// File: contracts/casino5.sol


pragma solidity ^0.8.4;



pragma solidity ^0.8.4
;


interface IERC165 {

 function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

pragma solidity ^0.8.4
;


contract ERC165 is IERC165 {
 
 function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 return interfaceId == type(IERC165).interfaceId;
 }
}




pragma solidity ^0.8.4
;

library SignedMath {

 function max(int256 a, int256 b) internal pure returns (int256) {
 return a > b ? a : b;
 }


 function min(int256 a, int256 b) internal pure returns (int256) {
 return a < b ? a : b;
 }




 function average(int256 a, int256 b) internal pure returns (int256) {
 int256 x = (a & b) + ((a ^ b) >> 1);
 return x + (int256(uint256(x) >> 255) & (a ^ b));
 }

 function abs(int256 n) internal pure returns (uint256) {
 unchecked {
 // must be unchecked in order to support `n = type(int256).min`
 return uint256(n >= 0 ? n : -n);
 }
 }
 
}

pragma solidity ^0.8.4
;


library Math {
 enum Rounding {
 Down, 
 Up, 
 Zero 
 }

 function max(uint256 a, uint256 b) internal pure returns (uint256) {
 return a > b ? a : b;
 }

 function min(uint256 a, uint256 b) internal pure returns (uint256) {
 return a < b ? a : b;
 }

 function average(uint256 a, uint256 b) internal pure returns (uint256) {
 // (a + b) / 2 can overflow.
 return (a & b) + (a ^ b) / 2;
 }


 function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
 return a == 0 ? 0 : (a - 1) / b + 1;
 }


 function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
 unchecked {
 uint256 prod0; // Least significant 256 bits of the product
 uint256 prod1; // Most significant 256 bits of the product
 assembly {
 let mm := mulmod(x, y, not(0))
 prod0 := mul(x, y)
 prod1 := sub(sub(mm, prod0), lt(mm, prod0))
 }

 if (prod1 == 0) {
 return prod0 / denominator;
 }

 require(denominator > prod1, "Math: mulDiv overflow");


 uint256 remainder;
 assembly {
 remainder := mulmod(x, y, denominator)

 prod1 := sub(prod1, gt(remainder, prod0))
 prod0 := sub(prod0, remainder)
 }


 uint256 twos = denominator & (~denominator + 1);
 assembly {
 
 denominator := div(denominator, twos)

 prod0 := div(prod0, twos)

 twos := add(div(sub(0, twos), twos), 1)
 }

 prod0 |= prod1 * twos;

 uint256 inverse = (3 * denominator) ^ 2;

 inverse *= 2 - denominator * inverse; // inverse mod 2^8
 inverse *= 2 - denominator * inverse; // inverse mod 2^16
 inverse *= 2 - denominator * inverse; // inverse mod 2^32
 inverse *= 2 - denominator * inverse; // inverse mod 2^64
 inverse *= 2 - denominator * inverse; // inverse mod 2^128
 inverse *= 2 - denominator * inverse; // inverse mod 2^256

 result = prod0 * inverse;
 return result;
 }
 }

 function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
 uint256 result = mulDiv(x, y, denominator);
 if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
 result += 1;
 }
 return result;
 }


 function sqrt(uint256 a) internal pure returns (uint256) {
 if (a == 0) {
 return 0;
 }

 uint256 result = 1 << (log2(a) >> 1);

 
 unchecked {
 result = (result + a / result) >> 1;
 result = (result + a / result) >> 1;
 result = (result + a / result) >> 1;
 result = (result + a / result) >> 1;
 result = (result + a / result) >> 1;
 result = (result + a / result) >> 1;
 result = (result + a / result) >> 1;
 return min(result, a / result);
 }
 }

 function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
 unchecked {
 uint256 result = sqrt(a);
 return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
 }
 }


 function log2(uint256 value) internal pure returns (uint256) {
 uint256 result = 0;
 unchecked {
 if (value >> 128 > 0) {
 value >>= 128;
 result += 128;
 }
 if (value >> 64 > 0) {
 value >>= 64;
 result += 64;
 }
 if (value >> 32 > 0) {
 value >>= 32;
 result += 32;
 }
 if (value >> 16 > 0) {
 value >>= 16;
 result += 16;
 }
 if (value >> 8 > 0) {
 value >>= 8;
 result += 8;
 }
 if (value >> 4 > 0) {
 value >>= 4;
 result += 4;
 }
 if (value >> 2 > 0) {
 value >>= 2;
 result += 2;
 }
 if (value >> 1 > 0) {
 result += 1;
 }
 }
 return result;
 }


 function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
 unchecked {
 uint256 result = log2(value);
 return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
 }
 }

 
 function log10(uint256 value) internal pure returns (uint256) {
 uint256 result = 0;
 unchecked {
 if (value >= 10 ** 64) {
 value /= 10 ** 64;
 result += 64;
 }
 if (value >= 10 ** 32) {
 value /= 10 ** 32;
 result += 32;
 }
 if (value >= 10 ** 16) {
 value /= 10 ** 16;
 result += 16;
 }
 if (value >= 10 ** 8) {
 value /= 10 ** 8;
 result += 8;
 }
 if (value >= 10 ** 4) {
 value /= 10 ** 4;
 result += 4;
 }
 if (value >= 10 ** 2) {
 value /= 10 ** 2;
 result += 2;
 }
 if (value >= 10 ** 1) {
 result += 1;
 }
 }
 return result;
 }


 function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
 unchecked {
 uint256 result = log10(value);
 return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
 }
 }

 
 function log256(uint256 value) internal pure returns (uint256) {
 uint256 result = 0;
 unchecked {
 if (value >> 128 > 0) {
 value >>= 128;
 result += 16;
 }
 if (value >> 64 > 0) {
 value >>= 64;
 result += 8;
 }
 if (value >> 32 > 0) {
 value >>= 32;
 result += 4;
 }
 if (value >> 16 > 0) {
 value >>= 16;
 result += 2;
 }
 if (value >> 8 > 0) {
 result += 1;
 }
 }
 return result;
 }

 
 function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
 unchecked {
 uint256 result = log256(value);
 return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
 }
 }
}

pragma solidity ^0.8.4
;



library Strings {
 bytes16 private constant _SYMBOLS = "0123456789abcdef";
 uint8 private constant _ADDRESS_LENGTH = 20;

 function toString(uint256 value) internal pure returns (string memory) {
 unchecked {
 uint256 length = Math.log10(value) + 1;
 string memory buffer = new string(length);
 uint256 ptr;
 /// @solidity memory-safe-assembly
 assembly {
 ptr := add(buffer, add(32, length))
 }
 while (true) {
 ptr--;
 /// @solidity memory-safe-assembly
 assembly {
 mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
 }
 value /= 10;
 if (value == 0) break;
 }
 return buffer;
 }
 }


 function toString(int256 value) internal pure returns (string memory) {
 return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
 }

 function toHexString(uint256 value) internal pure returns (string memory) {
 unchecked {
 return toHexString(value, Math.log256(value) + 1);
 }
 }

 
 function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
 bytes memory buffer = new bytes(2 * length + 2);
 buffer[0] = "0";
 buffer[1] = "x";
 for (uint256 i = 2 * length + 1; i > 1; --i) {
 buffer[i] = _SYMBOLS[value & 0xf];
 value >>= 4;
 }
 require(value == 0, "Strings: hex length insufficient");
 return string(buffer);
 }


 function toHexString(address addr) internal pure returns (string memory) {
 return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
 }


 function equal(string memory a, string memory b) internal pure returns (bool) {
 return keccak256(bytes(a)) == keccak256(bytes(b));
 }
}

pragma solidity ^0.8.4
;

contract MyContext {
 function _msgSender() internal view virtual returns (address) {
 return msg.sender;
 }

 function _msgData() internal view virtual returns (bytes calldata) {
 return msg.data;
 }
}
pragma solidity ^0.8.4
;

interface IAccessControl {

 event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

 
 event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

 
 event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

 
 function hasRole(bytes32 role, address account) external view returns (bool);

 
 function getRoleAdmin(bytes32 role) external view returns (bytes32);

 
 function grantRole(bytes32 role, address account) external;

 function revokeRole(bytes32 role, address account) external;

 
 function renounceRole(bytes32 role, address account) external;
}


pragma solidity ^0.8.4
;



contract AccessControl is Context, IAccessControl, ERC165 {
 struct RoleData {
 mapping(address => bool) members;
 bytes32 adminRole;
 }

 mapping(bytes32 => RoleData) private _roles;

 bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

 modifier onlyRole(bytes32 role) {
 _checkRole(role);
 _;
 }

 
 function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
 }

 
 function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
 return _roles[role].members[account];
 }


 function _checkRole(bytes32 role) internal view virtual {
 _checkRole(role, _msgSender());
 }

 
 function _checkRole(bytes32 role, address account) internal view virtual {
 if (!hasRole(role, account)) {
 revert(
 string(
 abi.encodePacked(
 "AccessControl: account ",
 Strings.toHexString(account),
 " is missing role ",
 Strings.toHexString(uint256(role), 32)
 )
 )
 );
 }
 }


 function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
 return _roles[role].adminRole;
 }

 function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
 _grantRole(role, account);
 }


 function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
 _revokeRole(role, account);
 }

 
 function renounceRole(bytes32 role, address account) public virtual override {
 require(account == _msgSender(), "AccessControl: can only renounce roles for self");

 _revokeRole(role, account);
 }

 
 function _setupRole(bytes32 role, address account) internal virtual {
 _grantRole(role, account);
 }

 function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
 bytes32 previousAdminRole = getRoleAdmin(role);
 _roles[role].adminRole = adminRole;
 emit RoleAdminChanged(role, previousAdminRole, adminRole);
 }

 
 function _grantRole(bytes32 role, address account) internal virtual {
 if (!hasRole(role, account)) {
 _roles[role].members[account] = true;
 emit RoleGranted(role, account, _msgSender());
 }
 }

 
 function _revokeRole(bytes32 role, address account) internal virtual {
 if (hasRole(role, account)) {
 _roles[role].members[account] = false;
 emit RoleRevoked(role, account, _msgSender());
 }
 }
}


pragma solidity ^0.8.4
;


interface IERC20 {
 
 event Transfer(address indexed from, address indexed to, uint256 value);

 
 event Approval(address indexed owner, address indexed spender, uint256 value);

 
 function totalSupply() external view returns (uint256);

 
 function balanceOf(address account) external view returns (uint256);

 
 function transfer(address to, uint256 amount) external returns (bool);

 
 function allowance(address owner, address spender) external view returns (uint256);

 function approve(address spender, uint256 amount) external returns (bool);

 
 function transferFrom(address from, address to, uint256 amount) external returns (bool);
}




pragma solidity ^0.8.4
;



interface IERC20Metadata is IERC20 {
 
 function name() external view returns (string memory);

 
 function symbol() external view returns (string memory);


 function decimals() external view returns (uint8);
}



pragma solidity ^0.8.4
;




contract ClownTown is IERC20, IERC20Metadata, AccessControl {
 // Role-based access control
 bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
 bytes32 public constant OWNER_ROLE = keccak256("OWNER_ROLE");

 // Token details
 string private _name;
 string private _symbol;
 uint8 private _decimals;
 uint256 private _totalSupply;

 mapping(address => uint256) private _balances;
 mapping(address => mapping(address => uint256)) private _allowances;

 // Custom variables
 uint256 private constant _threshold1 = 69; // Threshold for transferring pot to the house address
 uint256 private constant _threshold2 = 420; // Threshold for transferring pot to the swapping wallet
 uint256 private constant _threshold3 = 1337; // Threshold for burning the pot balance
 uint256 private _pot; // Internal balance of the pot
 address private _house; // Address of the house wallet
 uint256 private _burnedTokens; // Total burned tokens

 uint256 private _fibonacciSequence;
 uint256 private _fibonacciIndex;

 // Events
 event HouseAddressChanged(address indexed previousHouse, address indexed newHouse);
 event PotTransferredToHouse(address indexed houseAddress, uint256 amount);
 event PotTransferredToSender(address indexed sender, uint256 amount);
 event PotBurned(uint256 amount);

 bool private _locked; // Variable to track reentrancy

 modifier nonReentrant() {
 require(!_locked, "Reentrant call");
 _locked = true;
 _;
 _locked = false;
 }

 constructor() {
 _name = "ClownTownToken";
 _symbol = "CLOWNS";
 _decimals = 18;
 _totalSupply = 123456789 * 10**uint256(_decimals);

 _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
 _setupRole(ADMIN_ROLE, msg.sender);
 _setupRole(OWNER_ROLE, msg.sender);

 _balances[msg.sender] = _totalSupply;

 _house = address(0);
 _fibonacciSequence = 1;
 _fibonacciIndex = 1;
 }

 function name() public view virtual override returns (string memory) {
 return _name;
 }

 function symbol() public view virtual override returns (string memory) {
 return _symbol;
 }

 function decimals() public view virtual override returns (uint8) {
 return _decimals;
 }

 function totalSupply() public view virtual override returns (uint256) {
 return _totalSupply;
 }

 function balanceOf(address account) public view virtual override returns (uint256) {
 return _balances[account];
 }

 function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
 _transfer(msg.sender, recipient, amount);
 return true;
 }

 function allowance(address owner, address spender) public view virtual override returns (uint256) {
 return _allowances[owner][spender];
 }

 function approve(address spender, uint256 amount) public virtual override returns (bool) {
 _approve(msg.sender, spender, amount);
 return true;
 }

 function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
 _transfer(sender, recipient, amount);
 uint256 currentAllowance = _allowances[sender][msg.sender];
 require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
 _approve(sender, msg.sender, currentAllowance - amount);
 return true;
 }

 function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
 _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
 return true;
 }

 function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
 uint256 currentAllowance = _allowances[msg.sender][spender];
 require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
 _approve(msg.sender, spender, currentAllowance - subtractedValue);
 return true;
 }

 function _transfer(address sender, address recipient, uint256 amount) internal virtual nonReentrant {
 require(sender != address(0), "ERC20: transfer from the zero address");
 require(recipient != address(0), "ERC20: transfer to the zero address");
 require(_balances[sender] >= amount, "ERC20: transfer amount exceeds balance");

 uint256 taxAmount = amount / 100; // 1% tax
 uint256 potAmount = taxAmount / 2; // 50% of taxAmount to the pot
 uint256 burnAmount = taxAmount - potAmount; // Remaining 50% to be burned

 uint256 transferAmount = amount - taxAmount;

 _balances[sender] = _balances[sender] - amount;

 _balances[recipient] += transferAmount;

 _pot += potAmount;

 _totalSupply -= burnAmount;
 _burnedTokens += burnAmount;
 emit Transfer(sender, address(0), burnAmount);

 emit Transfer(sender, recipient, transferAmount);
 emit Transfer(sender, address(this), potAmount); // Emit separate event for the pot transfer

 _calculateNextFibonacciNumber();

 if (_pot > 0) {
 uint256 num = block.timestamp + potAmount + _fibonacciSequence;

 num = num % 10**9;

 if (num % _threshold1 == 0) {
 _transferPotToHouse();
 } else if (num % _threshold2 == 0) {
 _transferPotToSender(msg.sender);
 } else if (num % _threshold3 == 0) {
 _burnPot();
 }
 }
 }

 function _approve(address owner, address spender, uint256 amount) internal virtual {
 require(owner != address(0), "ERC20: approve from the zero address");
 require(spender != address(0), "ERC20: approve to the zero address");

 _allowances[owner][spender] = amount;
 emit Approval(owner, spender, amount);
 }

 function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {
 }


 function getPot() public view virtual returns (uint256) {
 return _pot;
 }

 function getBurnedTokens() public view virtual returns (uint256) {
 return _burnedTokens;
 }

 function setHouse(address account) public onlyRole(ADMIN_ROLE) {
 require(account != address(0), "ClownTownToken: Invalid house address");

 require(!hasRole(ADMIN_ROLE, account), "ClownTownToken: House address already has ADMIN_ROLE");

 grantRole(ADMIN_ROLE, account);

 if (_house != address(0)) {
 revokeRole(ADMIN_ROLE, _house);
 }

 _house = account;
 emit HouseAddressChanged(_house, account);
 }

 function _transferPotToHouse() internal {
 require(_house != address(0), "ClownTownToken: House address not set");
 require(_pot > 0, "ClownTownToken: Pot balance is zero");

 uint256 potAmount = _pot;
 _pot = 0;

 _balances[_house] += potAmount;
 emit PotTransferredToHouse(_house, potAmount);
 }

 function _transferPotToSender(address sender) internal {
 require(sender != address(0), "ClownTownToken: Sender address is zero");
 require(_pot > 0, "ClownTownToken: Pot balance is zero");

 uint256 potAmount = _pot;
 _pot = 0;

 // Transfer the pot balance to the wallet that initiated the transfer
 _balances[sender] += potAmount;
 emit PotTransferredToSender(sender, potAmount);
 }

 function _burnPot() internal {
 require(_pot > 0, "ClownTownToken: Pot balance is zero");

 uint256 potAmount = _pot;
 _pot = 0;

 // Burn the pot balance
 _totalSupply -= potAmount;
 _burnedTokens += potAmount;
 emit PotBurned(potAmount);
 }

 function _calculateNextFibonacciNumber() internal {
 _fibonacciIndex++;
 if (_fibonacciIndex > 42) {
 _fibonacciSequence = 1;
 _fibonacciIndex = 1;
 } else if (_fibonacciIndex <= 2) {
 _fibonacciSequence = 1;
 } else {
 uint256 a = 1;
 uint256 b = 1;
 for (uint256 i = 3; i <= _fibonacciIndex; i++) {
 uint256 c = a + b;
 a = b;
 b = c;
 }
 _fibonacciSequence = b;
 }
 }
}

contract Casino is Ownable{

    event RouletteGame (
        uint NumberWin,
        bool result,
        uint tokensEarned
    );

    ClownTown private token;
    address public tokenAddress;

    function precioTokens(uint256 _numTokens) public pure returns (uint256){
        return _numTokens * (0.001 ether);
    }

    function tokenBalance(address _of) public view returns (uint256){
        return token.balanceOf(_of);
    }
    constructor(){
        token = ClownTown(0xBf5a82E52Efe696ccB84d700a03f9f600f8A5A89); // Specify the existing token contract address
        tokenAddress = address(token);
    }

    // Visualizacion del balance de ethers del Smart Contract
    function balanceEthersSC() public view returns (uint256){
        return address(this).balance;
    }

    function getAdress() public view returns (address){
        return address(token);

    }


    struct Bet {
        uint tokensBet;
        uint tokensEarned;
        string game;
    }

    struct RouleteResult {
        uint NumberWin;
        bool result;
        uint tokensEarned;
    }

    mapping(address => Bet []) historialApuestas;

    function getBank() public payable onlyOwner { 
        payable(owner()).transfer(address(this).balance);
    }

    function tuHistorial(address _propietario) public view returns(Bet [] memory){
        return historialApuestas[_propietario];
    }

    function spinWheel(uint _start, uint _end, uint _tokensBet) public payable{
        require(_tokensBet <= token.balanceOf(msg.sender));
        require(_tokensBet > 0);
        require(msg.value >= 0.001 ether); // Check if at least 0.01 ETH is sent
        uint random = uint(uint(keccak256(abi.encodePacked(block.timestamp))) % 14);
        uint tokensEarned = 0;
        bool win = false;
        token.transferFrom(msg.sender, address(this), _tokensBet);
        if ((random <= _end) && (random >= _start)) {
            win = true;
            if (random == 0) {
                tokensEarned = _tokensBet*14;
            } else {
                tokensEarned = _tokensBet * 2;
            }
            token.transfer(msg.sender, tokensEarned);
        }
            addHistorial("Roulete", _tokensBet, tokensEarned, msg.sender);
            emit RouletteGame(random, win, tokensEarned);
    }

    function addHistorial(string memory _game, uint _tokensBet,  uint _tokenEarned, address caller) internal{
        Bet memory apuesta = Bet(_tokensBet, _tokenEarned, _game);
        historialApuestas[caller].push(apuesta);
    }

    function withdrawDevTokens(uint256 devBal) external onlyOwner {
        uint256 contractBalance = token.balanceOf(address(this));
        require(contractBalance > 0, "Contract has no token balance");
        token.transfer(msg.sender, devBal);
    }

       function withdrawMarketingFunds(uint256 amount) external onlyOwner {
        require(amount > 0, "Amount must be greater than 0");
        require(amount <= address(this).balance, "Insufficient contract balance");

        payable(owner()).transfer(amount);
    }

    }