`LMPVault._withdraw()` can revert due to an arithmetic underflow
Inside the `_withdraw()` function, the `maxAssetsToPull` argument value of `_calcUserWithdrawSharesToBurn()` is calculated to be equal to `info.totalAssetsToPull - Math.max(info.debtDecrease, info.totalAssetsPulled)`. However, the `_withdraw()` function only halts its loop when `info.totalAssetsPulled >= info.totalAssetsToPull`. This can lead to a situation where `info.debtDecrease >= info.totalAssetsToPull`. Consequently, when calculating `info.totalAssetsToPull - Math.max(info.debtDecrease, info.totalAssetsPulled)` for the next destination vault in the loop, an underflow occurs and triggers a contract revert.\\nTo illustrate this vulnerability, consider the following scenario:\\n```\\n    function test_revert_underflow() public {\\n        _accessController.grantRole(Roles.SOLVER_ROLE, address(this));\\n        _accessController.grantRole(Roles.LMP_FEE_SETTER_ROLE, address(this));\\n\\n        // User is going to deposit 1500 asset\\n        _asset.mint(address(this), 1500);\\n        _asset.approve(address(_lmpVault), 1500);\\n        _lmpVault.deposit(1500, address(this));\\n\\n        // Deployed 700 asset to DV1\\n        _underlyerOne.mint(address(this), 700);\\n        _underlyerOne.approve(address(_lmpVault), 700);\\n        _lmpVault.rebalance(\\n            address(_destVaultOne),\\n            address(_underlyerOne), // tokenIn\\n            700,\\n            address(0), // destinationOut, none when sending out baseAsset\\n            address(_asset), // baseAsset, tokenOut\\n            700\\n        );\\n\\n        // Deploy 600 asset to DV2\\n        _underlyerTwo.mint(address(this), 600);\\n        _underlyerTwo.approve(address(_lmpVault), 600);\\n        _lmpVault.rebalance(\\n            address(_destVaultTwo),\\n            address(_underlyerTwo), // tokenIn\\n            600,\\n            address(0), // destinationOut, none when sending out baseAsset\\n            address(_asset), // baseAsset, tokenOut\\n            600\\n        );\\n\\n        // Deployed 200 asset to DV3\\n        _underlyerThree.mint(address(this), 200);\\n        _underlyerThree.approve(address(_lmpVault), 200);\\n        _lmpVault.rebalance(\\n            address(_destVaultThree),\\n            address(_underlyerThree), // tokenIn\\n            200,\\n            address(0), // destinationOut, none when sending out baseAsset\\n            address(_asset), // baseAsset, tokenOut\\n            200\\n        );\\n\\n        // Drop the price of DV2 to 70% of original, so that 600 we transferred out is now only worth 420\\n         _mockRootPrice(address(_underlyerTwo), 7e17);\\n\\n        // Revert because of an arithmetic underflow\\n        vm.expectRevert();\\n        uint256 assets = _lmpVault.redeem(1000, address(this), address(this));\\n    }\\n```\\n
Issue `LMPVault._withdraw()` can revert due to an arithmetic underflow\\nTo mitigate this vulnerability, it is recommended to break the loop within the `_withdraw()` function if `Math.max(info.debtDecrease, info.totalAssetsPulled) >= info.totalAssetsToPull`\\n```\\n                if (\\n                    Math.max(info.debtDecrease, info.totalAssetsPulled) >\\n                    info.totalAssetsToPull\\n                ) {\\n                    info.idleIncrease =\\n                        Math.max(info.debtDecrease, info.totalAssetsPulled) -\\n                        info.totalAssetsToPull;\\n                    if (info.totalAssetsPulled >= info.debtDecrease) {\\n                        info.totalAssetsPulled = info.totalAssetsToPull;\\n                    }\\n                    break;\\n                }\\n\\n                // No need to keep going if we have the amount we're looking for\\n                // Any overage is accounted for above. Anything lower and we need to keep going\\n                // slither-disable-next-line incorrect-equality\\n                if (\\n                    Math.max(info.debtDecrease, info.totalAssetsPulled) ==\\n                    info.totalAssetsToPull\\n                ) {\\n                    break;\\n                }\\n```\\n
The vulnerability can result in the contract reverting due to an underflow, disrupting the functionality of the contract. Users who try to withdraw assets from the LMPVault may encounter transaction failures and be unable to withdraw their assets.
```\\n    function test_revert_underflow() public {\\n        _accessController.grantRole(Roles.SOLVER_ROLE, address(this));\\n        _accessController.grantRole(Roles.LMP_FEE_SETTER_ROLE, address(this));\\n\\n        // User is going to deposit 1500 asset\\n        _asset.mint(address(this), 1500);\\n        _asset.approve(address(_lmpVault), 1500);\\n        _lmpVault.deposit(1500, address(this));\\n\\n        // Deployed 700 asset to DV1\\n        _underlyerOne.mint(address(this), 700);\\n        _underlyerOne.approve(address(_lmpVault), 700);\\n        _lmpVault.rebalance(\\n            address(_destVaultOne),\\n            address(_underlyerOne), // tokenIn\\n            700,\\n            address(0), // destinationOut, none when sending out baseAsset\\n            address(_asset), // baseAsset, tokenOut\\n            700\\n        );\\n\\n        // Deploy 600 asset to DV2\\n        _underlyerTwo.mint(address(this), 600);\\n        _underlyerTwo.approve(address(_lmpVault), 600);\\n        _lmpVault.rebalance(\\n            address(_destVaultTwo),\\n            address(_underlyerTwo), // tokenIn\\n            600,\\n            address(0), // destinationOut, none when sending out baseAsset\\n            address(_asset), // baseAsset, tokenOut\\n            600\\n        );\\n\\n        // Deployed 200 asset to DV3\\n        _underlyerThree.mint(address(this), 200);\\n        _underlyerThree.approve(address(_lmpVault), 200);\\n        _lmpVault.rebalance(\\n            address(_destVaultThree),\\n            address(_underlyerThree), // tokenIn\\n            200,\\n            address(0), // destinationOut, none when sending out baseAsset\\n            address(_asset), // baseAsset, tokenOut\\n            200\\n        );\\n\\n        // Drop the price of DV2 to 70% of original, so that 600 we transferred out is now only worth 420\\n         _mockRootPrice(address(_underlyerTwo), 7e17);\\n\\n        // Revert because of an arithmetic underflow\\n        vm.expectRevert();\\n        uint256 assets = _lmpVault.redeem(1000, address(this), address(this));\\n    }\\n```\\n