GasProviderHelper.sol
1 // SPDX-License-Identifier: MIT 2 pragma solidity ^0.8.20; 3 4 import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol'; 5 import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol'; 6 import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 import "solmate/tokens/WETH.sol"; 8 9 contract GasProviderHelper { 10 using Address for address payable; 11 12 WETH constant weth = WETH(payable(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270)); 13 ISwapRouter swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); 14 address immutable gasBroker; 15 uint256 constant MAX_INT = 2**256 - 1; 16 17 18 constructor(address _gasBroker, address token) { 19 gasBroker = _gasBroker; 20 IERC20(token).approve(address(swapRouter), MAX_INT); 21 } 22 23 function swapWithFlashloan( 24 address pool, 25 address token, 26 uint256 weiToBorrow, 27 bytes memory swapCalldata 28 ) external payable returns (uint256 balanceAfter) { 29 // borrow WMATIC 30 bytes memory data = abi.encode( 31 msg.sender, 32 msg.value, 33 token, 34 weiToBorrow, 35 swapCalldata 36 ); 37 IUniswapV3Pool(pool).flash(address(this), weiToBorrow, 0, data); 38 balanceAfter = msg.sender.balance; 39 } 40 41 function uniswapV3FlashCallback(uint256 fee0, uint256 fee1, bytes calldata data) external { 42 ( 43 address gasProvider, 44 uint256 extraValue, 45 address token, 46 uint256 weiToBorrow, 47 bytes memory swapCalldata 48 ) = abi.decode( 49 data, 50 (address,uint256,address,uint256,bytes) 51 ); 52 53 weth.withdraw(weiToBorrow); 54 (bool success, bytes memory data) = gasBroker.call{ value: extraValue + weiToBorrow }(swapCalldata); 55 require(success, "Swap failed"); 56 swapExactInputSingle(token, IERC20(token).balanceOf(address(this))); 57 weth.deposit{value: address(this).balance}(); 58 uint256 amountToRepay = weiToBorrow + fee0; 59 require(weth.balanceOf(address(this)) >= amountToRepay, "Cannot repay flashloan"); 60 61 weth.transfer(msg.sender, amountToRepay); 62 uint256 wethBalance = weth.balanceOf(address(this)); 63 if (wethBalance > 0) { 64 weth.withdraw(wethBalance); 65 payable(gasProvider).sendValue(wethBalance); 66 } 67 } 68 69 function swapTokensForGas(address token) external { 70 uint256 tokenBalance = IERC20(token).balanceOf(msg.sender); 71 SafeERC20.safeTransferFrom(IERC20(token), msg.sender, address(this), tokenBalance); 72 IERC20(token).approve(address(swapRouter), tokenBalance); 73 uint256 wethBalance = swapExactInputSingle(token, tokenBalance); 74 weth.withdraw(wethBalance); 75 payable(msg.sender).sendValue(wethBalance); 76 } 77 78 function swapExactInputSingle(address tokenIn, uint256 amountIn) private returns (uint256 amountOut) { 79 ISwapRouter.ExactInputSingleParams memory params = 80 ISwapRouter.ExactInputSingleParams({ 81 tokenIn: tokenIn, 82 tokenOut: address(weth), 83 fee: 500, 84 recipient: address(this), 85 deadline: block.timestamp, 86 amountIn: amountIn, 87 amountOutMinimum: 0, 88 sqrtPriceLimitX96: 0 89 }); 90 91 amountOut = swapRouter.exactInputSingle(params); 92 } 93 94 receive() external payable {} 95 96 }