// File: Address.sol



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

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}
// File: IERC20.sol



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

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
    
    // Burn function
    function burn(uint256 amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Burn(address indexed burner, uint256 value);
}
// File: IERC20Permit.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// File: ISLAMvsVOLKANOVSKIFIGHTBETS.sol



/*
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@:            @@     .@@@@           @@+     @@      @@             @@
@@@@@@            @@#     @@@             @@      @@      @@             @@
@@@@@@            @@      @@.             @@      @@      @@             @@
@@@@@@            @@      @@             -@@     %@@     @@-            @@@
@@@@@            .@@     #@@             @@      @@      @@             @@@
@@@@@@@@@@@@@@@@@@@.     @@      @@@@@@@@@@      @@      @@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@      @@      @@@@@@@@@@      @@     +@@@@@@@@@@@@@@@@@@
@@@@%          @@@@      @@     :       %@@             @@@@@@      @@@@@@@
@@@@           @@@@     @@*     @       @@              @@@@@@     @@@@@@@@
@@@@           @@@      @@      @       @@              @@@@@      @@@@@@@@
@@@@          *@@@      @@              @@             @@@@@@      @@@@@@@@
@@@.          @@@@     :@@     %       @@+             @@@@@@      @@@@@@@@
@@@      @@@@@@@@*     @@.     @@      @@      @@      @@@@@@     @@@@@@@@@
@@@      @@@@@@@@      @@      @@      @@      @@     .@@@@@      @@@@@@@@@
@@@     @@@@@@@@@      @@      @      =@@     %@@     @@@@@@      @@@@@@@@@
@@      @@@@@@@@@     %@@             @@      @@      @@@@@@     -@@@@@@@@@
@@      @@@@@@@@.     @@#             @@      @@      @@@@@=     @@@@@@@@@@
@@     :@@@@@@@@      @@@            @@@      @@     +@@@@@      @@@@@@@@@@
@#     @@@@@@@@@      @@@:          @@@@     @@:     @@@@@@      @@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@      @@@      @@@      @@@      @@#             @@@@@@
@@@@@@@@@@@@@@@@@@@@      @@#      @@:      @@       @@              .@@@@@
@@@@@@@@@@@@@@@@@@@       @@       @@       @@      .@@               @@@@@
@@@@@@@@@@@@@@@@@@@      :@@      *@@      @@@      @@@               @@@@@
@@@@@@@@@@@@@@@@@@@      @@@      @@@      @@#      @@-               @@@@@
@@@@@@@@@@@@@@@@@@*      @@:      @@       @@       @@@@@@@@@@@      .@@@@@
@@@@@@@@@@@@@@@@@@       @@       @@      .@@      +@@@@@@@@@@@      @@@@@@
@@@@@@@@@@@@@@@@@@      #@@      @@@      @@@      @@@@@@@@@@@       @@@@@@
@@@@@@@@@@@@@@@@@@               @@#      @@:      @@                @@@@@@
@@@@@@@@@@@@@@@@@:               @@       @@       @@               @@@@@@@
@@@@@@@@@@@@@@@@@               .@@      #@@      @@@              @@@@@@@@
@@@@@@@@@@@@@@@@@               @@@      @@@      @@%               @@@@@@@
@@@@@@@@@@@@@@@@@               @@:      @@       @@                @@@@@@@
@@@@@@@@@@@@@@@@                @@       @@      .@@      =@=      @@@@@@@@
@@@@@@@@@@@@@@@@      .@@      *@@      @@@      @@@      @@@      @@@@@@@@
@@@@@@@@@@@@@@@@      @@@      @@@      @@*      @@-      @@       @@@@@@@@
@@@@@@@@@@@@@@@#      @@:      @@        -       @@       #        @@@@@@@@
@@@@@@@@@@@@@@@       @@       @@               *@@               @@@@@@@@@
@@@@@@@@@@@@@@@      *@@      @@@               @@@               @@@@@@@@@
@@@@@@@@@@@@@@@      @@@      @@@              @@@               @@@@@@@@@@
@@@@@@@@@@@@@@:      @@       @@@@            @@@@              @@@@@@@@@@@
@@@@@@@@@@@@@@       @@      .@@@@@         .@@@@@            =@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/*

/*
WEBSITE   - https://FightHub.xyz
TWITTER/X - https://twitter.com/FightHubXyz
TELEGRAM  - https://t.me/FightHubXyz
*/

// SPDX-License-Identifier: None
pragma solidity ^0.8.21;

import "./ReentrancyGuard.sol";
import "./IERC20.sol";
import "./SafeERC20.sol";

