VM Exception while processing transaction: reverted with reason string 'STF'
jweboy opened this issue · 0 comments
jweboy commented
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);
});
});