From db20e261bf5bca2de5ee0bc7ac72f307b02edd60 Mon Sep 17 00:00:00 2001 From: studionebula01 <156440599+studionebula01@users.noreply.github.com> Date: Tue, 4 Feb 2025 14:00:35 +0000 Subject: [PATCH] Pending changes exported from your codespace --- .../FlashLoanArbitrage-checkpoint.sol | 156 ++++++++++++++++++ .../Untitled-checkpoint.ipynb | 33 ++++ .../.ipynb_checkpoints/untitled-checkpoint.md | 0 contracts/Untitled.ipynb | 69 ++++++++ contracts/new-workspace.jupyterlab-workspace | 1 + contracts/untitled.md | 0 6 files changed, 259 insertions(+) create mode 100644 contracts/.ipynb_checkpoints/FlashLoanArbitrage-checkpoint.sol create mode 100644 contracts/.ipynb_checkpoints/Untitled-checkpoint.ipynb create mode 100644 contracts/.ipynb_checkpoints/untitled-checkpoint.md create mode 100644 contracts/Untitled.ipynb create mode 100644 contracts/new-workspace.jupyterlab-workspace create mode 100644 contracts/untitled.md diff --git a/contracts/.ipynb_checkpoints/FlashLoanArbitrage-checkpoint.sol b/contracts/.ipynb_checkpoints/FlashLoanArbitrage-checkpoint.sol new file mode 100644 index 0000000..7831d9f --- /dev/null +++ b/contracts/.ipynb_checkpoints/FlashLoanArbitrage-checkpoint.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol"; +import "@aave/core-v3/contracts/interfaces/IPool.sol"; +import "@aave/core-v3/contracts/interfaces/IPoolAddressesProvider.sol"; +import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract FlashLoanArbitrage is FlashLoanSimpleReceiverBase, ReentrancyGuard, Ownable { + IUniswapV2Router02 private uniswapRouter; + IUniswapV2Router02 private sushiswapRouter; + + // Add events for monitoring + event ArbitrageExecuted(address asset, uint256 amount, uint256 profit); + event FlashLoanFailed(address asset, uint256 amount, string reason); + + // Add new state variables at the top of contract + uint256 public constant MAX_BORROW_AMOUNT = 100 ether; // Increased to 100 tokens + uint256 public constant MIN_BORROW_AMOUNT = 5 ether; // Minimum 5 tokens + uint256 public constant MAX_PRICE_IMPACT = 3; // 3% max price impact + + // Add Base-specific constants + uint256 public constant GAS_PRICE_LIMIT = 1 gwei; // Adjust based on Base's typical gas prices + uint256 public constant MAX_GAS_LIMIT = 2000000; // Conservative gas limit for Base + + // Add new constant at the top with other constants + uint256 public constant MIN_PROFIT_USD = 0.0005 ether; // Approximately $1 worth of ETH at ~$2000/ETH + + constructor( + address _addressProvider, + address _uniswapRouter, + address _sushiswapRouter + ) FlashLoanSimpleReceiverBase(IPoolAddressesProvider(_addressProvider)) Ownable(msg.sender) { + require(_uniswapRouter != address(0), "Invalid Uniswap router"); + require(_sushiswapRouter != address(0), "Invalid Sushiswap router"); + uniswapRouter = IUniswapV2Router02(_uniswapRouter); + sushiswapRouter = IUniswapV2Router02(_sushiswapRouter); + } + + function executeArbitrage( + address asset, + uint256 amount, + address[] calldata path + ) external nonReentrant onlyOwner { + require(amount >= MIN_BORROW_AMOUNT, "Amount below minimum threshold"); + require(amount <= MAX_BORROW_AMOUNT, "Amount exceeds maximum borrow limit"); + require(path.length >= 2, "Invalid path length"); + require(path[0] == asset && path[path.length - 1] == asset, "Invalid path"); + + // Check price impact before executing + uint256 priceImpact = calculatePriceImpact(asset, amount, path); + require(priceImpact <= MAX_PRICE_IMPACT, "Price impact too high"); + + // Add Base-specific checks + require(tx.gasprice <= GAS_PRICE_LIMIT, "Gas price too high"); + require(gasleft() >= MAX_GAS_LIMIT, "Insufficient gas"); + + bytes memory params = abi.encode(path); + try POOL.flashLoanSimple( + address(this), + asset, + amount, + params, + 0 // referralCode (0 for no referral) + ) { + // Flash loan initiated successfully + } catch Error(string memory reason) { + emit FlashLoanFailed(asset, amount, reason); + revert(reason); + } + } + + function executeOperation( + address _asset, + uint256 amount, + uint256 premium, + address _initiator, + bytes calldata params + ) external override returns (bool) { + (address[] memory path) = abi.decode(params, (address[])); + + // Get expected output from both DEXes + uint256 uniswapOutput = getAmountOutMin(uniswapRouter, path, amount); + uint256 sushiswapOutput = getAmountOutMin(sushiswapRouter, path, amount); + + // Calculate required amount to repay flash loan + uint256 requiredAmount = amount + premium; + + // Determine which DEX offers better price + (IUniswapV2Router02 sourceRouter, uint256 expectedOutput) = + uniswapOutput > sushiswapOutput + ? (uniswapRouter, uniswapOutput) + : (sushiswapRouter, sushiswapOutput); + + // Adjust profit calculation to account for L2 gas costs + uint256 estimatedGasCost = tx.gasprice * MAX_GAS_LIMIT; + uint256 minProfitMargin = requiredAmount + estimatedGasCost + MIN_PROFIT_USD; + require(expectedOutput > minProfitMargin, "Insufficient profit after gas"); + + // Execute the swap on the more profitable DEX + IERC20(_asset).approve(address(sourceRouter), amount); + sourceRouter.swapExactTokensForTokens( + amount, + expectedOutput, + path, + address(this), + block.timestamp + ); + + uint256 profit = IERC20(_asset).balanceOf(address(this)) - requiredAmount; + require(profit > 0, "No profit generated"); + + // Transfer profit and approve repayment + IERC20(_asset).transfer(owner(), profit); + IERC20(_asset).approve(address(POOL), requiredAmount); + + emit ArbitrageExecuted(_asset, amount, profit); + return true; + } + + function getAmountOutMin( + IUniswapV2Router02 router, + address[] memory path, + uint256 amountIn + ) internal view returns (uint256) { + uint256[] memory amountsOut = router.getAmountsOut( + amountIn, + path + ); + return amountsOut[amountsOut.length - 1]; + } + + // Add new helper function + function calculatePriceImpact( + address asset, + uint256 amount, + address[] memory path + ) internal view returns (uint256) { + // Get price for small amount (0.1% of intended swap) + uint256 smallAmount = amount / 1000; + uint256 smallSwapPrice = getAmountOutMin(uniswapRouter, path, smallAmount); + + // Get price for actual amount + uint256 largeSwapPrice = getAmountOutMin(uniswapRouter, path, amount); + + // Calculate price impact + uint256 expectedPrice = (smallSwapPrice * 1000); + uint256 priceImpact = ((expectedPrice - largeSwapPrice) * 10000) / expectedPrice; + + return priceImpact; // Returns basis points (e.g., 100 = 1%) + } +} diff --git a/contracts/.ipynb_checkpoints/Untitled-checkpoint.ipynb b/contracts/.ipynb_checkpoints/Untitled-checkpoint.ipynb new file mode 100644 index 0000000..e1e31b1 --- /dev/null +++ b/contracts/.ipynb_checkpoints/Untitled-checkpoint.ipynb @@ -0,0 +1,33 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "5a5d4eac-07ac-4005-9307-8ebac8b7333f", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/contracts/.ipynb_checkpoints/untitled-checkpoint.md b/contracts/.ipynb_checkpoints/untitled-checkpoint.md new file mode 100644 index 0000000..e69de29 diff --git a/contracts/Untitled.ipynb b/contracts/Untitled.ipynb new file mode 100644 index 0000000..354f857 --- /dev/null +++ b/contracts/Untitled.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "5a5d4eac-07ac-4005-9307-8ebac8b7333f", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d4794b1-af40-44a2-aceb-a2e2ec49d42d", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e9469dd-466c-406c-8bed-1f69558a1192", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14852f27-0f58-4389-a7a3-dedd9841a157", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/contracts/new-workspace.jupyterlab-workspace b/contracts/new-workspace.jupyterlab-workspace new file mode 100644 index 0000000..fa45c83 --- /dev/null +++ b/contracts/new-workspace.jupyterlab-workspace @@ -0,0 +1 @@ +{"data":{"file-browser-filebrowser:columns":{"sizes":{"name":139.5,"file_size":null,"is_selected":18,"last_modified":86.5}},"layout-restorer:data":{"main":{"dock":{"type":"tab-area","currentIndex":0,"widgets":["setting-editor:setting-editor","plugin-manager:plugins"]}},"down":{"size":0,"widgets":[]},"left":{"collapsed":false,"visible":true,"current":"extensionmanager.main-view","widgets":["filebrowser","running-sessions","git-sessions","@jupyterlab/toc:plugin","extensionmanager.main-view"],"widgetStates":{"jp-running-sessions":{"sizes":[0,0,0.16339869281045752,0.16339869281045752,0.16339869281045752,0.5098039215686274],"expansionStates":[false,false,false,false,false,false]},"extensionmanager.main-view":{"sizes":[0.33472803347280333,0.4560669456066945,0.20920502092050208],"expansionStates":[true,true,true]}}},"right":{"collapsed":true,"visible":true,"widgets":["jp-property-inspector","debugger-sidebar"],"widgetStates":{"jp-debugger-sidebar":{"sizes":[0.2,0.2,0.2,0.2,0.2],"expansionStates":[false,false,false,false,false]}}},"relativeSizes":[0.246078431372549,0.753921568627451,0],"top":{"simpleVisibility":true}},"docmanager:recents":{"opened":[{"path":"contracts","contentType":"directory","root":"/workspaces/Flash"},{"path":"contracts/Untitled.ipynb","contentType":"notebook","factory":"Notebook","root":"/workspaces/Flash"}],"closed":[{"path":"contracts/Untitled.ipynb","contentType":"notebook","factory":"Notebook","root":"/workspaces/Flash"}]},"file-browser-filebrowser:cwd":{"path":"contracts"},"jp-running-sessions":{"listViewSections":["Kernels"]},"setting-editor:setting-editor":{"data":{}},"plugin-manager:plugins":{"data":{"query":"","isDisclaimed":false}}},"metadata":{"id":"new-workspace","last_modified":"2025-02-04T11:56:03.776822+00:00","created":"2025-02-04T11:56:03.776822+00:00"}} \ No newline at end of file diff --git a/contracts/untitled.md b/contracts/untitled.md new file mode 100644 index 0000000..e69de29