Merge pull request #166 from propeller-heads/router/dc/ENG-4437-uniswapv4-refactor
feat: Do not use V4Router for uniswap v4
This commit is contained in:
@@ -786,8 +786,8 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
returns (bytes memory)
|
returns (bytes memory)
|
||||||
{
|
{
|
||||||
if (data.length < 24) revert TychoRouter__InvalidDataLength();
|
if (data.length < 24) revert TychoRouter__InvalidDataLength();
|
||||||
_handleCallback(data);
|
bytes memory result = _handleCallback(data);
|
||||||
return "";
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _balanceOf(address token, address owner)
|
function _balanceOf(address token, address owner)
|
||||||
|
|||||||
@@ -2,28 +2,48 @@
|
|||||||
pragma solidity ^0.8.26;
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
import "@interfaces/IExecutor.sol";
|
import "@interfaces/IExecutor.sol";
|
||||||
|
import {ICallback} from "@interfaces/ICallback.sol";
|
||||||
|
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||||
import {
|
import {
|
||||||
IERC20,
|
IERC20,
|
||||||
SafeERC20
|
SafeERC20
|
||||||
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
|
|
||||||
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
||||||
import {
|
import {
|
||||||
Currency, CurrencyLibrary
|
Currency, CurrencyLibrary
|
||||||
} from "@uniswap/v4-core/src/types/Currency.sol";
|
} from "@uniswap/v4-core/src/types/Currency.sol";
|
||||||
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
||||||
|
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
|
||||||
|
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
|
||||||
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
||||||
import {V4Router} from "@uniswap/v4-periphery/src/V4Router.sol";
|
|
||||||
import {Actions} from "@uniswap/v4-periphery/src/libraries/Actions.sol";
|
|
||||||
import {IV4Router} from "@uniswap/v4-periphery/src/interfaces/IV4Router.sol";
|
|
||||||
import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
|
import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
|
||||||
import {ICallback} from "@interfaces/ICallback.sol";
|
import {IUnlockCallback} from
|
||||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
"@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol";
|
||||||
|
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
|
||||||
|
import {TransientStateLibrary} from
|
||||||
|
"@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
||||||
|
|
||||||
error UniswapV4Executor__InvalidDataLength();
|
error UniswapV4Executor__InvalidDataLength();
|
||||||
|
error UniswapV4Executor__NotPoolManager();
|
||||||
|
error UniswapV4Executor__DeltaNotPositive(Currency currency);
|
||||||
|
error UniswapV4Executor__DeltaNotNegative(Currency currency);
|
||||||
|
error UniswapV4Executor__V4TooMuchRequested(
|
||||||
|
uint256 maxAmountInRequested, uint256 amountRequested
|
||||||
|
);
|
||||||
|
|
||||||
contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
contract UniswapV4Executor is
|
||||||
|
IExecutor,
|
||||||
|
IUnlockCallback,
|
||||||
|
ICallback,
|
||||||
|
TokenTransfer
|
||||||
|
{
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
using CurrencyLibrary for Currency;
|
using CurrencyLibrary for Currency;
|
||||||
|
using SafeCast for *;
|
||||||
|
using TransientStateLibrary for IPoolManager;
|
||||||
|
|
||||||
|
IPoolManager public immutable poolManager;
|
||||||
|
|
||||||
struct UniswapV4Pool {
|
struct UniswapV4Pool {
|
||||||
address intermediaryToken;
|
address intermediaryToken;
|
||||||
@@ -32,9 +52,20 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(IPoolManager _poolManager, address _permit2)
|
constructor(IPoolManager _poolManager, address _permit2)
|
||||||
V4Router(_poolManager)
|
|
||||||
TokenTransfer(_permit2)
|
TokenTransfer(_permit2)
|
||||||
{}
|
{
|
||||||
|
poolManager = _poolManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Modifier to restrict access to only the pool manager.
|
||||||
|
*/
|
||||||
|
modifier poolManagerOnly() virtual {
|
||||||
|
if (msg.sender != address(poolManager)) {
|
||||||
|
revert UniswapV4Executor__NotPoolManager();
|
||||||
|
}
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
function swap(uint256 amountIn, bytes calldata data)
|
function swap(uint256 amountIn, bytes calldata data)
|
||||||
external
|
external
|
||||||
@@ -49,18 +80,6 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
|||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
// TODO move this into callback when we implement callback transfer type support
|
|
||||||
_transfer(
|
|
||||||
tokenIn,
|
|
||||||
msg.sender,
|
|
||||||
// Receiver can never be the pool, since the pool expects funds in the router contract
|
|
||||||
// Thus, this call will only ever be used to transfer funds from the user into the router.
|
|
||||||
address(this),
|
|
||||||
amountIn,
|
|
||||||
transferType
|
|
||||||
);
|
|
||||||
|
|
||||||
bytes memory swapData;
|
bytes memory swapData;
|
||||||
if (pools.length == 1) {
|
if (pools.length == 1) {
|
||||||
PoolKey memory key = PoolKey({
|
PoolKey memory key = PoolKey({
|
||||||
@@ -70,26 +89,16 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
|||||||
tickSpacing: pools[0].tickSpacing,
|
tickSpacing: pools[0].tickSpacing,
|
||||||
hooks: IHooks(address(0))
|
hooks: IHooks(address(0))
|
||||||
});
|
});
|
||||||
bytes memory actions = abi.encodePacked(
|
swapData = abi.encodeWithSelector(
|
||||||
uint8(Actions.SWAP_EXACT_IN_SINGLE),
|
this.swapExactInputSingle.selector,
|
||||||
uint8(Actions.SETTLE_ALL),
|
key,
|
||||||
uint8(Actions.TAKE)
|
zeroForOne,
|
||||||
|
amountIn,
|
||||||
|
msg.sender,
|
||||||
|
transferType,
|
||||||
|
receiver,
|
||||||
|
bytes("")
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes[] memory params = new bytes[](3);
|
|
||||||
|
|
||||||
params[0] = abi.encode(
|
|
||||||
IV4Router.ExactInputSingleParams({
|
|
||||||
poolKey: key,
|
|
||||||
zeroForOne: zeroForOne,
|
|
||||||
amountIn: uint128(amountIn),
|
|
||||||
amountOutMinimum: uint128(0),
|
|
||||||
hookData: bytes("")
|
|
||||||
})
|
|
||||||
);
|
|
||||||
params[1] = abi.encode(tokenIn, amountIn); // currency to settle
|
|
||||||
params[2] = abi.encode(tokenOut, receiver, uint256(0)); // currency to take. 0 means to take the full amount
|
|
||||||
swapData = abi.encode(actions, params);
|
|
||||||
} else {
|
} else {
|
||||||
PathKey[] memory path = new PathKey[](pools.length);
|
PathKey[] memory path = new PathKey[](pools.length);
|
||||||
for (uint256 i = 0; i < pools.length; i++) {
|
for (uint256 i = 0; i < pools.length; i++) {
|
||||||
@@ -102,51 +111,22 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes memory actions = abi.encodePacked(
|
|
||||||
uint8(Actions.SWAP_EXACT_IN),
|
|
||||||
uint8(Actions.SETTLE_ALL),
|
|
||||||
uint8(Actions.TAKE)
|
|
||||||
);
|
|
||||||
|
|
||||||
bytes[] memory params = new bytes[](3);
|
|
||||||
|
|
||||||
Currency currencyIn = Currency.wrap(tokenIn);
|
Currency currencyIn = Currency.wrap(tokenIn);
|
||||||
params[0] = abi.encode(
|
swapData = abi.encodeWithSelector(
|
||||||
IV4Router.ExactInputParams({
|
this.swapExactInput.selector,
|
||||||
currencyIn: currencyIn,
|
currencyIn,
|
||||||
path: path,
|
path,
|
||||||
amountIn: uint128(amountIn),
|
amountIn,
|
||||||
amountOutMinimum: uint128(0)
|
msg.sender,
|
||||||
})
|
transferType,
|
||||||
|
receiver
|
||||||
);
|
);
|
||||||
params[1] = abi.encode(currencyIn, amountIn);
|
|
||||||
params[2] =
|
|
||||||
abi.encode(Currency.wrap(tokenOut), receiver, uint256(0));
|
|
||||||
swapData = abi.encode(actions, params);
|
|
||||||
}
|
}
|
||||||
uint256 tokenOutBalanceBefore;
|
|
||||||
|
|
||||||
tokenOutBalanceBefore = tokenOut == address(0)
|
bytes memory result = poolManager.unlock(swapData);
|
||||||
? receiver.balance
|
uint128 amountOut = abi.decode(result, (uint128));
|
||||||
: IERC20(tokenOut).balanceOf(receiver);
|
|
||||||
|
|
||||||
executeActions(swapData);
|
return amountOut;
|
||||||
|
|
||||||
uint256 tokenOutBalanceAfter;
|
|
||||||
|
|
||||||
tokenOutBalanceAfter = tokenOut == address(0)
|
|
||||||
? receiver.balance
|
|
||||||
: IERC20(tokenOut).balanceOf(receiver);
|
|
||||||
|
|
||||||
calculatedAmount = tokenOutBalanceAfter - tokenOutBalanceBefore;
|
|
||||||
|
|
||||||
return calculatedAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// necessary to convert bytes memory to bytes calldata
|
|
||||||
function executeActions(bytes memory unlockData) public {
|
|
||||||
// slither-disable-next-line unused-return
|
|
||||||
poolManager.unlock(unlockData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _decodeData(bytes calldata data)
|
function _decodeData(bytes calldata data)
|
||||||
@@ -191,6 +171,9 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Handles the callback from the pool manager. This is used for callbacks from the router.
|
||||||
|
*/
|
||||||
function handleCallback(bytes calldata data)
|
function handleCallback(bytes calldata data)
|
||||||
external
|
external
|
||||||
returns (bytes memory)
|
returns (bytes memory)
|
||||||
@@ -199,15 +182,256 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
|
|||||||
return _unlockCallback(data);
|
return _unlockCallback(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyCallback(bytes calldata) public view onlyPoolManager {}
|
function verifyCallback(bytes calldata) public view poolManagerOnly {}
|
||||||
|
|
||||||
function _pay(Currency token, address, uint256 amount) internal override {
|
/**
|
||||||
IERC20(Currency.unwrap(token)).safeTransfer(
|
* @notice Handles the unlock callback from the pool manager. This is used for swaps against the executor directly (bypassing the router).
|
||||||
address(poolManager), amount
|
*/
|
||||||
);
|
function unlockCallback(bytes calldata data)
|
||||||
|
external
|
||||||
|
poolManagerOnly
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return _unlockCallback(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function msgSender() public view override returns (address) {
|
/**
|
||||||
return address(this);
|
* @dev Internal function to handle the unlock callback.
|
||||||
|
* The executor address is needed to perform the call. If the router is being used, the executor address is in
|
||||||
|
* transient storage. If it is not, then address(this) should be used.
|
||||||
|
*/
|
||||||
|
function _unlockCallback(bytes calldata data)
|
||||||
|
internal
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
address executor;
|
||||||
|
// slither-disable-next-line assembly
|
||||||
|
assembly {
|
||||||
|
executor := tload(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executor == address(0)) {
|
||||||
|
executor = address(this);
|
||||||
|
}
|
||||||
|
// here we expect to call either `swapExactInputSingle` or `swapExactInput`. See `swap` to see how we encode the selector and the calldata
|
||||||
|
// slither-disable-next-line low-level-calls
|
||||||
|
(bool success, bytes memory returnData) = executor.delegatecall(data);
|
||||||
|
if (!success) {
|
||||||
|
revert(
|
||||||
|
string(
|
||||||
|
returnData.length > 0
|
||||||
|
? returnData
|
||||||
|
: abi.encodePacked("Uniswap v4 Callback failed")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return returnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Performs an exact input single swap. It settles and takes the tokens after the swap.
|
||||||
|
* @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 receiver The address of the receiver.
|
||||||
|
* @param hookData Additional data for hook contracts.
|
||||||
|
*/
|
||||||
|
function swapExactInputSingle(
|
||||||
|
PoolKey memory poolKey,
|
||||||
|
bool zeroForOne,
|
||||||
|
uint128 amountIn,
|
||||||
|
address sender,
|
||||||
|
TransferType transferType,
|
||||||
|
address receiver,
|
||||||
|
bytes calldata hookData
|
||||||
|
) external returns (uint128) {
|
||||||
|
uint128 amountOut = _swap(
|
||||||
|
poolKey, zeroForOne, -int256(uint256(amountIn)), hookData
|
||||||
|
).toUint128();
|
||||||
|
|
||||||
|
Currency currencyIn = zeroForOne ? poolKey.currency0 : poolKey.currency1;
|
||||||
|
uint256 amount = _getFullDebt(currencyIn);
|
||||||
|
if (amount > amountIn) {
|
||||||
|
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||||
|
}
|
||||||
|
_settle(currencyIn, amount, sender, transferType);
|
||||||
|
|
||||||
|
Currency currencyOut =
|
||||||
|
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
||||||
|
_take(currencyOut, receiver, _mapTakeAmount(amountOut, currencyOut));
|
||||||
|
return amountOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Performs an exact input swap along a path. It settles and takes the tokens after the swap.
|
||||||
|
* @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 receiver The address of the receiver.
|
||||||
|
*/
|
||||||
|
function swapExactInput(
|
||||||
|
Currency currencyIn,
|
||||||
|
PathKey[] calldata path,
|
||||||
|
uint128 amountIn,
|
||||||
|
address sender,
|
||||||
|
TransferType transferType,
|
||||||
|
address receiver
|
||||||
|
) external returns (uint128) {
|
||||||
|
uint128 amountOut = 0;
|
||||||
|
Currency swapCurrencyIn = currencyIn;
|
||||||
|
uint256 swapAmountIn = amountIn;
|
||||||
|
unchecked {
|
||||||
|
uint256 pathLength = path.length;
|
||||||
|
PathKey calldata pathKey;
|
||||||
|
|
||||||
|
for (uint256 i = 0; i < pathLength; i++) {
|
||||||
|
pathKey = path[i];
|
||||||
|
(PoolKey memory poolKey, bool zeroForOne) =
|
||||||
|
pathKey.getPoolAndSwapDirection(swapCurrencyIn);
|
||||||
|
// The output delta will always be positive, except for when interacting with certain hook pools
|
||||||
|
amountOut = _swap(
|
||||||
|
poolKey,
|
||||||
|
zeroForOne,
|
||||||
|
-int256(uint256(swapAmountIn)),
|
||||||
|
pathKey.hookData
|
||||||
|
).toUint128();
|
||||||
|
|
||||||
|
swapAmountIn = amountOut;
|
||||||
|
swapCurrencyIn = pathKey.intermediateCurrency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 amount = _getFullDebt(currencyIn);
|
||||||
|
if (amount > amountIn) {
|
||||||
|
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||||
|
}
|
||||||
|
_settle(currencyIn, amount, sender, transferType);
|
||||||
|
|
||||||
|
_take(
|
||||||
|
swapCurrencyIn, // at the end of the loop this is actually currency out
|
||||||
|
receiver,
|
||||||
|
_mapTakeAmount(amountOut, swapCurrencyIn)
|
||||||
|
);
|
||||||
|
return amountOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _swap(
|
||||||
|
PoolKey memory poolKey,
|
||||||
|
bool zeroForOne,
|
||||||
|
int256 amountSpecified,
|
||||||
|
bytes calldata hookData
|
||||||
|
) private returns (int128 reciprocalAmount) {
|
||||||
|
unchecked {
|
||||||
|
// slither-disable-next-line calls-loop
|
||||||
|
BalanceDelta delta = poolManager.swap(
|
||||||
|
poolKey,
|
||||||
|
IPoolManager.SwapParams(
|
||||||
|
zeroForOne,
|
||||||
|
amountSpecified,
|
||||||
|
zeroForOne
|
||||||
|
? TickMath.MIN_SQRT_PRICE + 1
|
||||||
|
: TickMath.MAX_SQRT_PRICE - 1
|
||||||
|
),
|
||||||
|
hookData
|
||||||
|
);
|
||||||
|
|
||||||
|
reciprocalAmount = (zeroForOne == amountSpecified < 0)
|
||||||
|
? delta.amount1()
|
||||||
|
: delta.amount0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Obtains the full amount owed by this contract (negative delta).
|
||||||
|
* @param currency The currency to get the delta for.
|
||||||
|
* @return amount The amount owed by this contract.
|
||||||
|
*/
|
||||||
|
function _getFullCredit(Currency currency)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint256 amount)
|
||||||
|
{
|
||||||
|
int256 _amount = poolManager.currencyDelta(address(this), currency);
|
||||||
|
// If the amount is negative, it should be settled not taken.
|
||||||
|
if (_amount < 0) revert UniswapV4Executor__DeltaNotPositive(currency);
|
||||||
|
amount = uint256(_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Obtain the full amount owed by this contract (negative delta)
|
||||||
|
/// @param currency Currency to get the delta for
|
||||||
|
/// @return amount The amount owed by this contract as a uint256
|
||||||
|
function _getFullDebt(Currency currency)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint256 amount)
|
||||||
|
{
|
||||||
|
int256 _amount = poolManager.currencyDelta(address(this), currency);
|
||||||
|
// If the amount is positive, it should be taken not settled.
|
||||||
|
if (_amount > 0) revert UniswapV4Executor__DeltaNotNegative(currency);
|
||||||
|
// Casting is safe due to limits on the total supply of a pool
|
||||||
|
amount = uint256(-_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Pays and settles a currency to the pool manager.
|
||||||
|
* @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.
|
||||||
|
* @dev Returns early if the amount is 0.
|
||||||
|
*/
|
||||||
|
function _settle(
|
||||||
|
Currency currency,
|
||||||
|
uint256 amount,
|
||||||
|
address sender,
|
||||||
|
TransferType transferType
|
||||||
|
) internal {
|
||||||
|
if (amount == 0) return;
|
||||||
|
poolManager.sync(currency);
|
||||||
|
if (currency.isAddressZero()) {
|
||||||
|
// slither-disable-next-line unused-return
|
||||||
|
poolManager.settle{value: amount}();
|
||||||
|
} else {
|
||||||
|
_transfer(
|
||||||
|
Currency.unwrap(currency),
|
||||||
|
sender,
|
||||||
|
address(poolManager),
|
||||||
|
amount,
|
||||||
|
transferType
|
||||||
|
);
|
||||||
|
// slither-disable-next-line unused-return
|
||||||
|
poolManager.settle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Takes an amount of currency out of the pool manager.
|
||||||
|
* @param currency The currency to take.
|
||||||
|
* @param recipient The address to receive the currency.
|
||||||
|
* @param amount The amount to take.
|
||||||
|
* @dev Returns early if the amount is 0.
|
||||||
|
*/
|
||||||
|
function _take(Currency currency, address recipient, uint256 amount)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
if (amount == 0) return;
|
||||||
|
poolManager.take(currency, recipient, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _mapTakeAmount(uint256 amount, Currency currency)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
if (amount == 0) {
|
||||||
|
return _getFullCredit(currency);
|
||||||
|
} else {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||||
// Encoded solution generated using `test_sequential_encoding_strategy_usv4`
|
// Encoded solution generated using `test_sequential_encoding_strategy_usv4`
|
||||||
(bool success,) = tychoRouterAddr.call(
|
(bool success,) = tychoRouterAddr.call(
|
||||||
hex"51bcc7b6000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000682db60700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006806300f00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041c5715acd97f16c669ba5b6a15d911e61f9b5a056c1bb4f0576dbf7c1251bddd70ac5e929270186517e593e1c8d1d1ecf5c742576affcd5d64cac409600ad054e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000880086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330004cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f4000000000000000000000000000000000000000000000000"
|
hex"7c553846000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006828a8d900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000680122e10000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412fb2c4e85c1b2236aef343641c10f81e4abfd675f520d86778cb9db16c9f500d11fe28b99285dd1bef082b9ccde3360a8077c57ece0775677fddfd5ff11b6e081c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d008b0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000000000000000"
|
||||||
);
|
);
|
||||||
|
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -43,7 +43,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
|
|
||||||
// Encoded solution generated using `test_single_encoding_strategy_usv4_eth_in`
|
// Encoded solution generated using `test_single_encoding_strategy_usv4_eth_in`
|
||||||
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
|
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
|
||||||
hex"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000682db9c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000680633c800000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417d375e095d10a0d69c183082f533f2393e7ec356e4d222d32943ecab59683b013047017436b824fb8d00c2cdda2ab4136da5bc32ea79c6305b237633f6d0978c1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000"
|
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006828a8d900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000680122e1000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041b7928a6257d4f01539c357c322036b5df1799313f83a119c843a239ca474955820f791f028fa10a9fe3ec0d6be7d782e5824ac1942e27ebd2a0a3e1687bec4451c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000000000000000"
|
||||||
);
|
);
|
||||||
|
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -70,7 +70,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
|
|
||||||
// Encoded solution generated using `test_single_encoding_strategy_usv4_eth_out`
|
// Encoded solution generated using `test_single_encoding_strategy_usv4_eth_out`
|
||||||
(bool success,) = tychoRouterAddr.call(
|
(bool success,) = tychoRouterAddr.call(
|
||||||
hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006826193a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fe9342000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041dbb84c68a4293bcf6303ca45327614667c54226086ddcfa2daa9289c1657da9a57268f4d8ceea3c831d43e5a96b1dc54766bc3fda8845d5c7e266981b9d84c651b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000004cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000"
|
hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006828a8d900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000680122e1000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041bf1373f3d3943e0865f8081b1569b4deb66b56b8690500c4c9f1c1f7e1299510720e3d4c92abf6ec75f0b14a87b92957fd43408562f26b8616857469f94012e21b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000"
|
||||||
);
|
);
|
||||||
|
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
USDT_ADDR,
|
USDT_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_ROUTER,
|
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -480,7 +480,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
WBTC_ADDR,
|
WBTC_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE,
|
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
USDT_ADDR,
|
USDT_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE,
|
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -172,7 +172,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
WBTC_ADDR,
|
WBTC_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE,
|
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pub static IN_TRANSFER_REQUIRED_PROTOCOLS: LazyLock<HashSet<&'static str>> = Laz
|
|||||||
set.insert("pancakeswap_v2");
|
set.insert("pancakeswap_v2");
|
||||||
set.insert("uniswap_v3");
|
set.insert("uniswap_v3");
|
||||||
set.insert("pancakeswap_v3");
|
set.insert("pancakeswap_v3");
|
||||||
|
set.insert("uniswap_v4");
|
||||||
set.insert("ekubo_v2");
|
set.insert("ekubo_v2");
|
||||||
set
|
set
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2314,7 +2314,7 @@ mod tests {
|
|||||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
|
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
|
||||||
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
|
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"04", // transfer type (transfer to router)
|
"02", // transfer type (transfer to router)
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
// First pool params
|
// First pool params
|
||||||
"0000000000000000000000000000000000000000", // intermediary token (ETH)
|
"0000000000000000000000000000000000000000", // intermediary token (ETH)
|
||||||
|
|||||||
Reference in New Issue
Block a user