我一直在与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的余额。
课程可能是什么?我该如何解决这个问题?过去两周我一直在尝试这个
我也遇到过同样的问题,差点丢失了我转移的硬币,但我通过给官方支持发短信解决了这个问题。寻求支持:uniswap 支持
单击实时聊天图标即可发起聊天。