Last active
October 17, 2024 04:43
-
-
Save liranmarkin/3c2c687dbb4765c77380c50a0b7488e3 to your computer and use it in GitHub Desktop.
pufETHArbitrage.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import "@openzeppelin/contracts/interfaces/IERC4626.sol"; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "@aave/core-v3/contracts/interfaces/IPool.sol"; | |
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; | |
interface IOneInchRouter { | |
struct SwapDescription { | |
IERC20 srcToken; | |
IERC20 dstToken; | |
address srcReceiver; | |
address dstReceiver; | |
uint256 amount; | |
uint256 minReturnAmount; | |
uint256 flags; | |
} | |
function swap( | |
address caller, | |
SwapDescription calldata desc, | |
bytes calldata data | |
) external returns (uint256 returnAmount, uint256 spentAmount); | |
} | |
contract PufETHArbitrage is Ownable { | |
IERC20 public constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); | |
IERC4626 public constant pufferVault = IERC4626(0xD9A442856C234a39a81a089C06451EBAa4306a72); | |
IERC20 public constant pufETH = IERC20(0xD9A442856C234a39a81a089C06451EBAa4306a72); | |
IPool public constant aavePool = IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2); | |
IOneInchRouter public constant oneInchRouter = IOneInchRouter(0x1111111254EEB25477B68fb85Ed929f73A960582); | |
// Add this event declaration at the contract level | |
event ArbitrageExecuted( | |
uint256 flashLoanAmount, | |
uint256 pufETHReceived, | |
uint256 ethReceived, | |
uint256 profit | |
); | |
constructor() Ownable(msg.sender) {} | |
function executeArbitrage(uint256 amount, bytes calldata swapData) external onlyOwner { | |
uint256 balanceBefore = address(this).balance; | |
// Step 1: Request flash loan | |
aavePool.flashLoanSimple( | |
address(this), | |
address(WETH), | |
amount, | |
abi.encode(amount, swapData), | |
0 | |
); | |
// Step 6: Check profitability and transfer profit | |
uint256 profit = address(this).balance - balanceBefore; | |
require(profit > 0, "Arbitrage not profitable"); | |
payable(owner()).transfer(profit); | |
// Log the arbitrage execution | |
emit ArbitrageExecuted(amount, 0, 0, profit); | |
} | |
function executeOperation( | |
address, | |
uint256 amount, | |
uint256 premium, | |
address, | |
bytes calldata params | |
) external returns (bool) { | |
require(msg.sender == address(aavePool), "Caller must be Aave pool"); | |
(uint256 flashLoanAmount, bytes memory swapData) = abi.decode(params, (uint256, bytes)); | |
uint256 totalDebt = flashLoanAmount + premium; | |
// Step 2: Swap WETH for pufETH using 1inch | |
TransferHelper.safeApprove(address(WETH), address(oneInchRouter), amount); | |
(uint256 pufETHReceived, ) = oneInchRouter.swap( | |
address(this), | |
IOneInchRouter.SwapDescription({ | |
srcToken: WETH, | |
dstToken: pufETH, | |
srcReceiver: address(this), | |
dstReceiver: address(this), | |
amount: amount, | |
minReturnAmount: 0, | |
flags: 0 | |
}), | |
swapData | |
); | |
// Step 3: Redeem pufETH for ETH | |
TransferHelper.safeApprove(address(pufETH), address(pufferVault), pufETHReceived); | |
uint256 ethReceived = pufferVault.redeem(pufETHReceived, address(this), address(this)); | |
// Step 4: Check profitability | |
require(ethReceived > totalDebt, "Arbitrage not profitable"); | |
// Step 5: Repay flash loan | |
TransferHelper.safeApprove(address(WETH), address(aavePool), totalDebt); | |
// Log the arbitrage details | |
emit ArbitrageExecuted(flashLoanAmount, pufETHReceived, ethReceived, ethReceived - totalDebt); | |
return true; | |
} | |
receive() external payable {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment