Description:
Decentralized Finance (DeFi) protocol contract providing Swap, Factory functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/BalancerFlashloanArbitrage.sol": {
"content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.19;\r
\r
// Simple ownership contract\r
contract Ownable {\r
address private _owner;\r
\r
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\r
\r
constructor() {\r
_owner = msg.sender;\r
emit OwnershipTransferred(address(0), msg.sender);\r
}\r
\r
modifier onlyOwner() {\r
require(_owner == msg.sender, "Ownable: caller is not the owner");\r
_;\r
}\r
\r
function owner() public view returns (address) {\r
return _owner;\r
}\r
\r
function transferOwnership(address newOwner) public onlyOwner {\r
require(newOwner != address(0), "Ownable: new owner is the zero address");\r
emit OwnershipTransferred(_owner, newOwner);\r
_owner = newOwner;\r
}\r
}\r
\r
// Simple reentrancy guard\r
contract ReentrancyGuard {\r
uint256 private constant _NOT_ENTERED = 1;\r
uint256 private constant _ENTERED = 2;\r
uint256 private _status;\r
\r
constructor() {\r
_status = _NOT_ENTERED;\r
}\r
\r
modifier nonReentrant() {\r
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");\r
_status = _ENTERED;\r
_;\r
_status = _NOT_ENTERED;\r
}\r
}\r
\r
// ERC20 Interface\r
interface IERC20 {\r
function totalSupply() external view returns (uint256);\r
function balanceOf(address account) external view returns (uint256);\r
function transfer(address to, uint256 amount) external returns (bool);\r
function allowance(address owner, address spender) external view returns (uint256);\r
function approve(address spender, uint256 amount) external returns (bool);\r
function transferFrom(address from, address to, uint256 amount) external returns (bool);\r
}\r
\r
// Balancer V2 Interfaces\r
interface IBalancerVault {\r
function flashLoan(\r
address recipient,\r
address[] memory tokens,\r
uint256[] memory amounts,\r
bytes memory userData\r
) external;\r
}\r
\r
interface IFlashLoanRecipient {\r
function receiveFlashLoan(\r
address[] memory tokens,\r
uint256[] memory amounts,\r
uint256[] memory feeAmounts,\r
bytes memory userData\r
) external;\r
}\r
\r
// Uniswap V2 Interface\r
interface IUniswapV2Router {\r
function swapExactTokensForTokens(\r
uint amountIn,\r
uint amountOutMin,\r
address[] calldata path,\r
address to,\r
uint deadline\r
) external returns (uint[] memory amounts);\r
\r
function getAmountsOut(uint amountIn, address[] calldata path)\r
external view returns (uint[] memory amounts);\r
}\r
\r
// WETH Interface\r
interface IWETH {\r
function deposit() external payable;\r
function withdraw(uint256) external;\r
function balanceOf(address) external view returns (uint256);\r
function transfer(address, uint256) external returns (bool);\r
function approve(address, uint256) external returns (bool);\r
}\r
\r
/**\r
* @title BalancerFlashloanArbitrage\r
* @dev Real flashloan arbitrage contract using Balancer V2 (0% fees)\r
* @notice Executes profitable arbitrage between DEXs using FREE flashloans\r
*/\r
contract BalancerFlashloanArbitrage is IFlashLoanRecipient, Ownable, ReentrancyGuard {\r
\r
// ???? Balancer V2 Vault (FREE flashloans)\r
IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);\r
\r
// ???? DEX Routers\r
IUniswapV2Router public constant UNISWAP_V2 = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);\r
IUniswapV2Router public constant SUSHISWAP = IUniswapV2Router(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);\r
\r
// ???? Token addresses\r
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\r
address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\r
\r
// ???? Trading parameters\r
uint256 public minProfitBasisPoints = 10; // 0.1% minimum profit\r
uint256 public maxSlippageBasisPoints = 50; // 0.5% max slippage\r
\r
// ???? Events\r
event FlashloanArbitrageExecuted(\r
address indexed token,\r
uint256 flashloanAmount,\r
uint256 profit,\r
address buyDex,\r
address sellDex\r
);\r
\r
event ProfitWithdrawn(address indexed owner, uint256 amount);\r
\r
// ???? Modifiers\r
modifier onlyBalancerVault() {\r
require(msg.sender == address(BALANCER_VAULT), "Only Balancer Vault");\r
_;\r
}\r
\r
constructor() {}\r
\r
/**\r
* @dev Initiate flashloan arbitrage\r
* @param flashloanAmount Amount to borrow (in WETH wei)\r
* @param buyDexRouter Router to buy on (cheaper)\r
* @param sellDexRouter Router to sell on (expensive)\r
*/\r
function executeFlashloanArbitrage(\r
uint256 flashloanAmount,\r
address buyDexRouter,\r
address sellDexRouter\r
) external onlyOwner nonReentrant {\r
require(flashloanAmount > 0, "Invalid flashloan amount");\r
require(buyDexRouter != sellDexRouter, "Same DEX");\r
require(\r
buyDexRouter == address(UNISWAP_V2) || buyDexRouter == address(SUSHISWAP),\r
"Invalid buy DEX"\r
);\r
require(\r
sellDexRouter == address(UNISWAP_V2) || sellDexRouter == address(SUSHISWAP),\r
"Invalid sell DEX"\r
);\r
\r
// ???? Prepare flashloan data\r
address[] memory tokens = new address[](1);\r
tokens[0] = WETH;\r
\r
uint256[] memory amounts = new uint256[](1);\r
amounts[0] = flashloanAmount;\r
\r
// ???? Encode arbitrage parameters\r
bytes memory userData = abi.encode(buyDexRouter, sellDexRouter, flashloanAmount);\r
\r
// ???? Execute FREE Balancer flashloan\r
BALANCER_VAULT.flashLoan(address(this), tokens, amounts, userData);\r
}\r
\r
/**\r
* @dev Balancer flashloan callback - THE CORE ARBITRAGE LOGIC\r
* @param tokens Array of tokens (WETH)\r
* @param amounts Array of amounts borrowed\r
* @param feeAmounts Array of fees (0 for Balancer!)\r
* @param userData Encoded arbitrage parameters\r
*/\r
function receiveFlashLoan(\r
address[] memory tokens,\r
uint256[] memory amounts,\r
uint256[] memory feeAmounts,\r
bytes memory userData\r
) external override onlyBalancerVault {\r
require(tokens.length == 1 && tokens[0] == WETH, "Invalid token");\r
require(amounts.length == 1 && amounts[0] > 0, "Invalid amount");\r
require(feeAmounts[0] == 0, "Balancer should be fee-free");\r
\r
// ???? Decode arbitrage parameters\r
(address buyDexRouter, address sellDexRouter, uint256 flashloanAmount) = \r
abi.decode(userData, (address, address, uint256));\r
\r
// ???? Borrowed amount verification\r
require(amounts[0] == flashloanAmount, "Amount mismatch");\r
require(IERC20(WETH).balanceOf(address(this)) >= flashloanAmount, "Insufficient WETH received");\r
\r
// ???? EXECUTE ARBITRAGE STRATEGY\r
uint256 profit = _executeArbitrageStrategy(\r
flashloanAmount,\r
buyDexRouter,\r
sellDexRouter\r
);\r
\r
// ???? Repay flashloan (amount + fees, but fees = 0!)\r
uint256 totalRepayment = amounts[0] + feeAmounts[0]; // feeAmounts[0] = 0\r
require(\r
IERC20(WETH).balanceOf(address(this)) >= totalRepayment,\r
"Insufficient WETH for repayment"\r
);\r
\r
// ???? Repay flashloan to Balancer\r
require(IERC20(WETH).transfer(address(BALANCER_VAULT), totalRepayment), "Repayment failed");\r
\r
// ???? Emit success event\r
emit FlashloanArbitrageExecuted(\r
WETH,\r
flashloanAmount,\r
profit,\r
buyDexRouter,\r
sellDexRouter\r
);\r
}\r
\r
/**\r
* @dev Execute the actual arbitrage strategy\r
* @param flashloanAmount Amount borrowed\r
* @param buyDexRouter DEX to buy on (cheaper)\r
* @param sellDexRouter DEX to sell on (expensive)\r
* @return profit Profit earned from arbitrage\r
*/\r
function _executeArbitrageStrategy(\r
uint256 flashloanAmount,\r
address buyDexRouter,\r
address sellDexRouter\r
) internal returns (uint256 profit) {\r
uint256 initialWETH = IERC20(WETH).balanceOf(address(this));\r
\r
// ???? Step 1: Convert WETH to DAI on cheaper DEX\r
uint256 daiReceived = _swapWETHForDAI(flashloanAmount, buyDexRouter);\r
require(daiReceived > 0, "No DAI received");\r
\r
// ???? Step 2: Convert DAI back to WETH on expensive DEX\r
uint256 wethReceived = _swapDAIForWETH(daiReceived, sellDexRouter);\r
require(wethReceived > 0, "No WETH received");\r
\r
// ???? Calculate profit\r
uint256 finalWETH = IERC20(WETH).balanceOf(address(this));\r
require(finalWETH >= initialWETH, "Trade resulted in loss");\r
\r
profit = finalWETH - initialWETH;\r
require(profit > 0, "No profit achieved");\r
\r
// ???? Verify minimum profit\r
uint256 minProfit = (flashloanAmount * minProfitBasisPoints) / 10000;\r
require(profit >= minProfit, "Insufficient profit");\r
\r
return profit;\r
}\r
\r
/**\r
* @dev Swap WETH for DAI on specified DEX\r
*/\r
function _swapWETHForDAI(uint256 wethAmount, address dexRouter) internal returns (uint256) {\r
require(IERC20(WETH).approve(dexRouter, wethAmount), "WETH approval failed");\r
\r
address[] memory path = new address[](2);\r
path[0] = WETH;\r
path[1] = DAI;\r
\r
uint256[] memory amounts = IUniswapV2Router(dexRouter).swapExactTokensForTokens(\r
wethAmount,\r
0, // Accept any amount of DAI\r
path,\r
address(this),\r
block.timestamp + 300\r
);\r
\r
return amounts[1]; // DAI received\r
}\r
\r
/**\r
* @dev Swap DAI for WETH on specified DEX\r
*/\r
function _swapDAIForWETH(uint256 daiAmount, address dexRouter) internal returns (uint256) {\r
require(IERC20(DAI).approve(dexRouter, daiAmount), "DAI approval failed");\r
\r
address[] memory path = new address[](2);\r
path[0] = DAI;\r
path[1] = WETH;\r
\r
uint256[] memory amounts = IUniswapV2Router(dexRouter).swapExactTokensForTokens(\r
daiAmount,\r
0, // Accept any amount of WETH\r
path,\r
address(this),\r
block.timestamp + 300\r
);\r
\r
return amounts[1]; // WETH received\r
}\r
\r
/**\r
* @dev Check arbitrage opportunity before execution\r
*/\r
function checkArbitrageOpportunity(\r
uint256 flashloanAmount,\r
address buyDexRouter,\r
address sellDexRouter\r
) external view returns (\r
bool profitable,\r
uint256 estimatedProfit,\r
uint256 buyPrice,\r
uint256 sellPrice\r
) {\r
// Get prices from both DEXs\r
address[] memory path = new address[](2);\r
path[0] = WETH;\r
path[1] = DAI;\r
\r
uint256[] memory buyAmounts = IUniswapV2Router(buyDexRouter).getAmountsOut(flashloanAmount, path);\r
uint256 daiFromBuy = buyAmounts[1];\r
\r
path[0] = DAI;\r
path[1] = WETH;\r
uint256[] memory sellAmounts = IUniswapV2Router(sellDexRouter).getAmountsOut(daiFromBuy, path);\r
uint256 wethFromSell = sellAmounts[1];\r
\r
if (wethFromSell > flashloanAmount) {\r
estimatedProfit = wethFromSell - flashloanAmount;\r
uint256 minProfit = (flashloanAmount * minProfitBasisPoints) / 10000;\r
profitable = estimatedProfit >= minProfit;\r
}\r
\r
buyPrice = daiFromBuy;\r
sellPrice = wethFromSell;\r
}\r
\r
/**\r
* @dev Withdraw profits to owner\r
*/\r
function withdrawProfits() external onlyOwner {\r
uint256 wethBalance = IERC20(WETH).balanceOf(address(this));\r
require(wethBalance > 0, "No WETH to withdraw");\r
\r
require(IERC20(WETH).transfer(owner(), wethBalance), "WETH transfer failed");\r
emit ProfitWithdrawn(owner(), wethBalance);\r
}\r
\r
/**\r
* @dev Withdraw any ERC20 token (emergency)\r
*/\r
function withdrawToken(address token, uint256 amount) external onlyOwner {\r
require(token != address(0), "Invalid token");\r
require(IERC20(token).transfer(owner(), amount), "Token transfer failed");\r
}\r
\r
/**\r
* @dev Withdraw ETH (emergency)\r
*/\r
function withdrawETH() external onlyOwner {\r
uint256 balance = address(this).balance;\r
require(balance > 0, "No ETH to withdraw");\r
payable(owner()).transfer(balance);\r
}\r
\r
/**\r
* @dev Update trading parameters\r
*/\r
function updateTradingParams(\r
uint256 _minProfitBasisPoints,\r
uint256 _maxSlippageBasisPoints\r
) external onlyOwner {\r
require(_minProfitBasisPoints <= 1000, "Max 10% min profit"); // Max 10%\r
require(_maxSlippageBasisPoints <= 1000, "Max 10% slippage"); // Max 10%\r
\r
minProfitBasisPoints = _minProfitBasisPoints;\r
maxSlippageBasisPoints = _maxSlippageBasisPoints;\r
}\r
\r
/**\r
* @dev Receive ETH\r
*/\r
receive() external payable {}\r
}"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-11-02 12:27:22
Comments
Log in to comment.
No comments yet.