Merge branch 'main' into router/dc/ENG-4454-remove-executor-script
This commit is contained in:
@@ -127,7 +127,9 @@ contract Dispatcher {
|
||||
tstore(_CURRENTLY_SWAPPING_EXECUTOR_SLOT, 0)
|
||||
}
|
||||
|
||||
// this is necessary because the delegatecall will prepend extra bytes we don't want like the length and prefix
|
||||
// The final callback result should not be ABI encoded. That is why we are decoding here.
|
||||
// ABI encoding is very gas expensive and we want to avoid it if possible.
|
||||
// The result from `handleCallback` is always ABI encoded.
|
||||
bytes memory decodedResult = abi.decode(result, (bytes));
|
||||
return decodedResult;
|
||||
}
|
||||
|
||||
@@ -436,15 +436,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
Address.sendValue(payable(receiver), amountOut);
|
||||
}
|
||||
|
||||
if (tokenIn != tokenOut) {
|
||||
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
|
||||
if (userAmount != amountOut) {
|
||||
revert TychoRouter__AmountOutNotFullyReceived(
|
||||
userAmount, amountOut
|
||||
);
|
||||
}
|
||||
}
|
||||
_verifyAmountOutWasReceived(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
initialBalanceTokenOut,
|
||||
amountOut,
|
||||
receiver,
|
||||
amountIn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,15 +492,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
Address.sendValue(payable(receiver), amountOut);
|
||||
}
|
||||
|
||||
if (tokenIn != tokenOut) {
|
||||
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
|
||||
if (userAmount != amountOut) {
|
||||
revert TychoRouter__AmountOutNotFullyReceived(
|
||||
userAmount, amountOut
|
||||
);
|
||||
}
|
||||
}
|
||||
_verifyAmountOutWasReceived(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
initialBalanceTokenOut,
|
||||
amountOut,
|
||||
receiver,
|
||||
amountIn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -546,16 +544,14 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
_unwrapETH(amountOut);
|
||||
Address.sendValue(payable(receiver), amountOut);
|
||||
}
|
||||
|
||||
if (tokenIn != tokenOut) {
|
||||
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
|
||||
if (userAmount != amountOut) {
|
||||
revert TychoRouter__AmountOutNotFullyReceived(
|
||||
userAmount, amountOut
|
||||
);
|
||||
}
|
||||
}
|
||||
_verifyAmountOutWasReceived(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
initialBalanceTokenOut,
|
||||
amountOut,
|
||||
receiver,
|
||||
amountIn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -657,13 +653,8 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
/**
|
||||
* @dev We use the fallback function to allow flexibility on callback.
|
||||
*/
|
||||
fallback() external {
|
||||
bytes memory result = _callHandleCallbackOnExecutor(msg.data);
|
||||
// slither-disable-next-line assembly
|
||||
assembly ("memory-safe") {
|
||||
// Propagate the result
|
||||
return(add(result, 32), mload(result))
|
||||
}
|
||||
fallback(bytes calldata data) external returns (bytes memory) {
|
||||
return _callHandleCallbackOnExecutor(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -778,18 +769,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
require(msg.sender.code.length != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Called by UniswapV4 pool manager after achieving unlock state.
|
||||
*/
|
||||
function unlockCallback(bytes calldata data)
|
||||
external
|
||||
returns (bytes memory)
|
||||
{
|
||||
if (data.length < 24) revert TychoRouter__InvalidDataLength();
|
||||
bytes memory result = _callHandleCallbackOnExecutor(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets balance of a token for a given address. Supports both native ETH and ERC20 tokens.
|
||||
*/
|
||||
@@ -801,4 +780,27 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
return
|
||||
token == address(0) ? owner.balance : IERC20(token).balanceOf(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Verifies that the expected amount of output tokens was received by the receiver.
|
||||
* It also handles the case of arbitrage swaps where the input and output tokens are the same.
|
||||
*/
|
||||
function _verifyAmountOutWasReceived(
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint256 initialBalanceTokenOut,
|
||||
uint256 amountOut,
|
||||
address receiver,
|
||||
uint256 amountIn
|
||||
) internal view {
|
||||
uint256 currentBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
if (tokenIn == tokenOut) {
|
||||
// If it is an arbitrage, we need to remove the amountIn from the initial balance to get a correct userAmount
|
||||
initialBalanceTokenOut -= amountIn;
|
||||
}
|
||||
uint256 userAmount = currentBalanceTokenOut - initialBalanceTokenOut;
|
||||
if (userAmount != amountOut) {
|
||||
revert TychoRouter__AmountOutNotFullyReceived(userAmount, amountOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,11 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
||||
receiver = address(bytes20(data[65:85]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Even though this contract is mostly called through delegatecall, we still want to be able to receive ETH.
|
||||
* This is needed when using the executor directly and it makes testing easier.
|
||||
* There are some curve pools that take ETH directly.
|
||||
*/
|
||||
receive() external payable {
|
||||
require(msg.sender.code.length != 0);
|
||||
}
|
||||
|
||||
@@ -13,14 +13,12 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
address public immutable factory;
|
||||
address private immutable self;
|
||||
|
||||
constructor(address _factory, address _permit2) TokenTransfer(_permit2) {
|
||||
if (_factory == address(0)) {
|
||||
revert MaverickV2Executor__InvalidFactory();
|
||||
}
|
||||
factory = _factory;
|
||||
self = address(this);
|
||||
}
|
||||
|
||||
// slither-disable-next-line locked-ether
|
||||
|
||||
@@ -6,6 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||
|
||||
error TokenTransfer__AddressZero();
|
||||
error TokenTransfer__InvalidTransferType();
|
||||
|
||||
contract TokenTransfer {
|
||||
using SafeERC20 for IERC20;
|
||||
@@ -45,7 +46,9 @@ contract TokenTransfer {
|
||||
uint256 amount,
|
||||
TransferType transferType
|
||||
) internal {
|
||||
if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
|
||||
if (transferType == TransferType.NONE) {
|
||||
return;
|
||||
} else if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
|
||||
if (tokenIn == address(0)) {
|
||||
payable(receiver).transfer(amount);
|
||||
} else {
|
||||
@@ -65,6 +68,8 @@ contract TokenTransfer {
|
||||
permit2.transferFrom(
|
||||
sender, address(this), uint160(amount), tokenIn
|
||||
);
|
||||
} else {
|
||||
revert TokenTransfer__InvalidTransferType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,8 +184,11 @@ contract UniswapV4Executor is
|
||||
external
|
||||
returns (bytes memory)
|
||||
{
|
||||
verifyCallback(data);
|
||||
return _unlockCallback(data);
|
||||
bytes calldata stripped = data[68:];
|
||||
verifyCallback(stripped);
|
||||
// Our general callback logic returns a not ABI encoded result.
|
||||
// However, the pool manager expects the result to be ABI encoded. That is why we need to encode it here again.
|
||||
return abi.encode(_unlockCallback(stripped));
|
||||
}
|
||||
|
||||
function verifyCallback(bytes calldata) public view poolManagerOnly {}
|
||||
|
||||
Reference in New Issue
Block a user