sherlock-audit / 2024-02-jala-swap-judging

6 stars 4 forks source link

Arabadzhiev - In `JalaMasterRouter::swapExactTokensForETH` the `amountIn` value is not being scaled up when performing the wrapped token swap call to `JalaRouter02::swapExactTokensForETH` #191

Closed sherlock-admin2 closed 7 months ago

sherlock-admin2 commented 8 months ago

Arabadzhiev

high

In JalaMasterRouter::swapExactTokensForETH the amountIn value is not being scaled up when performing the wrapped token swap call to JalaRouter02::swapExactTokensForETH

Summary

When the wrapped token to ETH swap is performed in JalaMasterRouter::swapExactTokensForETH, the amountIn value which is in the decumals of the underlying token is not scaled up in order to match the wrapped token decimals

Vulnerability Detail

The JalaMasterRouter::swapExactTokensForETH is intended to be used for swapping a particular token for ETH. This is done by first wrapping the amountIn of the token in its ChilizWrappedERC20 counterpart and then performing a swap to ETH using the wrapped token to ETH Jala pair. However, there is a critical problem with the implementation of that function. When calling JalaRouter02::swapExactTokensForETH, the amountIn is passed in to that function call as it is. This is incorrect, since amountIn is in the decimals of the underlying token, while the swap is performed using the wrapped token. The wrapped token will always have 18 decimals, while the underlying token will always have less than that, potentially even as low as 0 in the case where the BAR or PSG tokens are being swapped.

Taking all of those things into account, there are only two scenarios that could play out when JalaMasterRouter::swapExactTokensForETH is used:

Impact

The function will not work properly, potentially leading to users loosing their funds

Code Snippet

JalaMasterRouter.sol#L300

Tool used

Manual Review

Recommendation

When performing the actual swap, scale up the amountIn value using the wrapped token decimal offset, so that it matches its decimals:

    function swapExactTokensForETH(
        address originTokenAddress,
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external virtual override returns (uint256[] memory amounts) {
        address wrappedTokenIn = IChilizWrapperFactory(wrapperFactory).wrappedTokenFor(originTokenAddress);

        require(path[0] == wrappedTokenIn, "MS: !path");

        TransferHelper.safeTransferFrom(originTokenAddress, msg.sender, address(this), amountIn);
        _approveAndWrap(originTokenAddress, amountIn);
        IERC20(wrappedTokenIn).approve(router, IERC20(wrappedTokenIn).balanceOf(address(this)));

-       amounts = IJalaRouter02(router).swapExactTokensForETH(amountIn, amountOutMin, path, to, deadline);
+       amounts = IJalaRouter02(router).swapExactTokensForETH(amountIn * IChilizWrappedERC20(wrappedTokenIn).getDecimalsOffset(), amountOutMin, path, to, deadline);
    }

Duplicate of #146