Merge pull request #198 from propeller-heads/audit/dc/one-transfer-from-only
feat: Restrict transferFrom
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -4445,9 +4445,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tycho-common"
|
name = "tycho-common"
|
||||||
version = "0.66.4"
|
version = "0.70.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5131fdb21cbd754822b0947fc6c763494531837ba8bb34123f6c7f4f89cb69f7"
|
checksum = "5237d0e4ab6979a1ca9cdb749a2a97240ca6dc716c0da6f42543960d3141255a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ clap = { version = "4.5.3", features = ["derive"] }
|
|||||||
alloy = { version = "0.9.2", features = ["providers", "rpc-types-eth", "eip712", "signer-local"], optional = true }
|
alloy = { version = "0.9.2", features = ["providers", "rpc-types-eth", "eip712", "signer-local"], optional = true }
|
||||||
alloy-sol-types = { version = "0.8.14", optional = true }
|
alloy-sol-types = { version = "0.8.14", optional = true }
|
||||||
alloy-primitives = { version = "0.8.9", optional = true }
|
alloy-primitives = { version = "0.8.9", optional = true }
|
||||||
tycho-common = "^0.66.4"
|
tycho-common = ">0.66.4"
|
||||||
once_cell = "1.20.2"
|
once_cell = "1.20.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ error Dispatcher__InvalidDataLength();
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @title Dispatcher - Dispatch execution to external contracts
|
* @title Dispatcher - Dispatch execution to external contracts
|
||||||
* @author PropellerHeads Devs
|
|
||||||
* @dev Provides the ability to delegate execution of swaps to external
|
* @dev Provides the ability to delegate execution of swaps to external
|
||||||
* contracts. This allows dynamically adding new supported protocols
|
* contracts. This allows dynamically adding new supported protocols
|
||||||
* without needing to upgrade any contracts. External contracts will
|
* without needing to upgrade any contracts. External contracts will
|
||||||
|
|||||||
133
foundry/src/RestrictTransferFrom.sol
Normal file
133
foundry/src/RestrictTransferFrom.sol
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
import "@interfaces/IExecutor.sol";
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
|
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||||
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
|
|
||||||
|
error RestrictTransferFrom__AddressZero();
|
||||||
|
error RestrictTransferFrom__ExceededTransferFromAllowance(
|
||||||
|
uint256 allowedAmount, uint256 amountAttempted
|
||||||
|
);
|
||||||
|
error RestrictTransferFrom__UnknownTransferType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title RestrictTransferFrom - Restrict transferFrom upto allowed amount of token
|
||||||
|
* @dev Restricts to one `transferFrom` (using `permit2` or regular `transferFrom`)
|
||||||
|
* per swap, while ensuring that the `transferFrom` is only performed on the input
|
||||||
|
* token upto input amount, from the msg.sender's wallet that calls the main swap
|
||||||
|
* method. Reverts if `transferFrom`s are attempted above this allowed amount.
|
||||||
|
*/
|
||||||
|
contract RestrictTransferFrom {
|
||||||
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
|
IAllowanceTransfer public immutable permit2;
|
||||||
|
// keccak256("Dispatcher#TOKEN_IN_SLOT")
|
||||||
|
uint256 private constant _TOKEN_IN_SLOT =
|
||||||
|
0x66f353cfe8e3cbe0d03292348fbf0fca32e6e07fa0c2a52b4aac22193ac3b894;
|
||||||
|
// keccak256("Dispatcher#AMOUNT_ALLOWED_SLOT")
|
||||||
|
uint256 private constant _AMOUNT_ALLOWED_SLOT =
|
||||||
|
0xc76591aca92830b1554f3dcc7893e7519ec7c57bd4e64fec0c546d9078033291;
|
||||||
|
// keccak256("Dispatcher#IS_PERMIT2_SLOT")
|
||||||
|
uint256 private constant _IS_PERMIT2_SLOT =
|
||||||
|
0x3162c9d1175ca0ca7441f87984fdac41bbfdb13246f42c8bb4414d345da39e2a;
|
||||||
|
// keccak256("Dispatcher#SENDER_SLOT")
|
||||||
|
uint256 private constant _SENDER_SLOT =
|
||||||
|
0x5dcc7974be5cb30f183f878073999aaa6620995b9e052ab5a713071ff60ae9b5;
|
||||||
|
// keccak256("Dispatcher#AMOUNT_SPENT_SLOT")
|
||||||
|
uint256 private constant _AMOUNT_SPENT_SLOT =
|
||||||
|
0x56044a5eb3aa5bd3ad908b7f15d1e8cb830836bb4ad178a0bf08955c94c40d30;
|
||||||
|
|
||||||
|
constructor(address _permit2) {
|
||||||
|
if (_permit2 == address(0)) {
|
||||||
|
revert RestrictTransferFrom__AddressZero();
|
||||||
|
}
|
||||||
|
permit2 = IAllowanceTransfer(_permit2);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TransferType {
|
||||||
|
TransferFrom,
|
||||||
|
Transfer,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev This function is used to store the transfer information in the
|
||||||
|
* contract's storage. This is done as the first step in the swap process in TychoRouter.
|
||||||
|
*/
|
||||||
|
// slither-disable-next-line assembly
|
||||||
|
function _tstoreTransferFromInfo(
|
||||||
|
address tokenIn,
|
||||||
|
uint256 amountIn,
|
||||||
|
bool isPermit2,
|
||||||
|
bool transferFromNeeded
|
||||||
|
) internal {
|
||||||
|
uint256 amountAllowed = amountIn;
|
||||||
|
if (!transferFromNeeded) {
|
||||||
|
amountAllowed = 0;
|
||||||
|
}
|
||||||
|
assembly {
|
||||||
|
tstore(_TOKEN_IN_SLOT, tokenIn)
|
||||||
|
tstore(_AMOUNT_ALLOWED_SLOT, amountAllowed)
|
||||||
|
tstore(_IS_PERMIT2_SLOT, isPermit2)
|
||||||
|
tstore(_SENDER_SLOT, caller())
|
||||||
|
tstore(_AMOUNT_SPENT_SLOT, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev This function is used to transfer the tokens from the sender to the receiver.
|
||||||
|
* This function is called within the Executor contracts.
|
||||||
|
* If the TransferType is TransferFrom, it will check if the amount is within the allowed amount and transfer those funds from the user.
|
||||||
|
* If the TransferType is Transfer, it will transfer the funds from the TychoRouter to the receiver.
|
||||||
|
* If the TransferType is None, it will do nothing.
|
||||||
|
*/
|
||||||
|
// slither-disable-next-line assembly
|
||||||
|
function _transfer(
|
||||||
|
address receiver,
|
||||||
|
TransferType transferType,
|
||||||
|
address tokenIn,
|
||||||
|
uint256 amount
|
||||||
|
) internal {
|
||||||
|
if (transferType == TransferType.TransferFrom) {
|
||||||
|
bool isPermit2;
|
||||||
|
address sender;
|
||||||
|
uint256 amountSpent;
|
||||||
|
uint256 amountAllowed;
|
||||||
|
assembly {
|
||||||
|
tokenIn := tload(_TOKEN_IN_SLOT)
|
||||||
|
amountAllowed := tload(_AMOUNT_ALLOWED_SLOT)
|
||||||
|
isPermit2 := tload(_IS_PERMIT2_SLOT)
|
||||||
|
sender := tload(_SENDER_SLOT)
|
||||||
|
amountSpent := tload(_AMOUNT_SPENT_SLOT)
|
||||||
|
}
|
||||||
|
uint256 amountAttempted = amountSpent + amount;
|
||||||
|
if (amountAttempted > amountAllowed) {
|
||||||
|
revert RestrictTransferFrom__ExceededTransferFromAllowance(
|
||||||
|
amountAllowed, amountAttempted
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assembly {
|
||||||
|
tstore(_AMOUNT_SPENT_SLOT, amountAttempted)
|
||||||
|
}
|
||||||
|
if (isPermit2) {
|
||||||
|
// Permit2.permit is already called from the TychoRouter
|
||||||
|
permit2.transferFrom(sender, receiver, uint160(amount), tokenIn);
|
||||||
|
} else {
|
||||||
|
// slither-disable-next-line arbitrary-send-erc20
|
||||||
|
IERC20(tokenIn).safeTransferFrom(sender, receiver, amount);
|
||||||
|
}
|
||||||
|
} else if (transferType == TransferType.Transfer) {
|
||||||
|
if (tokenIn == address(0)) {
|
||||||
|
Address.sendValue(payable(receiver), amount);
|
||||||
|
} else {
|
||||||
|
IERC20(tokenIn).safeTransfer(receiver, amount);
|
||||||
|
}
|
||||||
|
} else if (transferType == TransferType.None) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
revert RestrictTransferFrom__UnknownTransferType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
|||||||
import "./Dispatcher.sol";
|
import "./Dispatcher.sol";
|
||||||
import {LibSwap} from "../lib/LibSwap.sol";
|
import {LibSwap} from "../lib/LibSwap.sol";
|
||||||
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
||||||
|
import {RestrictTransferFrom} from "./RestrictTransferFrom.sol";
|
||||||
|
|
||||||
// ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷
|
// ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷
|
||||||
// ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷
|
// ✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷✷
|
||||||
@@ -65,8 +66,13 @@ error TychoRouter__MessageValueMismatch(uint256 value, uint256 amount);
|
|||||||
error TychoRouter__InvalidDataLength();
|
error TychoRouter__InvalidDataLength();
|
||||||
error TychoRouter__UndefinedMinAmountOut();
|
error TychoRouter__UndefinedMinAmountOut();
|
||||||
|
|
||||||
contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
contract TychoRouter is
|
||||||
IAllowanceTransfer public immutable permit2;
|
AccessControl,
|
||||||
|
Dispatcher,
|
||||||
|
Pausable,
|
||||||
|
ReentrancyGuard,
|
||||||
|
RestrictTransferFrom
|
||||||
|
{
|
||||||
IWETH private immutable _weth;
|
IWETH private immutable _weth;
|
||||||
|
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
@@ -87,7 +93,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
address indexed token, uint256 amount, address indexed receiver
|
address indexed token, uint256 amount, address indexed receiver
|
||||||
);
|
);
|
||||||
|
|
||||||
constructor(address _permit2, address weth) {
|
constructor(address _permit2, address weth)
|
||||||
|
RestrictTransferFrom(_permit2)
|
||||||
|
{
|
||||||
if (_permit2 == address(0) || weth == address(0)) {
|
if (_permit2 == address(0) || weth == address(0)) {
|
||||||
revert TychoRouter__AddressZero();
|
revert TychoRouter__AddressZero();
|
||||||
}
|
}
|
||||||
@@ -115,6 +123,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
* @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 transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms
|
||||||
* @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.
|
||||||
@@ -128,13 +137,18 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
uint256 nTokens,
|
uint256 nTokens,
|
||||||
address receiver,
|
address receiver,
|
||||||
|
bool transferFromNeeded,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
|
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||||
|
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
|
||||||
|
|
||||||
return _splitSwapChecked(
|
return _splitSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
|
initialBalanceTokenOut,
|
||||||
wrapEth,
|
wrapEth,
|
||||||
unwrapEth,
|
unwrapEth,
|
||||||
nTokens,
|
nTokens,
|
||||||
@@ -182,16 +196,19 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
bytes calldata signature,
|
bytes calldata signature,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
|
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||||
// 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, true);
|
||||||
|
|
||||||
return _splitSwapChecked(
|
return _splitSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
|
initialBalanceTokenOut,
|
||||||
wrapEth,
|
wrapEth,
|
||||||
unwrapEth,
|
unwrapEth,
|
||||||
nTokens,
|
nTokens,
|
||||||
@@ -218,6 +235,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
* @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 transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms
|
||||||
* @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.
|
||||||
@@ -230,13 +248,18 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
address receiver,
|
address receiver,
|
||||||
|
bool transferFromNeeded,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
|
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||||
|
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
|
||||||
|
|
||||||
return _sequentialSwapChecked(
|
return _sequentialSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
|
initialBalanceTokenOut,
|
||||||
wrapEth,
|
wrapEth,
|
||||||
unwrapEth,
|
unwrapEth,
|
||||||
receiver,
|
receiver,
|
||||||
@@ -280,16 +303,20 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
bytes calldata signature,
|
bytes calldata signature,
|
||||||
bytes calldata swaps
|
bytes calldata swaps
|
||||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
|
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||||
// 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, true);
|
||||||
|
|
||||||
return _sequentialSwapChecked(
|
return _sequentialSwapChecked(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
|
initialBalanceTokenOut,
|
||||||
wrapEth,
|
wrapEth,
|
||||||
unwrapEth,
|
unwrapEth,
|
||||||
receiver,
|
receiver,
|
||||||
@@ -313,6 +340,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
* @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 transferFromNeeded If false, the contract will assume that the input token is already transferred to the contract and don't allow any transferFroms
|
||||||
* @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.
|
||||||
@@ -325,13 +353,18 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
address receiver,
|
address receiver,
|
||||||
|
bool transferFromNeeded,
|
||||||
bytes calldata swapData
|
bytes calldata swapData
|
||||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
|
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||||
|
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
|
||||||
|
|
||||||
return _singleSwap(
|
return _singleSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
|
initialBalanceTokenOut,
|
||||||
wrapEth,
|
wrapEth,
|
||||||
unwrapEth,
|
unwrapEth,
|
||||||
receiver,
|
receiver,
|
||||||
@@ -375,16 +408,19 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
bytes calldata signature,
|
bytes calldata signature,
|
||||||
bytes calldata swapData
|
bytes calldata swapData
|
||||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||||
|
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||||
// 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, true);
|
||||||
|
|
||||||
return _singleSwap(
|
return _singleSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
tokenIn,
|
tokenIn,
|
||||||
tokenOut,
|
tokenOut,
|
||||||
minAmountOut,
|
minAmountOut,
|
||||||
|
initialBalanceTokenOut,
|
||||||
wrapEth,
|
wrapEth,
|
||||||
unwrapEth,
|
unwrapEth,
|
||||||
receiver,
|
receiver,
|
||||||
@@ -405,6 +441,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
uint256 minAmountOut,
|
uint256 minAmountOut,
|
||||||
|
uint256 initialBalanceTokenOut,
|
||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
uint256 nTokens,
|
uint256 nTokens,
|
||||||
@@ -424,7 +461,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
tokenIn = address(_weth);
|
tokenIn = address(_weth);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
|
||||||
amountOut = _splitSwap(amountIn, nTokens, swaps);
|
amountOut = _splitSwap(amountIn, nTokens, swaps);
|
||||||
|
|
||||||
if (amountOut < minAmountOut) {
|
if (amountOut < minAmountOut) {
|
||||||
@@ -459,6 +495,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
uint256 minAmountOut,
|
uint256 minAmountOut,
|
||||||
|
uint256 initialBalanceTokenOut,
|
||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
address receiver,
|
address receiver,
|
||||||
@@ -480,7 +517,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
(address executor, bytes calldata protocolData) =
|
(address executor, bytes calldata protocolData) =
|
||||||
swap_.decodeSingleSwap();
|
swap_.decodeSingleSwap();
|
||||||
|
|
||||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
|
||||||
amountOut = _callSwapOnExecutor(executor, amountIn, protocolData);
|
amountOut = _callSwapOnExecutor(executor, amountIn, protocolData);
|
||||||
|
|
||||||
if (amountOut < minAmountOut) {
|
if (amountOut < minAmountOut) {
|
||||||
@@ -515,6 +551,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
uint256 minAmountOut,
|
uint256 minAmountOut,
|
||||||
|
uint256 initialBalanceTokenOut,
|
||||||
bool wrapEth,
|
bool wrapEth,
|
||||||
bool unwrapEth,
|
bool unwrapEth,
|
||||||
address receiver,
|
address receiver,
|
||||||
@@ -533,7 +570,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
|||||||
tokenIn = address(_weth);
|
tokenIn = address(_weth);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
|
||||||
amountOut = _sequentialSwap(amountIn, swaps);
|
amountOut = _sequentialSwap(amountIn, swaps);
|
||||||
|
|
||||||
if (amountOut < minAmountOut) {
|
if (amountOut < minAmountOut) {
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ 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";
|
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||||
|
|
||||||
error BalancerV2Executor__InvalidDataLength();
|
error BalancerV2Executor__InvalidDataLength();
|
||||||
|
|
||||||
contract BalancerV2Executor is IExecutor, TokenTransfer {
|
contract BalancerV2Executor is IExecutor, RestrictTransferFrom {
|
||||||
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) RestrictTransferFrom(_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)
|
||||||
@@ -32,21 +32,13 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
|||||||
IERC20 tokenOut,
|
IERC20 tokenOut,
|
||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool approvalNeeded,
|
||||||
TransferType transferType
|
TransferType transferType
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
_transfer(
|
_transfer(address(this), transferType, address(tokenIn), givenAmount);
|
||||||
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 (approvalNeeded) {
|
||||||
// slither-disable-next-line unused-return
|
// slither-disable-next-line unused-return
|
||||||
tokenIn.forceApprove(VAULT, type(uint256).max);
|
tokenIn.forceApprove(VAULT, type(uint256).max);
|
||||||
}
|
}
|
||||||
@@ -81,7 +73,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
|||||||
IERC20 tokenOut,
|
IERC20 tokenOut,
|
||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool approvalNeeded,
|
||||||
TransferType transferType
|
TransferType transferType
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -93,7 +85,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
|||||||
tokenOut = IERC20(address(bytes20(data[20:40])));
|
tokenOut = IERC20(address(bytes20(data[20:40])));
|
||||||
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;
|
approvalNeeded = data[92] != 0;
|
||||||
transferType = TransferType(uint8(data[93]));
|
transferType = TransferType(uint8(data[93]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ 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";
|
||||||
|
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||||
|
|
||||||
error CurveExecutor__AddressZero();
|
error CurveExecutor__AddressZero();
|
||||||
error CurveExecutor__InvalidDataLength();
|
error CurveExecutor__InvalidDataLength();
|
||||||
@@ -35,13 +35,13 @@ interface CryptoPoolETH {
|
|||||||
// slither-disable-end naming-convention
|
// slither-disable-end naming-convention
|
||||||
}
|
}
|
||||||
|
|
||||||
contract CurveExecutor is IExecutor, TokenTransfer {
|
contract CurveExecutor is IExecutor, RestrictTransferFrom {
|
||||||
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)
|
RestrictTransferFrom(_permit2)
|
||||||
{
|
{
|
||||||
if (_nativeToken == address(0)) {
|
if (_nativeToken == address(0)) {
|
||||||
revert CurveExecutor__AddressZero();
|
revert CurveExecutor__AddressZero();
|
||||||
@@ -64,25 +64,16 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
|||||||
uint8 poolType,
|
uint8 poolType,
|
||||||
int128 i,
|
int128 i,
|
||||||
int128 j,
|
int128 j,
|
||||||
bool tokenApprovalNeeded,
|
bool approvalNeeded,
|
||||||
TransferType transferType,
|
TransferType transferType,
|
||||||
address receiver
|
address receiver
|
||||||
) = _decodeData(data);
|
) = _decodeData(data);
|
||||||
|
|
||||||
_transfer(
|
if (approvalNeeded && tokenIn != nativeToken) {
|
||||||
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) {
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
_transfer(address(this), transferType, tokenIn, amountIn);
|
||||||
|
|
||||||
/// Inspired by Curve's router contract: https://github.com/curvefi/curve-router-ng/blob/9ab006ca848fc7f1995b6fbbecfecc1e0eb29e2a/contracts/Router.vy#L44
|
/// Inspired by Curve's router contract: https://github.com/curvefi/curve-router-ng/blob/9ab006ca848fc7f1995b6fbbecfecc1e0eb29e2a/contracts/Router.vy#L44
|
||||||
uint256 balanceBefore = _balanceOf(tokenOut);
|
uint256 balanceBefore = _balanceOf(tokenOut);
|
||||||
@@ -133,7 +124,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
|||||||
uint8 poolType,
|
uint8 poolType,
|
||||||
int128 i,
|
int128 i,
|
||||||
int128 j,
|
int128 j,
|
||||||
bool tokenApprovalNeeded,
|
bool approvalNeeded,
|
||||||
TransferType transferType,
|
TransferType transferType,
|
||||||
address receiver
|
address receiver
|
||||||
)
|
)
|
||||||
@@ -144,7 +135,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
|||||||
poolType = uint8(data[60]);
|
poolType = uint8(data[60]);
|
||||||
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;
|
approvalNeeded = data[63] != 0;
|
||||||
transferType = TransferType(uint8(data[64]));
|
transferType = TransferType(uint8(data[64]));
|
||||||
receiver = address(bytes20(data[65:85]));
|
receiver = address(bytes20(data[65:85]));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: UNLICENSED
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
pragma solidity ^0.8.26;
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
import {IExecutor} from "@interfaces/IExecutor.sol";
|
import {IExecutor} from "@interfaces/IExecutor.sol";
|
||||||
import {ICallback} from "@interfaces/ICallback.sol";
|
import {ICallback} from "@interfaces/ICallback.sol";
|
||||||
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
||||||
@@ -11,14 +11,15 @@ 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 {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||||
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
|
|
||||||
contract EkuboExecutor is
|
contract EkuboExecutor is
|
||||||
IExecutor,
|
IExecutor,
|
||||||
ILocker,
|
ILocker,
|
||||||
IPayer,
|
IPayer,
|
||||||
ICallback,
|
ICallback,
|
||||||
TokenTransfer
|
RestrictTransferFrom
|
||||||
{
|
{
|
||||||
error EkuboExecutor__InvalidDataLength();
|
error EkuboExecutor__InvalidDataLength();
|
||||||
error EkuboExecutor__CoreOnly();
|
error EkuboExecutor__CoreOnly();
|
||||||
@@ -26,13 +27,17 @@ contract EkuboExecutor is
|
|||||||
|
|
||||||
ICore immutable core;
|
ICore immutable core;
|
||||||
|
|
||||||
uint256 constant POOL_DATA_OFFSET = 77;
|
uint256 constant POOL_DATA_OFFSET = 57;
|
||||||
uint256 constant HOP_BYTE_LEN = 52;
|
uint256 constant HOP_BYTE_LEN = 52;
|
||||||
|
|
||||||
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) {
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
|
constructor(address _core, address _permit2)
|
||||||
|
RestrictTransferFrom(_permit2)
|
||||||
|
{
|
||||||
core = ICore(_core);
|
core = ICore(_core);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,16 +46,11 @@ contract EkuboExecutor is
|
|||||||
payable
|
payable
|
||||||
returns (uint256 calculatedAmount)
|
returns (uint256 calculatedAmount)
|
||||||
{
|
{
|
||||||
if (data.length < 93) revert EkuboExecutor__InvalidDataLength();
|
if (data.length < 92) 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)
|
||||||
@@ -125,11 +125,9 @@ contract EkuboExecutor is
|
|||||||
function _locked(bytes calldata swapData) internal returns (int128) {
|
function _locked(bytes calldata swapData) internal returns (int128) {
|
||||||
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]));
|
TransferType transferType = TransferType(uint8(swapData[16]));
|
||||||
uint8 transferType = uint8(swapData[36]);
|
address receiver = address(bytes20(swapData[17:37]));
|
||||||
|
address tokenIn = address(bytes20(swapData[37:57]));
|
||||||
address receiver = address(bytes20(swapData[37:57]));
|
|
||||||
address tokenIn = address(bytes20(swapData[57:77]));
|
|
||||||
|
|
||||||
address nextTokenIn = tokenIn;
|
address nextTokenIn = tokenIn;
|
||||||
|
|
||||||
@@ -163,17 +161,14 @@ contract EkuboExecutor is
|
|||||||
offset += HOP_BYTE_LEN;
|
offset += HOP_BYTE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
_pay(tokenIn, tokenInDebtAmount, sender, transferType);
|
_pay(tokenIn, tokenInDebtAmount, transferType);
|
||||||
core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn));
|
core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn));
|
||||||
return nextAmountIn;
|
return nextAmountIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _pay(
|
function _pay(address token, uint128 amount, TransferType transferType)
|
||||||
address token,
|
internal
|
||||||
uint128 amount,
|
{
|
||||||
address sender,
|
|
||||||
uint8 transferType
|
|
||||||
) internal {
|
|
||||||
address target = address(core);
|
address target = address(core);
|
||||||
|
|
||||||
if (token == NATIVE_TOKEN_ADDRESS) {
|
if (token == NATIVE_TOKEN_ADDRESS) {
|
||||||
@@ -186,11 +181,10 @@ 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, transferType))
|
||||||
mstore(add(free, 72), shl(248, transferType))
|
|
||||||
|
|
||||||
// 4 (selector) + 32 (token) + 16 (amount) + 20 (sender) + 1 (transferType) = 73
|
// 4 (selector) + 32 (token) + 16 (amount) + 1 (transferType) = 53
|
||||||
if iszero(call(gas(), target, 0, free, 73, 0, 0)) {
|
if iszero(call(gas(), target, 0, free, 53, 0, 0)) {
|
||||||
returndatacopy(0, 0, returndatasize())
|
returndatacopy(0, 0, returndatasize())
|
||||||
revert(0, returndatasize())
|
revert(0, returndatasize())
|
||||||
}
|
}
|
||||||
@@ -201,9 +195,8 @@ 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]));
|
TransferType transferType = TransferType(uint8(payData[48]));
|
||||||
TransferType transferType = TransferType(uint8(payData[68]));
|
_transfer(address(core), transferType, token, amount);
|
||||||
_transfer(token, sender, address(core), amount, transferType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// To receive withdrawals from Core
|
// To receive withdrawals from Core
|
||||||
|
|||||||
@@ -3,18 +3,21 @@ 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 {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||||
|
|
||||||
error MaverickV2Executor__InvalidDataLength();
|
error MaverickV2Executor__InvalidDataLength();
|
||||||
error MaverickV2Executor__InvalidTarget();
|
error MaverickV2Executor__InvalidTarget();
|
||||||
error MaverickV2Executor__InvalidFactory();
|
error MaverickV2Executor__InvalidFactory();
|
||||||
|
|
||||||
contract MaverickV2Executor is IExecutor, TokenTransfer {
|
contract MaverickV2Executor is IExecutor, RestrictTransferFrom {
|
||||||
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)
|
||||||
|
RestrictTransferFrom(_permit2)
|
||||||
|
{
|
||||||
if (_factory == address(0)) {
|
if (_factory == address(0)) {
|
||||||
revert MaverickV2Executor__InvalidFactory();
|
revert MaverickV2Executor__InvalidFactory();
|
||||||
}
|
}
|
||||||
@@ -47,9 +50,8 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
|||||||
tickLimit: tickLimit
|
tickLimit: tickLimit
|
||||||
});
|
});
|
||||||
|
|
||||||
_transfer(
|
_transfer(target, transferType, address(tokenIn), givenAmount);
|
||||||
address(tokenIn), msg.sender, target, givenAmount, transferType
|
|
||||||
);
|
|
||||||
// slither-disable-next-line unused-return
|
// slither-disable-next-line unused-return
|
||||||
(, calculatedAmount) = pool.swap(receiver, swapParams, "");
|
(, calculatedAmount) = pool.swap(receiver, swapParams, "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// SPDX-License-Identifier: BUSL-1.1
|
|
||||||
pragma solidity ^0.8.26;
|
|
||||||
|
|
||||||
import "@interfaces/IExecutor.sol";
|
|
||||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
||||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
|
||||||
|
|
||||||
error TokenTransfer__AddressZero();
|
|
||||||
error TokenTransfer__InvalidTransferType();
|
|
||||||
|
|
||||||
contract TokenTransfer {
|
|
||||||
using SafeERC20 for IERC20;
|
|
||||||
|
|
||||||
IAllowanceTransfer public immutable permit2;
|
|
||||||
|
|
||||||
enum TransferType {
|
|
||||||
// Assume funds are in the TychoRouter - transfer into the pool
|
|
||||||
TRANSFER_TO_PROTOCOL,
|
|
||||||
// Assume funds are in msg.sender's wallet - transferFrom into the pool
|
|
||||||
TRANSFER_FROM_TO_PROTOCOL,
|
|
||||||
// Assume funds are in msg.sender's wallet - permit2TransferFrom into the pool
|
|
||||||
TRANSFER_PERMIT2_TO_PROTOCOL,
|
|
||||||
// Assume funds are in msg.sender's wallet - but the pool requires it to be
|
|
||||||
// in the router contract when calling swap - transferFrom into the router
|
|
||||||
// contract
|
|
||||||
TRANSFER_FROM_TO_ROUTER,
|
|
||||||
// Assume funds are in msg.sender's wallet - but the pool requires it to be
|
|
||||||
// in the router contract when calling swap - transferFrom into the router
|
|
||||||
// contract using permit2
|
|
||||||
TRANSFER_PERMIT2_TO_ROUTER,
|
|
||||||
// Assume funds have already been transferred into the pool. Do nothing.
|
|
||||||
NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(address _permit2) {
|
|
||||||
if (_permit2 == address(0)) {
|
|
||||||
revert TokenTransfer__AddressZero();
|
|
||||||
}
|
|
||||||
permit2 = IAllowanceTransfer(_permit2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _transfer(
|
|
||||||
address tokenIn,
|
|
||||||
address sender,
|
|
||||||
address receiver,
|
|
||||||
uint256 amount,
|
|
||||||
TransferType transferType
|
|
||||||
) internal {
|
|
||||||
if (transferType == TransferType.NONE) {
|
|
||||||
return;
|
|
||||||
} else if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
|
|
||||||
if (tokenIn == address(0)) {
|
|
||||||
payable(receiver).transfer(amount);
|
|
||||||
} else {
|
|
||||||
IERC20(tokenIn).safeTransfer(receiver, amount);
|
|
||||||
}
|
|
||||||
} else if (transferType == TransferType.TRANSFER_FROM_TO_PROTOCOL) {
|
|
||||||
// slither-disable-next-line arbitrary-send-erc20
|
|
||||||
IERC20(tokenIn).safeTransferFrom(sender, receiver, amount);
|
|
||||||
} else if (transferType == TransferType.TRANSFER_PERMIT2_TO_PROTOCOL) {
|
|
||||||
// Permit2.permit is already called from the TychoRouter
|
|
||||||
permit2.transferFrom(sender, receiver, uint160(amount), tokenIn);
|
|
||||||
} else if (transferType == TransferType.TRANSFER_FROM_TO_ROUTER) {
|
|
||||||
// slither-disable-next-line arbitrary-send-erc20
|
|
||||||
IERC20(tokenIn).safeTransferFrom(sender, address(this), amount);
|
|
||||||
} else if (transferType == TransferType.TRANSFER_PERMIT2_TO_ROUTER) {
|
|
||||||
// Permit2.permit is already called from the TychoRouter
|
|
||||||
permit2.transferFrom(
|
|
||||||
sender, address(this), uint160(amount), tokenIn
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
revert TokenTransfer__InvalidTransferType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ 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 "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol";
|
import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol";
|
||||||
import "./TokenTransfer.sol";
|
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||||
|
|
||||||
error UniswapV2Executor__InvalidDataLength();
|
error UniswapV2Executor__InvalidDataLength();
|
||||||
error UniswapV2Executor__InvalidTarget();
|
error UniswapV2Executor__InvalidTarget();
|
||||||
@@ -12,7 +12,7 @@ error UniswapV2Executor__InvalidFactory();
|
|||||||
error UniswapV2Executor__InvalidInitCode();
|
error UniswapV2Executor__InvalidInitCode();
|
||||||
error UniswapV2Executor__InvalidFee();
|
error UniswapV2Executor__InvalidFee();
|
||||||
|
|
||||||
contract UniswapV2Executor is IExecutor, TokenTransfer {
|
contract UniswapV2Executor is IExecutor, RestrictTransferFrom {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
address public immutable factory;
|
address public immutable factory;
|
||||||
@@ -25,7 +25,7 @@ contract UniswapV2Executor is IExecutor, TokenTransfer {
|
|||||||
bytes32 _initCode,
|
bytes32 _initCode,
|
||||||
address _permit2,
|
address _permit2,
|
||||||
uint256 _feeBps
|
uint256 _feeBps
|
||||||
) TokenTransfer(_permit2) {
|
) RestrictTransferFrom(_permit2) {
|
||||||
if (_factory == address(0)) {
|
if (_factory == address(0)) {
|
||||||
revert UniswapV2Executor__InvalidFactory();
|
revert UniswapV2Executor__InvalidFactory();
|
||||||
}
|
}
|
||||||
@@ -59,9 +59,8 @@ contract UniswapV2Executor is IExecutor, TokenTransfer {
|
|||||||
_verifyPairAddress(target);
|
_verifyPairAddress(target);
|
||||||
|
|
||||||
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
||||||
_transfer(
|
|
||||||
address(tokenIn), msg.sender, target, givenAmount, transferType
|
_transfer(target, transferType, address(tokenIn), givenAmount);
|
||||||
);
|
|
||||||
|
|
||||||
IUniswapV2Pair pool = IUniswapV2Pair(target);
|
IUniswapV2Pair pool = IUniswapV2Pair(target);
|
||||||
if (zeroForOne) {
|
if (zeroForOne) {
|
||||||
@@ -88,7 +87,7 @@ contract UniswapV2Executor 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]));
|
||||||
zeroForOne = uint8(data[60]) > 0;
|
zeroForOne = data[60] != 0;
|
||||||
transferType = TransferType(uint8(data[61]));
|
transferType = TransferType(uint8(data[61]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ import "@interfaces/IExecutor.sol";
|
|||||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||||||
import "@interfaces/ICallback.sol";
|
import "@interfaces/ICallback.sol";
|
||||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||||
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
|
|
||||||
error UniswapV3Executor__InvalidDataLength();
|
error UniswapV3Executor__InvalidDataLength();
|
||||||
error UniswapV3Executor__InvalidFactory();
|
error UniswapV3Executor__InvalidFactory();
|
||||||
error UniswapV3Executor__InvalidTarget();
|
error UniswapV3Executor__InvalidTarget();
|
||||||
error UniswapV3Executor__InvalidInitCode();
|
error UniswapV3Executor__InvalidInitCode();
|
||||||
error UniswapV3Executor__InvalidTransferType(uint8 transferType);
|
|
||||||
|
|
||||||
contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
uint160 private constant MIN_SQRT_RATIO = 4295128739;
|
uint160 private constant MIN_SQRT_RATIO = 4295128739;
|
||||||
@@ -25,7 +25,7 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
|||||||
address private immutable self;
|
address private immutable self;
|
||||||
|
|
||||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||||
TokenTransfer(_permit2)
|
RestrictTransferFrom(_permit2)
|
||||||
{
|
{
|
||||||
if (_factory == address(0)) {
|
if (_factory == address(0)) {
|
||||||
revert UniswapV3Executor__InvalidFactory();
|
revert UniswapV3Executor__InvalidFactory();
|
||||||
@@ -97,21 +97,14 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
|||||||
abi.decode(msgData[4:68], (int256, int256));
|
abi.decode(msgData[4:68], (int256, int256));
|
||||||
|
|
||||||
address tokenIn = address(bytes20(msgData[132:152]));
|
address tokenIn = address(bytes20(msgData[132:152]));
|
||||||
|
|
||||||
// Transfer type does not exist
|
|
||||||
if (uint8(msgData[175]) > uint8(TransferType.NONE)) {
|
|
||||||
revert UniswapV3Executor__InvalidTransferType(uint8(msgData[175]));
|
|
||||||
}
|
|
||||||
|
|
||||||
TransferType transferType = TransferType(uint8(msgData[175]));
|
TransferType transferType = TransferType(uint8(msgData[175]));
|
||||||
address sender = address(bytes20(msgData[176:196]));
|
|
||||||
|
|
||||||
verifyCallback(msgData[132:]);
|
verifyCallback(msgData[132:]);
|
||||||
|
|
||||||
uint256 amountOwed =
|
uint256 amountOwed =
|
||||||
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
|
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
|
||||||
|
|
||||||
_transfer(tokenIn, sender, msg.sender, amountOwed, transferType);
|
_transfer(msg.sender, transferType, tokenIn, amountOwed);
|
||||||
|
|
||||||
return abi.encode(amountOwed, tokenIn);
|
return abi.encode(amountOwed, tokenIn);
|
||||||
}
|
}
|
||||||
@@ -162,10 +155,8 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
|||||||
address tokenOut,
|
address tokenOut,
|
||||||
uint24 fee,
|
uint24 fee,
|
||||||
TransferType transferType
|
TransferType transferType
|
||||||
) internal view returns (bytes memory) {
|
) internal pure returns (bytes memory) {
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(tokenIn, tokenOut, fee, uint8(transferType));
|
||||||
tokenIn, tokenOut, fee, uint8(transferType), msg.sender
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _verifyPairAddress(
|
function _verifyPairAddress(
|
||||||
|
|||||||
@@ -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,8 @@ 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 "../RestrictTransferFrom.sol";
|
||||||
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
|
|
||||||
error UniswapV4Executor__InvalidDataLength();
|
error UniswapV4Executor__InvalidDataLength();
|
||||||
error UniswapV4Executor__NotPoolManager();
|
error UniswapV4Executor__NotPoolManager();
|
||||||
@@ -37,7 +38,7 @@ contract UniswapV4Executor is
|
|||||||
IExecutor,
|
IExecutor,
|
||||||
IUnlockCallback,
|
IUnlockCallback,
|
||||||
ICallback,
|
ICallback,
|
||||||
TokenTransfer
|
RestrictTransferFrom
|
||||||
{
|
{
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
using CurrencyLibrary for Currency;
|
using CurrencyLibrary for Currency;
|
||||||
@@ -47,8 +48,8 @@ contract UniswapV4Executor is
|
|||||||
IPoolManager public immutable poolManager;
|
IPoolManager public immutable poolManager;
|
||||||
address private immutable _self;
|
address private immutable _self;
|
||||||
|
|
||||||
bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x8bc6d0d7;
|
bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x6022fbcd;
|
||||||
bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0xaf90aeb1;
|
bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0x044f0d3d;
|
||||||
|
|
||||||
struct UniswapV4Pool {
|
struct UniswapV4Pool {
|
||||||
address intermediaryToken;
|
address intermediaryToken;
|
||||||
@@ -57,7 +58,7 @@ contract UniswapV4Executor is
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(IPoolManager _poolManager, address _permit2)
|
constructor(IPoolManager _poolManager, address _permit2)
|
||||||
TokenTransfer(_permit2)
|
RestrictTransferFrom(_permit2)
|
||||||
{
|
{
|
||||||
poolManager = _poolManager;
|
poolManager = _poolManager;
|
||||||
_self = address(this);
|
_self = address(this);
|
||||||
@@ -100,7 +101,6 @@ contract UniswapV4Executor is
|
|||||||
key,
|
key,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
amountIn,
|
amountIn,
|
||||||
msg.sender,
|
|
||||||
transferType,
|
transferType,
|
||||||
receiver,
|
receiver,
|
||||||
bytes("")
|
bytes("")
|
||||||
@@ -123,7 +123,6 @@ contract UniswapV4Executor is
|
|||||||
currencyIn,
|
currencyIn,
|
||||||
path,
|
path,
|
||||||
amountIn,
|
amountIn,
|
||||||
msg.sender,
|
|
||||||
transferType,
|
transferType,
|
||||||
receiver
|
receiver
|
||||||
);
|
);
|
||||||
@@ -153,7 +152,7 @@ contract UniswapV4Executor is
|
|||||||
|
|
||||||
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]));
|
transferType = TransferType(uint8(data[41]));
|
||||||
receiver = address(bytes20(data[42:62]));
|
receiver = address(bytes20(data[42:62]));
|
||||||
|
|
||||||
@@ -239,8 +238,7 @@ 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 transferType The type of action necessary to pay back the pool.
|
||||||
* @param transferType The type of transfer in to use.
|
|
||||||
* @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,7 +246,6 @@ contract UniswapV4Executor is
|
|||||||
PoolKey memory poolKey,
|
PoolKey memory poolKey,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
uint128 amountIn,
|
uint128 amountIn,
|
||||||
address sender,
|
|
||||||
TransferType transferType,
|
TransferType transferType,
|
||||||
address receiver,
|
address receiver,
|
||||||
bytes calldata hookData
|
bytes calldata hookData
|
||||||
@@ -262,7 +259,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, transferType);
|
||||||
|
|
||||||
Currency currencyOut =
|
Currency currencyOut =
|
||||||
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
||||||
@@ -275,15 +272,13 @@ 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 transferType The type of action necessary to pay back the pool.
|
||||||
* @param transferType The type of transfer in to use.
|
|
||||||
* @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,
|
|
||||||
TransferType transferType,
|
TransferType transferType,
|
||||||
address receiver
|
address receiver
|
||||||
) external returns (uint128) {
|
) external returns (uint128) {
|
||||||
@@ -315,7 +310,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, transferType);
|
||||||
|
|
||||||
_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,14 +382,12 @@ 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 transferType The type of action necessary to pay back the pool.
|
||||||
* @param transferType The type of transfer to use.
|
|
||||||
* @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,
|
|
||||||
TransferType transferType
|
TransferType transferType
|
||||||
) internal {
|
) internal {
|
||||||
if (amount == 0) return;
|
if (amount == 0) return;
|
||||||
@@ -404,11 +397,10 @@ contract UniswapV4Executor is
|
|||||||
poolManager.settle{value: amount}();
|
poolManager.settle{value: amount}();
|
||||||
} else {
|
} else {
|
||||||
_transfer(
|
_transfer(
|
||||||
Currency.unwrap(currency),
|
|
||||||
sender,
|
|
||||||
address(poolManager),
|
address(poolManager),
|
||||||
amount,
|
transferType,
|
||||||
transferType
|
Currency.unwrap(currency),
|
||||||
|
amount
|
||||||
);
|
);
|
||||||
// slither-disable-next-line unused-return
|
// slither-disable-next-line unused-return
|
||||||
poolManager.settle();
|
poolManager.settle();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
USDT_ADDR,
|
USDT_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL,
|
RestrictTransferFrom.TransferType.TransferFrom,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -55,7 +55,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
// This test has two uniswap v4 hops that will be executed inside of the V4 pool manager
|
// This test has two uniswap v4 hops that will be executed inside of the V4 pool manager
|
||||||
// USDE -> USDT -> WBTC
|
// USDE -> USDT -> WBTC
|
||||||
uint256 amountIn = 100 ether;
|
uint256 amountIn = 100 ether;
|
||||||
deal(USDE_ADDR, tychoRouterAddr, amountIn);
|
deal(USDE_ADDR, ALICE, amountIn);
|
||||||
|
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||||
@@ -74,7 +74,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
WBTC_ADDR,
|
WBTC_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
RestrictTransferFrom.TransferType.TransferFrom,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -82,8 +82,18 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||||
|
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn);
|
||||||
tychoRouter.singleSwap(
|
tychoRouter.singleSwap(
|
||||||
amountIn, USDE_ADDR, WBTC_ADDR, 118280, false, false, ALICE, swap
|
amountIn,
|
||||||
|
USDE_ADDR,
|
||||||
|
WBTC_ADDR,
|
||||||
|
118280,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
ALICE,
|
||||||
|
true,
|
||||||
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281);
|
assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281);
|
||||||
@@ -262,7 +272,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
|||||||
ALICE,
|
ALICE,
|
||||||
DAI_WETH_USV3,
|
DAI_WETH_USV3,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
encodeSingleSwap(address(usv3Executor), protocolData);
|
encodeSingleSwap(address(usv3Executor), protocolData);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
RestrictTransferFrom.TransferType.TransferFrom // 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
|
RestrictTransferFrom.TransferType.None // funds already sent to pool
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
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,
|
||||||
@@ -82,7 +78,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 +87,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -107,7 +104,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 +114,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -129,7 +127,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 +137,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -154,7 +153,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;
|
||||||
|
|
||||||
@@ -204,9 +203,9 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
encodeUniswapV2Swap(
|
encodeUniswapV2Swap(
|
||||||
WETH_ADDR,
|
WETH_ADDR,
|
||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
tychoRouterAddr,
|
DAI_USDC_POOL,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -218,7 +217,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
DAI_USDC_POOL,
|
DAI_USDC_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.None
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -266,7 +265,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
DAI_USDC_POOL,
|
DAI_USDC_POOL,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -278,7 +277,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -315,7 +314,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3,
|
USDC_WETH_USV3,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
||||||
@@ -324,7 +323,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3_2,
|
USDC_WETH_USV3_2,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
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
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -67,7 +67,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -82,6 +82,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.None
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -116,7 +117,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
|
|
||||||
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, swap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -150,6 +151,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -169,7 +171,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -192,6 +194,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
swap
|
swap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -218,7 +221,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer // ETH has already been transferred to router
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -261,7 +264,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap =
|
bytes memory swap =
|
||||||
@@ -287,6 +290,49 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
|||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testSingleSwapNoTransferNeededIllegalTransfer() public {
|
||||||
|
// Tokens are already in the router, there is no need to transfer them.
|
||||||
|
// Failure because there will be an attempt on an illegal transfer.
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
|
||||||
|
deal(WETH_ADDR, address(tychoRouter), amountIn);
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
// Approve the tokenIn to be transferred to the router
|
||||||
|
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
||||||
|
|
||||||
|
bytes memory protocolData = encodeUniswapV2Swap(
|
||||||
|
WETH_ADDR,
|
||||||
|
WETH_DAI_POOL,
|
||||||
|
ALICE,
|
||||||
|
false,
|
||||||
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
|
);
|
||||||
|
|
||||||
|
bytes memory swap =
|
||||||
|
encodeSingleSwap(address(usv2Executor), protocolData);
|
||||||
|
|
||||||
|
vm.expectRevert(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
RestrictTransferFrom__ExceededTransferFromAllowance.selector,
|
||||||
|
0, // allowed amount
|
||||||
|
amountIn // attempted amount
|
||||||
|
)
|
||||||
|
);
|
||||||
|
uint256 amountOut = tychoRouter.singleSwap(
|
||||||
|
amountIn,
|
||||||
|
WETH_ADDR,
|
||||||
|
DAI_ADDR,
|
||||||
|
2000 * 1e18,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
ALICE,
|
||||||
|
false,
|
||||||
|
swap
|
||||||
|
);
|
||||||
|
|
||||||
|
vm.stopPrank();
|
||||||
|
}
|
||||||
|
|
||||||
function testSingleSwapIntegration() public {
|
function testSingleSwapIntegration() public {
|
||||||
// Tests swapping WETH -> DAI on a USV2 pool with regular approvals
|
// Tests swapping WETH -> DAI on a USV2 pool with regular approvals
|
||||||
deal(WETH_ADDR, ALICE, 1 ether);
|
deal(WETH_ADDR, ALICE, 1 ether);
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
pragma solidity ^0.8.26;
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
import "@src/executors/UniswapV4Executor.sol";
|
import "@src/executors/UniswapV4Executor.sol";
|
||||||
import {TychoRouter} from "@src/TychoRouter.sol";
|
import {TychoRouter, RestrictTransferFrom} from "@src/TychoRouter.sol";
|
||||||
import "./TychoRouterTestSetup.sol";
|
import "./TychoRouterTestSetup.sol";
|
||||||
import "./executors/UniswapV4Utils.sol";
|
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(bool transferFrom)
|
||||||
private
|
private
|
||||||
view
|
view
|
||||||
returns (bytes[] memory)
|
returns (bytes[] memory)
|
||||||
@@ -19,10 +19,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
// -> WBTC ->
|
// -> WBTC ->
|
||||||
// (univ2) (univ2)
|
// (univ2) (univ2)
|
||||||
bytes[] memory swaps = new bytes[](4);
|
bytes[] memory swaps = new bytes[](4);
|
||||||
|
RestrictTransferFrom.TransferType transferType = transferFrom
|
||||||
TokenTransfer.TransferType inTransferType = permit2
|
? RestrictTransferFrom.TransferType.TransferFrom
|
||||||
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
: RestrictTransferFrom.TransferType.Transfer;
|
||||||
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
|
||||||
|
|
||||||
// WETH -> WBTC (60%)
|
// WETH -> WBTC (60%)
|
||||||
swaps[0] = encodeSplitSwap(
|
swaps[0] = encodeSplitSwap(
|
||||||
@@ -31,11 +30,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, transferType
|
||||||
WETH_WBTC_POOL,
|
|
||||||
tychoRouterAddr,
|
|
||||||
false,
|
|
||||||
inTransferType
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// WBTC -> USDC
|
// WBTC -> USDC
|
||||||
@@ -49,7 +44,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDC_WBTC_POOL,
|
USDC_WBTC_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// WETH -> DAI
|
// WETH -> DAI
|
||||||
@@ -59,7 +54,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, transferType
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -74,7 +69,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
DAI_USDC_POOL,
|
DAI_USDC_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -85,9 +80,8 @@ 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(false);
|
bytes[] memory swaps = _getSplitSwaps(false);
|
||||||
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
|
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -138,7 +132,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(true);
|
||||||
|
|
||||||
tychoRouter.splitSwap(
|
tychoRouter.splitSwap(
|
||||||
amountIn,
|
amountIn,
|
||||||
@@ -149,6 +143,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
4,
|
4,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -165,7 +160,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(true);
|
||||||
|
|
||||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||||
tychoRouter.splitSwap(
|
tychoRouter.splitSwap(
|
||||||
@@ -177,6 +172,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
4,
|
4,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
@@ -190,7 +186,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(true);
|
||||||
|
|
||||||
vm.expectRevert();
|
vm.expectRevert();
|
||||||
tychoRouter.splitSwap(
|
tychoRouter.splitSwap(
|
||||||
@@ -202,6 +198,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
false,
|
false,
|
||||||
2,
|
2,
|
||||||
ALICE,
|
ALICE,
|
||||||
|
true,
|
||||||
pleEncode(swaps)
|
pleEncode(swaps)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -270,7 +267,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
ALICE,
|
ALICE,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap = encodeSplitSwap(
|
bytes memory swap = encodeSplitSwap(
|
||||||
@@ -319,7 +316,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.TransferFrom
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap = encodeSplitSwap(
|
bytes memory swap = encodeSplitSwap(
|
||||||
@@ -365,10 +362,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 +373,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3,
|
USDC_WETH_USV3,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
|
||||||
@@ -385,7 +382,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3_2,
|
USDC_WETH_USV3_2,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap(
|
bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap(
|
||||||
@@ -393,7 +390,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDC_WETH_USV2,
|
USDC_WETH_USV2,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes[] memory swaps = new bytes[](3);
|
bytes[] memory swaps = new bytes[](3);
|
||||||
@@ -426,6 +423,74 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99654537);
|
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99654537);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testSplitInputIllegalTransfers() public {
|
||||||
|
// This test attempts to perform multiple `transferFrom`s - which is not
|
||||||
|
// permitted by the TychoRouter.
|
||||||
|
//
|
||||||
|
// The flow is:
|
||||||
|
// ┌─ (USV3, 60% split) ───┐
|
||||||
|
// │ │
|
||||||
|
// USDC ──────┤ ├────> WETH
|
||||||
|
// │ │
|
||||||
|
// └─ (USV3, 40% split) ───┘
|
||||||
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
|
|
||||||
|
// Assume funds have already been transferred to tychoRouter
|
||||||
|
deal(USDC_ADDR, ALICE, amountIn);
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
IERC20(USDC_ADDR).approve(tychoRouterAddr, amountIn);
|
||||||
|
|
||||||
|
bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap(
|
||||||
|
USDC_ADDR,
|
||||||
|
WETH_ADDR,
|
||||||
|
tychoRouterAddr,
|
||||||
|
USDC_WETH_USV3,
|
||||||
|
true,
|
||||||
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
|
);
|
||||||
|
|
||||||
|
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
|
||||||
|
USDC_ADDR,
|
||||||
|
WETH_ADDR,
|
||||||
|
tychoRouterAddr,
|
||||||
|
USDC_WETH_USV3_2,
|
||||||
|
true,
|
||||||
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
|
);
|
||||||
|
|
||||||
|
bytes[] memory swaps = new bytes[](2);
|
||||||
|
// USDC -> WETH (60% split)
|
||||||
|
swaps[0] = encodeSplitSwap(
|
||||||
|
uint8(0),
|
||||||
|
uint8(1),
|
||||||
|
(0xffffff * 60) / 100, // 60%
|
||||||
|
address(usv3Executor),
|
||||||
|
usdcWethV3Pool1ZeroOneData
|
||||||
|
);
|
||||||
|
// USDC -> WETH (40% remainder)
|
||||||
|
swaps[1] = encodeSplitSwap(
|
||||||
|
uint8(0),
|
||||||
|
uint8(1),
|
||||||
|
uint24(0),
|
||||||
|
address(usv3Executor),
|
||||||
|
usdcWethV3Pool2ZeroOneData
|
||||||
|
);
|
||||||
|
vm.expectRevert();
|
||||||
|
tychoRouter.splitSwap(
|
||||||
|
amountIn,
|
||||||
|
USDC_ADDR,
|
||||||
|
WETH_ADDR,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
2,
|
||||||
|
ALICE,
|
||||||
|
true,
|
||||||
|
pleEncode(swaps)
|
||||||
|
);
|
||||||
|
vm.stopPrank();
|
||||||
|
}
|
||||||
|
|
||||||
function testSplitOutputCyclicSwapInternalMethod() public {
|
function testSplitOutputCyclicSwapInternalMethod() public {
|
||||||
// This test has start and end tokens that are the same
|
// This test has start and end tokens that are the same
|
||||||
// The flow is:
|
// The flow is:
|
||||||
@@ -443,7 +508,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDC_WETH_USV2,
|
USDC_WETH_USV2,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap(
|
||||||
@@ -452,7 +517,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3,
|
USDC_WETH_USV3,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
||||||
@@ -461,7 +526,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
USDC_WETH_USV3_2,
|
USDC_WETH_USV3_2,
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes[] memory swaps = new bytes[](3);
|
bytes[] memory swaps = new bytes[](3);
|
||||||
@@ -504,7 +569,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
|||||||
USDC_MAG7_POOL,
|
USDC_MAG7_POOL,
|
||||||
tychoRouterAddr,
|
tychoRouterAddr,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes memory swap = encodeSplitSwap(
|
bytes memory swap = encodeSplitSwap(
|
||||||
|
|||||||
@@ -28,6 +28,17 @@ contract TychoRouterExposed is TychoRouter {
|
|||||||
return _unwrapETH(amount);
|
return _unwrapETH(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tstoreExposed(
|
||||||
|
address tokenIn,
|
||||||
|
uint256 amountIn,
|
||||||
|
bool isPermit2,
|
||||||
|
bool transferFromNeeded
|
||||||
|
) external {
|
||||||
|
_tstoreTransferFromInfo(
|
||||||
|
tokenIn, amountIn, isPermit2, transferFromNeeded
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function exposedSplitSwap(
|
function exposedSplitSwap(
|
||||||
uint256 amountIn,
|
uint256 amountIn,
|
||||||
uint256 nTokens,
|
uint256 nTokens,
|
||||||
@@ -185,7 +196,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
|||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zero2one,
|
bool zero2one,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) internal pure returns (bytes memory) {
|
) internal pure returns (bytes memory) {
|
||||||
return
|
return
|
||||||
abi.encodePacked(tokenIn, target, receiver, zero2one, transferType);
|
abi.encodePacked(tokenIn, target, receiver, zero2one, transferType);
|
||||||
@@ -197,7 +208,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zero2one,
|
bool zero2one,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) internal view returns (bytes memory) {
|
) internal view returns (bytes memory) {
|
||||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010500
|
test_uniswap_v3_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200
|
||||||
test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759805cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000
|
test_single_encoding_strategy_ekubo:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759802cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000
|
||||||
test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010000000000000000000000
|
test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000
|
||||||
test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010300525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000
|
test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||||
test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000
|
test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||||
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006852b03300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3b00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041558653365a24c992e17bbf18a802b91eb3cf936eeb1f214d3e5e6cad70ba57070c7e92db5c3f0399d7da505798950313ce1d0c399e54cca0049868ee0f0005501b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
|
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041b70914df20e4b2675adc5a61d26b959e0fd21e7cce6503b884d5ba9e1db2c82164112e4dc362b9a3ef794a03fcfebe0710700028b79abe8b7de525288ac904991c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
|
||||||
test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006852b03300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3b000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c34556c17e3de4636f371033dc793b59f217facb4643ee3113acf72d3c2d7a3d22cf66c34d8d9c7bc119ac2b0fb2781a2097aa743fd77718f2a4e5ef5f92acbf1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000
|
test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c8000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c33e9da2d2a5bea1087e27f42b9255fcaea06efa76558843f6192d571b15c09c5818e1a4b3a111bb6accc4cb8b583c318d2386e0e94cc87b9fcc4065db0d65611c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000
|
||||||
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041c55b2e21396823d694e6da247eee51ef542d57d3c5901911b85b3c195d89a56d03e85c23251af0d3981b0e07ca05caaaca029ae5efba9d58178be2f38d08cced1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000200525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000
|
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||||
test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||||
test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||||
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3b00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160a5490c6e80921cf7b1ad8e7a59a02febd09780fa88c17070663c5a78635116227c299592fac934afa013d95f8711a70fdeb54fc07a2c22352f9cf263924d931c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
|
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f59744bfe3e154be7c72429eb93db7ef2ec00344feeb1376195a2e3f133437f7533c3df955de146e229e4a37fda22acbe11d9393215d14cf1e19334aebbf35e61b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
|
||||||
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ff87cdaae49fca40cccacadeab4710cdbd41d4901ba28cdabf36dbe07b198887506a6d4960e95f586b5d39011f74d4d57d61a7585ca7b8bdd86f550a9973e5571b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000000000
|
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000
|
||||||
test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010005cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||||
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041c55b2e21396823d694e6da247eee51ef542d57d3c5901911b85b3c195d89a56d03e85c23251af0d3981b0e07ca05caaaca029ae5efba9d58178be2f38d08cced1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200020000000000000000000000000000
|
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||||
test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000103cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||||
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410e67daacc0a64ee7e7a57211b347b4af6d4d8865acbb9f549395fe42cf5ea87e1ac51293305eef8aebba46d510052e6fdea42e2caf1c34624260108f32ea6a641b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501020000000000000000000000000000
|
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e5679a7262a283109d2e312e4ffbec563f501f347efc00418f3a6701492635977583d4e2ff29904a33496b64f1bc2ac73796a546a495ab110cca86e6de1655b61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000
|
||||||
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417b597f22dfb861c6ac1ec78eecab17b5e8b8e389494a9d3c2f27efbc35dbd73846d4dc5fef1b9530c4d3b8d7065fbc4d190821c1b5efbfd41ce388163e3812911c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160aa554efc922689a7f426a984f9fc278aa948b9c78f4e7cc0a5f177e5fb6859632b92d3326f710603d43d3a8ea5753c58a61316fd1bff8e0b388f74c98993b91b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||||
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041ff87cdaae49fca40cccacadeab4710cdbd41d4901ba28cdabf36dbe07b198887506a6d4960e95f586b5d39011f74d4d57d61a7585ca7b8bdd86f550a9973e5571b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950102006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000
|
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000
|
||||||
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041ff87cdaae49fca40cccacadeab4710cdbd41d4901ba28cdabf36dbe07b198887506a6d4960e95f586b5d39011f74d4d57d61a7585ca7b8bdd86f550a9973e5571b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80102005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000
|
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000
|
||||||
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c55b2e21396823d694e6da247eee51ef542d57d3c5901911b85b3c195d89a56d03e85c23251af0d3981b0e07ca05caaaca029ae5efba9d58178be2f38d08cced1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950002005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950002005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000000000
|
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000
|
||||||
test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000
|
test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000
|
||||||
test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf00000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004153ce45df3a0b2c8061d920d172d594ee02cf37b1967001935d3a6055700a300f79f68cda34bd3c6f64bfd154a113a43aafd15e6443dcc402e5b6ac9263e6ff031c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501020072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010500691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001053ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598003ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000
|
test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a81d713c715dd501edf102a3c3a755a931e3c72e7322d66b620ece81d7c98bae3d46479041445649eeefdb6ccc09c2b933cd37eda3ae8c99034e84f5570eb2c31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000
|
||||||
test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0105
|
test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102
|
||||||
test_ekubo_encode_swap_multi:00ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032
|
test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032
|
||||||
test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c
|
test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c
|
||||||
test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001
|
test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001
|
||||||
test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc201000000000000000000000000000000
|
test_single_encoding_strategy_maverick:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||||
test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e00
|
test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01
|
||||||
|
test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
WETH_BAL_POOL_ID,
|
WETH_BAL_POOL_ID,
|
||||||
address(2),
|
address(2),
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE
|
RestrictTransferFrom.TransferType.None
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -55,7 +55,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = balancerV2Exposed.decodeParams(params);
|
) = balancerV2Exposed.decodeParams(params);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
@@ -63,7 +63,9 @@ 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));
|
assertEq(
|
||||||
|
uint8(transferType), uint8(RestrictTransferFrom.TransferType.None)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParamsInvalidDataLength() public {
|
function testDecodeParamsInvalidDataLength() public {
|
||||||
@@ -82,7 +84,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
WETH_BAL_POOL_ID,
|
WETH_BAL_POOL_ID,
|
||||||
BOB,
|
BOB,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.NONE
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);
|
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);
|
||||||
@@ -104,7 +106,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
|||||||
bytes32 poolId,
|
bytes32 poolId,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool needsApproval,
|
bool needsApproval,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = balancerV2Exposed.decodeParams(protocolData);
|
) = balancerV2Exposed.decodeParams(protocolData);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
@@ -112,7 +114,9 @@ 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));
|
assertEq(
|
||||||
|
uint8(transferType), uint8(RestrictTransferFrom.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,
|
RestrictTransferFrom.TransferType transferType,
|
||||||
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,
|
RestrictTransferFrom.TransferType.None,
|
||||||
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,
|
RestrictTransferFrom.TransferType transferType,
|
||||||
address receiver
|
address receiver
|
||||||
) = curveExecutorExposed.decodeData(data);
|
) = curveExecutorExposed.decodeData(data);
|
||||||
|
|
||||||
@@ -91,7 +91,9 @@ 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(
|
||||||
|
uint8(transferType), uint8(RestrictTransferFrom.TransferType.None)
|
||||||
|
);
|
||||||
assertEq(receiver, ALICE);
|
assertEq(receiver, ALICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +102,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
|
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data = _getData(DAI_ADDR, USDC_ADDR, TRIPOOL, 1, ALICE);
|
bytes memory data = _getData(
|
||||||
|
DAI_ADDR,
|
||||||
|
USDC_ADDR,
|
||||||
|
TRIPOOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -113,8 +122,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(address(curveExecutorExposed), amountIn);
|
deal(address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(ETH_ADDR_FOR_CURVE, STETH_ADDR, STETH_POOL, 1, ALICE);
|
ETH_ADDR_FOR_CURVE,
|
||||||
|
STETH_ADDR,
|
||||||
|
STETH_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -130,8 +145,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(WETH_ADDR, WBTC_ADDR, TRICRYPTO2_POOL, 3, ALICE);
|
WETH_ADDR,
|
||||||
|
WBTC_ADDR,
|
||||||
|
TRICRYPTO2_POOL,
|
||||||
|
3,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -144,7 +165,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 100 * 10 ** 6;
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data = _getData(USDC_ADDR, SUSD_ADDR, SUSD_POOL, 1, ALICE);
|
bytes memory data = _getData(
|
||||||
|
USDC_ADDR,
|
||||||
|
SUSD_ADDR,
|
||||||
|
SUSD_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -157,8 +185,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(FRAX_ADDR, address(curveExecutorExposed), amountIn);
|
deal(FRAX_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(FRAX_ADDR, USDC_ADDR, FRAX_USDC_POOL, 1, ALICE);
|
FRAX_ADDR,
|
||||||
|
USDC_ADDR,
|
||||||
|
FRAX_USDC_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -171,8 +205,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 100 * 10 ** 6;
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(USDC_ADDR, USDE_ADDR, USDE_USDC_POOL, 1, ALICE);
|
USDC_ADDR,
|
||||||
|
USDE_ADDR,
|
||||||
|
USDE_USDC_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -185,8 +225,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 100 * 10 ** 6;
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
deal(DOLA_ADDR, address(curveExecutorExposed), amountIn);
|
deal(DOLA_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1, ALICE);
|
DOLA_ADDR,
|
||||||
|
FRAXPYUSD_POOL,
|
||||||
|
DOLA_FRAXPYUSD_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -200,8 +246,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 initialBalance = address(ALICE).balance; // this address already has some ETH assigned to it
|
uint256 initialBalance = address(ALICE).balance; // this address already has some ETH assigned to it
|
||||||
deal(XYO_ADDR, address(curveExecutorExposed), amountIn);
|
deal(XYO_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(XYO_ADDR, ETH_ADDR_FOR_CURVE, ETH_XYO_POOL, 2, ALICE);
|
XYO_ADDR,
|
||||||
|
ETH_ADDR_FOR_CURVE,
|
||||||
|
ETH_XYO_POOL,
|
||||||
|
2,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -214,8 +266,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1000 ether;
|
uint256 amountIn = 1000 ether;
|
||||||
deal(BSGG_ADDR, address(curveExecutorExposed), amountIn);
|
deal(BSGG_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(BSGG_ADDR, USDT_ADDR, BSGG_USDT_POOL, 2, ALICE);
|
BSGG_ADDR,
|
||||||
|
USDT_ADDR,
|
||||||
|
BSGG_USDT_POOL,
|
||||||
|
2,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -228,8 +286,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(WETH_ADDR, USDC_ADDR, TRICRYPTO_POOL, 2, ALICE);
|
WETH_ADDR,
|
||||||
|
USDC_ADDR,
|
||||||
|
TRICRYPTO_POOL,
|
||||||
|
2,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -242,8 +306,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(UWU_ADDR, address(curveExecutorExposed), amountIn);
|
deal(UWU_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(UWU_ADDR, WETH_ADDR, UWU_WETH_POOL, 2, ALICE);
|
UWU_ADDR,
|
||||||
|
WETH_ADDR,
|
||||||
|
UWU_WETH_POOL,
|
||||||
|
2,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -256,8 +326,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 1 ether;
|
uint256 amountIn = 1 ether;
|
||||||
deal(USDT_ADDR, address(curveExecutorExposed), amountIn);
|
deal(USDT_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(USDT_ADDR, CRVUSD_ADDR, CRVUSD_USDT_POOL, 1, ALICE);
|
USDT_ADDR,
|
||||||
|
CRVUSD_ADDR,
|
||||||
|
CRVUSD_USDT_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -270,8 +346,14 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
uint256 amountIn = 100 * 10 ** 9; // 9 decimals
|
uint256 amountIn = 100 * 10 ** 9; // 9 decimals
|
||||||
deal(WTAO_ADDR, address(curveExecutorExposed), amountIn);
|
deal(WTAO_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
bytes memory data =
|
bytes memory data = _getData(
|
||||||
_getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1, ALICE);
|
WTAO_ADDR,
|
||||||
|
WSTTAO_ADDR,
|
||||||
|
WSTTAO_WTAO_POOL,
|
||||||
|
1,
|
||||||
|
ALICE,
|
||||||
|
RestrictTransferFrom.TransferType.None
|
||||||
|
);
|
||||||
|
|
||||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
@@ -284,7 +366,8 @@ contract CurveExecutorTest is Test, Constants {
|
|||||||
address tokenOut,
|
address tokenOut,
|
||||||
address pool,
|
address pool,
|
||||||
uint8 poolType,
|
uint8 poolType,
|
||||||
address receiver
|
address receiver,
|
||||||
|
RestrictTransferFrom.TransferType transferType
|
||||||
) internal view returns (bytes memory data) {
|
) internal view returns (bytes memory data) {
|
||||||
(int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool);
|
(int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool);
|
||||||
data = abi.encodePacked(
|
data = abi.encodePacked(
|
||||||
@@ -295,7 +378,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,
|
transferType,
|
||||||
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 "@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)
|
uint8(RestrictTransferFrom.TransferType.Transfer), // transfer type (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)
|
uint8(RestrictTransferFrom.TransferType.Transfer), // 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
|
uint8(RestrictTransferFrom.TransferType.Transfer), // 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
|
RestrictTransferFrom.TransferType transferType
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -43,14 +43,14 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
GHO_ADDR,
|
GHO_ADDR,
|
||||||
GHO_USDC_POOL,
|
GHO_USDC_POOL,
|
||||||
address(2),
|
address(2),
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
IERC20 tokenIn,
|
IERC20 tokenIn,
|
||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = maverickV2Exposed.decodeParams(params);
|
) = maverickV2Exposed.decodeParams(params);
|
||||||
|
|
||||||
assertEq(address(tokenIn), GHO_ADDR);
|
assertEq(address(tokenIn), GHO_ADDR);
|
||||||
@@ -58,7 +58,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
assertEq(receiver, address(2));
|
assertEq(receiver, address(2));
|
||||||
assertEq(
|
assertEq(
|
||||||
uint8(transferType),
|
uint8(transferType),
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
GHO_ADDR,
|
GHO_ADDR,
|
||||||
GHO_USDC_POOL,
|
GHO_USDC_POOL,
|
||||||
BOB,
|
BOB,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(GHO_ADDR, address(maverickV2Exposed), amountIn);
|
deal(GHO_ADDR, address(maverickV2Exposed), amountIn);
|
||||||
@@ -98,7 +98,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
IERC20 tokenIn,
|
IERC20 tokenIn,
|
||||||
address pool,
|
address pool,
|
||||||
address receiver,
|
address receiver,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = maverickV2Exposed.decodeParams(protocolData);
|
) = maverickV2Exposed.decodeParams(protocolData);
|
||||||
|
|
||||||
assertEq(address(tokenIn), GHO_ADDR);
|
assertEq(address(tokenIn), GHO_ADDR);
|
||||||
@@ -106,7 +106,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
|||||||
assertEq(receiver, BOB);
|
assertEq(receiver, BOB);
|
||||||
assertEq(
|
assertEq(
|
||||||
uint8(transferType),
|
uint8(transferType),
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// SPDX-License-Identifier: BUSL-1.1
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
pragma solidity ^0.8.26;
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
import "../TestUtils.sol";
|
||||||
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 {Constants} from "../Constants.sol";
|
import {Constants} from "../Constants.sol";
|
||||||
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||||
|
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||||
|
|
||||||
contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -23,7 +23,7 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
|||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -52,7 +52,7 @@ contract FakeUniswapV2Pool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
UniswapV2ExecutorExposed uniswapV2Exposed;
|
UniswapV2ExecutorExposed uniswapV2Exposed;
|
||||||
@@ -60,7 +60,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,7 +79,6 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
PERMIT2_ADDRESS,
|
PERMIT2_ADDRESS,
|
||||||
25
|
25
|
||||||
);
|
);
|
||||||
permit2 = IAllowanceTransfer(PERMIT2_ADDRESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDecodeParams() public view {
|
function testDecodeParams() public view {
|
||||||
@@ -89,7 +87,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(2),
|
address(2),
|
||||||
address(3),
|
address(3),
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -97,7 +95,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = uniswapV2Exposed.decodeParams(params);
|
) = uniswapV2Exposed.decodeParams(params);
|
||||||
|
|
||||||
assertEq(address(tokenIn), WETH_ADDR);
|
assertEq(address(tokenIn), WETH_ADDR);
|
||||||
@@ -105,8 +103,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
assertEq(receiver, address(3));
|
assertEq(receiver, address(3));
|
||||||
assertEq(zeroForOne, false);
|
assertEq(zeroForOne, false);
|
||||||
assertEq(
|
assertEq(
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL),
|
uint8(transferType),
|
||||||
uint8(transferType)
|
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +161,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
BOB,
|
BOB,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||||
@@ -173,59 +171,6 @@ 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;
|
||||||
@@ -235,7 +180,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
WETH_DAI_POOL,
|
WETH_DAI_POOL,
|
||||||
BOB,
|
BOB,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
uint8(TokenTransfer.TransferType.NONE)
|
RestrictTransferFrom.TransferType.None
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(WETH_ADDR, address(this), amountIn);
|
deal(WETH_ADDR, address(this), amountIn);
|
||||||
@@ -248,27 +193,29 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
|
|
||||||
function testDecodeIntegration() public view {
|
function testDecodeIntegration() public view {
|
||||||
bytes memory protocolData =
|
bytes memory protocolData =
|
||||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010000";
|
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010001";
|
||||||
|
|
||||||
(
|
(
|
||||||
IERC20 tokenIn,
|
IERC20 tokenIn,
|
||||||
address target,
|
address target,
|
||||||
address receiver,
|
address receiver,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = 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(
|
||||||
assertEq(0, uint8(transferType));
|
uint8(transferType),
|
||||||
|
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSwapIntegration() public {
|
function testSwapIntegration() public {
|
||||||
bytes memory protocolData =
|
bytes memory protocolData =
|
||||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0000";
|
loadCallDataFromFile("test_encode_uniswap_v2");
|
||||||
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);
|
||||||
@@ -287,7 +234,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
fakePool,
|
fakePool,
|
||||||
BOB,
|
BOB,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||||
@@ -307,7 +254,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
USDC_MAG7_POOL,
|
USDC_MAG7_POOL,
|
||||||
BOB,
|
BOB,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);
|
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return _decodeData(data);
|
return _decodeData(data);
|
||||||
@@ -71,7 +71,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(2),
|
address(2),
|
||||||
address(3),
|
address(3),
|
||||||
false,
|
false,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -81,7 +81,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) = uniswapV3Exposed.decodeData(data);
|
) = uniswapV3Exposed.decodeData(data);
|
||||||
|
|
||||||
assertEq(tokenIn, WETH_ADDR);
|
assertEq(tokenIn, WETH_ADDR);
|
||||||
@@ -92,7 +92,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
assertEq(zeroForOne, false);
|
assertEq(zeroForOne, false);
|
||||||
assertEq(
|
assertEq(
|
||||||
uint8(transferType),
|
uint8(transferType),
|
||||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(this),
|
address(this),
|
||||||
DAI_WETH_USV3,
|
DAI_WETH_USV3,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
|
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
|
||||||
@@ -150,7 +150,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
WETH_ADDR,
|
WETH_ADDR,
|
||||||
DAI_ADDR,
|
DAI_ADDR,
|
||||||
poolFee,
|
poolFee,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
RestrictTransferFrom.TransferType.Transfer,
|
||||||
address(uniswapV3Exposed)
|
address(uniswapV3Exposed)
|
||||||
);
|
);
|
||||||
uint256 dataOffset = 3; // some offset
|
uint256 dataOffset = 3; // some offset
|
||||||
@@ -184,7 +184,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address(this),
|
address(this),
|
||||||
fakePool,
|
fakePool,
|
||||||
zeroForOne,
|
zeroForOne,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
RestrictTransferFrom.TransferType.Transfer
|
||||||
);
|
);
|
||||||
|
|
||||||
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);
|
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);
|
||||||
@@ -197,7 +197,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
|||||||
address receiver,
|
address receiver,
|
||||||
address target,
|
address target,
|
||||||
bool zero2one,
|
bool zero2one,
|
||||||
TokenTransfer.TransferType transferType
|
RestrictTransferFrom.TransferType transferType
|
||||||
) internal view returns (bytes memory) {
|
) internal view returns (bytes memory) {
|
||||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||||
return abi.encodePacked(
|
return abi.encodePacked(
|
||||||
|
|||||||
@@ -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,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
TokenTransfer.TransferType transferType,
|
RestrictTransferFrom.TransferType transferType,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Pool[] memory pools
|
UniswapV4Pool[] memory pools
|
||||||
)
|
)
|
||||||
@@ -53,8 +52,6 @@ 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 =
|
|
||||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
|
||||||
|
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||||
@@ -70,14 +67,19 @@ 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,
|
||||||
|
RestrictTransferFrom.TransferType.Transfer,
|
||||||
|
ALICE,
|
||||||
|
pools
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOneDecoded,
|
bool zeroForOneDecoded,
|
||||||
TokenTransfer.TransferType transferTypeDecoded,
|
RestrictTransferFrom.TransferType transferType,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
||||||
) = uniswapV4Exposed.decodeData(data);
|
) = uniswapV4Exposed.decodeData(data);
|
||||||
@@ -85,7 +87,10 @@ 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(
|
||||||
|
uint8(transferType),
|
||||||
|
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||||
|
);
|
||||||
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);
|
||||||
@@ -115,7 +120,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
USDT_ADDR,
|
USDT_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
RestrictTransferFrom.TransferType.Transfer,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
@@ -172,7 +177,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
|||||||
USDE_ADDR,
|
USDE_ADDR,
|
||||||
WBTC_ADDR,
|
WBTC_ADDR,
|
||||||
true,
|
true,
|
||||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
RestrictTransferFrom.TransferType.Transfer,
|
||||||
ALICE,
|
ALICE,
|
||||||
pools
|
pools
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ library UniswapV4Utils {
|
|||||||
address tokenIn,
|
address tokenIn,
|
||||||
address tokenOut,
|
address tokenOut,
|
||||||
bool zeroForOne,
|
bool zeroForOne,
|
||||||
UniswapV4Executor.TransferType transferType,
|
RestrictTransferFrom.TransferType transferType,
|
||||||
address receiver,
|
address receiver,
|
||||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||||
) public pure returns (bytes memory) {
|
) public pure returns (bytes memory) {
|
||||||
|
|||||||
@@ -34,11 +34,12 @@ pub static IN_TRANSFER_REQUIRED_PROTOCOLS: LazyLock<HashSet<&'static str>> = Laz
|
|||||||
set
|
set
|
||||||
});
|
});
|
||||||
|
|
||||||
// The protocols here are a subset of the ones defined in IN_TRANSFER_REQUIRED_PROTOCOLS. The tokens
|
// The protocols here are a subset of the ones defined in IN_TRANSFER_REQUIRED_PROTOCOLS. The in
|
||||||
// can not be sent directly from the previous pool into a pool of this protocol. The tokens need to
|
// transfer needs to be performed inside the callback logic. This means, the tokens can not be sent
|
||||||
// be sent to the router and only then transferred into the pool. This is the case for uniswap v3
|
// directly from the previous pool into a pool of this protocol. The tokens need to be sent to the
|
||||||
// because of the callback logic. The only way for this to work it would be to call the second swap
|
// router and only then transferred into the pool. This is the case for uniswap v3 because of the
|
||||||
// during the callback of the first swap. This is currently not supported.
|
// callback logic. The only way for this to work it would be to call the second swap during the
|
||||||
|
// callback of the first swap. This is currently not supported.
|
||||||
pub static CALLBACK_CONSTRAINED_PROTOCOLS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
|
pub static CALLBACK_CONSTRAINED_PROTOCOLS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
set.insert("uniswap_v3");
|
set.insert("uniswap_v3");
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use crate::encoding::{
|
|||||||
/// * `selector`: String, the selector for the swap function in the router contract
|
/// * `selector`: String, the selector for the swap function in the router contract
|
||||||
/// * `router_address`: Address of the router to be used to execute swaps
|
/// * `router_address`: Address of the router to be used to execute swaps
|
||||||
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
||||||
|
/// * `token_in_already_in_router`: bool, whether the token in is already in the router
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SingleSwapStrategyEncoder {
|
pub struct SingleSwapStrategyEncoder {
|
||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
@@ -40,6 +41,7 @@ pub struct SingleSwapStrategyEncoder {
|
|||||||
selector: String,
|
selector: String,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
transfer_optimization: TransferOptimization,
|
transfer_optimization: TransferOptimization,
|
||||||
|
token_in_already_in_router: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SingleSwapStrategyEncoder {
|
impl SingleSwapStrategyEncoder {
|
||||||
@@ -55,10 +57,10 @@ impl SingleSwapStrategyEncoder {
|
|||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
"singleSwap(uint256,address,address,uint256,bool,bool,address,bytes)".to_string(),
|
"singleSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)"
|
||||||
|
.to_string(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let permit2_is_active = permit2.is_some();
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
permit2,
|
permit2,
|
||||||
selector,
|
selector,
|
||||||
@@ -67,10 +69,10 @@ impl SingleSwapStrategyEncoder {
|
|||||||
transfer_optimization: TransferOptimization::new(
|
transfer_optimization: TransferOptimization::new(
|
||||||
chain.native_token()?,
|
chain.native_token()?,
|
||||||
chain.wrapped_token()?,
|
chain.wrapped_token()?,
|
||||||
permit2_is_active,
|
|
||||||
token_in_already_in_router,
|
token_in_already_in_router,
|
||||||
router_address,
|
router_address,
|
||||||
),
|
),
|
||||||
|
token_in_already_in_router,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,16 +127,16 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
|||||||
let swap_receiver =
|
let swap_receiver =
|
||||||
if !unwrap { solution.receiver.clone() } else { self.router_address.clone() };
|
if !unwrap { solution.receiver.clone() } else { self.router_address.clone() };
|
||||||
|
|
||||||
let transfer_type = self
|
let transfer = self
|
||||||
.transfer_optimization
|
.transfer_optimization
|
||||||
.get_transfer_type(grouped_swap.clone(), solution.given_token.clone(), wrap, false);
|
.get_transfers(grouped_swap.clone(), solution.given_token.clone(), wrap, false);
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
receiver: swap_receiver.clone(),
|
receiver: swap_receiver.clone(),
|
||||||
exact_out: solution.exact_out,
|
exact_out: solution.exact_out,
|
||||||
router_address: Some(self.router_address.clone()),
|
router_address: Some(self.router_address.clone()),
|
||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer_type.clone(),
|
transfer_type: transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||||
@@ -178,6 +180,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
|||||||
wrap,
|
wrap,
|
||||||
unwrap,
|
unwrap,
|
||||||
bytes_to_address(&solution.receiver)?,
|
bytes_to_address(&solution.receiver)?,
|
||||||
|
!self.token_in_already_in_router,
|
||||||
swap_data,
|
swap_data,
|
||||||
)
|
)
|
||||||
.abi_encode()
|
.abi_encode()
|
||||||
@@ -210,6 +213,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
|||||||
/// * `sequential_swap_validator`: SequentialSwapValidator, responsible for checking validity of
|
/// * `sequential_swap_validator`: SequentialSwapValidator, responsible for checking validity of
|
||||||
/// sequential swap solutions
|
/// sequential swap solutions
|
||||||
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
||||||
|
/// * `token_in_already_in_router`: bool, whether the token in is already in the router
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SequentialSwapStrategyEncoder {
|
pub struct SequentialSwapStrategyEncoder {
|
||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
@@ -220,6 +224,7 @@ pub struct SequentialSwapStrategyEncoder {
|
|||||||
wrapped_address: Bytes,
|
wrapped_address: Bytes,
|
||||||
sequential_swap_validator: SequentialSwapValidator,
|
sequential_swap_validator: SequentialSwapValidator,
|
||||||
transfer_optimization: TransferOptimization,
|
transfer_optimization: TransferOptimization,
|
||||||
|
token_in_already_in_router: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SequentialSwapStrategyEncoder {
|
impl SequentialSwapStrategyEncoder {
|
||||||
@@ -235,11 +240,10 @@ impl SequentialSwapStrategyEncoder {
|
|||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
"sequentialSwap(uint256,address,address,uint256,bool,bool,address,bytes)"
|
"sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let permit2_is_active = permit2.is_some();
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
permit2,
|
permit2,
|
||||||
selector,
|
selector,
|
||||||
@@ -251,10 +255,10 @@ impl SequentialSwapStrategyEncoder {
|
|||||||
transfer_optimization: TransferOptimization::new(
|
transfer_optimization: TransferOptimization::new(
|
||||||
chain.native_token()?,
|
chain.native_token()?,
|
||||||
chain.wrapped_token()?,
|
chain.wrapped_token()?,
|
||||||
permit2_is_active,
|
|
||||||
token_in_already_in_router,
|
token_in_already_in_router,
|
||||||
router_address,
|
router_address,
|
||||||
),
|
),
|
||||||
|
token_in_already_in_router,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,9 +315,10 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
.transfer_optimization
|
.transfer_optimization
|
||||||
.get_receiver(solution.receiver.clone(), next_swap)?;
|
.get_receiver(solution.receiver.clone(), next_swap)?;
|
||||||
next_in_between_swap_optimization_allowed = next_swap_optimization;
|
next_in_between_swap_optimization_allowed = next_swap_optimization;
|
||||||
let transfer_type = self
|
|
||||||
|
let transfer = self
|
||||||
.transfer_optimization
|
.transfer_optimization
|
||||||
.get_transfer_type(
|
.get_transfers(
|
||||||
grouped_swap.clone(),
|
grouped_swap.clone(),
|
||||||
solution.given_token.clone(),
|
solution.given_token.clone(),
|
||||||
wrap,
|
wrap,
|
||||||
@@ -325,7 +330,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
router_address: Some(self.router_address.clone()),
|
router_address: Some(self.router_address.clone()),
|
||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer_type.clone(),
|
transfer_type: transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||||
@@ -374,6 +379,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
wrap,
|
wrap,
|
||||||
unwrap,
|
unwrap,
|
||||||
bytes_to_address(&solution.receiver)?,
|
bytes_to_address(&solution.receiver)?,
|
||||||
|
!self.token_in_already_in_router,
|
||||||
encoded_swaps,
|
encoded_swaps,
|
||||||
)
|
)
|
||||||
.abi_encode()
|
.abi_encode()
|
||||||
@@ -406,6 +412,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
/// solutions
|
/// solutions
|
||||||
/// * `router_address`: Address of the router to be used to execute swaps
|
/// * `router_address`: Address of the router to be used to execute swaps
|
||||||
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
||||||
|
/// * `token_in_already_in_router`: bool, whether the token in is already in the router
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SplitSwapStrategyEncoder {
|
pub struct SplitSwapStrategyEncoder {
|
||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
@@ -416,6 +423,7 @@ pub struct SplitSwapStrategyEncoder {
|
|||||||
split_swap_validator: SplitSwapValidator,
|
split_swap_validator: SplitSwapValidator,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
transfer_optimization: TransferOptimization,
|
transfer_optimization: TransferOptimization,
|
||||||
|
token_in_already_in_router: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SplitSwapStrategyEncoder {
|
impl SplitSwapStrategyEncoder {
|
||||||
@@ -431,11 +439,10 @@ impl SplitSwapStrategyEncoder {
|
|||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
"splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)"
|
"splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let permit2_is_active = permit2.is_some();
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
permit2,
|
permit2,
|
||||||
selector,
|
selector,
|
||||||
@@ -447,10 +454,10 @@ impl SplitSwapStrategyEncoder {
|
|||||||
transfer_optimization: TransferOptimization::new(
|
transfer_optimization: TransferOptimization::new(
|
||||||
chain.native_token()?,
|
chain.native_token()?,
|
||||||
chain.wrapped_token()?,
|
chain.wrapped_token()?,
|
||||||
permit2_is_active,
|
|
||||||
token_in_already_in_router,
|
token_in_already_in_router,
|
||||||
router_address,
|
router_address,
|
||||||
),
|
),
|
||||||
|
token_in_already_in_router,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,16 +560,16 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
|||||||
} else {
|
} else {
|
||||||
self.router_address.clone()
|
self.router_address.clone()
|
||||||
};
|
};
|
||||||
let transfer_type = self
|
let transfer = self
|
||||||
.transfer_optimization
|
.transfer_optimization
|
||||||
.get_transfer_type(grouped_swap.clone(), solution.given_token.clone(), wrap, false);
|
.get_transfers(grouped_swap.clone(), solution.given_token.clone(), wrap, false);
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
receiver: swap_receiver.clone(),
|
receiver: swap_receiver.clone(),
|
||||||
exact_out: solution.exact_out,
|
exact_out: solution.exact_out,
|
||||||
router_address: Some(self.router_address.clone()),
|
router_address: Some(self.router_address.clone()),
|
||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer_type.clone(),
|
transfer_type: transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||||
@@ -621,6 +628,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
|||||||
unwrap,
|
unwrap,
|
||||||
U256::from(tokens_len),
|
U256::from(tokens_len),
|
||||||
bytes_to_address(&solution.receiver)?,
|
bytes_to_address(&solution.receiver)?,
|
||||||
|
!self.token_in_already_in_router,
|
||||||
encoded_swaps,
|
encoded_swaps,
|
||||||
)
|
)
|
||||||
.abi_encode()
|
.abi_encode()
|
||||||
@@ -750,7 +758,7 @@ mod tests {
|
|||||||
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
||||||
let expected_input = [
|
let expected_input = [
|
||||||
"30ace1b1", // Function selector
|
"30ace1b1", // Function selector
|
||||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out
|
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||||
&expected_min_amount_encoded, // min amount out
|
&expected_min_amount_encoded, // min amount out
|
||||||
@@ -772,7 +780,7 @@ mod tests {
|
|||||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"02", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
"0000000000000000000000000000", // padding
|
"0000000000000000000000000000", // padding
|
||||||
));
|
));
|
||||||
let hex_calldata = encode(&calldata);
|
let hex_calldata = encode(&calldata);
|
||||||
@@ -839,7 +847,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
||||||
let expected_input = [
|
let expected_input = [
|
||||||
"20144a07", // Function selector
|
"5c4b639c", // Function selector
|
||||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||||
@@ -847,7 +855,8 @@ mod tests {
|
|||||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes
|
"0000000000000000000000000000000000000000000000000000000000000001", // transfer from needed
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes
|
||||||
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
||||||
|
|
||||||
// Swap data
|
// Swap data
|
||||||
@@ -856,8 +865,8 @@ mod tests {
|
|||||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"01", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
"0000000000000000000000000000", // padding
|
"0000000000000000000000000000", // padding
|
||||||
]
|
]
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
@@ -921,7 +930,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
||||||
let expected_input = [
|
let expected_input = [
|
||||||
"20144a07", // Function selector
|
"5c4b639c", // Function selector
|
||||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||||
@@ -929,7 +938,8 @@ mod tests {
|
|||||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes
|
"0000000000000000000000000000000000000000000000000000000000000000", // transfer from not needed
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes
|
||||||
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
||||||
|
|
||||||
// Swap data
|
// Swap data
|
||||||
@@ -938,7 +948,7 @@ mod tests {
|
|||||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"00", // transfer type
|
"01", // transfer type Transfer
|
||||||
"0000000000000000000000000000", // padding
|
"0000000000000000000000000000", // padding
|
||||||
]
|
]
|
||||||
.join("");
|
.join("");
|
||||||
@@ -1191,7 +1201,7 @@ mod tests {
|
|||||||
let hex_calldata = encode(&calldata);
|
let hex_calldata = encode(&calldata);
|
||||||
|
|
||||||
let expected = String::from(concat!(
|
let expected = String::from(concat!(
|
||||||
"e8a980d7", /* function selector */
|
"e21dd0d3", /* function selector */
|
||||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
|
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
|
||||||
@@ -1199,7 +1209,8 @@ mod tests {
|
|||||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"0000000000000000000000000000000000000000000000000000000000000100", /* length ple
|
"0000000000000000000000000000000000000000000000000000000000000001", /* transfer from needed */
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000120", /* length ple
|
||||||
* encode */
|
* encode */
|
||||||
"00000000000000000000000000000000000000000000000000000000000000a8",
|
"00000000000000000000000000000000000000000000000000000000000000a8",
|
||||||
// swap 1
|
// swap 1
|
||||||
@@ -1209,7 +1220,7 @@ mod tests {
|
|||||||
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
|
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
|
||||||
"004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool)
|
"004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool)
|
||||||
"00", // zero to one
|
"00", // zero to one
|
||||||
"01", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
// swap 2
|
// swap 2
|
||||||
"0052", // swap length
|
"0052", // swap length
|
||||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||||
@@ -1217,7 +1228,7 @@ mod tests {
|
|||||||
"004375dff511095cc5a197a54140a24efef3a416", // component id
|
"004375dff511095cc5a197a54140a24efef3a416", // component id
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
|
||||||
"01", // zero to one
|
"01", // zero to one
|
||||||
"05", // transfer type - None
|
"02", // transfer type None
|
||||||
"000000000000000000000000000000000000000000000000", // padding
|
"000000000000000000000000000000000000000000000000", // padding
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -1336,7 +1347,7 @@ mod tests {
|
|||||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||||
"01", // zero2one
|
"01", // zero2one
|
||||||
"02", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
"0069", // ple encoded swaps
|
"0069", // ple encoded swaps
|
||||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||||
@@ -1345,7 +1356,7 @@ mod tests {
|
|||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"00", // transfer type
|
"01", // transfer type Transfer
|
||||||
"00000000000000000000", // padding
|
"00000000000000000000", // padding
|
||||||
]
|
]
|
||||||
.join("");
|
.join("");
|
||||||
@@ -2062,7 +2073,7 @@ mod tests {
|
|||||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||||
"01", // zero2one
|
"01", // zero2one
|
||||||
"02", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
"006e", // ple encoded swaps
|
"006e", // ple encoded swaps
|
||||||
"00", // token in index
|
"00", // token in index
|
||||||
"01", // token out index
|
"01", // token out index
|
||||||
@@ -2074,7 +2085,7 @@ mod tests {
|
|||||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||||
"01", // zero2one
|
"01", // zero2one
|
||||||
"02", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
"0057", // ple encoded swaps
|
"0057", // ple encoded swaps
|
||||||
"01", // token in index
|
"01", // token in index
|
||||||
"00", // token out index
|
"00", // token out index
|
||||||
@@ -2084,7 +2095,7 @@ mod tests {
|
|||||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id,
|
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id,
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"00", // transfer type
|
"01", // transfer type Transfer
|
||||||
"00000000000000" // padding
|
"00000000000000" // padding
|
||||||
]
|
]
|
||||||
.join("");
|
.join("");
|
||||||
@@ -2224,7 +2235,7 @@ mod tests {
|
|||||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
|
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
|
||||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||||
"01", // zero2one
|
"01", // zero2one
|
||||||
"02", // transfer type
|
"00", // transfer type TransferFrom
|
||||||
"006e", // ple encoded swaps
|
"006e", // ple encoded swaps
|
||||||
"01", // token in index
|
"01", // token in index
|
||||||
"00", // token out index
|
"00", // token out index
|
||||||
@@ -2236,7 +2247,7 @@ mod tests {
|
|||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"00", // transfer type
|
"01", // transfer type Transfer
|
||||||
"006e", // ple encoded swaps
|
"006e", // ple encoded swaps
|
||||||
"01", // token in index
|
"01", // token in index
|
||||||
"00", // token out index
|
"00", // token out index
|
||||||
@@ -2248,7 +2259,7 @@ mod tests {
|
|||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"00", // transfer type
|
"01", // transfer type Transfer
|
||||||
"00000000000000" // padding
|
"00000000000000" // padding
|
||||||
]
|
]
|
||||||
.join("");
|
.join("");
|
||||||
@@ -2625,7 +2636,7 @@ mod tests {
|
|||||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
|
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
|
||||||
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
|
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
|
||||||
"00", // zero2one
|
"00", // zero2one
|
||||||
"02", // transfer type (transfer to router)
|
"00", // transfer type TransferFrom
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||||
// First pool params
|
// First pool params
|
||||||
"0000000000000000000000000000000000000000", // intermediary token (ETH)
|
"0000000000000000000000000000000000000000", // intermediary token (ETH)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use crate::encoding::{
|
|||||||
pub struct TransferOptimization {
|
pub struct TransferOptimization {
|
||||||
native_token: Bytes,
|
native_token: Bytes,
|
||||||
wrapped_token: Bytes,
|
wrapped_token: Bytes,
|
||||||
permit2: bool,
|
|
||||||
token_in_already_in_router: bool,
|
token_in_already_in_router: bool,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
}
|
}
|
||||||
@@ -25,69 +24,58 @@ impl TransferOptimization {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
native_token: Bytes,
|
native_token: Bytes,
|
||||||
wrapped_token: Bytes,
|
wrapped_token: Bytes,
|
||||||
permit2: bool,
|
|
||||||
token_in_already_in_router: bool,
|
token_in_already_in_router: bool,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
TransferOptimization {
|
TransferOptimization {
|
||||||
native_token,
|
native_token,
|
||||||
wrapped_token,
|
wrapped_token,
|
||||||
permit2,
|
|
||||||
token_in_already_in_router,
|
token_in_already_in_router,
|
||||||
router_address,
|
router_address,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the transfer method that should be used for the given swap and solution.
|
/// Returns the transfer type that should be used for the current transfer.
|
||||||
pub fn get_transfer_type(
|
pub fn get_transfers(
|
||||||
&self,
|
&self,
|
||||||
swap: SwapGroup,
|
swap: SwapGroup,
|
||||||
given_token: Bytes,
|
given_token: Bytes,
|
||||||
wrap: bool,
|
wrap: bool,
|
||||||
in_between_swap_optimization: bool,
|
in_between_swap_optimization: bool,
|
||||||
) -> TransferType {
|
) -> TransferType {
|
||||||
|
let is_first_swap = swap.token_in == given_token;
|
||||||
let in_transfer_required: bool =
|
let in_transfer_required: bool =
|
||||||
IN_TRANSFER_REQUIRED_PROTOCOLS.contains(&swap.protocol_system.as_str());
|
IN_TRANSFER_REQUIRED_PROTOCOLS.contains(&swap.protocol_system.as_str());
|
||||||
|
|
||||||
let is_first_swap = swap.token_in == given_token;
|
|
||||||
|
|
||||||
if swap.token_in == self.native_token {
|
if swap.token_in == self.native_token {
|
||||||
// Funds are already in router. All protocols currently take care of native transfers.
|
// Funds are already in router. All protocols currently take care of native transfers.
|
||||||
TransferType::None
|
TransferType::None
|
||||||
} else if (swap.token_in == self.wrapped_token) && wrap {
|
} else if (swap.token_in == self.wrapped_token) && wrap {
|
||||||
// Wrapping already happened in the router so we can just use a normal transfer.
|
// Wrapping already happened in the router so, we just do a normal transfer.
|
||||||
TransferType::TransferToProtocol
|
TransferType::Transfer
|
||||||
} else if is_first_swap {
|
} else if is_first_swap {
|
||||||
if in_transfer_required {
|
if in_transfer_required {
|
||||||
if self.token_in_already_in_router {
|
if self.token_in_already_in_router {
|
||||||
// Transfer from router to pool.
|
// Transfer from router to pool.
|
||||||
TransferType::TransferToProtocol
|
TransferType::Transfer
|
||||||
} else if self.permit2 {
|
|
||||||
// Transfer from swapper to pool using permit2.
|
|
||||||
TransferType::TransferPermit2ToProtocol
|
|
||||||
} else {
|
} else {
|
||||||
// Transfer from swapper to pool.
|
// Transfer from swapper to pool
|
||||||
TransferType::TransferFromToProtocol
|
TransferType::TransferFrom
|
||||||
}
|
}
|
||||||
// in transfer is not necessary for these protocols. Only make a transfer if the
|
// in transfer is not necessary for these protocols. Only make a transfer from the
|
||||||
// tokens are not already in the router
|
// swapper to the router if the tokens are not already in the router
|
||||||
} else if !self.token_in_already_in_router {
|
} else if !self.token_in_already_in_router {
|
||||||
if self.permit2 {
|
// Transfer from swapper to router using.
|
||||||
// Transfer from swapper to router using permit2.
|
TransferType::TransferFrom
|
||||||
TransferType::TransferPermit2ToRouter
|
|
||||||
} else {
|
|
||||||
// Transfer from swapper to router.
|
|
||||||
TransferType::TransferFromToRouter
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
TransferType::None
|
TransferType::None
|
||||||
}
|
}
|
||||||
// all other swaps
|
// all other swaps that not the first one
|
||||||
} else if !in_transfer_required || in_between_swap_optimization {
|
} else if !in_transfer_required || in_between_swap_optimization {
|
||||||
// funds should already be in the router or in the next pool
|
// funds should already be in the router or in the next pool
|
||||||
TransferType::None
|
TransferType::None
|
||||||
} else {
|
} else {
|
||||||
TransferType::TransferToProtocol
|
TransferType::Transfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,146 +143,63 @@ mod tests {
|
|||||||
Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f")
|
Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn test_first_swap_transfer_from_permit2() {
|
// First swap tests
|
||||||
|
// WETH -(univ2)-> DAI we expect a transfer from the user to the protocol
|
||||||
|
#[case(weth(), weth(), "uniswap_v2".to_string(), false, false,false, TransferType::TransferFrom)]
|
||||||
|
// Native token swap. No transfer is needed
|
||||||
|
#[case(eth(), eth(), "uniswap_v2".to_string(),false, false,false, TransferType::None)]
|
||||||
|
// ETH -(wrap)-> WETH -(univ2)-> DAI. Only a transfer from the router into the protocol is
|
||||||
|
// needed
|
||||||
|
#[case(eth(), weth(), "uniswap_v2".to_string(),true, false,false,TransferType::Transfer)]
|
||||||
|
// USDC -(univ2)-> DAI and the tokens are already in the router. Only a transfer from the router
|
||||||
|
// to the protocol is needed
|
||||||
|
#[case(usdc(), usdc(), "uniswap_v2".to_string(),false, true,false, TransferType::Transfer)]
|
||||||
|
// USDC -(curve)-> DAI and the tokens are already in the router. No transfer is needed
|
||||||
|
#[case(usdc(), usdc(), "vm:curve".to_string(),false, true, false,TransferType::None)]
|
||||||
|
// other swaps tests
|
||||||
|
// tokens need to be transferred into the pool
|
||||||
|
#[case(weth(), usdc(), "uniswap_v2".to_string(), false, false,false, TransferType::Transfer)]
|
||||||
|
// tokens are already in the pool (optimization)
|
||||||
|
#[case(weth(), usdc(), "uniswap_v2".to_string(), false, false, true, TransferType::None)]
|
||||||
|
// tokens are already in the router and don't need a transfer
|
||||||
|
#[case(weth(), usdc(), "vm:curve".to_string(), false, false, false, TransferType::None)]
|
||||||
|
fn test_get_transfers(
|
||||||
|
#[case] given_token: Bytes,
|
||||||
|
#[case] swap_token_in: Bytes,
|
||||||
|
#[case] protocol: String,
|
||||||
|
#[case] wrap: bool,
|
||||||
|
#[case] token_in_already_in_router: bool,
|
||||||
|
#[case] in_between_swap_optimization: bool,
|
||||||
|
#[case] expected_transfer: TransferType,
|
||||||
|
) {
|
||||||
// The swap token is the same as the given token, which is not the native token
|
// The swap token is the same as the given token, which is not the native token
|
||||||
let swap = SwapGroup {
|
let swaps = vec![Swap {
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
component: ProtocolComponent {
|
||||||
token_in: weth(),
|
protocol_system: "uniswap_v2".to_string(),
|
||||||
|
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
token_in: swap_token_in.clone(),
|
||||||
token_out: dai(),
|
token_out: dai(),
|
||||||
split: 0f64,
|
split: 0f64,
|
||||||
swaps: vec![],
|
}];
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), true, false, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_first_swap_transfer_from() {
|
|
||||||
// The swap token is the same as the given token, which is not the native token
|
|
||||||
let swap = SwapGroup {
|
let swap = SwapGroup {
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
protocol_system: protocol,
|
||||||
token_in: weth(),
|
token_in: swap_token_in,
|
||||||
token_out: dai(),
|
token_out: dai(),
|
||||||
split: 0f64,
|
split: 0f64,
|
||||||
swaps: vec![],
|
swaps,
|
||||||
};
|
};
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
let optimization =
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
|
TransferOptimization::new(eth(), weth(), token_in_already_in_router, router_address());
|
||||||
assert_eq!(transfer_method, TransferType::TransferFromToProtocol);
|
let transfer = optimization.get_transfers(
|
||||||
}
|
swap.clone(),
|
||||||
|
given_token,
|
||||||
#[test]
|
wrap,
|
||||||
fn test_first_swap_native() {
|
in_between_swap_optimization,
|
||||||
// The swap token is the same as the given token, and it's the native token.
|
);
|
||||||
// No transfer action is needed.
|
assert_eq!(transfer, expected_transfer);
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
|
||||||
token_in: eth(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), false, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_first_swap_wrapped() {
|
|
||||||
// The swap token is NOT the same as the given token, but we are wrapping.
|
|
||||||
// Since the swap's token in is the wrapped token - this is the first swap.
|
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
|
||||||
token_in: weth(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), true, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_not_first_swap() {
|
|
||||||
// The swap token is NOT the same as the given token, and we are NOT wrapping.
|
|
||||||
// Thus, this is not the first swap.
|
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
|
||||||
token_in: usdc(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_not_first_swap_funds_in_router() {
|
|
||||||
// Not the first swap and the protocol requires the funds to be in the router (which they
|
|
||||||
// already are, so the transfer type is None)
|
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "vm:curve".to_string(),
|
|
||||||
token_in: usdc(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_not_first_swap_in_between_swap_optimization() {
|
|
||||||
// Not the first swap and the in between swaps are optimized. The funds should already be in
|
|
||||||
// the next pool or in the router
|
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
|
||||||
token_in: usdc(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, true);
|
|
||||||
assert_eq!(transfer_method, TransferType::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_first_swap_tokens_already_in_router_optimization() {
|
|
||||||
// It is the first swap, tokens are already in the router and the protocol requires the
|
|
||||||
// transfer in
|
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "uniswap_v2".to_string(),
|
|
||||||
token_in: usdc(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, true, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), usdc(), false, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::TransferToProtocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_first_swap_tokens_already_in_router_no_transfer_needed_optimization() {
|
|
||||||
// It is the first swap, tokens are already in the router and the protocol does not require
|
|
||||||
// the transfer in
|
|
||||||
let swap = SwapGroup {
|
|
||||||
protocol_system: "vm:curve".to_string(),
|
|
||||||
token_in: usdc(),
|
|
||||||
token_out: dai(),
|
|
||||||
split: 0f64,
|
|
||||||
swaps: vec![],
|
|
||||||
};
|
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, true, router_address());
|
|
||||||
let transfer_method = optimization.get_transfer_type(swap.clone(), usdc(), false, false);
|
|
||||||
assert_eq!(transfer_method, TransferType::None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receiver() -> Bytes {
|
fn receiver() -> Bytes {
|
||||||
@@ -319,7 +224,7 @@ mod tests {
|
|||||||
#[case] expected_receiver: Bytes,
|
#[case] expected_receiver: Bytes,
|
||||||
#[case] expected_optimization: bool,
|
#[case] expected_optimization: bool,
|
||||||
) {
|
) {
|
||||||
let optimization = TransferOptimization::new(eth(), weth(), false, false, router_address());
|
let optimization = TransferOptimization::new(eth(), weth(), false, router_address());
|
||||||
|
|
||||||
let next_swap = if protocol.is_none() {
|
let next_swap = if protocol.is_none() {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encode_uniswap_v2() {
|
fn test_encode_uniswap_v2() {
|
||||||
let usv2_pool = ProtocolComponent {
|
let usv2_pool = ProtocolComponent {
|
||||||
id: String::from("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
id: String::from("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11"),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -605,12 +605,12 @@ mod tests {
|
|||||||
split: 0f64,
|
split: 0f64,
|
||||||
};
|
};
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
receiver: Bytes::from("0x0000000000000000000000000000000000000001"),
|
receiver: Bytes::from("0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e"), // BOB
|
||||||
exact_out: false,
|
exact_out: false,
|
||||||
router_address: Some(Bytes::zero(20)),
|
router_address: Some(Bytes::zero(20)),
|
||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
let encoder = UniswapV2SwapEncoder::new(
|
let encoder = UniswapV2SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -628,15 +628,16 @@ mod tests {
|
|||||||
// in token
|
// in token
|
||||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||||
// component id
|
// component id
|
||||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
|
"a478c2975ab1ea89e8196811f51a7b7ade33eb11",
|
||||||
// receiver
|
// receiver
|
||||||
"0000000000000000000000000000000000000001",
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
// zero for one
|
// zero for one
|
||||||
"00",
|
"00",
|
||||||
// transfer type (transfer)
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
write_calldata_to_file("test_encode_uniswap_v2", hex_swap.as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +669,7 @@ mod tests {
|
|||||||
router_address: Some(Bytes::zero(20)),
|
router_address: Some(Bytes::zero(20)),
|
||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
let encoder = UniswapV3SwapEncoder::new(
|
let encoder = UniswapV3SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -695,8 +696,8 @@ mod tests {
|
|||||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
|
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
|
||||||
// zero for one
|
// zero for one
|
||||||
"00",
|
"00",
|
||||||
// transfer type (transfer)
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -759,8 +760,8 @@ mod tests {
|
|||||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
// approval needed
|
// approval needed
|
||||||
"01",
|
"01",
|
||||||
// transfer type
|
// transfer type None
|
||||||
"05"
|
"02"
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
write_calldata_to_file("test_encode_balancer_v2", hex_swap.as_str());
|
write_calldata_to_file("test_encode_balancer_v2", hex_swap.as_str());
|
||||||
@@ -804,7 +805,7 @@ mod tests {
|
|||||||
|
|
||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
let encoder = UniswapV4SwapEncoder::new(
|
let encoder = UniswapV4SwapEncoder::new(
|
||||||
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
|
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
|
||||||
@@ -826,8 +827,8 @@ mod tests {
|
|||||||
"dac17f958d2ee523a2206206994597c13d831ec7",
|
"dac17f958d2ee523a2206206994597c13d831ec7",
|
||||||
// zero for one
|
// zero for one
|
||||||
"01",
|
"01",
|
||||||
// transfer type
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
// receiver
|
// receiver
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||||
// pool params:
|
// pool params:
|
||||||
@@ -875,7 +876,7 @@ mod tests {
|
|||||||
group_token_in: group_token_in.clone(),
|
group_token_in: group_token_in.clone(),
|
||||||
// Token out is the same as the group token out
|
// Token out is the same as the group token out
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder = UniswapV4SwapEncoder::new(
|
let encoder = UniswapV4SwapEncoder::new(
|
||||||
@@ -918,7 +919,7 @@ mod tests {
|
|||||||
router_address: Some(router_address.clone()),
|
router_address: Some(router_address.clone()),
|
||||||
group_token_in: usde_address.clone(),
|
group_token_in: usde_address.clone(),
|
||||||
group_token_out: wbtc_address.clone(),
|
group_token_out: wbtc_address.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup - First sequence: USDE -> USDT
|
// Setup - First sequence: USDE -> USDT
|
||||||
@@ -996,8 +997,8 @@ mod tests {
|
|||||||
"2260fac5e5542a773aa44fbcfedf7c193bc2c599",
|
"2260fac5e5542a773aa44fbcfedf7c193bc2c599",
|
||||||
// zero for one
|
// zero for one
|
||||||
"01",
|
"01",
|
||||||
// transfer type
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
// receiver
|
// receiver
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||||
// pool params:
|
// pool params:
|
||||||
@@ -1053,7 +1054,7 @@ mod tests {
|
|||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
exact_out: false,
|
exact_out: false,
|
||||||
router_address: Some(Bytes::default()),
|
router_address: Some(Bytes::default()),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder =
|
let encoder =
|
||||||
@@ -1069,8 +1070,8 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex_swap,
|
hex_swap,
|
||||||
concat!(
|
concat!(
|
||||||
// transfer type
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
// receiver
|
// receiver
|
||||||
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
|
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
|
||||||
// group token in
|
// group token in
|
||||||
@@ -1099,7 +1100,7 @@ mod tests {
|
|||||||
group_token_out: group_token_out.clone(),
|
group_token_out: group_token_out.clone(),
|
||||||
exact_out: false,
|
exact_out: false,
|
||||||
router_address: Some(Bytes::default()),
|
router_address: Some(Bytes::default()),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_swap = Swap {
|
let first_swap = Swap {
|
||||||
@@ -1149,8 +1150,8 @@ mod tests {
|
|||||||
combined_hex,
|
combined_hex,
|
||||||
// transfer type
|
// transfer type
|
||||||
concat!(
|
concat!(
|
||||||
// transfer type
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
// receiver
|
// receiver
|
||||||
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
|
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
|
||||||
// group token in
|
// group token in
|
||||||
@@ -1332,10 +1333,10 @@ mod tests {
|
|||||||
"01",
|
"01",
|
||||||
// approval needed
|
// approval needed
|
||||||
"01",
|
"01",
|
||||||
// transfer type
|
// transfer type None
|
||||||
"05",
|
"02",
|
||||||
// receiver,
|
// receiver,
|
||||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1403,10 +1404,10 @@ mod tests {
|
|||||||
"00",
|
"00",
|
||||||
// approval needed
|
// approval needed
|
||||||
"01",
|
"01",
|
||||||
// transfer type
|
// transfer type None
|
||||||
"05",
|
"02",
|
||||||
// receiver
|
// receiver
|
||||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1484,10 +1485,10 @@ mod tests {
|
|||||||
"01",
|
"01",
|
||||||
// approval needed
|
// approval needed
|
||||||
"01",
|
"01",
|
||||||
// transfer type
|
// transfer type None
|
||||||
"05",
|
"02",
|
||||||
// receiver
|
// receiver
|
||||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1516,7 +1517,7 @@ mod tests {
|
|||||||
router_address: Some(Bytes::default()),
|
router_address: Some(Bytes::default()),
|
||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: TransferType::Transfer,
|
||||||
};
|
};
|
||||||
let encoder = MaverickV2SwapEncoder::new(
|
let encoder = MaverickV2SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -1539,8 +1540,8 @@ mod tests {
|
|||||||
"14Cf6D2Fe3E1B326114b07d22A6F6bb59e346c67",
|
"14Cf6D2Fe3E1B326114b07d22A6F6bb59e346c67",
|
||||||
// receiver
|
// receiver
|
||||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
// transfer from router to protocol
|
// transfer true
|
||||||
"00",
|
"01",
|
||||||
))
|
))
|
||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use tycho_common::Bytes;
|
|||||||
use crate::encoding::{
|
use crate::encoding::{
|
||||||
errors::EncodingError,
|
errors::EncodingError,
|
||||||
evm::{
|
evm::{
|
||||||
constants::GROUPABLE_PROTOCOLS,
|
constants::{GROUPABLE_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS},
|
||||||
group_swaps::group_swaps,
|
group_swaps::group_swaps,
|
||||||
strategy_encoder::strategy_encoders::{
|
strategy_encoder::strategy_encoders::{
|
||||||
SequentialSwapStrategyEncoder, SingleSwapStrategyEncoder, SplitSwapStrategyEncoder,
|
SequentialSwapStrategyEncoder, SingleSwapStrategyEncoder, SplitSwapStrategyEncoder,
|
||||||
@@ -273,13 +273,20 @@ impl TychoExecutorEncoder {
|
|||||||
|
|
||||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||||
for swap in grouped_swap.swaps.iter() {
|
for swap in grouped_swap.swaps.iter() {
|
||||||
|
let transfer = if IN_TRANSFER_REQUIRED_PROTOCOLS
|
||||||
|
.contains(&swap.component.protocol_system.as_str())
|
||||||
|
{
|
||||||
|
TransferType::Transfer
|
||||||
|
} else {
|
||||||
|
TransferType::None
|
||||||
|
};
|
||||||
let encoding_context = EncodingContext {
|
let encoding_context = EncodingContext {
|
||||||
receiver: receiver.clone(),
|
receiver: receiver.clone(),
|
||||||
exact_out: solution.exact_out,
|
exact_out: solution.exact_out,
|
||||||
router_address: None,
|
router_address: None,
|
||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: TransferType::TransferToProtocol,
|
transfer_type: transfer,
|
||||||
};
|
};
|
||||||
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
|
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
|
||||||
grouped_protocol_data.extend(protocol_data);
|
grouped_protocol_data.extend(protocol_data);
|
||||||
@@ -461,7 +468,7 @@ mod tests {
|
|||||||
Bytes::from_str("0x3ede3eca2a72b3aecc820e955b36f38437d01395").unwrap()
|
Bytes::from_str("0x3ede3eca2a72b3aecc820e955b36f38437d01395").unwrap()
|
||||||
);
|
);
|
||||||
// single swap selector
|
// single swap selector
|
||||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07");
|
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "5c4b639c");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -486,7 +493,7 @@ mod tests {
|
|||||||
let transactions = transactions.unwrap();
|
let transactions = transactions.unwrap();
|
||||||
assert_eq!(transactions.len(), 1);
|
assert_eq!(transactions.len(), 1);
|
||||||
// single swap selector
|
// single swap selector
|
||||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07");
|
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "5c4b639c");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -533,7 +540,7 @@ mod tests {
|
|||||||
assert_eq!(transactions.len(), 1);
|
assert_eq!(transactions.len(), 1);
|
||||||
assert_eq!(transactions[0].value, eth_amount_in);
|
assert_eq!(transactions[0].value, eth_amount_in);
|
||||||
// sequential swap selector
|
// sequential swap selector
|
||||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e8a980d7");
|
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e21dd0d3");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1059,8 +1066,8 @@ mod tests {
|
|||||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||||
// zero for one
|
// zero for one
|
||||||
"00",
|
"00",
|
||||||
// transfer type
|
// transfer true
|
||||||
"00",
|
"01",
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1147,8 +1154,8 @@ mod tests {
|
|||||||
"6982508145454ce325ddbe47a25d4ec3d2311933",
|
"6982508145454ce325ddbe47a25d4ec3d2311933",
|
||||||
// zero for one
|
// zero for one
|
||||||
"00",
|
"00",
|
||||||
// transfer type
|
// transfer type Transfer
|
||||||
"00",
|
"01",
|
||||||
// receiver
|
// receiver
|
||||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||||
// first pool intermediary token (ETH)
|
// first pool intermediary token (ETH)
|
||||||
|
|||||||
@@ -96,27 +96,6 @@ pub struct Transaction {
|
|||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the type of transfer to be performed into the pool.
|
|
||||||
///
|
|
||||||
/// # Fields
|
|
||||||
///
|
|
||||||
/// * `TransferToProtocol`: Transfer the token from the router into the protocol.
|
|
||||||
/// * `TransferFromToProtocol`: Transfer the token from the sender to the protocol.
|
|
||||||
/// * `TransferPermit2ToProtocol`: Transfer the token from the sender to the protocol using Permit2.
|
|
||||||
/// * `TransferFromToRouter`: Transfer the token from the sender to the router.
|
|
||||||
/// * `TransferPermit2ToRouter`: Transfer the token from the sender to the router using Permit2.
|
|
||||||
/// * `None`: No transfer is needed. Tokens are already in the pool.
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum TransferType {
|
|
||||||
TransferToProtocol = 0,
|
|
||||||
TransferFromToProtocol = 1,
|
|
||||||
TransferPermit2ToProtocol = 2,
|
|
||||||
TransferFromToRouter = 3,
|
|
||||||
TransferPermit2ToRouter = 4,
|
|
||||||
None = 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents necessary attributes for encoding an order.
|
/// Represents necessary attributes for encoding an order.
|
||||||
///
|
///
|
||||||
/// # Fields
|
/// # Fields
|
||||||
@@ -127,6 +106,7 @@ pub enum TransferType {
|
|||||||
/// solution does not require router address.
|
/// solution does not require router address.
|
||||||
/// * `group_token_in`: Token to be used as the input for the group swap.
|
/// * `group_token_in`: Token to be used as the input for the group swap.
|
||||||
/// * `group_token_out`: Token to be used as the output for the group swap.
|
/// * `group_token_out`: Token to be used as the output for the group swap.
|
||||||
|
/// * `transfer`: Type of transfer to be performed. See `TransferType` for more details.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EncodingContext {
|
pub struct EncodingContext {
|
||||||
pub receiver: Bytes,
|
pub receiver: Bytes,
|
||||||
@@ -137,6 +117,21 @@ pub struct EncodingContext {
|
|||||||
pub transfer_type: TransferType,
|
pub transfer_type: TransferType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the type of transfer to be performed into the pool.
|
||||||
|
///
|
||||||
|
/// # Fields
|
||||||
|
///
|
||||||
|
/// * `TransferFrom`: Transfer the token from the sender to the protocol/router.
|
||||||
|
/// * `Transfer`: Transfer the token from the router into the protocol.
|
||||||
|
/// * `None`: No transfer is needed. Tokens are already in the pool.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum TransferType {
|
||||||
|
TransferFrom = 0,
|
||||||
|
Transfer = 1,
|
||||||
|
None = 2,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Chain {
|
pub struct Chain {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
|
|||||||
Reference in New Issue
Block a user