fix: Make all tests pass!
Delete TokenTransfer.sol
Make slither happy
Bugfixes:
- Executors
- Ekubo:
- Fix the POOL_DATA_OFFSET value and remove sender from callback data
- Use SafeERC20
- Maverick and Univ2: Use safeTransfer and not safeTransferFrom
- Univ3: update expected data length
- Univ4: update the selectors (the signature changed)
- Router:
- For split swap we don't need to pass the tokenInReceiver, it should always be the router address
- For single and sequential: change order of the parameters (to be before the permit2 specific objects)
- Encoders:
- Update selector signatures
- For split swap pass the transfer_from (we might not need to if the token in is ETH)
Took 2 hours 51 minutes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {IExecutor} from "@interfaces/IExecutor.sol";
|
||||
import {ICallback} from "@interfaces/ICallback.sol";
|
||||
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
||||
@@ -26,12 +26,14 @@ contract EkuboExecutor is
|
||||
|
||||
ICore immutable core;
|
||||
|
||||
uint256 constant POOL_DATA_OFFSET = 77;
|
||||
uint256 constant POOL_DATA_OFFSET = 58;
|
||||
uint256 constant HOP_BYTE_LEN = 52;
|
||||
|
||||
bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256)
|
||||
bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address)
|
||||
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
constructor(address _core, address _permit2)
|
||||
OneTransferFromOnly(_permit2)
|
||||
{
|
||||
@@ -122,12 +124,10 @@ contract EkuboExecutor is
|
||||
function _locked(bytes calldata swapData) internal returns (int128) {
|
||||
int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16])));
|
||||
uint128 tokenInDebtAmount = uint128(nextAmountIn);
|
||||
address sender = address(bytes20(swapData[16:36]));
|
||||
bool transferFromNeeded = (swapData[36] != 0);
|
||||
bool transferNeeded = (swapData[37] != 0);
|
||||
|
||||
address receiver = address(bytes20(swapData[38:58]));
|
||||
address tokenIn = address(bytes20(swapData[58:78]));
|
||||
bool transferFromNeeded = (swapData[16] != 0);
|
||||
bool transferNeeded = (swapData[17] != 0);
|
||||
address receiver = address(bytes20(swapData[18:38]));
|
||||
address tokenIn = address(bytes20(swapData[38:58]));
|
||||
|
||||
address nextTokenIn = tokenIn;
|
||||
|
||||
@@ -207,7 +207,7 @@ contract EkuboExecutor is
|
||||
if (token == address(0)) {
|
||||
payable(msg.sender).transfer(amount);
|
||||
} else {
|
||||
IERC20(token).transfer(msg.sender, amount);
|
||||
IERC20(token).safeTransfer(msg.sender, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "./TokenTransfer.sol";
|
||||
|
||||
error MaverickV2Executor__InvalidDataLength();
|
||||
error MaverickV2Executor__InvalidTarget();
|
||||
@@ -49,10 +48,11 @@ contract MaverickV2Executor is IExecutor {
|
||||
|
||||
if (transferNeeded) {
|
||||
if (address(tokenIn) == address(0)) {
|
||||
// slither-disable-next-line arbitrary-send-eth
|
||||
payable(target).transfer(givenAmount);
|
||||
} else {
|
||||
// slither-disable-next-line arbitrary-send-erc20
|
||||
tokenIn.safeTransferFrom(msg.sender, target, givenAmount);
|
||||
tokenIn.safeTransfer(target, givenAmount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||
|
||||
error TokenTransfer__AddressZero();
|
||||
|
||||
contract TokenTransfer {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
IAllowanceTransfer public immutable permit2;
|
||||
|
||||
enum TransferType {
|
||||
// Assume funds are in the TychoRouter - transfer into the pool
|
||||
TRANSFER_TO_PROTOCOL,
|
||||
// Assume funds are in msg.sender's wallet - transferFrom into the pool
|
||||
TRANSFER_FROM_TO_PROTOCOL,
|
||||
// Assume funds are in msg.sender's wallet - permit2TransferFrom into the pool
|
||||
TRANSFER_PERMIT2_TO_PROTOCOL,
|
||||
// Assume funds are in msg.sender's wallet - but the pool requires it to be
|
||||
// in the router contract when calling swap - transferFrom into the router
|
||||
// contract
|
||||
TRANSFER_FROM_TO_ROUTER,
|
||||
// Assume funds are in msg.sender's wallet - but the pool requires it to be
|
||||
// in the router contract when calling swap - transferFrom into the router
|
||||
// contract using permit2
|
||||
TRANSFER_PERMIT2_TO_ROUTER,
|
||||
// Assume funds have already been transferred into the pool. Do nothing.
|
||||
NONE
|
||||
}
|
||||
|
||||
constructor(address _permit2) {
|
||||
if (_permit2 == address(0)) {
|
||||
revert TokenTransfer__AddressZero();
|
||||
}
|
||||
permit2 = IAllowanceTransfer(_permit2);
|
||||
}
|
||||
|
||||
function _transfer(
|
||||
address tokenIn,
|
||||
address sender,
|
||||
address receiver,
|
||||
uint256 amount,
|
||||
TransferType transferType
|
||||
) internal {
|
||||
if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
|
||||
if (tokenIn == address(0)) {
|
||||
payable(receiver).transfer(amount);
|
||||
} else {
|
||||
IERC20(tokenIn).safeTransfer(receiver, amount);
|
||||
}
|
||||
} else if (transferType == TransferType.TRANSFER_FROM_TO_PROTOCOL) {
|
||||
// slither-disable-next-line arbitrary-send-erc20
|
||||
IERC20(tokenIn).safeTransferFrom(sender, receiver, amount);
|
||||
} else if (transferType == TransferType.TRANSFER_PERMIT2_TO_PROTOCOL) {
|
||||
// Permit2.permit is already called from the TychoRouter
|
||||
permit2.transferFrom(sender, receiver, uint160(amount), tokenIn);
|
||||
} else if (transferType == TransferType.TRANSFER_FROM_TO_ROUTER) {
|
||||
// slither-disable-next-line arbitrary-send-erc20
|
||||
IERC20(tokenIn).safeTransferFrom(sender, address(this), amount);
|
||||
} else if (transferType == TransferType.TRANSFER_PERMIT2_TO_ROUTER) {
|
||||
// Permit2.permit is already called from the TychoRouter
|
||||
permit2.transferFrom(
|
||||
sender, address(this), uint160(amount), tokenIn
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,12 +60,8 @@ contract UniswapV2Executor is IExecutor {
|
||||
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
||||
|
||||
if (transferNeeded) {
|
||||
if (address(tokenIn) == address(0)) {
|
||||
payable(target).transfer(givenAmount);
|
||||
} else {
|
||||
// slither-disable-next-line arbitrary-send-erc20
|
||||
tokenIn.safeTransferFrom(msg.sender, target, givenAmount);
|
||||
}
|
||||
// slither-disable-next-line arbitrary-send-erc20
|
||||
tokenIn.safeTransfer(target, givenAmount);
|
||||
}
|
||||
|
||||
IUniswapV2Pair pool = IUniswapV2Pair(target);
|
||||
|
||||
@@ -5,7 +5,6 @@ import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||||
import "@interfaces/ICallback.sol";
|
||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||
import {OneTransferFromOnly} from "../OneTransferFromOnly.sol";
|
||||
|
||||
error UniswapV3Executor__InvalidDataLength();
|
||||
@@ -152,7 +151,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
||||
bool transferNeeded
|
||||
)
|
||||
{
|
||||
if (data.length != 85) {
|
||||
if (data.length != 86) {
|
||||
revert UniswapV3Executor__InvalidDataLength();
|
||||
}
|
||||
tokenIn = address(bytes20(data[0:20]));
|
||||
|
||||
@@ -47,8 +47,8 @@ contract UniswapV4Executor is
|
||||
IPoolManager public immutable poolManager;
|
||||
address private immutable _self;
|
||||
|
||||
bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x8bc6d0d7;
|
||||
bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0xaf90aeb1;
|
||||
bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0xbaa46608;
|
||||
bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0x653f1785;
|
||||
|
||||
struct UniswapV4Pool {
|
||||
address intermediaryToken;
|
||||
|
||||
Reference in New Issue
Block a user