Vulnerability: Users redeem strategy tokens but receives no assets in return
Severity: high

Description:
Due to a rounding error in Solidity, it is possible that a user burns their strategy tokens, but receives no assets in return due to issues in the following functions:\\nStrategyUtils._convertStrategyTokensToBPTClaim\\nBoosted3TokenPoolUtils._redeem\\nTwoTokenPoolUtils._redeem\\nThis affects both the TwoToken and Boosted3Token vaults\\n```\\nint256 internal constant INTERNAL_TOKEN_PRECISION = 1e8;\\nuint256 internal constant BALANCER_PRECISION = 1e18;\\n```\\n\\nWithin the `StrategyUtils._convertStrategyTokensToBPTClaim` function, it was observed that if the numerator is smaller than the denominator, the `bptClaim` will be zero.\\n```\\nFile: StrategyUtils.sol\\n    function _convertStrategyTokensToBPTClaim(StrategyContext memory context, uint256 strategyTokenAmount)\\n        internal pure returns (uint256 bptClaim) {\\n        require(strategyTokenAmount <= context.vaultState.totalStrategyTokenGlobal);\\n        if (context.vaultState.totalStrategyTokenGlobal > 0) {\\n            bptClaim = (strategyTokenAmount * context.vaultState.totalBPTHeld) / context.vaultState.totalStrategyTokenGlobal;\\n        }\\n    }\\n```\\n\\nWhen the `bptClaim` is zero, the function returns zero instead of reverting. Therefore, it is possible that a user redeems ("burns") their strategy tokens, but receives no assets in return because the number of strategy tokens redeemed by the user is too small.\\n```\\nFile: Boosted3TokenPoolUtils.sol\\n    function _redeem(\\n        ThreeTokenPoolContext memory poolContext,\\n        StrategyContext memory strategyContext,\\n        AuraStakingContext memory stakingContext,\\n        uint256 strategyTokens,\\n        uint256 minPrimary\\n    ) internal returns (uint256 finalPrimaryBalance) {\\n        uint256 bptClaim = strategyContext._convertStrategyTokensToBPTClaim(strategyTokens);\\n\\n        if (bptClaim == 0) return 0;\\n\\n        finalPrimaryBalance = _unstakeAndExitPool({\\n            stakingContext: stakingContext,\\n            poolContext: poolContext,\\n            bptClaim: bptClaim,\\n            minPrimary: minPrimary\\n        });\\n\\n        strategyContext.vaultState.totalBPTHeld -= bptClaim;\\n        strategyContext.vaultState.totalStrategyTokenGlobal -= strategyTokens.toUint80();\\n        strategyContext.vaultState.setStrategyVaultState(); \\n    }\\n```\\n

Impact:
Loss of assets for the users as they burn their strategy tokens, but receive no assets in return.

Recommended mitigation:
Consider reverting if the assets (bptClaim) received is zero. This check has been implemented in many well-known vault designs as this is a commonly known issue (e.g. Solmate)\\n```\\nfunction _redeem(\\n    ThreeTokenPoolContext memory poolContext,\\n    StrategyContext memory strategyContext,\\n    AuraStakingContext memory stakingContext,\\n    uint256 strategyTokens,\\n    uint256 minPrimary\\n) internal returns (uint256 finalPrimaryBalance) {\\n    uint256 bptClaim = strategyContext._convertStrategyTokensToBPTClaim(strategyTokens);\\n\\n// Remove the line below\\n   if (bptClaim == 0) return 0;\\n// Add the line below\\n require(bptClaim > 0, "zero asset")\\n\\n    finalPrimaryBalance = _unstakeAndExitPool({\\n        stakingContext: stakingContext,\\n        poolContext: poolContext,\\n        bptClaim: bptClaim,\\n        minPrimary: minPrimary\\n    });\\n\\n    strategyContext.vaultState.totalBPTHeld // Remove the line below\\n= bptClaim;\\n    strategyContext.vaultState.totalStrategyTokenGlobal // Remove the line below\\n= strategyTokens.toUint80();\\n    strategyContext.vaultState.setStrategyVaultState(); \\n}\\n```\\n