我遇到了这个错误“获取 VM 异常:在 Solidity 合约中执行套利期间因原因字符串“UniswapV2:K”错误而恢复”

问题描述 投票:0回答:1

我一直在与uniswap和SushiSwap进行交叉交易所闪贷套利,但我不断收到此错误

VM 异常:已恢复,原因字符串“UniswapV2:K”

在 Solidity 合约中执行套利期间。

这是我的错误

user@user-HP-ProBook-4530s:~/Project/blockchainbase/flashloans/flas-swap/uniswap-sushi$ npx hardhat test


  flashSwap contract
    Arbitrage execution
Whale Balance: 65519.853357882756414289
      ✔ ensures the contract is funded
Whale Balance: 65519.848944619279065916
amountRequired 62397446242317897
amountRecieved 62397446242317897
amountRequired 946999
amountRecieved 946999
      1) executes the arbitrage


  1 passing (42s)
  1 failing

  1) flashSwap contract
       Arbitrage execution
         executes the arbitrage:
     Error: VM Exception while processing transaction: reverted with reason string 'UniswapV2: K'
    at <UnrecognizedContract>.<unknown> (0x397ff1542f962076d0bfe58ea045ffa2d347aca0)
    at uniswapCrossFlash.performInitialSwap (contracts/FlashSwap.sol:111)
    at uniswapCrossFlash.startArbitrage (contracts/FlashSwap.sol:184)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1866:23)
    at HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:524:16)
    at EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1482:18)
    at HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:124:18)
    at EthersProviderWrapper.send (node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)

这是我的智能合约代码:

solidity

//SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.6 ;

import "hardhat/console.sol";

// import interfaces Uniswap
import "./libraries/UniswapV2Library.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IUniswapV2Router01.sol";
import "./interfaces/IUniswapV2Router02.sol";
import "./interfaces/IUniswapV2Pair.sol";
import "./interfaces/IUniswapV2Factory.sol";
import "./interfaces/IERC20.sol";
import "./libraries/SafeERC20.sol";

