I am trying to create my first smart contract based on https://docs.uniswap.org/protocol/guides/swaps/single-swaps I've deployed it on kovan test net using remix successfully but when trying to send the contract the amount of WETH9/DAI to swap i get this error https://kovan.etherscan.io/tx/0x1d038deff09b9dc338286bd9c8fe054ec247c05329072153a76fe545b6d7ab88 it seems that the smart contract is not withdrawing the amount to swap from metamask, I've tried to fix this myself for a few days now, but I'm stuck what is the problem here with the smart contract?

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
pragma abicoder v2;

import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';

interface IUniswapRouter is ISwapRouter {
    function refundETH() external payable;

contract Uniswap3 {
    // This example swaps WETH9/DAI for single path swaps.

    IUniswapRouter public constant uniswapRouter = IUniswapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
    address public constant DAI = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;
    address public constant WETH9 = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;

    // For this example, we will set the pool fee to 0.3%.
    uint24 public constant poolFee = 3000;

    /// @notice swapExactInputSingle swaps a fixed amount of WETH9 for a maximum possible amount of DAI
    /// using the WETH9/DAI 0.3% pool by calling `exactInputSingle` in the swap router.
    /// @dev The calling address must approve this contract to spend at least `amountIn` worth of its WETH9 for this function to succeed.
    /// @param amountIn The exact amount of WETH9 that will be swapped for DAI.
    /// @return amountOut The amount of DAI received.
    function swapExactInputSingle(uint256 amountIn) external returns (uint256 amountOut) {
        // msg.sender must approve this contract

        // Transfer the specified amount of WETH9 to this contract.
        TransferHelper.safeTransferFrom(WETH9, msg.sender, address(this), amountIn);

        // Approve the router to spend WETH9.
        TransferHelper.safeApprove(WETH9, address(uniswapRouter), amountIn);

        // Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum.
        // We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount.
        ISwapRouter.ExactInputSingleParams memory params =
                tokenIn: WETH9,
                tokenOut: DAI,
                fee: poolFee,
                recipient: msg.sender,
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0

        // The call to `exactInputSingle` executes the swap.
        amountOut = uniswapRouter.exactInputSingle(params);
        // refund leftover ETH to user
        (bool success,) = msg.sender.call{ value: address(this).balance }("");
        require(success, "refund failed");
    // important to receive ETH
    receive() payable external {}

3 Answers 3


Before calling the swapExactInputSingle of your contract you have to approve the contract to take the wETH from your account to the smart contract.

Like so (brownie test example):

   {"from": accounts[0]},

This is what the // msg.sender must approve this contract line means.


I just got the same problem and fix it as @pierre-mkt said, JUST send a approve transaction first, here is my sample

    const daiTokenContractAddress = "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa"

    const daiTokenContract = new web3.eth.Contract(erc20Abi, daiTokenContractAddress)
    const approveData = await daiTokenContract.methods.approve(swapContractAddress, 20000000000).encodeABI()
    const approveResult = await sendTx(account, daiTokenContractAddress, approveData)
    console.log(`Approve result: ${JSON.stringify(approveResult)}`)

replace dai to your fromToken(e.g WETH9 here) and make sure the swapContractAddress is your deployed contract address which you want to interact with, after that, just send this transaction, and then you can call your Swap Contract correctly.


SwapRouter Failed with error 'STF' due to:

SwapRouter inherits PeripheryPaymentsWithFee. sol, thereby also inheriting PeripheryPayments.sol, which includes the pay function, so it was an error when the contract program deducted inputAmount from the account of the original initiator. This error may be: 1. The SwapRouter contract is not authorized; 2. Insufficient authorization limit; 3. The transaction amount exceeds the account balance (caused by rounding and should be rounded down instead of up)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.