3

I know there are many similiar questions but i can not figure out how to implement the 'approve' part in.

pragma solidity ^0.8;
pragma abicoder v2;

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

contract SwapExamples { // For the scope of these swap examples, // we will detail the design considerations when using // exactInput, exactInputSingle, exactOutput, and exactOutputSingle.

// It should be noted that for the sake of these examples, we purposefully pass in the swap router instead of inherit the swap router for simplicity.
// More advanced example contracts will detail how to inherit the swap router safely.

ISwapRouter public immutable swapRouter;

// This example swaps DAI/WETH9 for single path swaps and DAI/USDC/WETH9 for multi path swaps.

address public constant DAI = 0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1;
address public constant WETH9 = 0x4200000000000000000000000000000000000006;
address public constant USDC = 0x4e62882864fB8CE54AFfcAf8D899A286762B011B;

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

constructor(ISwapRouter _swapRouter) {
    swapRouter = _swapRouter;
}

/// @notice swapExactInputSingle swaps a fixed amount of DAI for a maximum possible amount of WETH9
/// using the DAI/WETH9 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 DAI for this function to succeed.
/// @param amountIn The exact amount of DAI that will be swapped for WETH9.
/// @return amountOut The amount of WETH9 received.
function swapExactInputSingle(uint256 amountIn) external returns (uint256 amountOut) {
    // msg.sender must approve this contract

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

    // Approve the router to spend DAI.
    TransferHelper.safeApprove(DAI, address(swapRouter), 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 =
        ISwapRouter.ExactInputSingleParams({
            tokenIn: DAI,
            tokenOut: WETH9,
            fee: poolFee,
            recipient: msg.sender,
            deadline: block.timestamp,
            amountIn: amountIn,
            amountOutMinimum: 0,
            sqrtPriceLimitX96: 0
        });

    // The call to `exactInputSingle` executes the swap.
    amountOut = swapRouter.exactInputSingle(params);
}

/// @notice swapExactOutputSingle swaps a minimum possible amount of DAI for a fixed amount of WETH.
/// @dev The calling address must approve this contract to spend its DAI for this function to succeed. As the amount of input DAI is variable,
/// the calling address will need to approve for a slightly higher amount, anticipating some variance.
/// @param amountOut The exact amount of WETH9 to receive from the swap.
/// @param amountInMaximum The amount of DAI we are willing to spend to receive the specified amount of WETH9.
/// @return amountIn The amount of DAI actually spent in the swap.
function swapExactOutputSingle(uint256 amountOut, uint256 amountInMaximum) external returns (uint256 amountIn) {
    // Transfer the specified amount of DAI to this contract.
    TransferHelper.safeTransferFrom(DAI, msg.sender, address(this), amountInMaximum);

    // Approve the router to spend the specifed `amountInMaximum` of DAI.
    // In production, you should choose the maximum amount to spend based on oracles or other data sources to acheive a better swap.
    TransferHelper.safeApprove(DAI, address(swapRouter), amountInMaximum);

    ISwapRouter.ExactOutputSingleParams memory params =
        ISwapRouter.ExactOutputSingleParams({
            tokenIn: DAI,
            tokenOut: WETH9,
            fee: poolFee,
            recipient: msg.sender,
            deadline: block.timestamp,
            amountOut: amountOut,
            amountInMaximum: amountInMaximum,
            sqrtPriceLimitX96: 0
        });

    // Executes the swap returning the amountIn needed to spend to receive the desired amountOut.
    amountIn = swapRouter.exactOutputSingle(params);

    // For exact output swaps, the amountInMaximum may not have all been spent.
    // If the actual amount spent (amountIn) is less than the specified maximum amount, we must refund the msg.sender and approve the swapRouter to spend 0.
    if (amountIn < amountInMaximum) {
        TransferHelper.safeApprove(DAI, address(swapRouter), 0);
        TransferHelper.safeTransfer(DAI, msg.sender, amountInMaximum - amountIn);
    }
}

}

Here is my error:

Gas estimation failed
Close
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": -32000, "message": "execution reverted: STF" }
CloudTrauma
  • 31
  • 1
  • 1
  • 2
  • What is the "approve part" ? What have you tried so far ? – Itération 122442 Jun 02 '22 at 06:08
  • Trying to let the contract take some DAI from my metamask wallet but i supposedly need to approve the contract – CloudTrauma Jun 02 '22 at 18:59
  • @CloudTrauma Do you have the failed transaction hash? Usually to use transferFrom the owner has to call approve first, see the details here https://ethereum.stackexchange.com/a/46458/. – Ismael Jun 03 '22 at 12:57

2 Answers2

3

execution reverted: STF means execution is reverted by require assertion in TransferHelper.safeTransferFrom function.

Here is the code of Uniswap V3 Swap Router https://etherscan.io/address/0xe592427a0aece92de3edee1f18e0157c05861564#code

If you search this code for "STF", you'll find the implementation:

  function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
    }

Possible cause of this can be simply not enough DAI tokens on msg.sender

TechGeorgii
  • 299
  • 2
  • 8
0

Your error code is most likely attributed to not having the smart contract approved to access your DAI tokens.

This must be done MANUALLY, e.g. via Metamask or in a Node.Js file as follows:

const { ethers } = require('ethers')
require('dotenv').config()

// save the abi file locally and call it const ERC20ABI = require('../data/erc20.json')

// Token addresses for Ropsten const DAI = "0xaD6D458402F60fD3Bd25163575031ACDce07538D"

// import from .env file const INFURA = process.env.INFURA_ROPSTEN const WALLET_ADDRESS = process.env.WALLET_ADDRESS const WALLET_SECRET = process.env.WALLET_SECRET

// input here your deployed contract const SmartContractAddress = '0x......'

// initiate wallet with private key const provider = new ethers.providers.JsonRpcProvider(INFURA) const wallet = new ethers.Wallet(WALLET_SECRET) const connectedWallet = wallet.connect(provider)

// initiate ERC20 contract const DAIcontract = new ethers.Contract( DAI, ERC20ABI, provider )

// function to approve token const approve = async (ERC20contract, toApproveAddress) => { ERC20contract.connect(connectedWallet).approve( toApproveAddress, ethers.utils.parseEther("1").toString(), { gasLimit: ethers.utils.hexlify(1000000) } ).then(transaction => { console.log(transaction) }) }

async function main() { approve(DAIcontract, SmartContractAddress) }

main()