Medium Risk
https://github.com/Cyfrin/2023-12-the-standard/blob/91132936cb09ef9bf82f38ab1106346e2ad60f91/contracts/SmartVaultV3.sol#L221
Fixed fee level is used when swap tokens on Uniswap.
In Fees SmartVaultV3::swap
a fixed fee 3000 (0.3%) level is used:
function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount) external onlyOwner {
uint256 swapFee = _amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
address inToken = getSwapAddressFor(_inToken);
uint256 minimumAmountOut = calculateMinimumAmountOut(_inToken, _outToken, _amount);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getSwapAddressFor(_outToken),
@> fee: 3000, //@audit fixed fee
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount - swapFee,
amountOutMinimum: minimumAmountOut,
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
executeERC20SwapAndFee(params, swapFee);
}
Usually, there are multiple Uniswap V3 pools available for a given token pair with different swap fees.
For instance, the optimal route to swap USDC for WETH is using the 0.05% (500) swap fee pool, which has significantly more liquidity than the 0.3% (3000) swap fee pool and thus less slippage.
Additionally, if the desired pool is not available, the swap will fail, or an attacker could exploit this by creating an imbalanced pool with the desired swap fee and stealing the tokens.
The Fees contract uses inefficient swaps, which leads to higher slippage (receiving less WETH) or failing swaps.
Manual review.
It is recommended to Passing fee level to SmartVaultV3::swap
function as parameter:
+ function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount, uint24 _fee) external onlyOwner {
uint256 swapFee = _amount * ISmartVaultManagerV3(manager).swapFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
address inToken = getSwapAddressFor(_inToken);
uint256 minimumAmountOut = calculateMinimumAmountOut(_inToken, _outToken, _amount);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getSwapAddressFor(_outToken),
+ fee: _fee, //@audit
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount - swapFee,
amountOutMinimum: minimumAmountOut,
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
executeERC20SwapAndFee(params, swapFee);
}