contract LWXP is Context, Ownable, ERC20Burnable {
    // Loot weapon contract is available at https://etherscan.io/address/0x0ac0ecc6d249f1383c5c7c2ff4941bd56decdd14#code
    address public lootWeaponContractAddress =
        0x0ac0ECc6D249F1383c5C7c2Ff4941Bd56DEcDd14;
    IERC721Enumerable public lootWeaponContract;

    // Give out 100,000 LWXP for every Loot Bag that a user holds
    uint256 public LWXPPerTokenId = 100000 * (10**decimals());

    uint256 public tokenIdStart = 1;

    uint256 public tokenIdEnd = 10000;

    // Track claimed tokens
    mapping(uint256 => bool) public claimedByTokenId;

    constructor() Ownable() ERC20("Loot Wars XP ", "LWXP") {
        // Transfer ownership to the Loot DAO
        // Ownable by OpenZeppelin automatically sets owner to msg.sender, but
        // we're going to be using a separate wallet for deployment
        transferOwnership(0x132D373145d72f4Eb4859cD18f34D08c3d62C7a6);
        lootWeaponContract = IERC721Enumerable(lootWeaponContractAddress);
    }

    /// @notice Claim LWXP for a given Loot ID
    /// @param tokenId The tokenId of the Loot NFT
    function claimById(uint256 tokenId) external {
        // Follow the Checks-Effects-Interactions pattern to prevent reentrancy
        // attacks

        // Checks

        // Check that the msgSender owns the token that is being claimed
        require(
            _msgSender() == lootWeaponContract.ownerOf(tokenId),
            "MUST_OWN_TOKEN_ID"
        );

        // Further Checks, Effects, and Interactions are contained within the
        // _claim() function
        _claim(tokenId, _msgSender());
    }

    /// @notice Claim LWXP for all tokens owned by the sender
    /// @notice This function will run out of gas if you have too much loot! If
    /// this is a concern, you should use claimRangeForOwner and claim LWXP
    /// in batches.
    function claimAllForOwner() external {
        uint256 tokenBalanceOwner = lootWeaponContract.balanceOf(_msgSender());

        // Checks
        require(tokenBalanceOwner > 0, "NO_TOKENS_OWNED");

        // i < tokenBalanceOwner because tokenBalanceOwner is 1-indexed
        for (uint256 i = 0; i < tokenBalanceOwner; i++) {
            // Further Checks, Effects, and Interactions are contained within
            // the _claim() function
            _claim(
                lootWeaponContract.tokenOfOwnerByIndex(_msgSender(), i),
                _msgSender()
            );
        }
    }

    /// @notice Claim LWXP for all tokens owned by the sender within a
    /// given range
    /// @notice This function is useful if you own too much Loot to claim all at
    /// once or if you want to leave some Loot unclaimed.
    function claimRangeForOwner(uint256 ownerIndexStart, uint256 ownerIndexEnd)
        external
    {
        uint256 tokenBalanceOwner = lootWeaponContract.balanceOf(_msgSender());

        // Checks
        require(tokenBalanceOwner > 0, "NO_TOKENS_OWNED");

        // We use < for ownerIndexEnd and tokenBalanceOwner because
        // tokenOfOwnerByIndex is 0-indexed while the token balance is 1-indexed
        require(
            ownerIndexStart >= 0 && ownerIndexEnd < tokenBalanceOwner,
            "INDEX_OUT_OF_RANGE"
        );

        // i <= ownerIndexEnd because ownerIndexEnd is 0-indexed
        for (uint256 i = ownerIndexStart; i <= ownerIndexEnd; i++) {
            // Further Checks, Effects, and Interactions are contained within
            // the _claim() function
            _claim(
                lootWeaponContract.tokenOfOwnerByIndex(_msgSender(), i),
                _msgSender()
            );
        }
    }

    /// @dev Internal function to mint Loot upon claiming
    function _claim(uint256 tokenId, address tokenOwner) internal {
        // Checks
        // Check that the token ID is in range
        // We use >= and <= to here because all of the token IDs are 0-indexed
        require(
            tokenId >= tokenIdStart && tokenId <= tokenIdEnd,
            "TOKEN_ID_OUT_OF_RANGE"
        );

        // Check that LWXP have not already been claimed
        // for a given tokenId
        require(
            !claimedByTokenId[tokenId],
            "LWXP_CLAIMED_FOR_TOKEN_ID"
        );

        // Effects

        // Mark that LWXP has been claimed for the
        // given tokenId
        claimedByTokenId[tokenId] = true;

        // Interactions

        // Send LWXP to the owner of the token ID
        _mint(tokenOwner, LWXPPerTokenId);
    }

    /// @notice Allows the DAO to mint new tokens for use within the Loot
    /// Ecosystem
    /// @param amountDisplayValue The amount of Loot to mint. This should be
    /// input as the display value, not in raw decimals. If you want to mint
    /// 100 Loot, you should enter "100" rather than the value of 100 * 10^18.
    function daoMint(uint256 amountDisplayValue) external onlyOwner {
        _mint(owner(), amountDisplayValue * (10**decimals()));
    }

    /// @notice Allows the DAO to set a new contract address for Loot. This is
    /// relevant in the event that Loot migrates to a new contract.
    /// @param lootWeaponContractAddress_ The new contract address for Loot
    function daoSetLootWeaponContractAddress(address lootWeaponContractAddress_)
        external
        onlyOwner
    {
        lootWeaponContractAddress = lootWeaponContractAddress_;
        lootWeaponContract = IERC721Enumerable(lootWeaponContractAddress);
    }

    /// @notice Allows the DAO to set the token IDs that are eligible to claim
    /// Loot
    /// @param tokenIdStart_ The start of the eligible token range
    /// @param tokenIdEnd_ The end of the eligible token range
    /// @dev This is relevant in case a future Loot contract has a different
    /// total supply of Loot
    function daoSetTokenIdRange(uint256 tokenIdStart_, uint256 tokenIdEnd_)
        external
        onlyOwner
    {
        tokenIdStart = tokenIdStart_;
        tokenIdEnd = tokenIdEnd_;
    }
}
/// @title LWXP for Loot holders!
/// FORKED FROM: Adventure gold at 0x32353a6c91143bfd6c7d363b546e62a9a2489a20
/// @author Will Papper <https://twitter.com/WillPapper>
/// @notice This contract mints LWXP for Loot Weapon holders and provides
/// administrative functions to the Loot Wars DAO. It allows:
/// * Loot Weapon holders to claim LWXP
/// * A DAO to mint LWXP for use within the Loot ecosystem
function _claim(uint256 tokenId, address tokenOwner) internal {
    // Checks
    // Check that the token ID is in range
    // We use >= and <= to here because all of the token IDs are 0-indexed
    require(
        tokenId >= tokenIdStart && tokenId <= tokenIdEnd,
        "TOKEN_ID_OUT_OF_RANGE"
    );

    // Check that LWXP have not already been claimed
    // for a given tokenId
    require(
        !claimedByTokenId[tokenId],
        "LWXP_CLAIMED_FOR_TOKEN_ID"
    );

    // Effects

    // Mark that LWXP has been claimed for the
    // given tokenId
    claimedByTokenId[tokenId] = true;

    // Interactions

    // Send LWXP to the owner of the token ID
    _mint(tokenOwner, LWXPPerTokenId);
}

/// @dev Internal function to mint Loot upon claiming