forked from Uniswap/UniswapX
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSwapRouter02Executor.sol
99 lines (84 loc) · 4.35 KB
/
SwapRouter02Executor.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Owned} from "solmate/src/auth/Owned.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {WETH} from "solmate/src/tokens/WETH.sol";
import {IReactorCallback} from "../interfaces/IReactorCallback.sol";
import {IReactor} from "../interfaces/IReactor.sol";
import {CurrencyLibrary} from "../lib/CurrencyLibrary.sol";
import {ResolvedOrder, OutputToken} from "../base/ReactorStructs.sol";
import {ISwapRouter02} from "../external/ISwapRouter02.sol";
/// @notice A fill contract that uses SwapRouter02 to execute trades
contract SwapRouter02Executor is IReactorCallback, Owned {
using SafeTransferLib for ERC20;
using CurrencyLibrary for address;
/// @notice thrown if reactorCallback is called with a non-whitelisted filler
error CallerNotWhitelisted();
/// @notice thrown if reactorCallback is called by an adress other than the reactor
error MsgSenderNotReactor();
ISwapRouter02 private immutable swapRouter02;
address private immutable whitelistedCaller;
IReactor private immutable reactor;
WETH private immutable weth;
constructor(address _whitelistedCaller, IReactor _reactor, address _owner, ISwapRouter02 _swapRouter02)
Owned(_owner)
{
whitelistedCaller = _whitelistedCaller;
reactor = _reactor;
swapRouter02 = _swapRouter02;
weth = WETH(payable(_swapRouter02.WETH9()));
}
/// @param resolvedOrders The orders to fill
/// @param filler This filler must be `whitelistedCaller`
/// @param fillData It has the below encoded:
/// address[] memory tokensToApproveForSwapRouter02: Max approve these tokens to swapRouter02
/// address[] memory tokensToApproveForReactor: Max approve these tokens to reactor
/// bytes[] memory multicallData: Pass into swapRouter02.multicall()
function reactorCallback(ResolvedOrder[] calldata resolvedOrders, address filler, bytes calldata fillData)
external
{
if (msg.sender != address(reactor)) {
revert MsgSenderNotReactor();
}
if (filler != whitelistedCaller) {
revert CallerNotWhitelisted();
}
(address[] memory tokensToApproveForSwapRouter02, bytes[] memory multicallData) =
abi.decode(fillData, (address[], bytes[]));
for (uint256 i = 0; i < tokensToApproveForSwapRouter02.length; i++) {
ERC20(tokensToApproveForSwapRouter02[i]).safeApprove(address(swapRouter02), type(uint256).max);
}
swapRouter02.multicall(type(uint256).max, multicallData);
for (uint256 i = 0; i < resolvedOrders.length; i++) {
ResolvedOrder memory order = resolvedOrders[i];
for (uint256 j = 0; j < order.outputs.length; j++) {
OutputToken memory output = order.outputs[j];
output.token.transfer(output.recipient, output.amount);
}
}
}
/// @notice This function can be used to convert ERC20s to ETH that remains in this contract
/// @param tokensToApprove Max approve these tokens to swapRouter02
/// @param multicallData Pass into swapRouter02.multicall()
function multicall(ERC20[] calldata tokensToApprove, bytes[] calldata multicallData) external onlyOwner {
for (uint256 i = 0; i < tokensToApprove.length; i++) {
tokensToApprove[i].safeApprove(address(swapRouter02), type(uint256).max);
}
swapRouter02.multicall(type(uint256).max, multicallData);
}
/// @notice Unwraps the contract's WETH9 balance and sends it to the recipient as ETH. Can only be called by owner.
/// @param recipient The address receiving ETH
function unwrapWETH(address recipient) external onlyOwner {
uint256 balanceWETH = weth.balanceOf(address(this));
weth.withdraw(balanceWETH);
SafeTransferLib.safeTransferETH(recipient, address(this).balance);
}
/// @notice Transfer all ETH in this contract to the recipient. Can only be called by owner.
/// @param recipient The recipient of the ETH
function withdrawETH(address recipient) external onlyOwner {
SafeTransferLib.safeTransferETH(recipient, address(this).balance);
}
/// @notice Necessary for this contract to receive ETH when calling unwrapWETH()
receive() external payable {}
}