I'm new self-taught developer. I've been trying for over a 3 month. To write a polygon flashloan arbitrage bot. I've probable coded at least 500 different codes and either I can't get them compiled or deploy and can't interact. I don't know what to do . I've started my own project and this bot going help me for earning money for liquidity for tokens, and 3 months later still stuck.Now im at the point where able to deploy contract. I enter in the token that im trading against for the arbitrage. Next I enter in the amount to borrow then the minimum profit amount to start he arbitrage bot. I enter the information then hit transact in remix i get black box saying that my transaction will most likely failed because of fee.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
// Aave Interfaces
interface ILendingPoolAddressesProvider {
function getLendingPool() external view returns (address);
}
interface ILendingPool {
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
}
// Uniswap Interfaces
interface IUniswapV2Router01 {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
interface IUniswapV2Router02 is IUniswapV2Router01 {
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
// Base contract for Aave flash loan receivers
abstract contract FlashLoanReceiverBase {
using Address for address;
ILendingPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
ILendingPool public immutable LENDING_POOL;
constructor(ILendingPoolAddressesProvider provider) {
ADDRESSES_PROVIDER = provider;
LENDING_POOL = ILendingPool(provider.getLendingPool());
}
receive() external payable {}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external virtual returns (bool);
}
// Our Flashloan Arbitrage contract
contract FlashloanArbitrage is FlashLoanReceiverBase, Ownable {
IUniswapV2Router02 private uniswapRouter;
address private constant WETH = 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619; // WETH address on Polygon
event ArbitrageExecuted(address token, uint256 profit, uint256 timestamp);
constructor(ILendingPoolAddressesProvider _addressProvider, address _uniswapRouter)
FlashLoanReceiverBase(_addressProvider)
Ownable(msg.sender)
{
uniswapRouter = IUniswapV2Router02(_uniswapRouter);
}
// Override executeOperation to handle flashloan repayment and arbitrage logic
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address /* initiator */,
bytes calldata params
) external override returns (bool) {
// Decode parameters from flash loan
(address arbToken, uint256 arbMinProfit) = abi.decode(params, (address, uint256));
// Initial balance of WETH
uint256 initialWethBalance = IERC20(WETH).balanceOf(address(this));
require(initialWethBalance >= amounts[0], "Insufficient initial balance");
// Perform arbitrage
uint256 finalWethBalance = performArbitrage(amounts[0], arbToken);
// Calculate profit
uint256 profit = finalWethBalance - initialWethBalance;
require(profit >= arbMinProfit, "Profit is less than minimum required");
// Repay the flash loan
repayLoan(assets[0], amounts[0] + premiums[0]);
emit ArbitrageExecuted(arbToken, profit, block.timestamp);
return true;
}
// Internal function to perform arbitrage
function performArbitrage(uint256 amount, address arbToken) internal returns (uint256) {
// Swap WETH to arbToken
uint256 tokenBalance = swapWethToToken(amount, arbToken);
// Swap arbToken back to WETH
uint256 finalWethBalance = swapTokenToWeth(tokenBalance, arbToken);
return finalWethBalance;
}
// Internal function to swap WETH to specified token
function swapWethToToken(uint256 amount, address token) internal returns (uint256) {
address[] memory path = new address[](2);
path[0] = WETH;
path[1] = token;
IERC20(WETH).approve(address(uniswapRouter), amount);
uint256[] memory amountsOut = uniswapRouter.swapExactTokensForTokens(
amount,
0, // Accept any amount of Token
path,
address(this),
block.timestamp
);
return amountsOut[1];
}
// Internal function to swap specified token back to WETH
function swapTokenToWeth(uint256 amount, address token) internal returns (uint256) {
address[] memory path = new address[](2);
path[0] = token;
path[1] = WETH;
IERC20(token).approve(address(uniswapRouter), amount);
uint256[] memory amountsOut = uniswapRouter.swapExactTokensForTokens(
amount,
0, // Accept any amount of WETH
path,
address(this),
block.timestamp
);
return amountsOut[1];
}
// Internal function to repay flash loan
function repayLoan(address asset, uint256 amount) internal {
IERC20(asset).approve(address(LENDING_POOL), amount);
}
// Function to initiate the arbitrage process
function startArbitrage(
address token,
uint256 amount,
uint256 minProfit
) external onlyOwner {
address receiverAddress = address(this);
address onBehalfOf = address(this);
address[] memory assets = new address[](1);
assets[0] = WETH;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
uint256[] memory modes = new uint256[](1);
modes[0] = 0;
bytes memory params = abi.encode(token, minProfit);
uint16 referralCode = 0;
// Request the flash loan from Aave
LENDING_POOL.flashLoan(
receiverAddress,
assets,
amounts,
modes,
onBehalfOf,
params,
referralCode
);
}
// Function to withdraw any asset from the contract to the owner's address
function withdraw(address asset) external onlyOwner {
uint256 balance = IERC20(asset).balanceOf(address(this));
IERC20(asset).transfer(owner(), balance); // Use owner() from Ownable
}
}