contract uniswapCrossFlash{
    using SafeERC20 for IERC20;

    //factory address abd router address
    //uniswap and sushi swap
    address private constant UNISWAP_FACTORY = 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac;
    address private constant SUSHISWAP_FACTORY = 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac;

    address private constant UNISWAP_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address private constant SUSHISWAP_ROUTER = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F;

    // Trade Variables
    address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address private constant LINK = 0x514910771AF9Ca656af840dff83E8264EcF986CA;

    //trade variables
    uint256 private deadline = block.timestamp + 1 days;
    uint256 private constant MAX_INT = 
    115792089237316195423570985008687907853269984665640564039457584007913129639935
    ;

    //Fund swap contract
    //provide funtion to allow contract to be funded
    function fundFlashSwapContract( address _owner, address _token, uint256 _amount)  public {
        //IERC20(_token).transferFrom(_owner, address(this), _amount);
         IERC20(_token).transferFrom(_owner, address(this), _amount);
    }

    //Get Contract Balance
    // this allows public view of balance for contract
    function getBalanceOfToken(address _address) public view returns (uint256) {
        return IERC20(_address).balanceOf(address(this));
    }

    // PLACE A TRADE
    // Executed placing a trade
    function placeTrade(
        address _fromToken,
        address _toToken,
        uint256 _amountIn,
        address factory,
        address router
    ) private returns (uint256) {
        address pair = IUniswapV2Factory(factory).getPair(_fromToken, _toToken );
        require(pair != address(0), "Pool does not exist");
        
        //performing arbitrage = swaping for another token
        // Calculate Amount Out
        address[] memory path = new address[](2);
        path[0] = _fromToken;
        path[1] = _toToken;

        uint256 amountRequired = IUniswapV2Router01(router).getAmountsOut(_amountIn, path)[1];

        console.log("amountRequired", amountRequired);

        // Perform Arbitrage - Swap for another token
        uint256 amountReceived = IUniswapV2Router01(router).swapExactTokensForTokens(
            _amountIn, // amountIn
            amountRequired, // amountOutMin
            path, // path
            address(this), // address to
            deadline // deadline
            // if you are using a contract thats is not unv2 you need to change the function
        )[1];

        console.log("amountRecieved", amountReceived);

        require(amountReceived > 0, "Aborted Tx: Trade returned zero");

        return amountReceived;
    }

    // CHECK PROFITABILITY
    // Checks whether > output > input
    function checkProfitability(uint256 _input, uint256 _output) private pure returns (bool){
        return _output > _input;
    }

    Initiate Arbitrage
    //it begin receiving and performing arbitrage loans
    function startArbitrage(address _tokenBorrow, uint256 _amount) external {
        IERC20(WETH).safeApprove(address(UNISWAP_ROUTER), MAX_INT);
        IERC20(USDC).safeApprove(address(UNISWAP_ROUTER), MAX_INT);
        IERC20(LINK).safeApprove(address(UNISWAP_ROUTER), MAX_INT);
        
        //sushuswap
        IERC20(WETH).safeApprove(address(SUSHISWAP_ROUTER), MAX_INT);
        IERC20(USDC).safeApprove(address(SUSHISWAP_ROUTER), MAX_INT);
        IERC20(LINK).safeApprove(address(SUSHISWAP_ROUTER), MAX_INT);

        //get the factory of pair address for combined tokens
        address pair = IUniswapV2Factory(UNISWAP_FACTORY).getPair(
            _tokenBorrow,
            WETH
        );

        //return error if combination does not exist
        require(pair != address(0), "pool does not exist");

        //figure out which token (0 or 1) has theamount and assign
        address token0 = IUniswapV2Pair(pair).token0();
        address token1 = IUniswapV2Pair(pair).token1();
        uint256 amountOut = _tokenBorrow == token0 ? _amount:0;
        uint256 amountIn = _tokenBorrow == token1 ? _amount:0;

        //passing data as bytes so that the swap function knows it is a flashloan
        bytes memory data = abi.encode(_tokenBorrow, _amount, msg.sender);
        
        //execute the initial swap to get the loan
        IUniswapV2Pair(pair).swap(amountOut, amountIn, address(this), data);
    }    

    // Initiate Arbitrage
    function startArbitrage(address _tokenBorrow, uint256 _amount) external {
        IERC20(WETH).safeApprove(address(UNISWAP_ROUTER), MAX_INT);
        IERC20(USDC).safeApprove(address(UNISWAP_ROUTER), MAX_INT);
        IERC20(LINK).safeApprove(address(UNISWAP_ROUTER), MAX_INT);

        //sushuswap
        IERC20(WETH).safeApprove(address(SUSHISWAP_ROUTER), MAX_INT);
        IERC20(USDC).safeApprove(address(SUSHISWAP_ROUTER), MAX_INT);
        IERC20(LINK).safeApprove(address(SUSHISWAP_ROUTER), MAX_INT);

        //get the factory of pair address for combined tokens
        address pair = IUniswapV2Factory(UNISWAP_FACTORY).getPair(
            _tokenBorrow,
            WETH
        );

        //return error if combination does not exist
        require(pair != address(0), "pool does not exist");

        //figure out which token (0 or 1) has theamount and assign
        address token0 = IUniswapV2Pair(pair).token0();
        address token1 = IUniswapV2Pair(pair).token1();
        uint256 amountOut = _tokenBorrow == token0 ? _amount : 0;
        uint256 amountIn = _tokenBorrow == token1 ? _amount : 0;

        //passing data as bytes so that the swap function knows it is a flashloan
        bytes memory data = abi.encode(_tokenBorrow, _amount, msg.sender);

        //execute the initial swap to get the loan
        performInitialSwap(pair, amountOut, amountIn, data);

        // After getting the loan, add the logic to perform the arbitrage trade here
        // e.g., you can perform a trade on another DEX using the borrowed amount
        // and calculate the profit.
    }

    function uniswapV2Call(
        address _sender, 
        uint256 _amount0, 
        uint256 _amount1, 
        bytes calldata _data
        ) external{
            //ensure this request came from contract
            address token0 = IUniswapV2Pair(msg.sender).token0();
            address token1 = IUniswapV2Pair(msg.sender).token1();
            address pair = IUniswapV2Factory(UNISWAP_FACTORY).getPair(
                token0,
                token1
            );
            require(msg.sender == pair, "the sender needs to match the pair");
            require(_sender == address(this), "sender needs to match this contract");

            //Decode data for calculating the repayment
            (address tokenBorrow, uint256 amount, address myAddress) = abi.decode(
                _data,
                (address, uint256, address)
            );

            // After doing the arbitrage, repay the flash loan
            uint256 fee = (amount * 3) / 997;
            uint256 amountToRepay = amount + fee;

            //Do arbitrage
            //!!!!!!!!!!!!!

            // Assign loan amount
            uint256 loanAmount = _amount0 > 0 ? _amount0 : _amount1;

            // Place Trades
            //trade 1
            uint256 trade1Acquired = placeTrade(
               USDC,
               LINK,
               loanAmount,
               UNISWAP_FACTORY,
               UNISWAP_ROUTER
            );

            // Check liquidity after the first trade
            require(checkLiquidity(USDC, LINK, UNISWAP_FACTORY), "Insufficient liquidity after first trade");

            // Trade 2
            uint256 trade2Acquired = placeTrade(
               LINK,
               USDC,
               trade1Acquired,
               SUSHISWAP_FACTORY,
               SUSHISWAP_ROUTER
            );

            // Check liquidity after the second trade
            require(checkLiquidity(LINK, USDC, SUSHISWAP_FACTORY), "Insufficient liquidity after second trade");

            // //checkProfitability
            // bool profCheck = checkProfitability(amountToRepay, trade3AcquiredCoin);
            // require(profCheck,"arbitrage not profitable");

            //pay my self
            // IERC20 otherToken = IERC20(BUSD);
            // otherToken.transfer(myAddress, trade3AcquiredCoin - amountToRepay);
            
            //pay loan back
            IERC20(tokenBorrow).transfer(pair, amountToRepay);
        }
}

