Search code examples
ethereumsolidityuniswap

Simple swapExactInputSingle from Uniswap V3 fails on Rinkeby


I've tried to follow Uniswaps guide for implementing simple swapExactInputSingle function and deployed the contract on Rinkeby.

Code:

contract Swap {
    using LowGasSafeMath for uint256;

    address private constant SWAP_ROUTER =
        0xE592427A0AEce92De3Edee1F18E0157C05861564;
    address private constant WETH = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
    address public constant DAI = 0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735;

    address public immutable _owner;
    ISwapRouter public immutable swapRouter;

    constructor() {
        _owner = msg.sender;
        swapRouter = ISwapRouter(SWAP_ROUTER);
    }

    function swapExactInputSingle(uint256 amountIn)
        external
        returns (uint256 amountOut)
    {
        //Transfer DAI here, and approve its usage for router
        TransferHelper.safeTransferFrom(
            DAI,
            msg.sender,
            address(this),
            amountIn
        );
        TransferHelper.safeApprove(DAI, address(swapRouter), amountIn);

        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
            .ExactInputSingleParams({
                tokenIn: DAI,
                tokenOut: WETH,
                fee: 3000,
                recipient: msg.sender,
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0
            });

        amountOut = swapRouter.exactInputSingle(params);
    }

    receive() external payable {}
}

DAI and WETH addresses seems to be correct for the Rinkeby network. I've tried with both of Uniswap SwapRouters addresses (I'm not sure which I should use: SwapRouter or SwapRouter02 from their doc), changing them didn't influce the result. After deploying the contract, when I try to interact with it through etherscan with use of MetaMask, in the metamask before confirming the transaction I get a warning:

This transaction is expected to fail. Trying to execute it is expected to be expensive but fail, and is not recommended.

After confirming this transaction it takes really long time and eventually, it does indeed fail.

What am I doing wrong? I do have correct DAI in my Wallet

Also, why MetaMask for my transaction suggests gas limit of 28472169 and when I'm interacting with Uniswap V3 interface, for the same swap it suggests only 129129 ?


Solution

  • It turned our there were 2 separate problems.

    First one, was the thing mentioned by @Crypto_Rachel. The approval inside contract was only one of the two needed approvals. Before the trade, we also needed to manually approve OUR contract to get the token (DAI) from our wallet.

    As I mentioned in the question, I've been trying two different swap routers: SwapRouter and SwapRouter02. After the first issue has been fixed, I've kept testing using only SwapRouter02.

    It turned out, that SwapRouter02 uses different ExactInputSingleParams struct. It does not have delay parameter. With my usage of import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol" and the struct it provided I should have used SwapRouter. Switching to that router resolved an issue and made my transaction pass.

    If you want to read about that in details check this blogpost: https://brightinventions.pl/blog/single-swap-on-uniswap-v3-with-3-common-mistakes