/ src / GasProviderHelper.sol
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  }