Repository: CryptoBlades/cryptoblades
File: contracts/cryptoblades.sol (Solidity)

Code before:
            specialWeaponsManager.addShards(msg.sender, eventId, quantity);
        }
        SafeRandoms(links[LINK_SAFE_RANDOMS]).requestSingleSeed(msg.sender, getSeed(uint(WEAPON_SEED), quantity, chosenElement));
        claimWeaponData[msg.sender] = uint256(uint256(chosenElement) | (uint256(quantity) << 32));
    }

    function generateWeaponSeedUsingStakedSkill(uint32 quantity, uint8 chosenElement, uint256 eventId) external onlyNonContract oncePerBlock(msg.sender) {
        require(quantity > 0 && quantity <= 10);
        uint8 chosenElementFee = chosenElement == 100 ? 1 : 2;
        int128 discountedMintWeaponFee =
            getMintWeaponFee()
                .mul(PAYMENT_USING_STAKED_SKILL_COST_AFTER_DISCOUNT)
                .mul(ABDKMath64x64.fromUInt(quantity))
                .mul(ABDKMath64x64.fromUInt(chosenElementFee));
        _payContractStakedOnly(msg.sender, usdToSkill(discountedMintWeaponFee));
        _updateWeaponMintFee(quantity);
        if (eventId > 0) {
            specialWeaponsManager.addShards(msg.sender, eventId, quantity);
        }
        SafeRandoms(links[LINK_SAFE_RANDOMS]).requestSingleSeed(msg.sender, getSeed(uint(WEAPON_SEED), quantity, chosenElement));
        claimWeaponData[msg.sender] = uint256(uint256(chosenElement) | (uint256(quantity) << 32));
    }

    function mintWeapon() external onlyNonContract oncePerBlock(msg.sender) {
        uint8 chosenElement = uint8((claimWeaponData[msg.sender]) & 0xFF);
        uint32 quantity = uint32((claimWeaponData[msg.sender] >> 32) & 0xFFFFFFFF);
        claimWeaponData[msg.sender] = 0;
        uint256 seed = SafeRandoms(links[LINK_SAFE_RANDOMS]).popSingleSeed(msg.sender, getSeed(uint(WEAPON_SEED), quantity, chosenElement), true, false);
        weapons.mintN(msg.sender, quantity, seed, chosenElement);
    }

    function getSeed(uint seedId, uint quantity, uint element) internal pure returns (uint256 seed) {
        uint[] memory seeds = new uint[](3);
        seeds[0] = seedId;
        seeds[1] = quantity;
        seeds[2] = element;
        seed = RandomUtil.combineSeeds(seeds);
    }

    function _updateWeaponMintFee(uint256 num) internal {
        mintWeaponFee = getMintWeaponFee() + ABDKMath64x64.divu(vars[VAR_WEAPON_FEE_INCREASE].mul(num), 1e18);
        vars[VAR_WEAPON_MINT_TIMESTAMP] = block.timestamp;
    }

    function _updateCharacterMintFee() internal {
        mintCharacterFee = getMintCharacterFee() + ABDKMath64x64.divu(vars[VAR_CHARACTER_FEE_INCREASE], 1e18);
        vars[VAR_CHARACTER_MINT_TIMESTAMP] = block.timestamp;
    }

    function migrateRandoms(IRandoms _newRandoms) external {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender));

Review comment (bug):
I think we should require quantity > 0 here so the transaction fails with an error instead of passing and not minting anything while data is = 0.

Code after:
        if (eventId > 0) {
            specialWeaponsManager.addShards(msg.sender, eventId, quantity);
        }
        SafeRandoms(links[LINK_SAFE_RANDOMS]).requestSingleSeed(msg.sender, getSeed(uint(WEAPON_SEED), quantity, chosenElement));
        userVars[msg.sender][USERVAR_CLAIM_WEAPON_DATA] = uint256(uint256(chosenElement) | (uint256(quantity) << 32));
    }

    function generateWeaponSeedUsingStakedSkill(uint32 quantity, uint8 chosenElement, uint256 eventId) external onlyNonContract oncePerBlock(msg.sender) {
        require(quantity > 0 && quantity <= 10);
        require(userVars[msg.sender][USERVAR_CLAIM_WEAPON_DATA] == 0);
        uint8 chosenElementFee = chosenElement == 100 ? 1 : 2;
        int128 discountedMintWeaponFee =
            getMintWeaponFee()
                .mul(PAYMENT_USING_STAKED_SKILL_COST_AFTER_DISCOUNT)
                .mul(ABDKMath64x64.fromUInt(quantity))
                .mul(ABDKMath64x64.fromUInt(chosenElementFee));
        _payContractStakedOnly(msg.sender, usdToSkill(discountedMintWeaponFee));
        _updateWeaponMintFee(quantity);
        if (eventId > 0) {
            specialWeaponsManager.addShards(msg.sender, eventId, quantity);
        }
        SafeRandoms(links[LINK_SAFE_RANDOMS]).requestSingleSeed(msg.sender, getSeed(uint(WEAPON_SEED), quantity, chosenElement));
        userVars[msg.sender][USERVAR_CLAIM_WEAPON_DATA] = uint256(uint256(chosenElement) | (uint256(quantity) << 32));
    }

    function mintWeapon() external onlyNonContract oncePerBlock(msg.sender) {
        uint8 chosenElement = uint8((userVars[msg.sender][USERVAR_CLAIM_WEAPON_DATA]) & 0xFF);
        uint32 quantity = uint32((userVars[msg.sender][USERVAR_CLAIM_WEAPON_DATA] >> 32) & 0xFFFFFFFF);
        require(quantity > 0);
        userVars[msg.sender][USERVAR_CLAIM_WEAPON_DATA] = 0;
        uint256 seed = SafeRandoms(links[LINK_SAFE_RANDOMS]).popSingleSeed(msg.sender, getSeed(uint(WEAPON_SEED), quantity, chosenElement), true, false);
        weapons.mintN(msg.sender, quantity, seed, chosenElement);
    }

    function getSeed(uint seedId, uint quantity, uint element) internal pure returns (uint256 seed) {
        uint[] memory seeds = new uint[](3);
        seeds[0] = seedId;
        seeds[1] = quantity;
        seeds[2] = element;
        seed = RandomUtil.combineSeeds(seeds);
    }

    function _updateWeaponMintFee(uint256 num) internal {
        mintWeaponFee = getMintWeaponFee() + ABDKMath64x64.divu(vars[VAR_WEAPON_FEE_INCREASE].mul(num), 1e18);
        vars[VAR_WEAPON_MINT_TIMESTAMP] = block.timestamp;
    }

    function _updateCharacterMintFee() internal {
        mintCharacterFee = getMintCharacterFee() + ABDKMath64x64.divu(vars[VAR_CHARACTER_FEE_INCREASE], 1e18);
        vars[VAR_CHARACTER_MINT_TIMESTAMP] = block.timestamp;
    }