feat: Support new transfer logic in all executors
TODO: - Fix failing tests - Remove permit2 from initialization of contracts
This commit is contained in:
@@ -3,7 +3,6 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import {ICallback} from "@interfaces/ICallback.sol";
|
||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||
import {
|
||||
IERC20,
|
||||
SafeERC20
|
||||
@@ -23,6 +22,7 @@ import {IUnlockCallback} from
|
||||
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
|
||||
import {TransientStateLibrary} from
|
||||
"@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
||||
import "../OneTransferFromOnly.sol";
|
||||
|
||||
error UniswapV4Executor__InvalidDataLength();
|
||||
error UniswapV4Executor__NotPoolManager();
|
||||
@@ -37,7 +37,7 @@ contract UniswapV4Executor is
|
||||
IExecutor,
|
||||
IUnlockCallback,
|
||||
ICallback,
|
||||
TokenTransfer
|
||||
OneTransferFromOnly
|
||||
{
|
||||
using SafeERC20 for IERC20;
|
||||
using CurrencyLibrary for Currency;
|
||||
@@ -57,7 +57,7 @@ contract UniswapV4Executor is
|
||||
}
|
||||
|
||||
constructor(IPoolManager _poolManager, address _permit2)
|
||||
TokenTransfer(_permit2)
|
||||
OneTransferFromOnly(_permit2)
|
||||
{
|
||||
poolManager = _poolManager;
|
||||
_self = address(this);
|
||||
@@ -82,7 +82,8 @@ contract UniswapV4Executor is
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
bool zeroForOne,
|
||||
TransferType transferType,
|
||||
bool transferFromNeeded,
|
||||
bool transferNeeded,
|
||||
address receiver,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||
) = _decodeData(data);
|
||||
@@ -100,8 +101,8 @@ contract UniswapV4Executor is
|
||||
key,
|
||||
zeroForOne,
|
||||
amountIn,
|
||||
msg.sender,
|
||||
transferType,
|
||||
transferFromNeeded,
|
||||
transferNeeded,
|
||||
receiver,
|
||||
bytes("")
|
||||
);
|
||||
@@ -123,8 +124,8 @@ contract UniswapV4Executor is
|
||||
currencyIn,
|
||||
path,
|
||||
amountIn,
|
||||
msg.sender,
|
||||
transferType,
|
||||
transferFromNeeded,
|
||||
transferNeeded,
|
||||
receiver
|
||||
);
|
||||
}
|
||||
@@ -142,24 +143,26 @@ contract UniswapV4Executor is
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
bool zeroForOne,
|
||||
TransferType transferType,
|
||||
bool transferFromNeeded,
|
||||
bool transferNeeded,
|
||||
address receiver,
|
||||
UniswapV4Pool[] memory pools
|
||||
)
|
||||
{
|
||||
if (data.length < 88) {
|
||||
if (data.length < 89) {
|
||||
revert UniswapV4Executor__InvalidDataLength();
|
||||
}
|
||||
|
||||
tokenIn = address(bytes20(data[0:20]));
|
||||
tokenOut = address(bytes20(data[20:40]));
|
||||
zeroForOne = (data[40] != 0);
|
||||
transferType = TransferType(uint8(data[41]));
|
||||
receiver = address(bytes20(data[42:62]));
|
||||
transferFromNeeded = (data[41] != 0);
|
||||
transferNeeded = (data[42] != 0);
|
||||
receiver = address(bytes20(data[43:63]));
|
||||
|
||||
uint256 poolsLength = (data.length - 62) / 26; // 26 bytes per pool object
|
||||
uint256 poolsLength = (data.length - 63) / 26; // 26 bytes per pool object
|
||||
pools = new UniswapV4Pool[](poolsLength);
|
||||
bytes memory poolsData = data[62:];
|
||||
bytes memory poolsData = data[63:];
|
||||
uint256 offset = 0;
|
||||
for (uint256 i = 0; i < poolsLength; i++) {
|
||||
address intermediaryToken;
|
||||
@@ -239,8 +242,8 @@ contract UniswapV4Executor is
|
||||
* @param poolKey The key of the pool to swap in.
|
||||
* @param zeroForOne Whether the swap is from token0 to token1 (true) or vice versa (false).
|
||||
* @param amountIn The amount of tokens to swap in.
|
||||
* @param sender The address of the sender.
|
||||
* @param transferType The type of transfer in to use.
|
||||
* @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet .
|
||||
* @param transferNeeded Whether to transfer input tokens into the core contract from the router contract
|
||||
* @param receiver The address of the receiver.
|
||||
* @param hookData Additional data for hook contracts.
|
||||
*/
|
||||
@@ -248,8 +251,8 @@ contract UniswapV4Executor is
|
||||
PoolKey memory poolKey,
|
||||
bool zeroForOne,
|
||||
uint128 amountIn,
|
||||
address sender,
|
||||
TransferType transferType,
|
||||
bool transferFromNeeded,
|
||||
bool transferNeeded,
|
||||
address receiver,
|
||||
bytes calldata hookData
|
||||
) external returns (uint128) {
|
||||
@@ -262,7 +265,7 @@ contract UniswapV4Executor is
|
||||
if (amount > amountIn) {
|
||||
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||
}
|
||||
_settle(currencyIn, amount, sender, transferType);
|
||||
_settle(currencyIn, amount, transferFromNeeded, transferNeeded);
|
||||
|
||||
Currency currencyOut =
|
||||
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
||||
@@ -275,16 +278,16 @@ contract UniswapV4Executor is
|
||||
* @param currencyIn The currency of the input token.
|
||||
* @param path The path to swap along.
|
||||
* @param amountIn The amount of tokens to swap in.
|
||||
* @param sender The address of the sender.
|
||||
* @param transferType The type of transfer in to use.
|
||||
* @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet .
|
||||
* @param transferNeeded Whether to transfer input tokens into the core contract from the router contract
|
||||
* @param receiver The address of the receiver.
|
||||
*/
|
||||
function swapExactInput(
|
||||
Currency currencyIn,
|
||||
PathKey[] calldata path,
|
||||
uint128 amountIn,
|
||||
address sender,
|
||||
TransferType transferType,
|
||||
bool transferFromNeeded,
|
||||
bool transferNeeded,
|
||||
address receiver
|
||||
) external returns (uint128) {
|
||||
uint128 amountOut = 0;
|
||||
@@ -315,7 +318,7 @@ contract UniswapV4Executor is
|
||||
if (amount > amountIn) {
|
||||
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||
}
|
||||
_settle(currencyIn, amount, sender, transferType);
|
||||
_settle(currencyIn, amount, transferFromNeeded, transferNeeded);
|
||||
|
||||
_take(
|
||||
swapCurrencyIn, // at the end of the loop this is actually currency out
|
||||
@@ -387,15 +390,17 @@ contract UniswapV4Executor is
|
||||
* @dev The implementing contract must ensure that the `payer` is a secure address.
|
||||
* @param currency The currency to settle.
|
||||
* @param amount The amount to send.
|
||||
* @param sender The address of the payer.
|
||||
* @param transferType The type of transfer to use.
|
||||
* @param transferFromNeeded Whether to manually transferFrom input tokens into the
|
||||
* core contract from the swapper.
|
||||
* @param transferNeeded Whether to manually transfer input tokens into the
|
||||
* core contract from the router.
|
||||
* @dev Returns early if the amount is 0.
|
||||
*/
|
||||
function _settle(
|
||||
Currency currency,
|
||||
uint256 amount,
|
||||
address sender,
|
||||
TransferType transferType
|
||||
bool transferFromNeeded,
|
||||
bool transferNeeded
|
||||
) internal {
|
||||
if (amount == 0) return;
|
||||
poolManager.sync(currency);
|
||||
@@ -403,13 +408,18 @@ contract UniswapV4Executor is
|
||||
// slither-disable-next-line unused-return
|
||||
poolManager.settle{value: amount}();
|
||||
} else {
|
||||
_transfer(
|
||||
Currency.unwrap(currency),
|
||||
sender,
|
||||
address(poolManager),
|
||||
amount,
|
||||
transferType
|
||||
);
|
||||
if (transferFromNeeded) {
|
||||
// transferFrom swapper's wallet into the core contract
|
||||
_transfer(msg.sender);
|
||||
} else if (transferNeeded) {
|
||||
address tokenIn = Currency.unwrap(currency);
|
||||
// transfer from router contract into the core contract
|
||||
if (tokenIn == address(0)) {
|
||||
payable(msg.sender).transfer(amount);
|
||||
} else {
|
||||
IERC20(tokenIn).safeTransfer(msg.sender, amount);
|
||||
}
|
||||
}
|
||||
// slither-disable-next-line unused-return
|
||||
poolManager.settle();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user