feat: Handle native ETH outputs
- In this case, the ETH needs to be manually transferred to the reactor. - Native ETH input is not supported for UniswapX Source: https://support.uniswap.org/hc/en-us/articles/17544708791821-Are-there-network-costs-for-UniswapX
This commit is contained in:
@@ -20,6 +20,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
|
|||||||
// UniswapX V2DutchOrder Reactor
|
// UniswapX V2DutchOrder Reactor
|
||||||
IReactor public immutable reactor;
|
IReactor public immutable reactor;
|
||||||
address public immutable tychoRouter;
|
address public immutable tychoRouter;
|
||||||
|
address public immutable nativeAddress;
|
||||||
|
|
||||||
// keccak256("NAME_OF_ROLE") : save gas on deployment
|
// keccak256("NAME_OF_ROLE") : save gas on deployment
|
||||||
bytes32 public constant REACTOR_ROLE =
|
bytes32 public constant REACTOR_ROLE =
|
||||||
@@ -31,7 +32,11 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
|
|||||||
address indexed token, uint256 amount, address indexed receiver
|
address indexed token, uint256 amount, address indexed receiver
|
||||||
);
|
);
|
||||||
|
|
||||||
constructor(address _tychoRouter, address _reactor) {
|
constructor(
|
||||||
|
address _tychoRouter,
|
||||||
|
address _reactor,
|
||||||
|
address _native_address
|
||||||
|
) {
|
||||||
if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero();
|
if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero();
|
||||||
if (_reactor == address(0)) revert UniswapXFiller__AddressZero();
|
if (_reactor == address(0)) revert UniswapXFiller__AddressZero();
|
||||||
|
|
||||||
@@ -39,6 +44,7 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
|
|||||||
_grantRole(REACTOR_ROLE, address(_reactor));
|
_grantRole(REACTOR_ROLE, address(_reactor));
|
||||||
tychoRouter = _tychoRouter;
|
tychoRouter = _tychoRouter;
|
||||||
reactor = IReactor(_reactor);
|
reactor = IReactor(_reactor);
|
||||||
|
nativeAddress = _native_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(SignedOrder calldata order, bytes calldata callbackData)
|
function execute(SignedOrder calldata order, bytes calldata callbackData)
|
||||||
@@ -67,26 +73,14 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
|
|||||||
|
|
||||||
// The TychoRouter will take the input tokens from the filler
|
// The TychoRouter will take the input tokens from the filler
|
||||||
if (tokenInApprovalNeeded) {
|
if (tokenInApprovalNeeded) {
|
||||||
// TODO only if ERC20
|
// Native ETH input is not supported by UniswapX
|
||||||
IERC20(order.input.token).forceApprove(
|
IERC20(order.input.token).forceApprove(
|
||||||
tychoRouter, order.input.maxAmount
|
tychoRouter, order.input.maxAmount
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
// The filler will manually transfer into the TychoRouter
|
|
||||||
// Note: We are using the balance of our filler instead of the order
|
|
||||||
// input amount to avoid having to do a decay calculation in the filler.
|
|
||||||
IERC20 inputToken = IERC20(order.input.token);
|
|
||||||
inputToken.transfer(
|
|
||||||
tychoRouter, inputToken.balanceOf(address(this))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO properly handle native in and out tokens
|
|
||||||
uint256 ethValue = 0;
|
|
||||||
|
|
||||||
// slither-disable-next-line low-level-calls
|
// slither-disable-next-line low-level-calls
|
||||||
(bool success, bytes memory result) =
|
(bool success, bytes memory result) = tychoRouter.call(tychoCalldata);
|
||||||
tychoRouter.call{value: ethValue}(tychoCalldata);
|
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
revert(
|
revert(
|
||||||
@@ -101,9 +95,15 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
|
|||||||
if (tokenOutApprovalNeeded) {
|
if (tokenOutApprovalNeeded) {
|
||||||
// Multiple outputs are possible when taking fees - but token itself should
|
// Multiple outputs are possible when taking fees - but token itself should
|
||||||
// not change.
|
// not change.
|
||||||
// TODO only if ERC20
|
OutputToken memory output = order.outputs[0];
|
||||||
IERC20 token = IERC20(order.outputs[0].token);
|
if (output.token != nativeAddress) {
|
||||||
|
IERC20 token = IERC20(output.token);
|
||||||
token.forceApprove(address(reactor), type(uint256).max);
|
token.forceApprove(address(reactor), type(uint256).max);
|
||||||
|
} else {
|
||||||
|
// With native ETH - the filler is responsible for transferring back
|
||||||
|
// to the reactor.
|
||||||
|
Address.sendValue(payable(address(reactor)), output.amount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup {
|
|||||||
|
|
||||||
function fillerSetup() public {
|
function fillerSetup() public {
|
||||||
vm.startPrank(ADMIN);
|
vm.startPrank(ADMIN);
|
||||||
filler = new UniswapXFiller(tychoRouterAddr, REACTOR);
|
filler = new UniswapXFiller(tychoRouterAddr, REACTOR, address(0));
|
||||||
fillerAddr = address(filler);
|
fillerAddr = address(filler);
|
||||||
filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR);
|
filler.grantRole(keccak256("EXECUTOR_ROLE"), EXECUTOR);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -31,12 +31,12 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup {
|
|||||||
|
|
||||||
function testTychoAddressZeroTychoRouter() public {
|
function testTychoAddressZeroTychoRouter() public {
|
||||||
vm.expectRevert(UniswapXFiller__AddressZero.selector);
|
vm.expectRevert(UniswapXFiller__AddressZero.selector);
|
||||||
filler = new UniswapXFiller(address(0), REACTOR);
|
filler = new UniswapXFiller(address(0), REACTOR, address(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testTychoAddressZeroReactor() public {
|
function testTychoAddressZeroReactor() public {
|
||||||
vm.expectRevert(UniswapXFiller__AddressZero.selector);
|
vm.expectRevert(UniswapXFiller__AddressZero.selector);
|
||||||
filler = new UniswapXFiller(tychoRouterAddr, address(0));
|
filler = new UniswapXFiller(tychoRouterAddr, address(0), address(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCallback() public {
|
function testCallback() public {
|
||||||
|
|||||||
Reference in New Issue
Block a user