The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: medium
Valid

Fixed Fee Level Usage During Token Swaps on Uniswap

Summary

Fixed fee level is used when swap tokens on Uniswap.

Vulnerability Details

The SmartVaultV3.swap function is designed for swapping collateral tokens. It constructs the ISwapRouter.ExactInputSingleParams with a constant fee of 3000 (0.3%). However, not all Uniswap pools operate at this fee level. For instance, the XMON/ETH pool on Mainnet (0x59b4bb1f5d943cf71a10df63f6b743ee4a4489ee) has a 1% fee, and the WETH/BOB pool on Optimism (0x1a54ae9f662b463f8d432482975c17e51518b50d) charges 0.05%.

ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: inToken,
tokenOut: getSwapAddressFor(_outToken),
fee: 3000,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount - swapFee,
amountOutMinimum: minimumAmountOut,
sqrtPriceLimitX96: 0
});

Impact

This fixed fee approach poses several issues:

  1. It restricts swaps to pools with a 0.3% fee, potentially leading to suboptimal liquidity utilization. For example, the USDC/ETH pool with 0.05% fees has $161.32 million in TVL, compared to $71.89 million in the 0.3% fee pool. Higher liquidity pools could reduce slippage, offering better rates for users. A fixed fee can lead to missed opportunities for optimal swaps.

  2. The approach may cause transactions to revert when attempting to swap in non-existent pools with the fixed fee level.

Tools Used

Manual Review

Recommendations

Modify the SmartVaultV3.swap function to accept a variable fee parameter, enhancing flexibility and addressing the outlined issues. This change involves passing the fee as a parameter to the function, allowing for dynamic fee adjustments based on pool characteristics.

- function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount) external onlyOwner {
+ function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount, uint256 _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: 3000,
+ fee: _fee,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amount - swapFee,
amountOutMinimum: minimumAmountOut,
sqrtPriceLimitX96: 0
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
executeERC20SwapAndFee(params, swapFee);
}

By adopting this recommendation, the SmartVaultV3 will be able to interact more effectively with a broader range of liquidity pools, improving swap efficiency and potentially reducing transaction failures.

Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

fixed-uni-fee

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

hardcoded-fee

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.