Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VM Exception while processing transaction: reverted with reason string 'STF' #706

Open
jweboy opened this issue May 17, 2024 · 1 comment

Comments

@jweboy
Copy link

jweboy commented May 17, 2024

I started the local network from the fork mainnet through the hardhat node script, and then continued to execute the hardhat test --network localhost script to perform swap testing on the local network. When I executed the line simpleSwap.swapExactInputSingle, I I encountered the error VM Exception while processing transaction: reverted with reason string 'STF'. Please tell me how I should handle and solve this error.

Error stack

  1) Should provide a caller with more UST than they started with after a swap


  10 passing (5s)
  1 failing

  1) SimpleSwap
       Should provide a caller with more UST than they started with after a swap:
     ProviderError: Error: VM Exception while processing transaction: reverted with reason string 'STF'
      at HttpProvider.request (/Users/biubiubiu/GithubGroup/uvwstor/hanrdhat_swap_contract/node_modules/.pnpm/hardhat@2.22.4_ts-node@10.9.2_typescript@5.0.4/node_modules/hardhat/src/internal/core/providers/http.ts:90:21)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async HardhatEthersSigner.sendTransaction (/Users/biubiubiu/GithubGroup/uvwstor/hanrdhat_swap_contract/node_modules/.pnpm/@nomicfoundation+hardhat-ethers@3.0.6_ethers@6.12.1_hardhat@2.22.4/node_modules/@nomicfoundation/hardhat-ethers/src/signers.ts:125:18)
      at async send (/Users/biubiubiu/GithubGroup/uvwstor/hanrdhat_swap_contract/node_modules/.pnpm/ethers@6.12.1/node_modules/ethers/src.ts/contract/contract.ts:313:20)
      at async Proxy.swapExactInputSingle (/Users/biubiubiu/GithubGroup/uvwstor/hanrdhat_swap_contract/node_modules/.pnpm/ethers@6.12.1/node_modules/ethers/src.ts/contract/contract.ts:352:16)
      at async Context.<anonymous> (/Users/biubiubiu/GithubGroup/uvwstor/hanrdhat_swap_contract/test/SimpleSwap.test.ts:43:18)

hardhat.config.ts

import { vars } from "hardhat/config";
import type { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox-viem";
import "@nomicfoundation/hardhat-ethers";

const ALCHEMY_API_KEY = vars.get("ALCHEMY_API_KEY");
const SEPOLIA_PRIVATE_KEY = vars.get("SEPOLIA_PRIVATE_KEY");
const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY");

const config: HardhatUserConfig = {
  solidity: {
    compilers: [
      {
        version: "0.7.6",
      },
      {
        version: "0.8.24",
        settings: {},
      },
    ],
  },
  networks: {
    sepolia: {
      url: `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
      accounts: [SEPOLIA_PRIVATE_KEY],
    },
    hardhat: {
      forking: {
        url: `https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
      },
    },
  },
  etherscan: { apiKey: ETHERSCAN_API_KEY },
  sourcify: { enabled: true },
};

export default config;

My swap 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';

contract SimpleSwap {
    ISwapRouter public immutable swapRouter;
    address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
    address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    // 交换池的费用等级,如以下就是 0.3%
    uint24 public constant poolFee = 3000;

    constructor(ISwapRouter _swapRouter) {
        swapRouter = _swapRouter;
    }

    // 将固定数量的 DAI 与最大可能数量的 WETH9 互换。
    function swapExactInputSingle(uint256 amountIn) external returns (uint256 amountOut) {
        // 将指定金额的 DAI 转入到合约中
        TransferHelper.safeTransferFrom(DAI, msg.sender, address(this), amountIn);

        // 必须批准 Uniswap 协议路由合约,才能访问我们的合约账户,从调用账户中提取合约代币
        TransferHelper.safeApprove(DAI, address(swapRouter), amountIn);

        // 创建用于执行交换的参数
        ISwapRouter.ExactInputSingleParams memory params = 
            ISwapRouter.ExactInputSingleParams({
                // 入站代币的合约地址
                tokenIn: DAI,
                // 出站代币的合约地址
                tokenOut: WETH9,
                // 交换池的费用等级,用于确定执行交换的正确池合约
                fee: poolFee,
                // 出站 token 的目标地址
                recipient: msg.sender,
                // 交换截止时间,超过该时间后交换将失败,以防止长期未决交易和价格剧烈波动
                deadline: block.timestamp,
                amountIn: amountIn,
                amountOutMinimum: 0,
                // 用于设置交换将推动池的价格限制
                sqrtPriceLimitX96: 0
            });

        // 执行 swap 交换
        amountOut = swapRouter.exactInputSingle(params);
        return amountOut; 
    }
}

Test code

import hre, { ethers } from "hardhat";

const WETH_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const DAI_ADDRESS = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
const DAI_DECIMALS = 18;
const SwapRouterAddress = "0xE592427A0AEce92De3Edee1F18E0157C05861564";

const ercAbi = [
  // Read-Only Functions
  "function balanceOf(address owner) view returns (uint256)",
  // Authenticated Functions
  "function transfer(address to, uint amount) returns (bool)",
  "function deposit() public payable",
  "function approve(address spender, uint256 amount) returns (bool)",
];

describe("SimpleSwap", () => {
  it("Should provide a caller with more UST than they started with after a swap", async () => {
    // 合约部署
    const simpleSwapFactory = await ethers.getContractFactory("SimpleSwap");
    const simpleSwap = await simpleSwapFactory.deploy(SwapRouterAddress);
    await simpleSwap.waitForDeployment();
    const signers = await ethers.getSigners();

    // 包装一部分的 ETH 到 WETH
    const WETH = new ethers.Contract(WETH_ADDRESS, ercAbi, signers[0]);
    const deposit = await WETH.deposit({ value: ethers.parseEther("10") });
    await deposit.wait();

    // 检查 DAI 余额
    const DAI = new ethers.Contract(DAI_ADDRESS, ercAbi, signers[0]);
    const expandedDAIBalanceBefore = await DAI.balanceOf(signers[0].address);
    const DAIBalanceBefore = Number(
      ethers.formatUnits(expandedDAIBalanceBefore, DAI_DECIMALS)
    );
    console.log(await simpleSwap.getAddress(), simpleSwap.target);
    // 审批 WETH 转移到 swap 合约
    await WETH.approve(await simpleSwap.getAddress(), ethers.parseEther("1"));

    // 执行 swap
    const amountIn = ethers.parseEther("0.1");
    console.log(amountIn);
    const swap = await simpleSwap.swapExactInputSingle(amountIn, {
      gasLimit: 300000,
    });
    swap.wait();

    // const expandedDAIBalanceAfter = await DAI.balanceOf(signers[0].address);
    // const DAIBalanceAfter = Number(
    //   hre.ethers.formatUnits(expandedDAIBalanceAfter, DAI_DECIMALS)
    // );
    // console.log(DAIBalanceBefore, DAIBalanceAfter);
  });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@jweboy and others