110 lines
3.3 KiB
Solidity
110 lines
3.3 KiB
Solidity
// SPDX-License-Identifier: BUSL-1.1
|
|
pragma solidity ^0.8.26;
|
|
|
|
import "./IReactor.sol";
|
|
import "./IReactorCallback.sol";
|
|
import {
|
|
SafeERC20,
|
|
IERC20
|
|
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
import "@openzeppelin/contracts/access/AccessControl.sol";
|
|
import "@openzeppelin/contracts/utils/Address.sol";
|
|
|
|
error UniswapXFiller__AddressZero();
|
|
|
|
contract UniswapXFiller is AccessControl, IReactorCallback {
|
|
using SafeERC20 for IERC20;
|
|
|
|
// UniswapX V2DutchOrder Reactor
|
|
IReactor public immutable reactor;
|
|
address public immutable tychoRouter;
|
|
|
|
// keccak256("NAME_OF_ROLE") : save gas on deployment
|
|
bytes32 public constant REACTOR_ROLE =
|
|
0x39dd1d7269516fc1f719706a5e9b05cdcb1644978808b171257d9a8eab55dd57;
|
|
bytes32 public constant EXECUTOR_ROLE =
|
|
0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63;
|
|
|
|
event Withdrawal(
|
|
address indexed token, uint256 amount, address indexed receiver
|
|
);
|
|
|
|
constructor(address _tychoRouter, address _reactor) {
|
|
if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero();
|
|
if (_reactor == address(0)) revert UniswapXFiller__AddressZero();
|
|
|
|
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
_grantRole(REACTOR_ROLE, address(reactor));
|
|
tychoRouter = _tychoRouter;
|
|
reactor = IReactor(_reactor);
|
|
}
|
|
|
|
function execute(SignedOrder calldata order, bytes calldata callbackData)
|
|
external
|
|
onlyRole(EXECUTOR_ROLE)
|
|
{
|
|
reactor.executeWithCallback(order, callbackData);
|
|
}
|
|
|
|
function reactorCallback(
|
|
ResolvedOrder[] calldata resolvedOrders,
|
|
bytes calldata callbackData
|
|
) external onlyRole(REACTOR_ROLE) {
|
|
// TODO
|
|
}
|
|
|
|
/**
|
|
* @dev Allows granting roles to multiple accounts in a single call.
|
|
*/
|
|
function batchGrantRole(bytes32 role, address[] memory accounts)
|
|
external
|
|
onlyRole(DEFAULT_ADMIN_ROLE)
|
|
{
|
|
for (uint256 i = 0; i < accounts.length; i++) {
|
|
_grantRole(role, accounts[i]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Allows withdrawing any ERC20 funds.
|
|
*/
|
|
function withdraw(IERC20[] memory tokens, address receiver)
|
|
external
|
|
onlyRole(DEFAULT_ADMIN_ROLE)
|
|
{
|
|
if (receiver == address(0)) revert UniswapXFiller__AddressZero();
|
|
|
|
for (uint256 i = 0; i < tokens.length; i++) {
|
|
// slither-disable-next-line calls-loop
|
|
uint256 tokenBalance = tokens[i].balanceOf(address(this));
|
|
if (tokenBalance > 0) {
|
|
emit Withdrawal(address(tokens[i]), tokenBalance, receiver);
|
|
tokens[i].safeTransfer(receiver, tokenBalance);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Allows withdrawing any NATIVE funds.
|
|
*/
|
|
function withdrawNative(address receiver)
|
|
external
|
|
onlyRole(DEFAULT_ADMIN_ROLE)
|
|
{
|
|
if (receiver == address(0)) revert UniswapXFiller__AddressZero();
|
|
|
|
uint256 amount = address(this).balance;
|
|
if (amount > 0) {
|
|
emit Withdrawal(address(0), amount, receiver);
|
|
Address.sendValue(payable(receiver), amount);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Allows this contract to receive native token with empty msg.data from contracts
|
|
*/
|
|
receive() external payable {
|
|
require(msg.sender.code.length != 0);
|
|
}
|
|
}
|