The Standard

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

fixed fee limits pool selection exposing to undue slippage

Summary

Uniswap v3 supports multiple liquidity pools for the same token pair with differing fee amounts.

A swap with a hardcoded fee amount effects the Uniswap v3 pool selection by forcing it to a single pool,
despite multiple pools being available.

When the pools at alternative fee levels have greater depth of liquidity than the hardcoded,
the user will be forced to bear greater slippage, in addition to paying more in pool fees.

Vulnerability Details

While Uniswap v2 only had a single fee tier of 0.3%, Uniswap v3 introduced multiple fee tiers

Uniswap v3 introduces multiple pools for each token pair, each with a different swapping fee. Liquidity providers may initially create pools at three fee levels: 0.05%, 0.30%, and 1%. More fee levels may be added by UNI governance, e.g. the 0.01% fee level added by this governance proposal in November 2021, as executed here.

The swap is being performed using Uniswap v3 exactInputSingle function in SmartVaultV3::executeNativeSwapAndFee

function executeNativeSwapAndFee(ISwapRouter.ExactInputSingleParams memory _params, uint256 _swapFee) private {
(bool sent,) = payable(ISmartVaultManagerV3(manager).protocol()).call{value: _swapFee}("");
require(sent, "err-swap-fee-native");
@> ISwapRouter(ISmartVaultManagerV3(manager).swapRouter2()).exactInputSingle{value: _params.amountIn}(_params);
}

Pool selection by the Uniswap v3 router users the token pair and pool fee

fee The fee tier of the pool, used to determine the correct pool contract in which to execute the swap

On Arbitum there are multiple Uniswap pools available at different fee level with wildly varying liquidity depth

Token Pair Fee Liquidity Uniswap Info Terminal
WBTC / ETH 0.05% $23.27m Pools WBTC / ETH 0.05%
WBTC / ETH 0.3% $3.61m Pools WBTC / ETH 0.3%
ETH / ARB 0.05% $13.14m Pools ETH / ARB 0.05%
ETH / ARB 0.3% $7.84m Pools ETH / ARB 0.3%

Two of the better funded pools for the main tokens of WBTC and ETH still has quite a difference,
with the lower fee pool having ~640% more liquidity than the default pool.
Obviously larger trades need greater liquidity to minimise the slippage of the swap,
but smaller swaps would still benefit from lower fees even when the slippage is trivial.

Impact

The user is being denied the choice to decide which of the liquidity pools their swap is performed,
potentially subjecting them to higher fees and greater slippage.

In the worst case of a liquidity pool with no real liquidity, it would result in above a 95% loss due to slippage.

Tools Used

Manual review

Recommendations

Allow the user to select their fee when performing a swap and by inference their desired Uniswap pool.

Following changes to SmartVaultV3::swap()

- function swap(bytes32 _inToken, bytes32 _outToken, uint256 _amount) external onlyOwner {
+ 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: 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);
}
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.