这是我的

tester.js
javascript:

const { expect, assert } = require("chai");
const { ethers } = require("hardhat");
const { impersonateFundErc20 } = require("../utils/utilities");

const { abi } = require("../artifacts/contracts/interfaces/IERC20.sol/IERC20.json");

const provider = waffle.provider;

describe("flashSwap contract", () => {
  let FLASHSWAP,
    BORROW_AMOUNT,
    FUND_AMOUNT,
    initiateFundingHuman,
    txArbitrage

  const DECIMALS = 6;

  const USDC_WHALE = "0xcffad3200574698b78f32232aa9d63eabd290703";
  const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
  const LINK = "0x514910771AF9Ca656af840dff83E8264EcF986CA";

  const BASE_TOKEN_ADDRESS = USDC;

  const tokenBase = new ethers.Contract(BASE_TOKEN_ADDRESS, abi, provider);

  beforeEach(async () => {
    // get the owner as the signer
    [owner] = await ethers.getSigners();

    // Ensure that the WHALE has a balance
    const whale_balance = await provider.getBalance(USDC_WHALE);
    console.log("Whale Balance:", ethers.utils.formatEther(whale_balance));
    assert.notEqual(whale_balance, 0, "Whale account has insufficient balance");
    //expect(whale_balance).not.equal("0")

    // Deploy smart contract
    const flashSwap = await ethers.getContractFactory("uniswapCrossFlash");
    FLASHSWAP = await flashSwap.deploy();
    await FLASHSWAP.deployed();

    // Configured our borrowing
    const borrowAmountHuman = "1";
    BORROW_AMOUNT = ethers.utils.parseUnits(borrowAmountHuman, DECIMALS);

    // Configured funding - for testing only
    initiateFundingHuman = "100";
    FUND_AMOUNT = ethers.utils.parseUnits(initiateFundingHuman, DECIMALS);

    // Fund our contract - For testing only
    await impersonateFundErc20(
      tokenBase,
      USDC_WHALE,
      FLASHSWAP.address,
      initiateFundingHuman,
      DECIMALS
    );
  });

  describe("Arbitrage execution", () => {
    it("ensures the contract is funded", async () => {
      const flashSwapBalance = await FLASHSWAP.getBalanceOfToken(BASE_TOKEN_ADDRESS);

      const flashSwapBalanceHuman = ethers.utils.formatUnits(flashSwapBalance, 6); //i replaced decimals with 18

      //console.log("FlashSwap Balance:", flashSwapBalanceHuman);

      expect(Number(flashSwapBalanceHuman)).equal(Number(initiateFundingHuman)); //will un comment this 
      //expect(Number(flashSwapBalanceHuman)).closeTo(Number(initiateFundingHuman), 0.001); //will remove this and put ^
    });

    it("executes the arbitrage", async ()=> {
      txArbitrage = await FLASHSWAP.startArbitrage(
        BASE_TOKEN_ADDRESS,
        BORROW_AMOUNT,
      );

      assert(txArbitrage);

      //print balances
      const contractBalanceUSDC = await FLASHSWAP.getBalanceOfToken(USDC);
      const formattedBalUSDC = Number(
        ethers.utils.formatUnits(contractBalanceUSDC, DECIMALS)
      );
      console.log("balance of USDC" + formattedBalUSDC);

      const contractBalanceLINK = await FLASHSWAP.getBalanceOfToken(LINK );
      const formattedBalLINK  = Number(
        ethers.utils.formatUnits(contractBalanceLINK , DECIMALS)
      );
      console.log("Balance of LINK " + formattedBalLINK );

    });
  });
});

这是我的

hardhat.config.js

require("@nomiclabs/hardhat-waffle");

// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

/**
 * @type import('hardhat/config').HardhatUserConfig
 */
module.exports = {
  solidity: {
    compilers: [
      {version: "0.5.5"},
      {version: "0.6.6"},
      {version: "0.8.0"},
    ],
  },
  networks: {
    hardhat: {
      forking: {
        url: "https://eth-mainnet.g.alchemy.com/v2/",
      },
    },
    testnet: {
      url: "https://eth-sepolia.g.alchemy.com/v2/",
      chainId: 11155111,
      accounts: ["PRIVAT KEY"],
    },
    mainnet: {
      url: "https://eth-mainnet.g.alchemy.com",
      chainId: 1,
      accounts: ["0main net private key"],
    },
  },
};

我期待看到这个

Whale Balance: 65519.848944619279065916
amountRequired 62397446242317897
amountRecieved 62397446242317897
amountRequired 946999
amountRecieved 946999 

有usdc和link的余额。

课程可能是什么?我该如何解决这个问题?过去两周我一直在尝试这个

solidity smartcontracts hardhat uniswap
1个回答
0
投票

我也遇到过同样的问题,差点丢失了我转移的硬币,但我通过给官方支持发短信解决了这个问题。寻求支持:uniswap 支持

单击实时聊天图标即可发起聊天。

© www.soinside.com 2019 - 2024. All rights reserved.