The Standard

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

Fee-on-transfer tokens means amountIn received will be less than expected causing swap() reverts

Vulnerability Details

In SmartVaultV3::swap user provides _inToken and _amount representing the token they are giving in the swap and the amount.
The amountIn variable is the amount of _inputToken that the swapRouter will expect to receive.
However, the amount received by swapRouter will not be the same as the amount sent accurate for fee-on-transfer tokens; i,.e. PAXG.
The fee which will be charged on the transfer 0.02 should be taken into account.

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
});
inToken == ISmartVaultManagerV3(manager).weth() ?
executeNativeSwapAndFee(params, swapFee) :
executeERC20SwapAndFee(params, swapFee);

Impact

Transactions will be reverted where PAXG or another fee-on-transfer token is used as the _inputToken without taking fee into account.

Tools Used

Manual Review

Recommendations

Calculate the fee and deduct it from _amount as is done with the _swapFee:

```diff
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);

+   bytes32 PAXGSymbol = keccak256(abi.encodePacked("PAXG"));

+   if(){
+   // Check if the token symbol is PAXG
+   if (_inToken == PAXGSymbol) {
+       uint256 paxgFee = _amount_ * 2 / 10000;    // 0.02% fee
    }

    ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: inToken, // address
            tokenOut: getSwapAddressFor(_outToken),
            fee: 3000,
            recipient: address(this),
            deadline: block.timestamp,
-           amountIn: _amount - swapFee,
+           amountIn: _amount - swapFee - paxgFee, 
            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:

fee-on-transfer

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

fee-on-transfer

Support

FAQs

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