feat: Support new transfer logic in all executors
TODO: - Fix failing tests - Remove permit2 from initialization of contracts
This commit is contained in:
@@ -27,7 +27,7 @@ contract OneTransferFromOnly {
|
|||||||
|
|
||||||
function tstoreTransferFromInfo(
|
function tstoreTransferFromInfo(
|
||||||
address tokenIn,
|
address tokenIn,
|
||||||
address amountIn,
|
uint256 amountIn,
|
||||||
bool isPermit2,
|
bool isPermit2,
|
||||||
address sender
|
address sender
|
||||||
) internal {
|
) internal {
|
||||||
@@ -40,10 +40,7 @@ contract OneTransferFromOnly {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _transfer(address receiver)
|
function _transfer(address receiver) internal {
|
||||||
// we could pass the amount and address too and compare to what is in the slots?
|
|
||||||
internal
|
|
||||||
{
|
|
||||||
address tokenIn;
|
address tokenIn;
|
||||||
uint256 amount;
|
uint256 amount;
|
||||||
bool isPermit2;
|
bool isPermit2;
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ contract TychoRouter is
|
|||||||
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
|
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
|
||||||
* @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations).
|
* @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations).
|
||||||
* @param receiver The address to receive the output tokens.
|
* @param receiver The address to receive the output tokens.
|
||||||
|
* @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router.
|
||||||
|
* @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true.
|
||||||
* @param swaps Encoded swap graph data containing details of each swap.
|
* @param swaps Encoded swap graph data containing details of each swap.
|
||||||
*
|
*
|
||||||
* @return amountOut The total amount of the output token received by the receiver.
|
* @return amountOut The total amount of the output token received by the receiver.
|
||||||
@@ -135,9 +137,14 @@ contract TychoRouter is
|
|||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
uint256 nTokens,
|
uint256 nTokens,
|
||||||
address receiver,
|
address receiver,
|
||||||
|
bool transferFromRequired,
|
||||||
|
address tokenInReceiver,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender);
|
tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender);
|
||||||
|
if (transferFromRequired) {
|
||||||
|
_transfer(tokenInReceiver);
|
||||||
|
}
|
||||||
return _splitSwapChecked(
|
return _splitSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
@@ -173,6 +180,8 @@ contract TychoRouter is
|
|||||||
* @param receiver The address to receive the output tokens.
|
* @param receiver The address to receive the output tokens.
|
||||||
* @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true.
|
* @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true.
|
||||||
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
|
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
|
||||||
|
* @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router.
|
||||||
|
* @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true.
|
||||||
* @param swaps Encoded swap graph data containing details of each swap.
|
* @param swaps Encoded swap graph data containing details of each swap.
|
||||||
*
|
*
|
||||||
* @return amountOut The total amount of the output token received by the receiver.
|
* @return amountOut The total amount of the output token received by the receiver.
|
||||||
@@ -188,14 +197,18 @@ contract TychoRouter is
|
|||||||
address receiver,
|
address receiver,
|
||||||
IAllowanceTransfer.PermitSingle calldata permitSingle,
|
IAllowanceTransfer.PermitSingle calldata permitSingle,
|
||||||
bytes calldata signature,
|
bytes calldata signature,
|
||||||
|
bool transferFromRequired,
|
||||||
|
address tokenInReceiver,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
// For native ETH, assume funds already in our router. Else, handle approval.
|
// For native ETH, assume funds already in our router. Else, handle approval.
|
||||||
if (tokenIn != address(0)) {
|
if (tokenIn != address(0)) {
|
||||||
permit2.permit(msg.sender, permitSingle, signature);
|
permit2.permit(msg.sender, permitSingle, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender);
|
tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender);
|
||||||
|
if (transferFromRequired) {
|
||||||
|
_transfer(tokenInReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
return _splitSwapChecked(
|
return _splitSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -228,6 +241,8 @@ contract TychoRouter is
|
|||||||
* @param wrapEth If true, wraps the input token (native ETH) into WETH.
|
* @param wrapEth If true, wraps the input token (native ETH) into WETH.
|
||||||
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
|
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
|
||||||
* @param receiver The address to receive the output tokens.
|
* @param receiver The address to receive the output tokens.
|
||||||
|
* @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router.
|
||||||
|
* @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true.
|
||||||
* @param swaps Encoded swap graph data containing details of each swap.
|
* @param swaps Encoded swap graph data containing details of each swap.
|
||||||
*
|
*
|
||||||
* @return amountOut The total amount of the output token received by the receiver.
|
* @return amountOut The total amount of the output token received by the receiver.
|
||||||
@@ -240,9 +255,14 @@ contract TychoRouter is
|
|||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
address receiver,
|
address receiver,
|
||||||
|
bool transferFromRequired,
|
||||||
|
address tokenInReceiver,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender);
|
tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender);
|
||||||
|
if (transferFromRequired) {
|
||||||
|
_transfer(tokenInReceiver);
|
||||||
|
}
|
||||||
return _sequentialSwapChecked(
|
return _sequentialSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
@@ -275,6 +295,8 @@ contract TychoRouter is
|
|||||||
* @param receiver The address to receive the output tokens.
|
* @param receiver The address to receive the output tokens.
|
||||||
* @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true.
|
* @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true.
|
||||||
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
|
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
|
||||||
|
* @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router.
|
||||||
|
* @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true.
|
||||||
* @param swaps Encoded swap graph data containing details of each swap.
|
* @param swaps Encoded swap graph data containing details of each swap.
|
||||||
*
|
*
|
||||||
* @return amountOut The total amount of the output token received by the receiver.
|
* @return amountOut The total amount of the output token received by the receiver.
|
||||||
@@ -289,6 +311,8 @@ contract TychoRouter is
|
|||||||
address receiver,
|
address receiver,
|
||||||
IAllowanceTransfer.PermitSingle calldata permitSingle,
|
IAllowanceTransfer.PermitSingle calldata permitSingle,
|
||||||
bytes calldata signature,
|
bytes calldata signature,
|
||||||
|
bool transferFromRequired,
|
||||||
|
address tokenInReceiver,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
// For native ETH, assume funds already in our router. Else, handle approval.
|
// For native ETH, assume funds already in our router. Else, handle approval.
|
||||||
@@ -297,6 +321,9 @@ contract TychoRouter is
|
|||||||
}
|
}
|
||||||
|
|
||||||
tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender);
|
tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender);
|
||||||
|
if (transferFromRequired) {
|
||||||
|
_transfer(tokenInReceiver);
|
||||||
|
}
|
||||||
return _sequentialSwapChecked(
|
return _sequentialSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
@@ -325,6 +352,8 @@ contract TychoRouter is
|
|||||||
* @param wrapEth If true, wraps the input token (native ETH) into WETH.
|
* @param wrapEth If true, wraps the input token (native ETH) into WETH.
|
||||||
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
|
* @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver.
|
||||||
* @param receiver The address to receive the output tokens.
|
* @param receiver The address to receive the output tokens.
|
||||||
|
* @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router.
|
||||||
|
* @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true.
|
||||||
* @param swapData Encoded swap details.
|
* @param swapData Encoded swap details.
|
||||||
*
|
*
|
||||||
* @return amountOut The total amount of the output token received by the receiver.
|
* @return amountOut The total amount of the output token received by the receiver.
|
||||||
@@ -337,13 +366,13 @@ contract TychoRouter is
|
|||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool inTransferNeeded,
|
bool transferFromRequired,
|
||||||
address fundsReceiver,
|
address tokenInReceiver,
|
||||||
bytes calldata swapData
|
bytes calldata swapData
|
||||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender);
|
tstoreTransferFromInfo(tokenIn, amountIn, false, msg.sender);
|
||||||
if (inTransferNeeded) {
|
if (transferFromRequired) {
|
||||||
_transfer(fundsReceiver);
|
_transfer(tokenInReceiver);
|
||||||
}
|
}
|
||||||
return _singleSwap(
|
return _singleSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -377,6 +406,8 @@ contract TychoRouter is
|
|||||||
* @param receiver The address to receive the output tokens.
|
* @param receiver The address to receive the output tokens.
|
||||||
* @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true.
|
* @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true.
|
||||||
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
|
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
|
||||||
|
* @param transferFromRequired If true, the contract will transfer the input token from the caller to the receiver. Otherwise, assume funds are already in router.
|
||||||
|
* @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromRequired` is true.
|
||||||
* @param swapData Encoded swap details.
|
* @param swapData Encoded swap details.
|
||||||
*
|
*
|
||||||
* @return amountOut The total amount of the output token received by the receiver.
|
* @return amountOut The total amount of the output token received by the receiver.
|
||||||
@@ -391,6 +422,8 @@ contract TychoRouter is
|
|||||||
address receiver,
|
address receiver,
|
||||||
IAllowanceTransfer.PermitSingle calldata permitSingle,
|
IAllowanceTransfer.PermitSingle calldata permitSingle,
|
||||||
bytes calldata signature,
|
bytes calldata signature,
|
||||||
|
bool transferFromRequired,
|
||||||
|
address tokenInReceiver,
|
||||||
bytes calldata swapData
|
bytes calldata swapData
|
||||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
// For native ETH, assume funds already in our router. Else, handle approval.
|
// For native ETH, assume funds already in our router. Else, handle approval.
|
||||||
@@ -398,6 +431,9 @@ contract TychoRouter is
|
|||||||
permit2.permit(msg.sender, permitSingle, signature);
|
permit2.permit(msg.sender, permitSingle, signature);
|
||||||
}
|
}
|
||||||
tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender);
|
tstoreTransferFromInfo(tokenIn, amountIn, true, msg.sender);
|
||||||
|
if (transferFromRequired) {
|
||||||
|
_transfer(tokenInReceiver);
|
||||||
|
}
|
||||||
return _singleSwap(
|
return _singleSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
|
|||||||
@@ -10,16 +10,15 @@ import {
|
|||||||
import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol";
|
import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol";
|
||||||
// slither-disable-next-line solc-version
|
// slither-disable-next-line solc-version
|
||||||
import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
|
import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
|
||||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
|
||||||
|
|
||||||
error BalancerV2Executor__InvalidDataLength();
|
error BalancerV2Executor__InvalidDataLength();
|
||||||
|
|
||||||
contract BalancerV2Executor is IExecutor, TokenTransfer {
|
contract BalancerV2Executor is IExecutor {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
|
address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
|
||||||
|
|
||||||
constructor(address _permit2) TokenTransfer(_permit2) {}
|
constructor(address _permit2) {}
|
||||||
|
|
||||||
// slither-disable-next-line locked-ether
|
// slither-disable-next-line locked-ether
|
||||||
function swap(uint256 givenAmount, bytes calldata data)
|
function swap(uint256 givenAmount, bytes calldata data)
|
||||||
@@ -33,19 +32,9 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
_transfer(
|
|
||||||
address(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),
|
|
||||||
givenAmount,
|
|
||||||
transferType
|
|
||||||
);
|
|
||||||
|
|
||||||
if (needsApproval) {
|
if (needsApproval) {
|
||||||
// slither-disable-next-line unused-return
|
// slither-disable-next-line unused-return
|
||||||
tokenIn.forceApprove(VAULT, type(uint256).max);
|
tokenIn.forceApprove(VAULT, type(uint256).max);
|
||||||
@@ -82,7 +71,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (data.length != 94) {
|
if (data.length != 94) {
|
||||||
@@ -94,6 +83,6 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
|||||||
poolId = bytes32(data[40:72]);
|
poolId = bytes32(data[40:72]);
|
||||||
receiver = address(bytes20(data[72:92]));
|
receiver = address(bytes20(data[72:92]));
|
||||||
needsApproval = uint8(data[92]) > 0;
|
needsApproval = uint8(data[92]) > 0;
|
||||||
transferType = TransferType(uint8(data[93]));
|
transferNeeded = uint8(data[93]) > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ pragma solidity ^0.8.26;
|
|||||||
|
|
||||||
import "@interfaces/IExecutor.sol";
|
import "@interfaces/IExecutor.sol";
|
||||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
import "./TokenTransfer.sol";
|
|
||||||
import "@openzeppelin/contracts/utils/Address.sol";
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
|
|
||||||
error CurveExecutor__AddressZero();
|
error CurveExecutor__AddressZero();
|
||||||
@@ -35,14 +34,12 @@ interface CryptoPoolETH {
|
|||||||
// slither-disable-end naming-convention
|
// slither-disable-end naming-convention
|
||||||
}
|
}
|
||||||
|
|
||||||
contract CurveExecutor is IExecutor, TokenTransfer {
|
contract CurveExecutor is IExecutor {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
address public immutable nativeToken;
|
address public immutable nativeToken;
|
||||||
|
|
||||||
constructor(address _nativeToken, address _permit2)
|
constructor(address _nativeToken, address _permit2) {
|
||||||
TokenTransfer(_permit2)
|
|
||||||
{
|
|
||||||
if (_nativeToken == address(0)) {
|
if (_nativeToken == address(0)) {
|
||||||
revert CurveExecutor__AddressZero();
|
revert CurveExecutor__AddressZero();
|
||||||
}
|
}
|
||||||
@@ -65,20 +62,10 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
|||||||
int128 i,
|
int128 i,
|
||||||
int128 j,
|
int128 j,
|
||||||
bool tokenApprovalNeeded,
|
bool tokenApprovalNeeded,
|
||||||
TransferType transferType,
|
bool transferNeeded, // TODO remove this with the encoding
|
||||||
address receiver
|
address receiver
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
_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
|
|
||||||
);
|
|
||||||
|
|
||||||
if (tokenApprovalNeeded && tokenIn != nativeToken) {
|
if (tokenApprovalNeeded && tokenIn != nativeToken) {
|
||||||
// slither-disable-next-line unused-return
|
// slither-disable-next-line unused-return
|
||||||
IERC20(tokenIn).forceApprove(address(pool), type(uint256).max);
|
IERC20(tokenIn).forceApprove(address(pool), type(uint256).max);
|
||||||
@@ -134,7 +121,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
|||||||
int128 i,
|
int128 i,
|
||||||
int128 j,
|
int128 j,
|
||||||
bool tokenApprovalNeeded,
|
bool tokenApprovalNeeded,
|
||||||
TransferType transferType,
|
bool transferNeeded,
|
||||||
address receiver
|
address receiver
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -145,7 +132,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
|||||||
i = int128(uint128(uint8(data[61])));
|
i = int128(uint128(uint8(data[61])));
|
||||||
j = int128(uint128(uint8(data[62])));
|
j = int128(uint128(uint8(data[62])));
|
||||||
tokenApprovalNeeded = data[63] != 0;
|
tokenApprovalNeeded = data[63] != 0;
|
||||||
transferType = TransferType(uint8(data[64]));
|
transferNeeded = data[64] != 0;
|
||||||
receiver = address(bytes20(data[65:85]));
|
receiver = address(bytes20(data[65:85]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol";
|
|||||||
import {LibBytes} from "@solady/utils/LibBytes.sol";
|
import {LibBytes} from "@solady/utils/LibBytes.sol";
|
||||||
import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol";
|
import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol";
|
||||||
import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol";
|
import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol";
|
||||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
import "../OneTransferFromOnly.sol";
|
||||||
|
|
||||||
contract EkuboExecutor is
|
contract EkuboExecutor is
|
||||||
IExecutor,
|
IExecutor,
|
||||||
ILocker,
|
ILocker,
|
||||||
IPayer,
|
IPayer,
|
||||||
ICallback,
|
ICallback,
|
||||||
TokenTransfer
|
OneTransferFromOnly
|
||||||
{
|
{
|
||||||
error EkuboExecutor__InvalidDataLength();
|
error EkuboExecutor__InvalidDataLength();
|
||||||
error EkuboExecutor__CoreOnly();
|
error EkuboExecutor__CoreOnly();
|
||||||
@@ -32,7 +32,9 @@ contract EkuboExecutor is
|
|||||||
bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256)
|
bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256)
|
||||||
bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address)
|
bytes4 constant PAY_CALLBACK_SELECTOR = 0x599d0714; // payCallback(uint256,address)
|
||||||
|
|
||||||
constructor(address _core, address _permit2) TokenTransfer(_permit2) {
|
constructor(address _core, address _permit2)
|
||||||
|
OneTransferFromOnly(_permit2)
|
||||||
|
{
|
||||||
core = ICore(_core);
|
core = ICore(_core);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,13 +46,8 @@ contract EkuboExecutor is
|
|||||||
if (data.length < 93) revert EkuboExecutor__InvalidDataLength();
|
if (data.length < 93) revert EkuboExecutor__InvalidDataLength();
|
||||||
|
|
||||||
// amountIn must be at most type(int128).MAX
|
// amountIn must be at most type(int128).MAX
|
||||||
calculatedAmount = uint256(
|
calculatedAmount =
|
||||||
_lock(
|
uint256(_lock(bytes.concat(bytes16(uint128(amountIn)), data)));
|
||||||
bytes.concat(
|
|
||||||
bytes16(uint128(amountIn)), bytes20(msg.sender), data
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCallback(bytes calldata raw)
|
function handleCallback(bytes calldata raw)
|
||||||
@@ -126,10 +123,11 @@ contract EkuboExecutor is
|
|||||||
int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16])));
|
int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16])));
|
||||||
uint128 tokenInDebtAmount = uint128(nextAmountIn);
|
uint128 tokenInDebtAmount = uint128(nextAmountIn);
|
||||||
address sender = address(bytes20(swapData[16:36]));
|
address sender = address(bytes20(swapData[16:36]));
|
||||||
uint8 transferType = uint8(swapData[36]);
|
bool transferFromNeeded = (swapData[36] != 0);
|
||||||
|
bool transferNeeded = (swapData[37] != 0);
|
||||||
|
|
||||||
address receiver = address(bytes20(swapData[37:57]));
|
address receiver = address(bytes20(swapData[38:58]));
|
||||||
address tokenIn = address(bytes20(swapData[57:77]));
|
address tokenIn = address(bytes20(swapData[58:78]));
|
||||||
|
|
||||||
address nextTokenIn = tokenIn;
|
address nextTokenIn = tokenIn;
|
||||||
|
|
||||||
@@ -163,7 +161,7 @@ contract EkuboExecutor is
|
|||||||
offset += HOP_BYTE_LEN;
|
offset += HOP_BYTE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
_pay(tokenIn, tokenInDebtAmount, sender, transferType);
|
_pay(tokenIn, tokenInDebtAmount, transferFromNeeded, transferNeeded);
|
||||||
core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn));
|
core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn));
|
||||||
return nextAmountIn;
|
return nextAmountIn;
|
||||||
}
|
}
|
||||||
@@ -171,8 +169,8 @@ contract EkuboExecutor is
|
|||||||
function _pay(
|
function _pay(
|
||||||
address token,
|
address token,
|
||||||
uint128 amount,
|
uint128 amount,
|
||||||
address sender,
|
bool transferFromNeeded,
|
||||||
uint8 transferType
|
bool transferNeeded
|
||||||
) internal {
|
) internal {
|
||||||
address target = address(core);
|
address target = address(core);
|
||||||
|
|
||||||
@@ -186,11 +184,11 @@ contract EkuboExecutor is
|
|||||||
mstore(free, shl(224, 0x0c11dedd))
|
mstore(free, shl(224, 0x0c11dedd))
|
||||||
mstore(add(free, 4), token)
|
mstore(add(free, 4), token)
|
||||||
mstore(add(free, 36), shl(128, amount))
|
mstore(add(free, 36), shl(128, amount))
|
||||||
mstore(add(free, 52), shl(96, sender))
|
mstore(add(free, 52), shl(248, transferFromNeeded))
|
||||||
mstore(add(free, 72), shl(248, transferType))
|
mstore(add(free, 53), shl(248, transferNeeded))
|
||||||
|
|
||||||
// 4 (selector) + 32 (token) + 16 (amount) + 20 (sender) + 1 (transferType) = 73
|
// 4 (selector) + 32 (token) + 16 (amount) + 1 (transferFromNeeded) + 1 (transferNeeded) = 54
|
||||||
if iszero(call(gas(), target, 0, free, 73, 0, 0)) {
|
if iszero(call(gas(), target, 0, free, 54, 0, 0)) {
|
||||||
returndatacopy(0, 0, returndatasize())
|
returndatacopy(0, 0, returndatasize())
|
||||||
revert(0, returndatasize())
|
revert(0, returndatasize())
|
||||||
}
|
}
|
||||||
@@ -201,9 +199,17 @@ contract EkuboExecutor is
|
|||||||
function _payCallback(bytes calldata payData) internal {
|
function _payCallback(bytes calldata payData) internal {
|
||||||
address token = address(bytes20(payData[12:32])); // This arg is abi-encoded
|
address token = address(bytes20(payData[12:32])); // This arg is abi-encoded
|
||||||
uint128 amount = uint128(bytes16(payData[32:48]));
|
uint128 amount = uint128(bytes16(payData[32:48]));
|
||||||
address sender = address(bytes20(payData[48:68]));
|
bool transferFromNeeded = (payData[48] != 0);
|
||||||
TransferType transferType = TransferType(uint8(payData[68]));
|
bool transferNeeded = (payData[49] != 0);
|
||||||
_transfer(token, sender, address(core), amount, transferType);
|
if (transferFromNeeded) {
|
||||||
|
_transfer(msg.sender);
|
||||||
|
} else if (transferNeeded) {
|
||||||
|
if (token == address(0)) {
|
||||||
|
payable(msg.sender).transfer(amount);
|
||||||
|
} else {
|
||||||
|
IERC20(token).transfer(msg.sender, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To receive withdrawals from Core
|
// To receive withdrawals from Core
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ error MaverickV2Executor__InvalidDataLength();
|
|||||||
error MaverickV2Executor__InvalidTarget();
|
error MaverickV2Executor__InvalidTarget();
|
||||||
error MaverickV2Executor__InvalidFactory();
|
error MaverickV2Executor__InvalidFactory();
|
||||||
|
|
||||||
contract MaverickV2Executor is IExecutor, TokenTransfer {
|
contract MaverickV2Executor is IExecutor {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
address public immutable factory;
|
address public immutable factory;
|
||||||
|
|
||||||
constructor(address _factory, address _permit2) TokenTransfer(_permit2) {
|
constructor(address _factory, address _permit2) {
|
||||||
if (_factory == address(0)) {
|
if (_factory == address(0)) {
|
||||||
revert MaverickV2Executor__InvalidFactory();
|
revert MaverickV2Executor__InvalidFactory();
|
||||||
}
|
}
|
||||||
@@ -30,9 +30,9 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
|||||||
address target;
|
address target;
|
||||||
address receiver;
|
address receiver;
|
||||||
IERC20 tokenIn;
|
IERC20 tokenIn;
|
||||||
TransferType transferType;
|
bool transferNeeded;
|
||||||
|
|
||||||
(tokenIn, target, receiver, transferType) = _decodeData(data);
|
(tokenIn, target, receiver, transferNeeded) = _decodeData(data);
|
||||||
|
|
||||||
_verifyPairAddress(target);
|
_verifyPairAddress(target);
|
||||||
IMaverickV2Pool pool = IMaverickV2Pool(target);
|
IMaverickV2Pool pool = IMaverickV2Pool(target);
|
||||||
@@ -47,9 +47,15 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
|||||||
tickLimit: tickLimit
|
tickLimit: tickLimit
|
||||||
});
|
});
|
||||||
|
|
||||||
_transfer(
|
if (transferNeeded) {
|
||||||
address(tokenIn), msg.sender, target, givenAmount, transferType
|
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 unused-return
|
// slither-disable-next-line unused-return
|
||||||
(, calculatedAmount) = pool.swap(receiver, swapParams, "");
|
(, calculatedAmount) = pool.swap(receiver, swapParams, "");
|
||||||
}
|
}
|
||||||
@@ -61,7 +67,7 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
|||||||
IERC20 inToken,
|
IERC20 inToken,
|
||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (data.length != 61) {
|
if (data.length != 61) {
|
||||||
@@ -70,7 +76,7 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
|||||||
inToken = IERC20(address(bytes20(data[0:20])));
|
inToken = IERC20(address(bytes20(data[0:20])));
|
||||||
target = address(bytes20(data[20:40]));
|
target = address(bytes20(data[20:40]));
|
||||||
receiver = address(bytes20(data[40:60]));
|
receiver = address(bytes20(data[40:60]));
|
||||||
transferType = TransferType(uint8(data[60]));
|
transferNeeded = (data[60] != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _verifyPairAddress(address target) internal view {
|
function _verifyPairAddress(address target) internal view {
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ contract UniswapV2Executor is IExecutor {
|
|||||||
|
|
||||||
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
||||||
|
|
||||||
if (transferNeeded){
|
if (transferNeeded) {
|
||||||
if (tokenIn == address(0)) {
|
if (address(tokenIn) == address(0)) {
|
||||||
payable(target).transfer(givenAmount);
|
payable(target).transfer(givenAmount);
|
||||||
} else {
|
} else {
|
||||||
// slither-disable-next-line arbitrary-send-erc20
|
// slither-disable-next-line arbitrary-send-erc20
|
||||||
@@ -93,8 +93,8 @@ contract UniswapV2Executor is IExecutor {
|
|||||||
inToken = IERC20(address(bytes20(data[0:20])));
|
inToken = IERC20(address(bytes20(data[0:20])));
|
||||||
target = address(bytes20(data[20:40]));
|
target = address(bytes20(data[20:40]));
|
||||||
receiver = address(bytes20(data[40:60]));
|
receiver = address(bytes20(data[40:60]));
|
||||||
zeroForOne = uint8(data[60]) > 0;
|
zeroForOne = data[60] != 0;
|
||||||
transferNeeded = bool(data[61]);
|
transferNeeded = data[61] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getAmountOut(address target, uint256 amountIn, bool zeroForOne)
|
function _getAmountOut(address target, uint256 amountIn, bool zeroForOne)
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
bool inTransferNeeded,
|
bool transferFromNeeded,
|
||||||
bool inBetweenSwapsTransferNeeded
|
bool transferNeeded
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
_verifyPairAddress(tokenIn, tokenOut, fee, target);
|
_verifyPairAddress(tokenIn, tokenOut, fee, target);
|
||||||
@@ -62,11 +62,7 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
|||||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||||
|
|
||||||
bytes memory callbackData = _makeV3CallbackData(
|
bytes memory callbackData = _makeV3CallbackData(
|
||||||
tokenIn,
|
tokenIn, tokenOut, fee, transferFromNeeded, transferNeeded
|
||||||
tokenOut,
|
|
||||||
fee,
|
|
||||||
inTransferNeeded,
|
|
||||||
inBetweenSwapsTransferNeeded
|
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -104,8 +100,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
|||||||
|
|
||||||
address tokenIn = address(bytes20(msgData[132:152]));
|
address tokenIn = address(bytes20(msgData[132:152]));
|
||||||
|
|
||||||
bool inTransferNeeded = bool(msgData[175]);
|
bool transferFromNeeded = msgData[175] != 0;
|
||||||
bool inBetweenSwapsTransferNeeded = bool(msgData[176]);
|
bool transferNeeded = msgData[176] != 0;
|
||||||
address sender = address(bytes20(msgData[176:196]));
|
address sender = address(bytes20(msgData[176:196]));
|
||||||
|
|
||||||
verifyCallback(msgData[132:]);
|
verifyCallback(msgData[132:]);
|
||||||
@@ -113,9 +109,9 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
|||||||
uint256 amountOwed =
|
uint256 amountOwed =
|
||||||
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
|
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
|
||||||
|
|
||||||
if (inTransferNeeded) {
|
if (transferFromNeeded) {
|
||||||
_transfer(msg.sender);
|
_transfer(msg.sender);
|
||||||
} else if (inBetweenSwapsTransferNeeded) {
|
} else if (transferNeeded) {
|
||||||
if (tokenIn == address(0)) {
|
if (tokenIn == address(0)) {
|
||||||
payable(msg.sender).transfer(amountOwed);
|
payable(msg.sender).transfer(amountOwed);
|
||||||
} else {
|
} else {
|
||||||
@@ -152,8 +148,8 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
bool inTransferNeeded,
|
bool transferFromNeeded,
|
||||||
bool inBetweenSwapsTransferNeeded
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (data.length != 85) {
|
if (data.length != 85) {
|
||||||
@@ -165,23 +161,23 @@ contract UniswapV3Executor is IExecutor, ICallback, OneTransferFromOnly {
|
|||||||
receiver = address(bytes20(data[43:63]));
|
receiver = address(bytes20(data[43:63]));
|
||||||
target = address(bytes20(data[63:83]));
|
target = address(bytes20(data[63:83]));
|
||||||
zeroForOne = uint8(data[83]) > 0;
|
zeroForOne = uint8(data[83]) > 0;
|
||||||
inTransferNeeded = bool(data[84]);
|
transferFromNeeded = uint8(data[84]) > 0;
|
||||||
inBetweenSwapsTransferNeeded = bool(data[85]);
|
transferNeeded = uint8(data[85]) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _makeV3CallbackData(
|
function _makeV3CallbackData(
|
||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
uint24 fee,
|
uint24 fee,
|
||||||
bool inTransferNeeded,
|
bool transferFromNeeded,
|
||||||
bool inBetweenSwapsTransferNeeded
|
bool transferNeeded
|
||||||
) internal view returns (bytes memory) {
|
) internal view returns (bytes memory) {
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
fee,
|
fee,
|
||||||
inTransferNeeded,
|
transferFromNeeded,
|
||||||
inBetweenSwapsTransferNeeded,
|
transferNeeded,
|
||||||
msg.sender
|
msg.sender
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ pragma solidity ^0.8.26;
|
|||||||
|
|
||||||
import "@interfaces/IExecutor.sol";
|
import "@interfaces/IExecutor.sol";
|
||||||
import {ICallback} from "@interfaces/ICallback.sol";
|
import {ICallback} from "@interfaces/ICallback.sol";
|
||||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
|
||||||
import {
|
import {
|
||||||
IERC20,
|
IERC20,
|
||||||
SafeERC20
|
SafeERC20
|
||||||
@@ -23,6 +22,7 @@ import {IUnlockCallback} from
|
|||||||
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
|
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
|
||||||
import {TransientStateLibrary} from
|
import {TransientStateLibrary} from
|
||||||
"@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
"@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
||||||
|
import "../OneTransferFromOnly.sol";
|
||||||
|
|
||||||
error UniswapV4Executor__InvalidDataLength();
|
error UniswapV4Executor__InvalidDataLength();
|
||||||
error UniswapV4Executor__NotPoolManager();
|
error UniswapV4Executor__NotPoolManager();
|
||||||
@@ -37,7 +37,7 @@ contract UniswapV4Executor is
|
|||||||
IExecutor,
|
IExecutor,
|
||||||
IUnlockCallback,
|
IUnlockCallback,
|
||||||
ICallback,
|
ICallback,
|
||||||
TokenTransfer
|
OneTransferFromOnly
|
||||||
{
|
{
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
using CurrencyLibrary for Currency;
|
using CurrencyLibrary for Currency;
|
||||||
@@ -57,7 +57,7 @@ contract UniswapV4Executor is
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(IPoolManager _poolManager, address _permit2)
|
constructor(IPoolManager _poolManager, address _permit2)
|
||||||
TokenTransfer(_permit2)
|
OneTransferFromOnly(_permit2)
|
||||||
{
|
{
|
||||||
poolManager = _poolManager;
|
poolManager = _poolManager;
|
||||||
_self = address(this);
|
_self = address(this);
|
||||||
@@ -82,7 +82,8 @@ contract UniswapV4Executor is
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TransferType transferType,
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
@@ -100,8 +101,8 @@ contract UniswapV4Executor is
|
|||||||
key,
|
key,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
amountIn,
|
amountIn,
|
||||||
msg.sender,
|
transferFromNeeded,
|
||||||
transferType,
|
transferNeeded,
|
||||||
receiver,
|
receiver,
|
||||||
bytes("")
|
bytes("")
|
||||||
);
|
);
|
||||||
@@ -123,8 +124,8 @@ contract UniswapV4Executor is
|
|||||||
currencyIn,
|
currencyIn,
|
||||||
path,
|
path,
|
||||||
amountIn,
|
amountIn,
|
||||||
msg.sender,
|
transferFromNeeded,
|
||||||
transferType,
|
transferNeeded,
|
||||||
receiver
|
receiver
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -142,24 +143,26 @@ contract UniswapV4Executor is
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TransferType transferType,
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Pool[] memory pools
|
UniswapV4Pool[] memory pools
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (data.length < 88) {
|
if (data.length < 89) {
|
||||||
revert UniswapV4Executor__InvalidDataLength();
|
revert UniswapV4Executor__InvalidDataLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenIn = address(bytes20(data[0:20]));
|
tokenIn = address(bytes20(data[0:20]));
|
||||||
tokenOut = address(bytes20(data[20:40]));
|
tokenOut = address(bytes20(data[20:40]));
|
||||||
zeroForOne = (data[40] != 0);
|
zeroForOne = (data[40] != 0);
|
||||||
transferType = TransferType(uint8(data[41]));
|
transferFromNeeded = (data[41] != 0);
|
||||||
receiver = address(bytes20(data[42:62]));
|
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);
|
pools = new UniswapV4Pool[](poolsLength);
|
||||||
bytes memory poolsData = data[62:];
|
bytes memory poolsData = data[63:];
|
||||||
uint256 offset = 0;
|
uint256 offset = 0;
|
||||||
for (uint256 i = 0; i < poolsLength; i++) {
|
for (uint256 i = 0; i < poolsLength; i++) {
|
||||||
address intermediaryToken;
|
address intermediaryToken;
|
||||||
@@ -239,8 +242,8 @@ contract UniswapV4Executor is
|
|||||||
* @param poolKey The key of the pool to swap in.
|
* @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 zeroForOne Whether the swap is from token0 to token1 (true) or vice versa (false).
|
||||||
* @param amountIn The amount of tokens to swap in.
|
* @param amountIn The amount of tokens to swap in.
|
||||||
* @param sender The address of the sender.
|
* @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet .
|
||||||
* @param transferType The type of transfer in to use.
|
* @param transferNeeded Whether to transfer input tokens into the core contract from the router contract
|
||||||
* @param receiver The address of the receiver.
|
* @param receiver The address of the receiver.
|
||||||
* @param hookData Additional data for hook contracts.
|
* @param hookData Additional data for hook contracts.
|
||||||
*/
|
*/
|
||||||
@@ -248,8 +251,8 @@ contract UniswapV4Executor is
|
|||||||
PoolKey memory poolKey,
|
PoolKey memory poolKey,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
uint128 amountIn,
|
uint128 amountIn,
|
||||||
address sender,
|
bool transferFromNeeded,
|
||||||
TransferType transferType,
|
bool transferNeeded,
|
||||||
address receiver,
|
address receiver,
|
||||||
bytes calldata hookData
|
bytes calldata hookData
|
||||||
) external returns (uint128) {
|
) external returns (uint128) {
|
||||||
@@ -262,7 +265,7 @@ contract UniswapV4Executor is
|
|||||||
if (amount > amountIn) {
|
if (amount > amountIn) {
|
||||||
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||||
}
|
}
|
||||||
_settle(currencyIn, amount, sender, transferType);
|
_settle(currencyIn, amount, transferFromNeeded, transferNeeded);
|
||||||
|
|
||||||
Currency currencyOut =
|
Currency currencyOut =
|
||||||
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
||||||
@@ -275,16 +278,16 @@ contract UniswapV4Executor is
|
|||||||
* @param currencyIn The currency of the input token.
|
* @param currencyIn The currency of the input token.
|
||||||
* @param path The path to swap along.
|
* @param path The path to swap along.
|
||||||
* @param amountIn The amount of tokens to swap in.
|
* @param amountIn The amount of tokens to swap in.
|
||||||
* @param sender The address of the sender.
|
* @param transferFromNeeded Whether to transferFrom input tokens into the core contract from the swapper's wallet .
|
||||||
* @param transferType The type of transfer in to use.
|
* @param transferNeeded Whether to transfer input tokens into the core contract from the router contract
|
||||||
* @param receiver The address of the receiver.
|
* @param receiver The address of the receiver.
|
||||||
*/
|
*/
|
||||||
function swapExactInput(
|
function swapExactInput(
|
||||||
Currency currencyIn,
|
Currency currencyIn,
|
||||||
PathKey[] calldata path,
|
PathKey[] calldata path,
|
||||||
uint128 amountIn,
|
uint128 amountIn,
|
||||||
address sender,
|
bool transferFromNeeded,
|
||||||
TransferType transferType,
|
bool transferNeeded,
|
||||||
address receiver
|
address receiver
|
||||||
) external returns (uint128) {
|
) external returns (uint128) {
|
||||||
uint128 amountOut = 0;
|
uint128 amountOut = 0;
|
||||||
@@ -315,7 +318,7 @@ contract UniswapV4Executor is
|
|||||||
if (amount > amountIn) {
|
if (amount > amountIn) {
|
||||||
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||||
}
|
}
|
||||||
_settle(currencyIn, amount, sender, transferType);
|
_settle(currencyIn, amount, transferFromNeeded, transferNeeded);
|
||||||
|
|
||||||
_take(
|
_take(
|
||||||
swapCurrencyIn, // at the end of the loop this is actually currency out
|
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.
|
* @dev The implementing contract must ensure that the `payer` is a secure address.
|
||||||
* @param currency The currency to settle.
|
* @param currency The currency to settle.
|
||||||
* @param amount The amount to send.
|
* @param amount The amount to send.
|
||||||
* @param sender The address of the payer.
|
* @param transferFromNeeded Whether to manually transferFrom input tokens into the
|
||||||
* @param transferType The type of transfer to use.
|
* 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.
|
* @dev Returns early if the amount is 0.
|
||||||
*/
|
*/
|
||||||
function _settle(
|
function _settle(
|
||||||
Currency currency,
|
Currency currency,
|
||||||
uint256 amount,
|
uint256 amount,
|
||||||
address sender,
|
bool transferFromNeeded,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
) internal {
|
) internal {
|
||||||
if (amount == 0) return;
|
if (amount == 0) return;
|
||||||
poolManager.sync(currency);
|
poolManager.sync(currency);
|
||||||
@@ -403,13 +408,18 @@ contract UniswapV4Executor is
|
|||||||
// slither-disable-next-line unused-return
|
// slither-disable-next-line unused-return
|
||||||
poolManager.settle{value: amount}();
|
poolManager.settle{value: amount}();
|
||||||
} else {
|
} else {
|
||||||
_transfer(
|
if (transferFromNeeded) {
|
||||||
Currency.unwrap(currency),
|
// transferFrom swapper's wallet into the core contract
|
||||||
sender,
|
_transfer(msg.sender);
|
||||||
address(poolManager),
|
} else if (transferNeeded) {
|
||||||
amount,
|
address tokenIn = Currency.unwrap(currency);
|
||||||
transferType
|
// 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
|
// slither-disable-next-line unused-return
|
||||||
poolManager.settle();
|
poolManager.settle();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
USDT_ADDR,
|
USDT_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL,
|
true, // permit2 transferFrom to protocol
|
||||||
|
false, // transfer to protocol
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -44,6 +45,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
false,
|
||||||
|
address(0),
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -74,7 +77,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
WBTC_ADDR,
|
WBTC_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
true, // permit2 transferFrom to protocol
|
||||||
|
false, // transfer to protocol
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -83,7 +87,16 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||||
|
|
||||||
tychoRouter.singleSwap(
|
tychoRouter.singleSwap(
|
||||||
amountIn, USDE_ADDR, WBTC_ADDR, 118280, false, false, ALICE, swap
|
amountIn,
|
||||||
|
USDE_ADDR,
|
||||||
|
WBTC_ADDR,
|
||||||
|
118280,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
ALICE,
|
||||||
|
false,
|
||||||
|
address(0),
|
||||||
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281);
|
assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281);
|
||||||
@@ -262,7 +275,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
DAI_WETH_USV3,
|
DAI_WETH_USV3,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
true, // permit2 transferFrom to protocol
|
||||||
|
false // transfer to protocol
|
||||||
);
|
);
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
encodeSingleSwap(address(usv3Executor), protocolData);
|
encodeSingleSwap(address(usv3Executor), protocolData);
|
||||||
@@ -277,6 +291,8 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
false,
|
||||||
|
address(0),
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,25 +8,21 @@ import "./executors/UniswapV4Utils.sol";
|
|||||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||||
|
|
||||||
contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||||
function _getSequentialSwaps(bool permit2)
|
function _getSequentialSwaps() internal view returns (bytes[] memory) {
|
||||||
internal
|
|
||||||
view
|
|
||||||
returns (bytes[] memory)
|
|
||||||
{
|
|
||||||
// Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2
|
// Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2
|
||||||
// 1 WETH -> DAI -> USDC
|
// 1 WETH -> DAI -> USDC
|
||||||
// (univ2) (univ2)
|
// (univ2) (univ2)
|
||||||
|
|
||||||
TokenTransfer.TransferType transferType = permit2
|
|
||||||
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
|
||||||
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
|
||||||
|
|
||||||
bytes[] memory swaps = new bytes[](2);
|
bytes[] memory swaps = new bytes[](2);
|
||||||
// WETH -> DAI
|
// WETH -> DAI
|
||||||
swaps[0] = encodeSequentialSwap(
|
swaps[0] = encodeSequentialSwap(
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, transferType
|
WETH_ADDR,
|
||||||
|
WETH_DAI_POOL,
|
||||||
|
DAI_USDC_POOL, // receiver (direct to next pool)
|
||||||
|
false,
|
||||||
|
false // transfer to protocol from router
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -38,7 +34,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
DAI_USDC_POOL,
|
DAI_USDC_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false // transfer to protocol from router
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return swaps;
|
return swaps;
|
||||||
@@ -55,7 +51,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
bytes memory signature
|
bytes memory signature
|
||||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSequentialSwaps(true);
|
bytes[] memory swaps = _getSequentialSwaps();
|
||||||
tychoRouter.sequentialSwapPermit2(
|
tychoRouter.sequentialSwapPermit2(
|
||||||
amountIn,
|
amountIn,
|
||||||
WETH_ADDR,
|
WETH_ADDR,
|
||||||
@@ -66,6 +62,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSequentialSwaps(false);
|
bytes[] memory swaps = _getSequentialSwaps();
|
||||||
tychoRouter.sequentialSwap(
|
tychoRouter.sequentialSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
WETH_ADDR,
|
WETH_ADDR,
|
||||||
@@ -91,6 +89,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSequentialSwaps(false);
|
bytes[] memory swaps = _getSequentialSwaps();
|
||||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||||
tychoRouter.sequentialSwap(
|
tychoRouter.sequentialSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -117,6 +117,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -129,7 +131,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn - 1);
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn - 1);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSequentialSwaps(false);
|
bytes[] memory swaps = _getSequentialSwaps();
|
||||||
vm.expectRevert();
|
vm.expectRevert();
|
||||||
tychoRouter.sequentialSwap(
|
tychoRouter.sequentialSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -139,6 +141,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -154,7 +158,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
bytes memory signature
|
bytes memory signature
|
||||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSequentialSwaps(true);
|
bytes[] memory swaps = _getSequentialSwaps();
|
||||||
|
|
||||||
uint256 minAmountOut = 3000 * 1e18;
|
uint256 minAmountOut = 3000 * 1e18;
|
||||||
|
|
||||||
@@ -175,6 +179,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -202,24 +208,14 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
swaps[0] = encodeSequentialSwap(
|
swaps[0] = encodeSequentialSwap(
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
WETH_ADDR,
|
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true
|
||||||
WETH_DAI_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
false,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// DAI -> USDC
|
// DAI -> USDC
|
||||||
swaps[1] = encodeSequentialSwap(
|
swaps[1] = encodeSequentialSwap(
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true)
|
||||||
DAI_ADDR,
|
|
||||||
DAI_USDC_POOL,
|
|
||||||
ALICE,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}(
|
uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}(
|
||||||
@@ -232,6 +228,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
emptyPermitSingle,
|
emptyPermitSingle,
|
||||||
"",
|
"",
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
uint256 expectedAmount = 2005810530;
|
uint256 expectedAmount = 2005810530;
|
||||||
@@ -262,11 +260,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
swaps[0] = encodeSequentialSwap(
|
swaps[0] = encodeSequentialSwap(
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
USDC_ADDR,
|
USDC_ADDR, DAI_USDC_POOL, tychoRouterAddr, false, false
|
||||||
DAI_USDC_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
false,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -274,11 +268,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
swaps[1] = encodeSequentialSwap(
|
swaps[1] = encodeSequentialSwap(
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
DAI_ADDR,
|
DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true
|
||||||
WETH_DAI_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -292,6 +282,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true,
|
||||||
|
DAI_USDC_POOL,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -315,7 +307,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3,
|
USDC_WETH_USV3,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
||||||
@@ -324,7 +317,8 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3_2,
|
USDC_WETH_USV3_2,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false, // permit2 transferFrom to protocol
|
||||||
|
true // transfer to protocol
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes[] memory swaps = new bytes[](2);
|
bytes[] memory swaps = new bytes[](2);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
false // funds already in WETH_DAI_POOL, no transfer necessary
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -42,6 +42,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true, // transferFrom to WETH_DAI_POOL
|
||||||
|
WETH_DAI_POOL, // receiver of input tokens
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
false // funds already in WETH_DAI_POOL, no transfer necessary
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -82,6 +84,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -103,20 +107,24 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
||||||
|
|
||||||
bytes memory protocolData = encodeUniswapV2Swap(
|
bytes memory protocolData =
|
||||||
WETH_ADDR,
|
encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, false);
|
||||||
WETH_DAI_POOL,
|
|
||||||
ALICE,
|
|
||||||
false,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
|
||||||
);
|
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
encodeSingleSwap(address(usv2Executor), protocolData);
|
encodeSingleSwap(address(usv2Executor), protocolData);
|
||||||
|
|
||||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||||
tychoRouter.singleSwap(
|
tychoRouter.singleSwap(
|
||||||
amountIn, WETH_ADDR, DAI_ADDR, 0, false, false, ALICE, swap
|
amountIn,
|
||||||
|
WETH_ADDR,
|
||||||
|
DAI_ADDR,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
|
swap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +142,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
false // funds already in WETH_DAI_POOL, no transfer necessary
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -150,6 +158,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -169,7 +179,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
false // funds already in WETH_DAI_POOL, no transfer necessary
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -192,6 +202,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
WETH_DAI_POOL,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -213,13 +225,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
sigDeadline: 0
|
sigDeadline: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
bytes memory protocolData = encodeUniswapV2Swap(
|
bytes memory protocolData =
|
||||||
WETH_ADDR,
|
encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true);
|
||||||
WETH_DAI_POOL,
|
|
||||||
ALICE,
|
|
||||||
false,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
);
|
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
encodeSingleSwap(address(usv2Executor), protocolData);
|
encodeSingleSwap(address(usv2Executor), protocolData);
|
||||||
@@ -234,6 +241,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
emptyPermitSingle,
|
emptyPermitSingle,
|
||||||
"",
|
"",
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
uint256 expectedAmount = 2018817438608734439722;
|
uint256 expectedAmount = 2018817438608734439722;
|
||||||
@@ -257,11 +266,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
|
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes memory protocolData = encodeUniswapV2Swap(
|
bytes memory protocolData = encodeUniswapV2Swap(
|
||||||
DAI_ADDR,
|
DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, false
|
||||||
WETH_DAI_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -277,6 +282,8 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true, // transferFrom to WETH_DAI_POOL
|
||||||
|
WETH_DAI_POOL, // receiver of input tokens
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,7 @@ import "./executors/UniswapV4Utils.sol";
|
|||||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||||
|
|
||||||
contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||||
function _getSplitSwaps(bool permit2)
|
function _getSplitSwaps() private view returns (bytes[] memory) {
|
||||||
private
|
|
||||||
view
|
|
||||||
returns (bytes[] memory)
|
|
||||||
{
|
|
||||||
// Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2
|
// Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2
|
||||||
// -> DAI ->
|
// -> DAI ->
|
||||||
// 1 WETH USDC
|
// 1 WETH USDC
|
||||||
@@ -20,10 +16,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
// (univ2) (univ2)
|
// (univ2) (univ2)
|
||||||
bytes[] memory swaps = new bytes[](4);
|
bytes[] memory swaps = new bytes[](4);
|
||||||
|
|
||||||
TokenTransfer.TransferType inTransferType = permit2
|
|
||||||
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
|
||||||
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
|
||||||
|
|
||||||
// WETH -> WBTC (60%)
|
// WETH -> WBTC (60%)
|
||||||
swaps[0] = encodeSplitSwap(
|
swaps[0] = encodeSplitSwap(
|
||||||
uint8(0),
|
uint8(0),
|
||||||
@@ -31,11 +23,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
(0xffffff * 60) / 100, // 60%
|
(0xffffff * 60) / 100, // 60%
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
WETH_ADDR,
|
WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false, true
|
||||||
WETH_WBTC_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
false,
|
|
||||||
inTransferType
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// WBTC -> USDC
|
// WBTC -> USDC
|
||||||
@@ -44,13 +32,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
uint8(2),
|
uint8(2),
|
||||||
uint24(0),
|
uint24(0),
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true, true)
|
||||||
WBTC_ADDR,
|
|
||||||
USDC_WBTC_POOL,
|
|
||||||
ALICE,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
// WETH -> DAI
|
// WETH -> DAI
|
||||||
swaps[2] = encodeSplitSwap(
|
swaps[2] = encodeSplitSwap(
|
||||||
@@ -59,7 +41,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
uint24(0),
|
uint24(0),
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, inTransferType
|
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -69,13 +51,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
uint8(2),
|
uint8(2),
|
||||||
uint24(0),
|
uint24(0),
|
||||||
address(usv2Executor),
|
address(usv2Executor),
|
||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true)
|
||||||
DAI_ADDR,
|
|
||||||
DAI_USDC_POOL,
|
|
||||||
ALICE,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return swaps;
|
return swaps;
|
||||||
@@ -85,10 +61,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
// Trade 1 WETH for USDC through DAI and WBTC - see _getSplitSwaps for more info
|
// Trade 1 WETH for USDC through DAI and WBTC - see _getSplitSwaps for more info
|
||||||
|
|
||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(WETH_ADDR, ALICE, amountIn);
|
deal(WETH_ADDR, address(tychoRouterAddr), amountIn);
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
bytes[] memory swaps = _getSplitSwaps();
|
||||||
bytes[] memory swaps = _getSplitSwaps(false);
|
|
||||||
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
|
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
|
|
||||||
@@ -109,7 +84,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
bytes memory signature
|
bytes memory signature
|
||||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSplitSwaps(true);
|
bytes[] memory swaps = _getSplitSwaps();
|
||||||
|
|
||||||
tychoRouter.splitSwapPermit2(
|
tychoRouter.splitSwapPermit2(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -122,6 +97,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -138,7 +115,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSplitSwaps(false);
|
bytes[] memory swaps = _getSplitSwaps();
|
||||||
|
|
||||||
tychoRouter.splitSwap(
|
tychoRouter.splitSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -149,6 +126,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
4,
|
4,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -165,7 +144,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSplitSwaps(false);
|
bytes[] memory swaps = _getSplitSwaps();
|
||||||
|
|
||||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||||
tychoRouter.splitSwap(
|
tychoRouter.splitSwap(
|
||||||
@@ -177,6 +156,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
4,
|
4,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -190,7 +171,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
// Approve less than the amountIn
|
// Approve less than the amountIn
|
||||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1);
|
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1);
|
||||||
bytes[] memory swaps = _getSplitSwaps(false);
|
bytes[] memory swaps = _getSplitSwaps();
|
||||||
|
|
||||||
vm.expectRevert();
|
vm.expectRevert();
|
||||||
tychoRouter.splitSwap(
|
tychoRouter.splitSwap(
|
||||||
@@ -202,6 +183,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
2,
|
2,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -219,7 +202,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
bytes memory signature
|
bytes memory signature
|
||||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes[] memory swaps = _getSplitSwaps(true);
|
bytes[] memory swaps = _getSplitSwaps();
|
||||||
|
|
||||||
uint256 minAmountOut = 3000 * 1e18;
|
uint256 minAmountOut = 3000 * 1e18;
|
||||||
|
|
||||||
@@ -241,6 +224,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -265,13 +250,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
spender: address(0),
|
spender: address(0),
|
||||||
sigDeadline: 0
|
sigDeadline: 0
|
||||||
});
|
});
|
||||||
bytes memory protocolData = encodeUniswapV2Swap(
|
bytes memory protocolData =
|
||||||
WETH_ADDR,
|
encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true);
|
||||||
WETH_DAI_POOL,
|
|
||||||
ALICE,
|
|
||||||
false,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
);
|
|
||||||
|
|
||||||
bytes memory swap = encodeSplitSwap(
|
bytes memory swap = encodeSplitSwap(
|
||||||
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
|
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
|
||||||
@@ -290,6 +270,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
emptyPermitSingle,
|
emptyPermitSingle,
|
||||||
"",
|
"",
|
||||||
|
false,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
uint256 expectedAmount = 2018817438608734439722;
|
uint256 expectedAmount = 2018817438608734439722;
|
||||||
@@ -315,11 +297,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
|
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes memory protocolData = encodeUniswapV2Swap(
|
bytes memory protocolData = encodeUniswapV2Swap(
|
||||||
DAI_ADDR,
|
DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true
|
||||||
WETH_DAI_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap = encodeSplitSwap(
|
bytes memory swap = encodeSplitSwap(
|
||||||
@@ -339,6 +317,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
permitSingle,
|
permitSingle,
|
||||||
signature,
|
signature,
|
||||||
|
true,
|
||||||
|
tychoRouterAddr,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -365,10 +345,10 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
// │ │
|
// │ │
|
||||||
// └─ (USV3, 40% split) ──> WETH ─┘
|
// └─ (USV3, 40% split) ──> WETH ─┘
|
||||||
uint256 amountIn = 100 * 10 ** 6;
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
deal(USDC_ADDR, ALICE, amountIn);
|
|
||||||
|
// Assume funds have already been transferred to tychoRouter
|
||||||
|
deal(USDC_ADDR, tychoRouterAddr, amountIn);
|
||||||
vm.startPrank(ALICE);
|
vm.startPrank(ALICE);
|
||||||
// Approve the TychoRouter to spend USDC
|
|
||||||
IERC20(USDC_ADDR).approve(tychoRouterAddr, amountIn);
|
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap(
|
||||||
USDC_ADDR,
|
USDC_ADDR,
|
||||||
@@ -376,7 +356,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3,
|
USDC_WETH_USV3,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
false, // transferFrom swapper required
|
||||||
|
true // transfer from tycho router to protocol
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
|
||||||
@@ -385,7 +366,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3_2,
|
USDC_WETH_USV3_2,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
false, // transferFrom swapper required
|
||||||
|
true // transfer from tycho router to protocol
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap(
|
bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap(
|
||||||
@@ -393,7 +375,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDC_WETH_USV2,
|
USDC_WETH_USV2,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
true // transfer from tycho router to protocol
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes[] memory swaps = new bytes[](3);
|
bytes[] memory swaps = new bytes[](3);
|
||||||
@@ -443,7 +425,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDC_WETH_USV2,
|
USDC_WETH_USV2,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
true // transfer required
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap(
|
||||||
@@ -452,7 +434,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3,
|
USDC_WETH_USV3,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false, // transferFrom required
|
||||||
|
true // transfer required
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
||||||
@@ -461,7 +444,8 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3_2,
|
USDC_WETH_USV3_2,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false, // transferFrom required
|
||||||
|
true // transfer required
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes[] memory swaps = new bytes[](3);
|
bytes[] memory swaps = new bytes[](3);
|
||||||
@@ -500,11 +484,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
deal(BASE_USDC, tychoRouterAddr, amountIn);
|
deal(BASE_USDC, tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
bytes memory protocolData = encodeUniswapV2Swap(
|
bytes memory protocolData = encodeUniswapV2Swap(
|
||||||
BASE_USDC,
|
BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true, true
|
||||||
USDC_MAG7_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap = encodeSplitSwap(
|
bytes memory swap = encodeSplitSwap(
|
||||||
|
|||||||
@@ -185,10 +185,11 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
|||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zero2one,
|
bool zero2one,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferNeeded
|
||||||
) internal pure returns (bytes memory) {
|
) internal pure returns (bytes memory) {
|
||||||
return
|
return abi.encodePacked(
|
||||||
abi.encodePacked(tokenIn, target, receiver, zero2one, transferType);
|
tokenIn, target, receiver, zero2one, transferNeeded
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function encodeUniswapV3Swap(
|
function encodeUniswapV3Swap(
|
||||||
@@ -197,7 +198,8 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zero2one,
|
bool zero2one,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded
|
||||||
) internal view returns (bytes memory) {
|
) internal view returns (bytes memory) {
|
||||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
@@ -207,7 +209,8 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
|||||||
receiver,
|
receiver,
|
||||||
target,
|
target,
|
||||||
zero2one,
|
zero2one,
|
||||||
transferType
|
transferFromNeeded,
|
||||||
|
transferNeeded
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ contract BalancerV2ExecutorExposed is BalancerV2Executor {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -41,12 +41,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
|
|
||||||
function testDecodeParams() public view {
|
function testDecodeParams() public view {
|
||||||
bytes memory params = abi.encodePacked(
|
bytes memory params = abi.encodePacked(
|
||||||
WETH_ADDR,
|
WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, address(2), true, false
|
||||||
BAL_ADDR,
|
|
||||||
WETH_BAL_POOL_ID,
|
|
||||||
address(2),
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.NONE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -55,7 +50,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferNeeded
|
||||||
) = balancerV2Exposed.decodeParams(params);
|
) = balancerV2Exposed.decodeParams(params);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
@@ -63,7 +58,6 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
assertEq(poolId, WETH_BAL_POOL_ID);
|
assertEq(poolId, WETH_BAL_POOL_ID);
|
||||||
assertEq(receiver, address(2));
|
assertEq(receiver, address(2));
|
||||||
assertEq(needsApproval, true);
|
assertEq(needsApproval, true);
|
||||||
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParamsInvalidDataLength() public {
|
function testDecodeParamsInvalidDataLength() public {
|
||||||
@@ -77,12 +71,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
function testSwap() public {
|
function testSwap() public {
|
||||||
uint256 amountIn = 10 ** 18;
|
uint256 amountIn = 10 ** 18;
|
||||||
bytes memory protocolData = abi.encodePacked(
|
bytes memory protocolData = abi.encodePacked(
|
||||||
WETH_ADDR,
|
WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, BOB, true, false
|
||||||
BAL_ADDR,
|
|
||||||
WETH_BAL_POOL_ID,
|
|
||||||
BOB,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.NONE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);
|
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);
|
||||||
@@ -104,7 +93,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferNeeded
|
||||||
) = balancerV2Exposed.decodeParams(protocolData);
|
) = balancerV2Exposed.decodeParams(protocolData);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
@@ -112,7 +101,6 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
assertEq(poolId, WETH_BAL_POOL_ID);
|
assertEq(poolId, WETH_BAL_POOL_ID);
|
||||||
assertEq(receiver, BOB);
|
assertEq(receiver, BOB);
|
||||||
assertEq(needsApproval, true);
|
assertEq(needsApproval, true);
|
||||||
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapIntegration() public {
|
function testSwapIntegration() public {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ contract CurveExecutorExposed is CurveExecutor {
|
|||||||
int128 i,
|
int128 i,
|
||||||
int128 j,
|
int128 j,
|
||||||
bool tokenApprovalNeeded,
|
bool tokenApprovalNeeded,
|
||||||
TokenTransfer.TransferType transferType,
|
bool transferNeeded,
|
||||||
address receiver
|
address receiver
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,7 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint8(2),
|
uint8(2),
|
||||||
uint8(0),
|
uint8(0),
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE,
|
false,
|
||||||
ALICE
|
ALICE
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
int128 i,
|
int128 i,
|
||||||
int128 j,
|
int128 j,
|
||||||
bool tokenApprovalNeeded,
|
bool tokenApprovalNeeded,
|
||||||
TokenTransfer.TransferType transferType,
|
bool transferNeeded,
|
||||||
address receiver
|
address receiver
|
||||||
) = curveExecutorExposed.decodeData(data);
|
) = curveExecutorExposed.decodeData(data);
|
||||||
|
|
||||||
@@ -91,7 +91,6 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
assertEq(i, 2);
|
assertEq(i, 2);
|
||||||
assertEq(j, 0);
|
assertEq(j, 0);
|
||||||
assertEq(tokenApprovalNeeded, true);
|
assertEq(tokenApprovalNeeded, true);
|
||||||
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
|
|
||||||
assertEq(receiver, ALICE);
|
assertEq(receiver, ALICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +294,7 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint8(uint256(uint128(i))),
|
uint8(uint256(uint128(i))),
|
||||||
uint8(uint256(uint128(j))),
|
uint8(uint256(uint128(j))),
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE,
|
false,
|
||||||
receiver
|
receiver
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ pragma solidity ^0.8.26;
|
|||||||
|
|
||||||
import "../TestUtils.sol";
|
import "../TestUtils.sol";
|
||||||
import {Constants} from "../Constants.sol";
|
import {Constants} from "../Constants.sol";
|
||||||
import {EkuboExecutor, TokenTransfer} from "@src/executors/EkuboExecutor.sol";
|
import {EkuboExecutor} from "@src/executors/EkuboExecutor.sol";
|
||||||
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
||||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||||
import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol";
|
import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol";
|
||||||
@@ -45,7 +45,7 @@ contract EkuboExecutorTest is Constants, TestUtils {
|
|||||||
uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor));
|
uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor));
|
||||||
|
|
||||||
bytes memory data = abi.encodePacked(
|
bytes memory data = abi.encodePacked(
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), // transferType (transfer from executor to core)
|
true, // transferNeeded (transfer from executor to core)
|
||||||
address(executor), // receiver
|
address(executor), // receiver
|
||||||
NATIVE_TOKEN_ADDRESS, // tokenIn
|
NATIVE_TOKEN_ADDRESS, // tokenIn
|
||||||
USDC_ADDR, // tokenOut
|
USDC_ADDR, // tokenOut
|
||||||
@@ -82,7 +82,7 @@ contract EkuboExecutorTest is Constants, TestUtils {
|
|||||||
uint256 ethBalanceBeforeExecutor = address(executor).balance;
|
uint256 ethBalanceBeforeExecutor = address(executor).balance;
|
||||||
|
|
||||||
bytes memory data = abi.encodePacked(
|
bytes memory data = abi.encodePacked(
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), // transferType (transfer from executor to core)
|
true, // transferNeeded (transfer from executor to core)
|
||||||
address(executor), // receiver
|
address(executor), // receiver
|
||||||
USDC_ADDR, // tokenIn
|
USDC_ADDR, // tokenIn
|
||||||
NATIVE_TOKEN_ADDRESS, // tokenOut
|
NATIVE_TOKEN_ADDRESS, // tokenOut
|
||||||
@@ -140,7 +140,7 @@ contract EkuboExecutorTest is Constants, TestUtils {
|
|||||||
// Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi
|
// Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi
|
||||||
function testMultiHopSwap() public {
|
function testMultiHopSwap() public {
|
||||||
bytes memory data = abi.encodePacked(
|
bytes memory data = abi.encodePacked(
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL), // transferType
|
true, // transferNeeded (transfer from executor to core)
|
||||||
address(executor), // receiver
|
address(executor), // receiver
|
||||||
NATIVE_TOKEN_ADDRESS, // tokenIn
|
NATIVE_TOKEN_ADDRESS, // tokenIn
|
||||||
USDC_ADDR, // tokenOut of 1st swap
|
USDC_ADDR, // tokenOut of 1st swap
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ contract MaverickV2ExecutorExposed is MaverickV2Executor {
|
|||||||
IERC20 tokenIn,
|
IERC20 tokenIn,
|
||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -39,27 +39,16 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParams() public view {
|
function testDecodeParams() public view {
|
||||||
bytes memory params = abi.encodePacked(
|
bytes memory params =
|
||||||
GHO_ADDR,
|
abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, address(2), true);
|
||||||
GHO_USDC_POOL,
|
|
||||||
address(2),
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(IERC20 tokenIn, address target, address receiver, bool transferNeeded)
|
||||||
IERC20 tokenIn,
|
= maverickV2Exposed.decodeParams(params);
|
||||||
address target,
|
|
||||||
address receiver,
|
|
||||||
TokenTransfer.TransferType transferType
|
|
||||||
) = maverickV2Exposed.decodeParams(params);
|
|
||||||
|
|
||||||
assertEq(address(tokenIn), GHO_ADDR);
|
assertEq(address(tokenIn), GHO_ADDR);
|
||||||
assertEq(target, GHO_USDC_POOL);
|
assertEq(target, GHO_USDC_POOL);
|
||||||
assertEq(receiver, address(2));
|
assertEq(receiver, address(2));
|
||||||
assertEq(
|
assertEq(transferNeeded, true);
|
||||||
uint8(transferType),
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParamsInvalidDataLength() public {
|
function testDecodeParamsInvalidDataLength() public {
|
||||||
@@ -72,12 +61,8 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
|
|
||||||
function testSwap() public {
|
function testSwap() public {
|
||||||
uint256 amountIn = 10e18;
|
uint256 amountIn = 10e18;
|
||||||
bytes memory protocolData = abi.encodePacked(
|
bytes memory protocolData =
|
||||||
GHO_ADDR,
|
abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, BOB, true);
|
||||||
GHO_USDC_POOL,
|
|
||||||
BOB,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(GHO_ADDR, address(maverickV2Exposed), amountIn);
|
deal(GHO_ADDR, address(maverickV2Exposed), amountIn);
|
||||||
uint256 balanceBefore = USDC.balanceOf(BOB);
|
uint256 balanceBefore = USDC.balanceOf(BOB);
|
||||||
@@ -94,20 +79,13 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
bytes memory protocolData =
|
bytes memory protocolData =
|
||||||
loadCallDataFromFile("test_encode_maverick_v2");
|
loadCallDataFromFile("test_encode_maverick_v2");
|
||||||
|
|
||||||
(
|
(IERC20 tokenIn, address pool, address receiver, bool transferNeeded) =
|
||||||
IERC20 tokenIn,
|
maverickV2Exposed.decodeParams(protocolData);
|
||||||
address pool,
|
|
||||||
address receiver,
|
|
||||||
TokenTransfer.TransferType transferType
|
|
||||||
) = maverickV2Exposed.decodeParams(protocolData);
|
|
||||||
|
|
||||||
assertEq(address(tokenIn), GHO_ADDR);
|
assertEq(address(tokenIn), GHO_ADDR);
|
||||||
assertEq(pool, GHO_USDC_POOL);
|
assertEq(pool, GHO_USDC_POOL);
|
||||||
assertEq(receiver, BOB);
|
assertEq(receiver, BOB);
|
||||||
assertEq(
|
assertEq(transferNeeded, true);
|
||||||
uint8(transferType),
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapIntegration() public {
|
function testSwapIntegration() public {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
pragma solidity ^0.8.26;
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
import "@src/executors/UniswapV2Executor.sol";
|
import "@src/executors/UniswapV2Executor.sol";
|
||||||
import "@src/executors/TokenTransfer.sol";
|
|
||||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||||
import {Constants} from "../Constants.sol";
|
import {Constants} from "../Constants.sol";
|
||||||
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||||
@@ -23,7 +22,7 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
|||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TransferType transferType
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -60,7 +59,6 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
UniswapV2ExecutorExposed pancakeswapV2Exposed;
|
UniswapV2ExecutorExposed pancakeswapV2Exposed;
|
||||||
IERC20 WETH = IERC20(WETH_ADDR);
|
IERC20 WETH = IERC20(WETH_ADDR);
|
||||||
IERC20 DAI = IERC20(DAI_ADDR);
|
IERC20 DAI = IERC20(DAI_ADDR);
|
||||||
IAllowanceTransfer permit2;
|
|
||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
uint256 forkBlock = 17323404;
|
uint256 forkBlock = 17323404;
|
||||||
@@ -80,34 +78,25 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
PERMIT2_ADDRESS,
|
PERMIT2_ADDRESS,
|
||||||
25
|
25
|
||||||
);
|
);
|
||||||
permit2 = IAllowanceTransfer(PERMIT2_ADDRESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParams() public view {
|
function testDecodeParams() public view {
|
||||||
bytes memory params = abi.encodePacked(
|
bytes memory params =
|
||||||
WETH_ADDR,
|
abi.encodePacked(WETH_ADDR, address(2), address(3), false, true);
|
||||||
address(2),
|
|
||||||
address(3),
|
|
||||||
false,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
(
|
||||||
IERC20 tokenIn,
|
IERC20 tokenIn,
|
||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferNeeded
|
||||||
) = uniswapV2Exposed.decodeParams(params);
|
) = uniswapV2Exposed.decodeParams(params);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
assertEq(target, address(2));
|
assertEq(target, address(2));
|
||||||
assertEq(receiver, address(3));
|
assertEq(receiver, address(3));
|
||||||
assertEq(zeroForOne, false);
|
assertEq(zeroForOne, false);
|
||||||
assertEq(
|
assertEq(transferNeeded, true);
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL),
|
|
||||||
uint8(transferType)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParamsInvalidDataLength() public {
|
function testDecodeParamsInvalidDataLength() public {
|
||||||
@@ -158,13 +147,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
uint256 amountIn = 10 ** 18;
|
uint256 amountIn = 10 ** 18;
|
||||||
uint256 amountOut = 1847751195973566072891;
|
uint256 amountOut = 1847751195973566072891;
|
||||||
bool zeroForOne = false;
|
bool zeroForOne = false;
|
||||||
bytes memory protocolData = abi.encodePacked(
|
bytes memory protocolData =
|
||||||
WETH_ADDR,
|
abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, true);
|
||||||
WETH_DAI_POOL,
|
|
||||||
BOB,
|
|
||||||
zeroForOne,
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
uniswapV2Exposed.swap(amountIn, protocolData);
|
||||||
@@ -173,70 +157,12 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
assertGe(finalBalance, amountOut);
|
assertGe(finalBalance, amountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapWithTransferFrom() public {
|
|
||||||
uint256 amountIn = 10 ** 18;
|
|
||||||
uint256 amountOut = 1847751195973566072891;
|
|
||||||
bool zeroForOne = false;
|
|
||||||
bytes memory protocolData = abi.encodePacked(
|
|
||||||
WETH_ADDR,
|
|
||||||
WETH_DAI_POOL,
|
|
||||||
BOB,
|
|
||||||
zeroForOne,
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(WETH_ADDR, address(this), amountIn);
|
|
||||||
IERC20(WETH_ADDR).approve(address(uniswapV2Exposed), amountIn);
|
|
||||||
|
|
||||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
|
||||||
|
|
||||||
uint256 finalBalance = DAI.balanceOf(BOB);
|
|
||||||
assertGe(finalBalance, amountOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testSwapWithPermit2TransferFrom() public {
|
|
||||||
uint256 amountIn = 10 ** 18;
|
|
||||||
uint256 amountOut = 1847751195973566072891;
|
|
||||||
bool zeroForOne = false;
|
|
||||||
bytes memory protocolData = abi.encodePacked(
|
|
||||||
WETH_ADDR,
|
|
||||||
WETH_DAI_POOL,
|
|
||||||
ALICE,
|
|
||||||
zeroForOne,
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(WETH_ADDR, ALICE, amountIn);
|
|
||||||
vm.startPrank(ALICE);
|
|
||||||
(
|
|
||||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
|
||||||
bytes memory signature
|
|
||||||
) = handlePermit2Approval(
|
|
||||||
WETH_ADDR, address(uniswapV2Exposed), amountIn
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assume the permit2.approve method will be called from the TychoRouter
|
|
||||||
// Replicate this scenario in this test.
|
|
||||||
permit2.permit(ALICE, permitSingle, signature);
|
|
||||||
|
|
||||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
|
||||||
vm.stopPrank();
|
|
||||||
|
|
||||||
uint256 finalBalance = DAI.balanceOf(ALICE);
|
|
||||||
assertGe(finalBalance, amountOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testSwapNoTransfer() public {
|
function testSwapNoTransfer() public {
|
||||||
uint256 amountIn = 10 ** 18;
|
uint256 amountIn = 10 ** 18;
|
||||||
uint256 amountOut = 1847751195973566072891;
|
uint256 amountOut = 1847751195973566072891;
|
||||||
bool zeroForOne = false;
|
bool zeroForOne = false;
|
||||||
bytes memory protocolData = abi.encodePacked(
|
bytes memory protocolData =
|
||||||
WETH_ADDR,
|
abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, false);
|
||||||
WETH_DAI_POOL,
|
|
||||||
BOB,
|
|
||||||
zeroForOne,
|
|
||||||
uint8(TokenTransfer.TransferType.NONE)
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(WETH_ADDR, address(this), amountIn);
|
deal(WETH_ADDR, address(this), amountIn);
|
||||||
IERC20(WETH_ADDR).transfer(address(WETH_DAI_POOL), amountIn);
|
IERC20(WETH_ADDR).transfer(address(WETH_DAI_POOL), amountIn);
|
||||||
@@ -255,20 +181,19 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferNeeded
|
||||||
) = uniswapV2Exposed.decodeParams(protocolData);
|
) = uniswapV2Exposed.decodeParams(protocolData);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640);
|
assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640);
|
||||||
assertEq(receiver, 0x0000000000000000000000000000000000000001);
|
assertEq(receiver, 0x0000000000000000000000000000000000000001);
|
||||||
assertEq(zeroForOne, false);
|
assertEq(zeroForOne, false);
|
||||||
// TRANSFER = 0
|
assertEq(transferNeeded, false);
|
||||||
assertEq(0, uint8(transferType));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapIntegration() public {
|
function testSwapIntegration() public {
|
||||||
bytes memory protocolData =
|
bytes memory protocolData =
|
||||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0000";
|
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001";
|
||||||
uint256 amountIn = 10 ** 18;
|
uint256 amountIn = 10 ** 18;
|
||||||
uint256 amountOut = 1847751195973566072891;
|
uint256 amountOut = 1847751195973566072891;
|
||||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||||
@@ -282,13 +207,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
uint256 amountIn = 10 ** 18;
|
uint256 amountIn = 10 ** 18;
|
||||||
bool zeroForOne = false;
|
bool zeroForOne = false;
|
||||||
address fakePool = address(new FakeUniswapV2Pool(WETH_ADDR, DAI_ADDR));
|
address fakePool = address(new FakeUniswapV2Pool(WETH_ADDR, DAI_ADDR));
|
||||||
bytes memory protocolData = abi.encodePacked(
|
bytes memory protocolData =
|
||||||
WETH_ADDR,
|
abi.encodePacked(WETH_ADDR, fakePool, BOB, zeroForOne, true);
|
||||||
fakePool,
|
|
||||||
BOB,
|
|
||||||
zeroForOne,
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||||
vm.expectRevert(UniswapV2Executor__InvalidTarget.selector);
|
vm.expectRevert(UniswapV2Executor__InvalidTarget.selector);
|
||||||
@@ -302,13 +222,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
vm.rollFork(26857267);
|
vm.rollFork(26857267);
|
||||||
uint256 amountIn = 10 * 10 ** 6;
|
uint256 amountIn = 10 * 10 ** 6;
|
||||||
bool zeroForOne = true;
|
bool zeroForOne = true;
|
||||||
bytes memory protocolData = abi.encodePacked(
|
bytes memory protocolData =
|
||||||
BASE_USDC,
|
abi.encodePacked(BASE_USDC, USDC_MAG7_POOL, BOB, zeroForOne, true);
|
||||||
USDC_MAG7_POOL,
|
|
||||||
BOB,
|
|
||||||
zeroForOne,
|
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
|
|
||||||
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);
|
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TransferType transferType
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -71,7 +72,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(2),
|
address(2),
|
||||||
address(3),
|
address(3),
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -81,7 +83,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded
|
||||||
) = uniswapV3Exposed.decodeData(data);
|
) = uniswapV3Exposed.decodeData(data);
|
||||||
|
|
||||||
assertEq(tokenIn, WETH_ADDR);
|
assertEq(tokenIn, WETH_ADDR);
|
||||||
@@ -90,10 +93,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
assertEq(receiver, address(2));
|
assertEq(receiver, address(2));
|
||||||
assertEq(target, address(3));
|
assertEq(target, address(3));
|
||||||
assertEq(zeroForOne, false);
|
assertEq(zeroForOne, false);
|
||||||
assertEq(
|
assertEq(transferFromNeeded, false);
|
||||||
uint8(transferType),
|
assertEq(transferNeeded, true);
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapIntegration() public {
|
function testSwapIntegration() public {
|
||||||
@@ -109,7 +110,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(this),
|
address(this),
|
||||||
DAI_WETH_USV3,
|
DAI_WETH_USV3,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
|
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
|
||||||
@@ -184,7 +186,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(this),
|
address(this),
|
||||||
fakePool,
|
fakePool,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
false,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);
|
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);
|
||||||
@@ -197,7 +200,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zero2one,
|
bool zero2one,
|
||||||
TokenTransfer.TransferType transferType
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded
|
||||||
) internal view returns (bytes memory) {
|
) internal view returns (bytes memory) {
|
||||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
@@ -207,7 +211,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
receiver,
|
receiver,
|
||||||
target,
|
target,
|
||||||
zero2one,
|
zero2one,
|
||||||
transferType
|
transferFromNeeded,
|
||||||
|
transferNeeded
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ pragma solidity ^0.8.26;
|
|||||||
import "../../src/executors/UniswapV4Executor.sol";
|
import "../../src/executors/UniswapV4Executor.sol";
|
||||||
import "../TestUtils.sol";
|
import "../TestUtils.sol";
|
||||||
import "./UniswapV4Utils.sol";
|
import "./UniswapV4Utils.sol";
|
||||||
import "@src/executors/TokenTransfer.sol";
|
|
||||||
import "@src/executors/UniswapV4Executor.sol";
|
import "@src/executors/UniswapV4Executor.sol";
|
||||||
import {Constants} from "../Constants.sol";
|
import {Constants} from "../Constants.sol";
|
||||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||||
@@ -22,7 +21,8 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType,
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Pool[] memory pools
|
UniswapV4Pool[] memory pools
|
||||||
)
|
)
|
||||||
@@ -53,8 +53,8 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
int24 tickSpacing1 = 60;
|
int24 tickSpacing1 = 60;
|
||||||
uint24 pool2Fee = 1000;
|
uint24 pool2Fee = 1000;
|
||||||
int24 tickSpacing2 = -10;
|
int24 tickSpacing2 = -10;
|
||||||
TokenTransfer.TransferType transferType =
|
bool transferFromNeeded = false;
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
bool transferNeeded = true;
|
||||||
|
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||||
@@ -70,14 +70,21 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
});
|
});
|
||||||
|
|
||||||
bytes memory data = UniswapV4Utils.encodeExactInput(
|
bytes memory data = UniswapV4Utils.encodeExactInput(
|
||||||
USDE_ADDR, USDT_ADDR, zeroForOne, transferType, ALICE, pools
|
USDE_ADDR,
|
||||||
|
USDT_ADDR,
|
||||||
|
zeroForOne,
|
||||||
|
transferFromNeeded,
|
||||||
|
transferNeeded,
|
||||||
|
ALICE,
|
||||||
|
pools
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOneDecoded,
|
bool zeroForOneDecoded,
|
||||||
TokenTransfer.TransferType transferTypeDecoded,
|
bool transferFromNeededDecoded,
|
||||||
|
bool transferNeededDecoded,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
||||||
) = uniswapV4Exposed.decodeData(data);
|
) = uniswapV4Exposed.decodeData(data);
|
||||||
@@ -85,7 +92,8 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
assertEq(tokenIn, USDE_ADDR);
|
assertEq(tokenIn, USDE_ADDR);
|
||||||
assertEq(tokenOut, USDT_ADDR);
|
assertEq(tokenOut, USDT_ADDR);
|
||||||
assertEq(zeroForOneDecoded, zeroForOne);
|
assertEq(zeroForOneDecoded, zeroForOne);
|
||||||
assertEq(uint8(transferTypeDecoded), uint8(transferType));
|
assertEq(transferFromNeededDecoded, transferFromNeeded);
|
||||||
|
assertEq(transferNeededDecoded, transferNeeded);
|
||||||
assertEq(receiver, ALICE);
|
assertEq(receiver, ALICE);
|
||||||
assertEq(decodedPools.length, 2);
|
assertEq(decodedPools.length, 2);
|
||||||
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
|
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
|
||||||
@@ -112,12 +120,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
});
|
});
|
||||||
|
|
||||||
bytes memory data = UniswapV4Utils.encodeExactInput(
|
bytes memory data = UniswapV4Utils.encodeExactInput(
|
||||||
USDE_ADDR,
|
USDE_ADDR, USDT_ADDR, true, false, true, ALICE, pools
|
||||||
USDT_ADDR,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
|
||||||
ALICE,
|
|
||||||
pools
|
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
|
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
|
||||||
@@ -169,12 +172,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
});
|
});
|
||||||
|
|
||||||
bytes memory data = UniswapV4Utils.encodeExactInput(
|
bytes memory data = UniswapV4Utils.encodeExactInput(
|
||||||
USDE_ADDR,
|
USDE_ADDR, WBTC_ADDR, true, false, true, ALICE, pools
|
||||||
WBTC_ADDR,
|
|
||||||
true,
|
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
|
||||||
ALICE,
|
|
||||||
pools
|
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
|
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ library UniswapV4Utils {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
UniswapV4Executor.TransferType transferType,
|
bool transferFromNeeded,
|
||||||
|
bool transferNeeded,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||||
) public pure returns (bytes memory) {
|
) public pure returns (bytes memory) {
|
||||||
@@ -24,7 +25,12 @@ library UniswapV4Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
tokenIn, tokenOut, zeroForOne, transferType, receiver, encodedPools
|
tokenIn,
|
||||||
|
tokenOut,
|
||||||
|
zeroForOne,
|
||||||
|
transferNeeded,
|
||||||
|
receiver,
|
||||||
|
encodedPools
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user