contract ISLAMVSALEXANDERBETS is ReentrancyGuard {
	using SafeERC20 for IERC20;

    address public owner;
    IERC20 public FIGHTHUB;
    uint256 public requiredTokenAmount;
    bool public bettingOpen = true;
    bool public fightEnded;
    bool public paused = false;
    bytes32 public fightWinner;
    uint256 public contractDeploymentTime;

    bytes32 public constant ISLAM_MAKHACHEV = keccak256("IslamMakhachev");
    bytes32 public constant ALEXANDER_VOLKANOVSKI = keccak256("AlexanderVolkanovski");
    bytes32 public constant DRAW = keccak256("Draw");


    struct Bet {
        uint256 amount;
        bytes32 fighter;
        bool claimed;
    }

    mapping(address => Bet) public bets;
    mapping(address => uint256) public islamBets;
    mapping(address => uint256) public alexanderBets;
    mapping(address => uint256) public tokenBalances;

    uint256 public totalIslamBets;
    uint256 public totalAlexanderBets;

    event BetPlaced(address indexed bettor, bytes32 fighter, uint256 amount);
    event FightEnded(bytes32 winner);
    event PrizeClaimed(address indexed bettor, uint256 amount);
    event RefundClaimed(address indexed bettor, uint256 amount);
    event ContractPaused();
    event ContractResumed();
    event BettingStopped();
    event TokensBurned(uint256 amount);
    event TokenDeposited(address indexed user, uint256 amount);

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this function.");
        _;
    }

    modifier afterFight() {
        require(fightEnded, "Fight has not ended yet.");
        _;
    }

    modifier whenNotPaused() {
        require(!paused, "Contract is paused.");
        _;
    }

    modifier whenPaused() {
        require(paused, "Contract is not paused.");
        _;
    }

    constructor(address _FIGHTHUBAddress, uint256 _initialRequiredTokenAmount) {
        require(_FIGHTHUBAddress != address(0), "Token address cannot be zero.");
        owner = msg.sender;
        FIGHTHUB = IERC20(_FIGHTHUBAddress);
        contractDeploymentTime = block.timestamp;
        requiredTokenAmount = _initialRequiredTokenAmount;
    }

    function setRequiredTokenAmount(uint256 _newRequiredAmount) external onlyOwner {
        requiredTokenAmount = _newRequiredAmount; 
    }

    function burnTokens(uint256 _amount) external onlyOwner {
        
        // Ensure that the user is burning tokens
        require(_amount > 0, "Invalid burn amount");

        // Ensure that the contract has enough tokens to burn
        require(FIGHTHUB.balanceOf(address(this)) >= _amount, "Not enough tokens to burn");

        // Call the burn function of the ERC-20 token contract
        FIGHTHUB.burn(_amount);

        // Emit an event to log the token burning
        emit TokensBurned(_amount);
    }

    receive() external payable {
        revert("USE THE PLACE BET FUNCTION, WE DON'T ACCEPT RANDOM ETH SENDS");
    }

    function sendRequiredTokens() external whenNotPaused {
        require(bettingOpen, "Betting is closed.");
        require(tokenBalances[msg.sender] < requiredTokenAmount, "You've already sent the required amount.");

        // Ensure that the contract has the required allowance to transfer tokens
        require(FIGHTHUB.allowance(msg.sender, address(this)) >= requiredTokenAmount, "The $FIGHT contract does not have the correct token allowance");

        // Transfer the required tokens from the sender's wallet to the contract
        FIGHTHUB.safeTransferFrom(msg.sender, address(this), requiredTokenAmount);
        
        // Update the user's token balance
        tokenBalances[msg.sender] += requiredTokenAmount;

        // Emit an event to log the token deposit
        emit TokenDeposited(msg.sender, requiredTokenAmount);
    }

    function togglePause() external onlyOwner {
        paused = !paused;
        if (paused) {
            emit ContractPaused();
        } else {
            emit ContractResumed();
        }
    }

    function getTotalBetsForFighter(bytes32 _fighter) public view returns (uint256) {
        if (_fighter == ISLAM_MAKHACHEV) {
            return totalIslamBets;
        } else if (_fighter == ALEXANDER_VOLKANOVSKI) {
            return totalAlexanderBets;
        }
        return 0;
    }

    function getUserBet(address _user) public view returns (uint256, bytes32) {
        return (bets[_user].amount, bets[_user].fighter);
    }

    function safeTransfer(address payable recipient, uint256 amount) internal {
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Transfer failed.");
    }

    function placeBet(bytes32 _fighter) external payable whenNotPaused {
        require(msg.value > 0, "You must send some Ether to place a bet.");
        require(bets[msg.sender].amount == 0, "You have already placed a bet with this wallet.");
        require(bettingOpen, "Betting is closed.");
        require(_fighter == ISLAM_MAKHACHEV || _fighter == ALEXANDER_VOLKANOVSKI, "Invalid fighter selected.");
        require(tokenBalances[msg.sender] >= requiredTokenAmount, "Insufficient tokens deposited.");

        uint256 feeAmount = msg.value * 10 / 100; // assuming 10% fee
        uint256 betAmount = msg.value - feeAmount;

        // Transfer fee to the owner
        safeTransfer(payable(owner), feeAmount);

        bets[msg.sender] = Bet({
            amount: betAmount,
            fighter: _fighter,
            claimed: false
        });

        if (_fighter == ISLAM_MAKHACHEV) {
            islamBets[msg.sender] += betAmount;
            totalIslamBets += betAmount;
        } else if (_fighter == ALEXANDER_VOLKANOVSKI) {
            alexanderBets[msg.sender] += betAmount;
            totalAlexanderBets += betAmount;
        }

        emit BetPlaced(msg.sender, _fighter, betAmount);
    }

    function stopBets() external onlyOwner {
        bettingOpen = false;
        emit BettingStopped();
    }

    function endFight(bytes32 _winner) external onlyOwner {
        require(!fightEnded, "Fight has already ended.");
        require(_winner == ISLAM_MAKHACHEV || _winner == ALEXANDER_VOLKANOVSKI || _winner == DRAW, "Invalid fighter selected.");

        fightEnded = true;
        fightWinner = _winner;

        emit FightEnded(_winner);
    }

    function claimPrize() external afterFight nonReentrant {
        require(bets[msg.sender].amount > 0, "You didn't place a bet.");
        require(bets[msg.sender].fighter == fightWinner, "You bet on the wrong fighter.");
        require(!bets[msg.sender].claimed, "You have already claimed your rewards.");

        uint256 userWinnerShare = 0;
    	uint256 userLoserShare = 0;
    	
    	// Calculate the user's share of the winner pool (original bet)
    	userWinnerShare = bets[msg.sender].amount;

    	// Calculate the user's share of the loser pool based on their bets on the winning fighter
        if (fightWinner == ISLAM_MAKHACHEV) {
        	userLoserShare = (bets[msg.sender].amount * totalAlexanderBets) / totalIslamBets;
        } else if (fightWinner == ALEXANDER_VOLKANOVSKI) {
       	 	userLoserShare = (bets[msg.sender].amount * totalIslamBets) / totalAlexanderBets;
        }

        // Calculate the total prize (original bet + share of loser's pool)
        uint256 totalPrize = userWinnerShare + userLoserShare;

        bets[msg.sender].claimed = true;

        // Transfer the total prize to the user
        safeTransfer(payable(msg.sender), totalPrize);

        emit PrizeClaimed(msg.sender, totalPrize);
    }
    
    function claimRefund() external afterFight nonReentrant {
    	require(bets[msg.sender].amount > 0, "You didn't place a bet.");
    	require(!bets[msg.sender].claimed, "You have already claimed your refund.");
    	require(fightWinner == DRAW, "Refunds are only available in case of a draw.");

    	uint256 userBetAmount = bets[msg.sender].amount;
    	uint256 userTokenBalance = tokenBalances[msg.sender];

    	bets[msg.sender].claimed = true;

    	// Transfer the refund to the user (the original bet amount)
    	safeTransfer(payable(msg.sender), userBetAmount);
    	
    	// Transfer the refund of $FIGHT tokens to the user
    	FIGHTHUB.safeTransfer(msg.sender, userTokenBalance);

    	emit RefundClaimed(msg.sender, userBetAmount);
	}

    function getUserLoserPoolShare(address user) public view returns (uint256) {
        require(fightEnded, "Fight has not ended yet.");
        require(bets[user].amount > 0, "You didn't place a bet.");
        require(!bets[user].claimed, "You have already claimed your rewards.");

        uint256 userBetAmount = bets[user].amount;
        uint256 totalLoserPool = (fightWinner == ISLAM_MAKHACHEV) ? totalAlexanderBets : totalIslamBets;

        // Calculate the user's share as a percentage
        uint256 userSharePercentage = (userBetAmount * 10000) / totalLoserPool;

        return userSharePercentage;
    }

    function withdrawUnclaimedFunds() external onlyOwner {
        require(block.timestamp >= contractDeploymentTime + 30 days, "You can only withdraw after 1 month from deployment.");
        uint256 remainingBalance = address(this).balance;
        require(remainingBalance > 0, "No funds to withdraw.");

        safeTransfer(payable(owner), remainingBalance);
    }
}
// File: ReentrancyGuard.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.21;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        if (_status == _ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}
// File: SafeERC20.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Permit} from "./IERC20Permit.sol";
import {Address} from "./Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}