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]]
|
||||
name = "tycho-common"
|
||||
version = "0.66.4"
|
||||
version = "0.70.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5131fdb21cbd754822b0947fc6c763494531837ba8bb34123f6c7f4f89cb69f7"
|
||||
checksum = "5237d0e4ab6979a1ca9cdb749a2a97240ca6dc716c0da6f42543960d3141255a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"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-sol-types = { version = "0.8.14", 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"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -10,7 +10,6 @@ error Dispatcher__InvalidDataLength();
|
||||
|
||||
/**
|
||||
* @title Dispatcher - Dispatch execution to external contracts
|
||||
* @author PropellerHeads Devs
|
||||
* @dev Provides the ability to delegate execution of swaps to external
|
||||
* contracts. This allows dynamically adding new supported protocols
|
||||
* 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 {LibSwap} from "../lib/LibSwap.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__UndefinedMinAmountOut();
|
||||
|
||||
contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
IAllowanceTransfer public immutable permit2;
|
||||
contract TychoRouter is
|
||||
AccessControl,
|
||||
Dispatcher,
|
||||
Pausable,
|
||||
ReentrancyGuard,
|
||||
RestrictTransferFrom
|
||||
{
|
||||
IWETH private immutable _weth;
|
||||
|
||||
using SafeERC20 for IERC20;
|
||||
@@ -87,7 +93,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
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)) {
|
||||
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 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 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.
|
||||
*
|
||||
* @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,
|
||||
uint256 nTokens,
|
||||
address receiver,
|
||||
bool transferFromNeeded,
|
||||
bytes calldata swaps
|
||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
|
||||
|
||||
return _splitSwapChecked(
|
||||
amountIn,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
minAmountOut,
|
||||
initialBalanceTokenOut,
|
||||
wrapEth,
|
||||
unwrapEth,
|
||||
nTokens,
|
||||
@@ -182,16 +196,19 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
bytes calldata signature,
|
||||
bytes calldata swaps
|
||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
// For native ETH, assume funds already in our router. Else, handle approval.
|
||||
if (tokenIn != address(0)) {
|
||||
permit2.permit(msg.sender, permitSingle, signature);
|
||||
}
|
||||
_tstoreTransferFromInfo(tokenIn, amountIn, true, true);
|
||||
|
||||
return _splitSwapChecked(
|
||||
amountIn,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
minAmountOut,
|
||||
initialBalanceTokenOut,
|
||||
wrapEth,
|
||||
unwrapEth,
|
||||
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 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 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.
|
||||
*
|
||||
* @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 unwrapEth,
|
||||
address receiver,
|
||||
bool transferFromNeeded,
|
||||
bytes calldata swaps
|
||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
|
||||
|
||||
return _sequentialSwapChecked(
|
||||
amountIn,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
minAmountOut,
|
||||
initialBalanceTokenOut,
|
||||
wrapEth,
|
||||
unwrapEth,
|
||||
receiver,
|
||||
@@ -280,16 +303,20 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
bytes calldata signature,
|
||||
bytes calldata swaps
|
||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
// For native ETH, assume funds already in our router. Else, handle approval.
|
||||
if (tokenIn != address(0)) {
|
||||
permit2.permit(msg.sender, permitSingle, signature);
|
||||
}
|
||||
|
||||
_tstoreTransferFromInfo(tokenIn, amountIn, true, true);
|
||||
|
||||
return _sequentialSwapChecked(
|
||||
amountIn,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
minAmountOut,
|
||||
initialBalanceTokenOut,
|
||||
wrapEth,
|
||||
unwrapEth,
|
||||
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 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 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.
|
||||
*
|
||||
* @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 unwrapEth,
|
||||
address receiver,
|
||||
bool transferFromNeeded,
|
||||
bytes calldata swapData
|
||||
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
_tstoreTransferFromInfo(tokenIn, amountIn, false, transferFromNeeded);
|
||||
|
||||
return _singleSwap(
|
||||
amountIn,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
minAmountOut,
|
||||
initialBalanceTokenOut,
|
||||
wrapEth,
|
||||
unwrapEth,
|
||||
receiver,
|
||||
@@ -375,16 +408,19 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
bytes calldata signature,
|
||||
bytes calldata swapData
|
||||
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
// For native ETH, assume funds already in our router. Else, handle approval.
|
||||
if (tokenIn != address(0)) {
|
||||
permit2.permit(msg.sender, permitSingle, signature);
|
||||
}
|
||||
_tstoreTransferFromInfo(tokenIn, amountIn, true, true);
|
||||
|
||||
return _singleSwap(
|
||||
amountIn,
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
minAmountOut,
|
||||
initialBalanceTokenOut,
|
||||
wrapEth,
|
||||
unwrapEth,
|
||||
receiver,
|
||||
@@ -405,6 +441,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint256 minAmountOut,
|
||||
uint256 initialBalanceTokenOut,
|
||||
bool wrapEth,
|
||||
bool unwrapEth,
|
||||
uint256 nTokens,
|
||||
@@ -424,7 +461,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
tokenIn = address(_weth);
|
||||
}
|
||||
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
amountOut = _splitSwap(amountIn, nTokens, swaps);
|
||||
|
||||
if (amountOut < minAmountOut) {
|
||||
@@ -459,6 +495,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint256 minAmountOut,
|
||||
uint256 initialBalanceTokenOut,
|
||||
bool wrapEth,
|
||||
bool unwrapEth,
|
||||
address receiver,
|
||||
@@ -480,7 +517,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
(address executor, bytes calldata protocolData) =
|
||||
swap_.decodeSingleSwap();
|
||||
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
amountOut = _callSwapOnExecutor(executor, amountIn, protocolData);
|
||||
|
||||
if (amountOut < minAmountOut) {
|
||||
@@ -515,6 +551,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint256 minAmountOut,
|
||||
uint256 initialBalanceTokenOut,
|
||||
bool wrapEth,
|
||||
bool unwrapEth,
|
||||
address receiver,
|
||||
@@ -533,7 +570,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
|
||||
tokenIn = address(_weth);
|
||||
}
|
||||
|
||||
uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver);
|
||||
amountOut = _sequentialSwap(amountIn, swaps);
|
||||
|
||||
if (amountOut < minAmountOut) {
|
||||
|
||||
@@ -10,16 +10,16 @@ import {
|
||||
import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol";
|
||||
// slither-disable-next-line solc-version
|
||||
import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
|
||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||
|
||||
error BalancerV2Executor__InvalidDataLength();
|
||||
|
||||
contract BalancerV2Executor is IExecutor, TokenTransfer {
|
||||
contract BalancerV2Executor is IExecutor, RestrictTransferFrom {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
|
||||
|
||||
constructor(address _permit2) TokenTransfer(_permit2) {}
|
||||
constructor(address _permit2) RestrictTransferFrom(_permit2) {}
|
||||
|
||||
// slither-disable-next-line locked-ether
|
||||
function swap(uint256 givenAmount, bytes calldata data)
|
||||
@@ -32,21 +32,13 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
||||
IERC20 tokenOut,
|
||||
bytes32 poolId,
|
||||
address receiver,
|
||||
bool needsApproval,
|
||||
bool approvalNeeded,
|
||||
TransferType transferType
|
||||
) = _decodeData(data);
|
||||
|
||||
_transfer(
|
||||
address(tokenIn),
|
||||
msg.sender,
|
||||
// Receiver can never be the pool, since the pool expects funds in the router contract
|
||||
// Thus, this call will only ever be used to transfer funds from the user into the router.
|
||||
address(this),
|
||||
givenAmount,
|
||||
transferType
|
||||
);
|
||||
_transfer(address(this), transferType, address(tokenIn), givenAmount);
|
||||
|
||||
if (needsApproval) {
|
||||
if (approvalNeeded) {
|
||||
// slither-disable-next-line unused-return
|
||||
tokenIn.forceApprove(VAULT, type(uint256).max);
|
||||
}
|
||||
@@ -81,7 +73,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
||||
IERC20 tokenOut,
|
||||
bytes32 poolId,
|
||||
address receiver,
|
||||
bool needsApproval,
|
||||
bool approvalNeeded,
|
||||
TransferType transferType
|
||||
)
|
||||
{
|
||||
@@ -93,7 +85,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
||||
tokenOut = IERC20(address(bytes20(data[20:40])));
|
||||
poolId = bytes32(data[40:72]);
|
||||
receiver = address(bytes20(data[72:92]));
|
||||
needsApproval = uint8(data[92]) > 0;
|
||||
approvalNeeded = data[92] != 0;
|
||||
transferType = TransferType(uint8(data[93]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "./TokenTransfer.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||
|
||||
error CurveExecutor__AddressZero();
|
||||
error CurveExecutor__InvalidDataLength();
|
||||
@@ -35,13 +35,13 @@ interface CryptoPoolETH {
|
||||
// slither-disable-end naming-convention
|
||||
}
|
||||
|
||||
contract CurveExecutor is IExecutor, TokenTransfer {
|
||||
contract CurveExecutor is IExecutor, RestrictTransferFrom {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
address public immutable nativeToken;
|
||||
|
||||
constructor(address _nativeToken, address _permit2)
|
||||
TokenTransfer(_permit2)
|
||||
RestrictTransferFrom(_permit2)
|
||||
{
|
||||
if (_nativeToken == address(0)) {
|
||||
revert CurveExecutor__AddressZero();
|
||||
@@ -64,25 +64,16 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
||||
uint8 poolType,
|
||||
int128 i,
|
||||
int128 j,
|
||||
bool tokenApprovalNeeded,
|
||||
bool approvalNeeded,
|
||||
TransferType transferType,
|
||||
address receiver
|
||||
) = _decodeData(data);
|
||||
|
||||
_transfer(
|
||||
tokenIn,
|
||||
msg.sender,
|
||||
// Receiver can never be the pool, since the pool expects funds in the router contract
|
||||
// Thus, this call will only ever be used to transfer funds from the user into the router.
|
||||
address(this),
|
||||
amountIn,
|
||||
transferType
|
||||
);
|
||||
|
||||
if (tokenApprovalNeeded && tokenIn != nativeToken) {
|
||||
if (approvalNeeded && tokenIn != nativeToken) {
|
||||
// slither-disable-next-line unused-return
|
||||
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
|
||||
uint256 balanceBefore = _balanceOf(tokenOut);
|
||||
@@ -133,7 +124,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
||||
uint8 poolType,
|
||||
int128 i,
|
||||
int128 j,
|
||||
bool tokenApprovalNeeded,
|
||||
bool approvalNeeded,
|
||||
TransferType transferType,
|
||||
address receiver
|
||||
)
|
||||
@@ -144,7 +135,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
||||
poolType = uint8(data[60]);
|
||||
i = int128(uint128(uint8(data[61])));
|
||||
j = int128(uint128(uint8(data[62])));
|
||||
tokenApprovalNeeded = data[63] != 0;
|
||||
approvalNeeded = data[63] != 0;
|
||||
transferType = TransferType(uint8(data[64]));
|
||||
receiver = address(bytes20(data[65:85]));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import {IExecutor} from "@interfaces/IExecutor.sol";
|
||||
import {ICallback} from "@interfaces/ICallback.sol";
|
||||
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
||||
@@ -11,14 +11,15 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol";
|
||||
import {LibBytes} from "@solady/utils/LibBytes.sol";
|
||||
import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.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
|
||||
IExecutor,
|
||||
ILocker,
|
||||
IPayer,
|
||||
ICallback,
|
||||
TokenTransfer
|
||||
RestrictTransferFrom
|
||||
{
|
||||
error EkuboExecutor__InvalidDataLength();
|
||||
error EkuboExecutor__CoreOnly();
|
||||
@@ -26,13 +27,17 @@ contract EkuboExecutor is
|
||||
|
||||
ICore immutable core;
|
||||
|
||||
uint256 constant POOL_DATA_OFFSET = 77;
|
||||
uint256 constant POOL_DATA_OFFSET = 57;
|
||||
uint256 constant HOP_BYTE_LEN = 52;
|
||||
|
||||
bytes4 constant LOCKED_SELECTOR = 0xb45a3c0e; // locked(uint256)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -41,16 +46,11 @@ contract EkuboExecutor is
|
||||
payable
|
||||
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
|
||||
calculatedAmount = uint256(
|
||||
_lock(
|
||||
bytes.concat(
|
||||
bytes16(uint128(amountIn)), bytes20(msg.sender), data
|
||||
)
|
||||
)
|
||||
);
|
||||
calculatedAmount =
|
||||
uint256(_lock(bytes.concat(bytes16(uint128(amountIn)), data)));
|
||||
}
|
||||
|
||||
function handleCallback(bytes calldata raw)
|
||||
@@ -125,11 +125,9 @@ contract EkuboExecutor is
|
||||
function _locked(bytes calldata swapData) internal returns (int128) {
|
||||
int128 nextAmountIn = int128(uint128(bytes16(swapData[0:16])));
|
||||
uint128 tokenInDebtAmount = uint128(nextAmountIn);
|
||||
address sender = address(bytes20(swapData[16:36]));
|
||||
uint8 transferType = uint8(swapData[36]);
|
||||
|
||||
address receiver = address(bytes20(swapData[37:57]));
|
||||
address tokenIn = address(bytes20(swapData[57:77]));
|
||||
TransferType transferType = TransferType(uint8(swapData[16]));
|
||||
address receiver = address(bytes20(swapData[17:37]));
|
||||
address tokenIn = address(bytes20(swapData[37:57]));
|
||||
|
||||
address nextTokenIn = tokenIn;
|
||||
|
||||
@@ -163,17 +161,14 @@ contract EkuboExecutor is
|
||||
offset += HOP_BYTE_LEN;
|
||||
}
|
||||
|
||||
_pay(tokenIn, tokenInDebtAmount, sender, transferType);
|
||||
_pay(tokenIn, tokenInDebtAmount, transferType);
|
||||
core.withdraw(nextTokenIn, receiver, uint128(nextAmountIn));
|
||||
return nextAmountIn;
|
||||
}
|
||||
|
||||
function _pay(
|
||||
address token,
|
||||
uint128 amount,
|
||||
address sender,
|
||||
uint8 transferType
|
||||
) internal {
|
||||
function _pay(address token, uint128 amount, TransferType transferType)
|
||||
internal
|
||||
{
|
||||
address target = address(core);
|
||||
|
||||
if (token == NATIVE_TOKEN_ADDRESS) {
|
||||
@@ -186,11 +181,10 @@ contract EkuboExecutor is
|
||||
mstore(free, shl(224, 0x0c11dedd))
|
||||
mstore(add(free, 4), token)
|
||||
mstore(add(free, 36), shl(128, amount))
|
||||
mstore(add(free, 52), shl(96, sender))
|
||||
mstore(add(free, 72), shl(248, transferType))
|
||||
mstore(add(free, 52), shl(248, transferType))
|
||||
|
||||
// 4 (selector) + 32 (token) + 16 (amount) + 20 (sender) + 1 (transferType) = 73
|
||||
if iszero(call(gas(), target, 0, free, 73, 0, 0)) {
|
||||
// 4 (selector) + 32 (token) + 16 (amount) + 1 (transferType) = 53
|
||||
if iszero(call(gas(), target, 0, free, 53, 0, 0)) {
|
||||
returndatacopy(0, 0, returndatasize())
|
||||
revert(0, returndatasize())
|
||||
}
|
||||
@@ -201,9 +195,8 @@ contract EkuboExecutor is
|
||||
function _payCallback(bytes calldata payData) internal {
|
||||
address token = address(bytes20(payData[12:32])); // This arg is abi-encoded
|
||||
uint128 amount = uint128(bytes16(payData[32:48]));
|
||||
address sender = address(bytes20(payData[48:68]));
|
||||
TransferType transferType = TransferType(uint8(payData[68]));
|
||||
_transfer(token, sender, address(core), amount, transferType);
|
||||
TransferType transferType = TransferType(uint8(payData[48]));
|
||||
_transfer(address(core), transferType, token, amount);
|
||||
}
|
||||
|
||||
// To receive withdrawals from Core
|
||||
|
||||
@@ -3,18 +3,21 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.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__InvalidTarget();
|
||||
error MaverickV2Executor__InvalidFactory();
|
||||
|
||||
contract MaverickV2Executor is IExecutor, TokenTransfer {
|
||||
contract MaverickV2Executor is IExecutor, RestrictTransferFrom {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
address public immutable factory;
|
||||
|
||||
constructor(address _factory, address _permit2) TokenTransfer(_permit2) {
|
||||
constructor(address _factory, address _permit2)
|
||||
RestrictTransferFrom(_permit2)
|
||||
{
|
||||
if (_factory == address(0)) {
|
||||
revert MaverickV2Executor__InvalidFactory();
|
||||
}
|
||||
@@ -47,9 +50,8 @@ contract MaverickV2Executor is IExecutor, TokenTransfer {
|
||||
tickLimit: tickLimit
|
||||
});
|
||||
|
||||
_transfer(
|
||||
address(tokenIn), msg.sender, target, givenAmount, transferType
|
||||
);
|
||||
_transfer(target, transferType, address(tokenIn), givenAmount);
|
||||
|
||||
// slither-disable-next-line unused-return
|
||||
(, 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 "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol";
|
||||
import "./TokenTransfer.sol";
|
||||
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||
|
||||
error UniswapV2Executor__InvalidDataLength();
|
||||
error UniswapV2Executor__InvalidTarget();
|
||||
@@ -12,7 +12,7 @@ error UniswapV2Executor__InvalidFactory();
|
||||
error UniswapV2Executor__InvalidInitCode();
|
||||
error UniswapV2Executor__InvalidFee();
|
||||
|
||||
contract UniswapV2Executor is IExecutor, TokenTransfer {
|
||||
contract UniswapV2Executor is IExecutor, RestrictTransferFrom {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
address public immutable factory;
|
||||
@@ -25,7 +25,7 @@ contract UniswapV2Executor is IExecutor, TokenTransfer {
|
||||
bytes32 _initCode,
|
||||
address _permit2,
|
||||
uint256 _feeBps
|
||||
) TokenTransfer(_permit2) {
|
||||
) RestrictTransferFrom(_permit2) {
|
||||
if (_factory == address(0)) {
|
||||
revert UniswapV2Executor__InvalidFactory();
|
||||
}
|
||||
@@ -59,9 +59,8 @@ contract UniswapV2Executor is IExecutor, TokenTransfer {
|
||||
_verifyPairAddress(target);
|
||||
|
||||
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
||||
_transfer(
|
||||
address(tokenIn), msg.sender, target, givenAmount, transferType
|
||||
);
|
||||
|
||||
_transfer(target, transferType, address(tokenIn), givenAmount);
|
||||
|
||||
IUniswapV2Pair pool = IUniswapV2Pair(target);
|
||||
if (zeroForOne) {
|
||||
@@ -88,7 +87,7 @@ contract UniswapV2Executor is IExecutor, TokenTransfer {
|
||||
inToken = IERC20(address(bytes20(data[0:20])));
|
||||
target = address(bytes20(data[20:40]));
|
||||
receiver = address(bytes20(data[40:60]));
|
||||
zeroForOne = uint8(data[60]) > 0;
|
||||
zeroForOne = data[60] != 0;
|
||||
transferType = TransferType(uint8(data[61]));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@ import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||||
import "@interfaces/ICallback.sol";
|
||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||
import {RestrictTransferFrom} from "../RestrictTransferFrom.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
|
||||
error UniswapV3Executor__InvalidDataLength();
|
||||
error UniswapV3Executor__InvalidFactory();
|
||||
error UniswapV3Executor__InvalidTarget();
|
||||
error UniswapV3Executor__InvalidInitCode();
|
||||
error UniswapV3Executor__InvalidTransferType(uint8 transferType);
|
||||
|
||||
contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
||||
contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
uint160 private constant MIN_SQRT_RATIO = 4295128739;
|
||||
@@ -25,7 +25,7 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
||||
address private immutable self;
|
||||
|
||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||
TokenTransfer(_permit2)
|
||||
RestrictTransferFrom(_permit2)
|
||||
{
|
||||
if (_factory == address(0)) {
|
||||
revert UniswapV3Executor__InvalidFactory();
|
||||
@@ -97,21 +97,14 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
||||
abi.decode(msgData[4:68], (int256, int256));
|
||||
|
||||
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]));
|
||||
address sender = address(bytes20(msgData[176:196]));
|
||||
|
||||
verifyCallback(msgData[132:]);
|
||||
|
||||
uint256 amountOwed =
|
||||
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
|
||||
|
||||
_transfer(tokenIn, sender, msg.sender, amountOwed, transferType);
|
||||
_transfer(msg.sender, transferType, tokenIn, amountOwed);
|
||||
|
||||
return abi.encode(amountOwed, tokenIn);
|
||||
}
|
||||
@@ -162,10 +155,8 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
||||
address tokenOut,
|
||||
uint24 fee,
|
||||
TransferType transferType
|
||||
) internal view returns (bytes memory) {
|
||||
return abi.encodePacked(
|
||||
tokenIn, tokenOut, fee, uint8(transferType), msg.sender
|
||||
);
|
||||
) internal pure returns (bytes memory) {
|
||||
return abi.encodePacked(tokenIn, tokenOut, fee, uint8(transferType));
|
||||
}
|
||||
|
||||
function _verifyPairAddress(
|
||||
|
||||
@@ -3,7 +3,6 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import {ICallback} from "@interfaces/ICallback.sol";
|
||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||
import {
|
||||
IERC20,
|
||||
SafeERC20
|
||||
@@ -23,6 +22,8 @@ import {IUnlockCallback} from
|
||||
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
|
||||
import {TransientStateLibrary} from
|
||||
"@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
||||
import "../RestrictTransferFrom.sol";
|
||||
import "@openzeppelin/contracts/utils/Address.sol";
|
||||
|
||||
error UniswapV4Executor__InvalidDataLength();
|
||||
error UniswapV4Executor__NotPoolManager();
|
||||
@@ -37,7 +38,7 @@ contract UniswapV4Executor is
|
||||
IExecutor,
|
||||
IUnlockCallback,
|
||||
ICallback,
|
||||
TokenTransfer
|
||||
RestrictTransferFrom
|
||||
{
|
||||
using SafeERC20 for IERC20;
|
||||
using CurrencyLibrary for Currency;
|
||||
@@ -47,8 +48,8 @@ contract UniswapV4Executor is
|
||||
IPoolManager public immutable poolManager;
|
||||
address private immutable _self;
|
||||
|
||||
bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x8bc6d0d7;
|
||||
bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0xaf90aeb1;
|
||||
bytes4 constant SWAP_EXACT_INPUT_SINGLE_SELECTOR = 0x6022fbcd;
|
||||
bytes4 constant SWAP_EXACT_INPUT_SELECTOR = 0x044f0d3d;
|
||||
|
||||
struct UniswapV4Pool {
|
||||
address intermediaryToken;
|
||||
@@ -57,7 +58,7 @@ contract UniswapV4Executor is
|
||||
}
|
||||
|
||||
constructor(IPoolManager _poolManager, address _permit2)
|
||||
TokenTransfer(_permit2)
|
||||
RestrictTransferFrom(_permit2)
|
||||
{
|
||||
poolManager = _poolManager;
|
||||
_self = address(this);
|
||||
@@ -100,7 +101,6 @@ contract UniswapV4Executor is
|
||||
key,
|
||||
zeroForOne,
|
||||
amountIn,
|
||||
msg.sender,
|
||||
transferType,
|
||||
receiver,
|
||||
bytes("")
|
||||
@@ -123,7 +123,6 @@ contract UniswapV4Executor is
|
||||
currencyIn,
|
||||
path,
|
||||
amountIn,
|
||||
msg.sender,
|
||||
transferType,
|
||||
receiver
|
||||
);
|
||||
@@ -153,7 +152,7 @@ contract UniswapV4Executor is
|
||||
|
||||
tokenIn = address(bytes20(data[0:20]));
|
||||
tokenOut = address(bytes20(data[20:40]));
|
||||
zeroForOne = (data[40] != 0);
|
||||
zeroForOne = data[40] != 0;
|
||||
transferType = TransferType(uint8(data[41]));
|
||||
receiver = address(bytes20(data[42:62]));
|
||||
|
||||
@@ -239,8 +238,7 @@ contract UniswapV4Executor is
|
||||
* @param poolKey The key of the pool to swap in.
|
||||
* @param zeroForOne Whether the swap is from token0 to token1 (true) or vice versa (false).
|
||||
* @param amountIn The amount of tokens to swap in.
|
||||
* @param sender The address of the sender.
|
||||
* @param transferType The type of transfer in to use.
|
||||
* @param transferType The type of action necessary to pay back the pool.
|
||||
* @param receiver The address of the receiver.
|
||||
* @param hookData Additional data for hook contracts.
|
||||
*/
|
||||
@@ -248,7 +246,6 @@ contract UniswapV4Executor is
|
||||
PoolKey memory poolKey,
|
||||
bool zeroForOne,
|
||||
uint128 amountIn,
|
||||
address sender,
|
||||
TransferType transferType,
|
||||
address receiver,
|
||||
bytes calldata hookData
|
||||
@@ -262,7 +259,7 @@ contract UniswapV4Executor is
|
||||
if (amount > amountIn) {
|
||||
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||
}
|
||||
_settle(currencyIn, amount, sender, transferType);
|
||||
_settle(currencyIn, amount, transferType);
|
||||
|
||||
Currency currencyOut =
|
||||
zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
||||
@@ -275,15 +272,13 @@ contract UniswapV4Executor is
|
||||
* @param currencyIn The currency of the input token.
|
||||
* @param path The path to swap along.
|
||||
* @param amountIn The amount of tokens to swap in.
|
||||
* @param sender The address of the sender.
|
||||
* @param transferType The type of transfer in to use.
|
||||
* @param transferType The type of action necessary to pay back the pool.
|
||||
* @param receiver The address of the receiver.
|
||||
*/
|
||||
function swapExactInput(
|
||||
Currency currencyIn,
|
||||
PathKey[] calldata path,
|
||||
uint128 amountIn,
|
||||
address sender,
|
||||
TransferType transferType,
|
||||
address receiver
|
||||
) external returns (uint128) {
|
||||
@@ -315,7 +310,7 @@ contract UniswapV4Executor is
|
||||
if (amount > amountIn) {
|
||||
revert UniswapV4Executor__V4TooMuchRequested(amountIn, amount);
|
||||
}
|
||||
_settle(currencyIn, amount, sender, transferType);
|
||||
_settle(currencyIn, amount, transferType);
|
||||
|
||||
_take(
|
||||
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.
|
||||
* @param currency The currency to settle.
|
||||
* @param amount The amount to send.
|
||||
* @param sender The address of the payer.
|
||||
* @param transferType The type of transfer to use.
|
||||
* @param transferType The type of action necessary to pay back the pool.
|
||||
* @dev Returns early if the amount is 0.
|
||||
*/
|
||||
function _settle(
|
||||
Currency currency,
|
||||
uint256 amount,
|
||||
address sender,
|
||||
TransferType transferType
|
||||
) internal {
|
||||
if (amount == 0) return;
|
||||
@@ -404,11 +397,10 @@ contract UniswapV4Executor is
|
||||
poolManager.settle{value: amount}();
|
||||
} else {
|
||||
_transfer(
|
||||
Currency.unwrap(currency),
|
||||
sender,
|
||||
address(poolManager),
|
||||
amount,
|
||||
transferType
|
||||
transferType,
|
||||
Currency.unwrap(currency),
|
||||
amount
|
||||
);
|
||||
// slither-disable-next-line unused-return
|
||||
poolManager.settle();
|
||||
|
||||
@@ -26,7 +26,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL,
|
||||
RestrictTransferFrom.TransferType.TransferFrom,
|
||||
ALICE,
|
||||
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
|
||||
// USDE -> USDT -> WBTC
|
||||
uint256 amountIn = 100 ether;
|
||||
deal(USDE_ADDR, tychoRouterAddr, amountIn);
|
||||
deal(USDE_ADDR, ALICE, amountIn);
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||
@@ -74,7 +74,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
||||
USDE_ADDR,
|
||||
WBTC_ADDR,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||
RestrictTransferFrom.TransferType.TransferFrom,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
@@ -82,8 +82,18 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
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);
|
||||
@@ -262,7 +272,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
||||
ALICE,
|
||||
DAI_WETH_USV3,
|
||||
zeroForOne,
|
||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv3Executor), protocolData);
|
||||
|
||||
@@ -8,25 +8,21 @@ import "./executors/UniswapV4Utils.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
|
||||
contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
function _getSequentialSwaps(bool permit2)
|
||||
internal
|
||||
view
|
||||
returns (bytes[] memory)
|
||||
{
|
||||
function _getSequentialSwaps() internal view returns (bytes[] memory) {
|
||||
// Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2
|
||||
// 1 WETH -> DAI -> USDC
|
||||
// (univ2) (univ2)
|
||||
|
||||
TokenTransfer.TransferType transferType = permit2
|
||||
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
||||
|
||||
bytes[] memory swaps = new bytes[](2);
|
||||
// WETH -> DAI
|
||||
swaps[0] = encodeSequentialSwap(
|
||||
address(usv2Executor),
|
||||
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,
|
||||
ALICE,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.None // funds already sent to pool
|
||||
)
|
||||
);
|
||||
return swaps;
|
||||
@@ -55,7 +51,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps(true);
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
tychoRouter.sequentialSwapPermit2(
|
||||
amountIn,
|
||||
WETH_ADDR,
|
||||
@@ -82,7 +78,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps(false);
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
tychoRouter.sequentialSwap(
|
||||
amountIn,
|
||||
WETH_ADDR,
|
||||
@@ -91,6 +87,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
pleEncode(swaps)
|
||||
);
|
||||
|
||||
@@ -107,7 +104,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps(false);
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||
tychoRouter.sequentialSwap(
|
||||
amountIn,
|
||||
@@ -117,6 +114,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
pleEncode(swaps)
|
||||
);
|
||||
}
|
||||
@@ -129,7 +127,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn - 1);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps(false);
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
vm.expectRevert();
|
||||
tychoRouter.sequentialSwap(
|
||||
amountIn,
|
||||
@@ -139,6 +137,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
pleEncode(swaps)
|
||||
);
|
||||
}
|
||||
@@ -154,7 +153,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps(true);
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
|
||||
uint256 minAmountOut = 3000 * 1e18;
|
||||
|
||||
@@ -204,9 +203,9 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
encodeUniswapV2Swap(
|
||||
WETH_ADDR,
|
||||
WETH_DAI_POOL,
|
||||
tychoRouterAddr,
|
||||
DAI_USDC_POOL,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
)
|
||||
);
|
||||
|
||||
@@ -218,7 +217,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
DAI_USDC_POOL,
|
||||
ALICE,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.None
|
||||
)
|
||||
);
|
||||
|
||||
@@ -266,7 +265,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
DAI_USDC_POOL,
|
||||
tychoRouterAddr,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
)
|
||||
);
|
||||
|
||||
@@ -278,7 +277,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
tychoRouterAddr,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
)
|
||||
);
|
||||
|
||||
@@ -315,7 +314,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
tychoRouterAddr,
|
||||
USDC_WETH_USV3,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
||||
@@ -324,7 +323,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
tychoRouterAddr,
|
||||
USDC_WETH_USV3_2,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes[] memory swaps = new bytes[](2);
|
||||
|
||||
@@ -26,7 +26,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -67,7 +67,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -82,6 +82,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
swap
|
||||
);
|
||||
|
||||
@@ -108,7 +109,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -116,7 +117,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
|
||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||
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,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -150,6 +151,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
swap
|
||||
);
|
||||
}
|
||||
@@ -169,7 +171,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -192,6 +194,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
swap
|
||||
);
|
||||
}
|
||||
@@ -218,7 +221,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer // ETH has already been transferred to router
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -261,7 +264,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
tychoRouterAddr,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
@@ -287,6 +290,49 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
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 {
|
||||
// Tests swapping WETH -> DAI on a USV2 pool with regular approvals
|
||||
deal(WETH_ADDR, ALICE, 1 ether);
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {TychoRouter} from "@src/TychoRouter.sol";
|
||||
import {TychoRouter, RestrictTransferFrom} from "@src/TychoRouter.sol";
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
import "./executors/UniswapV4Utils.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
|
||||
contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
function _getSplitSwaps(bool permit2)
|
||||
function _getSplitSwaps(bool transferFrom)
|
||||
private
|
||||
view
|
||||
returns (bytes[] memory)
|
||||
@@ -19,10 +19,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
// -> WBTC ->
|
||||
// (univ2) (univ2)
|
||||
bytes[] memory swaps = new bytes[](4);
|
||||
|
||||
TokenTransfer.TransferType inTransferType = permit2
|
||||
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
||||
RestrictTransferFrom.TransferType transferType = transferFrom
|
||||
? RestrictTransferFrom.TransferType.TransferFrom
|
||||
: RestrictTransferFrom.TransferType.Transfer;
|
||||
|
||||
// WETH -> WBTC (60%)
|
||||
swaps[0] = encodeSplitSwap(
|
||||
@@ -31,11 +30,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(0xffffff * 60) / 100, // 60%
|
||||
address(usv2Executor),
|
||||
encodeUniswapV2Swap(
|
||||
WETH_ADDR,
|
||||
WETH_WBTC_POOL,
|
||||
tychoRouterAddr,
|
||||
false,
|
||||
inTransferType
|
||||
WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false, transferType
|
||||
)
|
||||
);
|
||||
// WBTC -> USDC
|
||||
@@ -49,7 +44,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
USDC_WBTC_POOL,
|
||||
ALICE,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
)
|
||||
);
|
||||
// WETH -> DAI
|
||||
@@ -59,7 +54,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
uint24(0),
|
||||
address(usv2Executor),
|
||||
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,
|
||||
ALICE,
|
||||
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
|
||||
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(WETH_ADDR, ALICE, amountIn);
|
||||
deal(WETH_ADDR, address(tychoRouterAddr), amountIn);
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
||||
bytes[] memory swaps = _getSplitSwaps(false);
|
||||
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
|
||||
vm.stopPrank();
|
||||
@@ -138,7 +132,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSplitSwaps(false);
|
||||
bytes[] memory swaps = _getSplitSwaps(true);
|
||||
|
||||
tychoRouter.splitSwap(
|
||||
amountIn,
|
||||
@@ -149,6 +143,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
4,
|
||||
ALICE,
|
||||
true,
|
||||
pleEncode(swaps)
|
||||
);
|
||||
|
||||
@@ -165,7 +160,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSplitSwaps(false);
|
||||
bytes[] memory swaps = _getSplitSwaps(true);
|
||||
|
||||
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
|
||||
tychoRouter.splitSwap(
|
||||
@@ -177,6 +172,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
4,
|
||||
ALICE,
|
||||
true,
|
||||
pleEncode(swaps)
|
||||
);
|
||||
vm.stopPrank();
|
||||
@@ -190,7 +186,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
vm.startPrank(ALICE);
|
||||
// Approve less than the amountIn
|
||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1);
|
||||
bytes[] memory swaps = _getSplitSwaps(false);
|
||||
bytes[] memory swaps = _getSplitSwaps(true);
|
||||
|
||||
vm.expectRevert();
|
||||
tychoRouter.splitSwap(
|
||||
@@ -202,6 +198,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
false,
|
||||
2,
|
||||
ALICE,
|
||||
true,
|
||||
pleEncode(swaps)
|
||||
);
|
||||
|
||||
@@ -270,7 +267,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory swap = encodeSplitSwap(
|
||||
@@ -319,7 +316,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
WETH_DAI_POOL,
|
||||
tychoRouterAddr,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
|
||||
bytes memory swap = encodeSplitSwap(
|
||||
@@ -365,10 +362,10 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
// │ │
|
||||
// └─ (USV3, 40% split) ──> WETH ─┘
|
||||
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);
|
||||
// Approve the TychoRouter to spend USDC
|
||||
IERC20(USDC_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
|
||||
bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap(
|
||||
USDC_ADDR,
|
||||
@@ -376,7 +373,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
tychoRouterAddr,
|
||||
USDC_WETH_USV3,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
|
||||
@@ -385,7 +382,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
tychoRouterAddr,
|
||||
USDC_WETH_USV3_2,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap(
|
||||
@@ -393,7 +390,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
USDC_WETH_USV2,
|
||||
tychoRouterAddr,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes[] memory swaps = new bytes[](3);
|
||||
@@ -426,6 +423,74 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
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 {
|
||||
// This test has start and end tokens that are the same
|
||||
// The flow is:
|
||||
@@ -443,7 +508,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
USDC_WETH_USV2,
|
||||
tychoRouterAddr,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap(
|
||||
@@ -452,7 +517,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
tychoRouterAddr,
|
||||
USDC_WETH_USV3,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
|
||||
@@ -461,7 +526,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
tychoRouterAddr,
|
||||
USDC_WETH_USV3_2,
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes[] memory swaps = new bytes[](3);
|
||||
@@ -504,7 +569,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
USDC_MAG7_POOL,
|
||||
tychoRouterAddr,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
bytes memory swap = encodeSplitSwap(
|
||||
|
||||
@@ -28,6 +28,17 @@ contract TychoRouterExposed is TychoRouter {
|
||||
return _unwrapETH(amount);
|
||||
}
|
||||
|
||||
function tstoreExposed(
|
||||
address tokenIn,
|
||||
uint256 amountIn,
|
||||
bool isPermit2,
|
||||
bool transferFromNeeded
|
||||
) external {
|
||||
_tstoreTransferFromInfo(
|
||||
tokenIn, amountIn, isPermit2, transferFromNeeded
|
||||
);
|
||||
}
|
||||
|
||||
function exposedSplitSwap(
|
||||
uint256 amountIn,
|
||||
uint256 nTokens,
|
||||
@@ -185,7 +196,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
||||
address target,
|
||||
address receiver,
|
||||
bool zero2one,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) internal pure returns (bytes memory) {
|
||||
return
|
||||
abi.encodePacked(tokenIn, target, receiver, zero2one, transferType);
|
||||
@@ -197,7 +208,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
||||
address receiver,
|
||||
address target,
|
||||
bool zero2one,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) internal view returns (bytes memory) {
|
||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||
return abi.encodePacked(
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
test_uniswap_v3_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010500
|
||||
test_single_encoding_strategy_ekubo:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759805cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000
|
||||
test_uniswap_v3_uniswap_v3:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010000000000000000000000
|
||||
test_balancer_v2_uniswap_v2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010300525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder_no_permit2:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006852b03300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3b00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041558653365a24c992e17bbf18a802b91eb3cf936eeb1f214d3e5e6cad70ba57070c7e92db5c3f0399d7da505798950313ce1d0c399e54cca0049868ee0f0005501b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006852b03300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3b000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c34556c17e3de4636f371033dc793b59f217facb4643ee3113acf72d3c2d7a3d22cf66c34d8d9c7bc119ac2b0fb2781a2097aa743fd77718f2a4e5ef5f92acbf1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041c55b2e21396823d694e6da247eee51ef542d57d3c5901911b85b3c195d89a56d03e85c23251af0d3981b0e07ca05caaaca029ae5efba9d58178be2f38d08cced1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000200525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20105000000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_no_permit2:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_no_transfer_in:20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3b00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160a5490c6e80921cf7b1ad8e7a59a02febd09780fa88c17070663c5a78635116227c299592fac934afa013d95f8711a70fdeb54fc07a2c22352f9cf263924d931c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
|
||||
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041ff87cdaae49fca40cccacadeab4710cdbd41d4901ba28cdabf36dbe07b198887506a6d4960e95f586b5d39011f74d4d57d61a7585ca7b8bdd86f550a9973e5571b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000000000
|
||||
test_single_encoding_strategy_curve_st_eth:20144a070000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010005cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041c55b2e21396823d694e6da247eee51ef542d57d3c5901911b85b3c195d89a56d03e85c23251af0d3981b0e07ca05caaaca029ae5efba9d58178be2f38d08cced1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200020000000000000000000000000000
|
||||
test_single_encoding_strategy_curve:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000103cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410e67daacc0a64ee7e7a57211b347b4af6d4d8865acbb9f549395fe42cf5ea87e1ac51293305eef8aebba46d510052e6fdea42e2caf1c34624260108f32ea6a641b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501020000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417b597f22dfb861c6ac1ec78eecab17b5e8b8e389494a9d3c2f27efbc35dbd73846d4dc5fef1b9530c4d3b8d7065fbc4d190821c1b5efbfd41ce388163e3812911c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041ff87cdaae49fca40cccacadeab4710cdbd41d4901ba28cdabf36dbe07b198887506a6d4960e95f586b5d39011f74d4d57d61a7585ca7b8bdd86f550a9973e5571b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950102006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000
|
||||
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041ff87cdaae49fca40cccacadeab4710cdbd41d4901ba28cdabf36dbe07b198887506a6d4960e95f586b5d39011f74d4d57d61a7585ca7b8bdd86f550a9973e5571b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80102005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000
|
||||
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c55b2e21396823d694e6da247eee51ef542d57d3c5901911b85b3c195d89a56d03e85c23251af0d3981b0e07ca05caaaca029ae5efba9d58178be2f38d08cced1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950002005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950002005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010000000000000000000000000000000000000000000000000000000000
|
||||
test_uniswap_v3_curve:e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000100691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000105cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000
|
||||
test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf00000000000000000000000000000000000000000000000000000000000006852b03400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b2a3c00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004153ce45df3a0b2c8061d920d172d594ee02cf37b1967001935d3a6055700a300f79f68cda34bd3c6f64bfd154a113a43aafd15e6443dcc402e5b6ac9263e6ff031c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501020072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010500691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001053ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598003ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000
|
||||
test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0105
|
||||
test_ekubo_encode_swap_multi:00ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032
|
||||
test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c
|
||||
test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001
|
||||
test_single_encoding_strategy_maverick:20144a070000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc201000000000000000000000000000000
|
||||
test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e00
|
||||
test_uniswap_v3_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000bf00692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb8004375dff511095cc5a197a54140a24efef3a416cbcdf9626bc03e24f779434178a73a0b4bad62ed000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010200
|
||||
test_single_encoding_strategy_ekubo:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000071a0cb889707d426a7a386870a03bc70d1b069759802cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000000000000000000000000000000000
|
||||
test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000
|
||||
test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041b70914df20e4b2675adc5a61d26b959e0fd21e7cce6503b884d5ba9e1db2c82164112e4dc362b9a3ef794a03fcfebe0710700028b79abe8b7de525288ac904991c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_out:7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c8000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c33e9da2d2a5bea1087e27f42b9255fcaea06efa76558843f6192d571b15c09c5818e1a4b3a111bb6accc4cb8b583c318d2386e0e94cc87b9fcc4065db0d65611c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007300710001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c00000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c800000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f59744bfe3e154be7c72429eb93db7ef2ec00344feeb1376195a2e3f133437f7533c3df955de146e229e4a37fda22acbe11d9393215d14cf1e19334aebbf35e61b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
|
||||
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000
|
||||
test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006b56051582a970000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e5679a7262a283109d2e312e4ffbec563f501f347efc00418f3a6701492635977583d4e2ff29904a33496b64f1bc2ac73796a546a495ab110cca86e6de1655b61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004160aa554efc922689a7f426a984f9fc278aa948b9c78f4e7cc0a5f177e5fb6859632b92d3326f710603d43d3a8ea5753c58a61316fd1bff8e0b388f74c98993b91b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000
|
||||
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415eb0e4c29f56696a0a8c0445740b653ae67c0f52fe364f52adc19c84fd6fdc837bc0df41516f33500ebe7f05f653bc0e53ec3ec27c223484d29e4567bf5a0f561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000
|
||||
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c90000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000410c38cb809e33a4b6239b5aab3ac879ec39ba3a6979404f6cfc882cc15b81e92f02fef7985c8edd3985b39224f2738ca6bbcfe7acf0cd44d8bab89636dcce3bfb1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000
|
||||
test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000
|
||||
test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000068529cc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000000000000000000000000000682b16c900000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041a81d713c715dd501edf102a3c3a755a931e3c72e7322d66b620ece81d7c98bae3d46479041445649eeefdb6ccc09c2b933cd37eda3ae8c99034e84f5570eb2c31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000
|
||||
test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102
|
||||
test_ekubo_encode_swap_multi:01ca4f73fe97d0b987a0d12b39bbd562c779bab6f60000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4851d02a5948496a67827242eabc5725531342527c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000001a36e2eb1c43200000032
|
||||
test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c
|
||||
test_encode_uniswap_v4_simple_swap:4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec7000064000001
|
||||
test_single_encoding_strategy_maverick:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000051a4ad4f68d0b91cfd19687c881e50f3a00242828c40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c67cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_encode_maverick_v2:40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f14cf6d2fe3e1b326114b07d22a6f6bb59e346c671d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01
|
||||
test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0001
|
||||
|
||||
@@ -46,7 +46,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
||||
WETH_BAL_POOL_ID,
|
||||
address(2),
|
||||
true,
|
||||
TokenTransfer.TransferType.NONE
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
(
|
||||
@@ -55,7 +55,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
||||
bytes32 poolId,
|
||||
address receiver,
|
||||
bool needsApproval,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = balancerV2Exposed.decodeParams(params);
|
||||
|
||||
assertEq(address(tokenIn), WETH_ADDR);
|
||||
@@ -63,7 +63,9 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
||||
assertEq(poolId, WETH_BAL_POOL_ID);
|
||||
assertEq(receiver, address(2));
|
||||
assertEq(needsApproval, true);
|
||||
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
|
||||
assertEq(
|
||||
uint8(transferType), uint8(RestrictTransferFrom.TransferType.None)
|
||||
);
|
||||
}
|
||||
|
||||
function testDecodeParamsInvalidDataLength() public {
|
||||
@@ -82,7 +84,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
||||
WETH_BAL_POOL_ID,
|
||||
BOB,
|
||||
true,
|
||||
TokenTransfer.TransferType.NONE
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);
|
||||
@@ -104,7 +106,7 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
||||
bytes32 poolId,
|
||||
address receiver,
|
||||
bool needsApproval,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = balancerV2Exposed.decodeParams(protocolData);
|
||||
|
||||
assertEq(address(tokenIn), WETH_ADDR);
|
||||
@@ -112,7 +114,9 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
|
||||
assertEq(poolId, WETH_BAL_POOL_ID);
|
||||
assertEq(receiver, BOB);
|
||||
assertEq(needsApproval, true);
|
||||
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
|
||||
assertEq(
|
||||
uint8(transferType), uint8(RestrictTransferFrom.TransferType.None)
|
||||
);
|
||||
}
|
||||
|
||||
function testSwapIntegration() public {
|
||||
|
||||
@@ -37,7 +37,7 @@ contract CurveExecutorExposed is CurveExecutor {
|
||||
int128 i,
|
||||
int128 j,
|
||||
bool tokenApprovalNeeded,
|
||||
TokenTransfer.TransferType transferType,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver
|
||||
)
|
||||
{
|
||||
@@ -68,7 +68,7 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint8(2),
|
||||
uint8(0),
|
||||
true,
|
||||
TokenTransfer.TransferType.NONE,
|
||||
RestrictTransferFrom.TransferType.None,
|
||||
ALICE
|
||||
);
|
||||
|
||||
@@ -80,7 +80,7 @@ contract CurveExecutorTest is Test, Constants {
|
||||
int128 i,
|
||||
int128 j,
|
||||
bool tokenApprovalNeeded,
|
||||
TokenTransfer.TransferType transferType,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver
|
||||
) = curveExecutorExposed.decodeData(data);
|
||||
|
||||
@@ -91,7 +91,9 @@ contract CurveExecutorTest is Test, Constants {
|
||||
assertEq(i, 2);
|
||||
assertEq(j, 0);
|
||||
assertEq(tokenApprovalNeeded, true);
|
||||
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
|
||||
assertEq(
|
||||
uint8(transferType), uint8(RestrictTransferFrom.TransferType.None)
|
||||
);
|
||||
assertEq(receiver, ALICE);
|
||||
}
|
||||
|
||||
@@ -100,7 +102,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
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);
|
||||
|
||||
@@ -113,8 +122,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(ETH_ADDR_FOR_CURVE, STETH_ADDR, STETH_POOL, 1, ALICE);
|
||||
bytes memory data = _getData(
|
||||
ETH_ADDR_FOR_CURVE,
|
||||
STETH_ADDR,
|
||||
STETH_POOL,
|
||||
1,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -130,8 +145,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(WETH_ADDR, WBTC_ADDR, TRICRYPTO2_POOL, 3, ALICE);
|
||||
bytes memory data = _getData(
|
||||
WETH_ADDR,
|
||||
WBTC_ADDR,
|
||||
TRICRYPTO2_POOL,
|
||||
3,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -144,7 +165,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 100 * 10 ** 6;
|
||||
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);
|
||||
|
||||
@@ -157,8 +185,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(FRAX_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(FRAX_ADDR, USDC_ADDR, FRAX_USDC_POOL, 1, ALICE);
|
||||
bytes memory data = _getData(
|
||||
FRAX_ADDR,
|
||||
USDC_ADDR,
|
||||
FRAX_USDC_POOL,
|
||||
1,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -171,8 +205,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 100 * 10 ** 6;
|
||||
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(USDC_ADDR, USDE_ADDR, USDE_USDC_POOL, 1, ALICE);
|
||||
bytes memory data = _getData(
|
||||
USDC_ADDR,
|
||||
USDE_ADDR,
|
||||
USDE_USDC_POOL,
|
||||
1,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -185,8 +225,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 100 * 10 ** 6;
|
||||
deal(DOLA_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1, ALICE);
|
||||
bytes memory data = _getData(
|
||||
DOLA_ADDR,
|
||||
FRAXPYUSD_POOL,
|
||||
DOLA_FRAXPYUSD_POOL,
|
||||
1,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
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
|
||||
deal(XYO_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(XYO_ADDR, ETH_ADDR_FOR_CURVE, ETH_XYO_POOL, 2, ALICE);
|
||||
bytes memory data = _getData(
|
||||
XYO_ADDR,
|
||||
ETH_ADDR_FOR_CURVE,
|
||||
ETH_XYO_POOL,
|
||||
2,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -214,8 +266,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1000 ether;
|
||||
deal(BSGG_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(BSGG_ADDR, USDT_ADDR, BSGG_USDT_POOL, 2, ALICE);
|
||||
bytes memory data = _getData(
|
||||
BSGG_ADDR,
|
||||
USDT_ADDR,
|
||||
BSGG_USDT_POOL,
|
||||
2,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -228,8 +286,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(WETH_ADDR, USDC_ADDR, TRICRYPTO_POOL, 2, ALICE);
|
||||
bytes memory data = _getData(
|
||||
WETH_ADDR,
|
||||
USDC_ADDR,
|
||||
TRICRYPTO_POOL,
|
||||
2,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -242,8 +306,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(UWU_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(UWU_ADDR, WETH_ADDR, UWU_WETH_POOL, 2, ALICE);
|
||||
bytes memory data = _getData(
|
||||
UWU_ADDR,
|
||||
WETH_ADDR,
|
||||
UWU_WETH_POOL,
|
||||
2,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -256,8 +326,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 1 ether;
|
||||
deal(USDT_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(USDT_ADDR, CRVUSD_ADDR, CRVUSD_USDT_POOL, 1, ALICE);
|
||||
bytes memory data = _getData(
|
||||
USDT_ADDR,
|
||||
CRVUSD_ADDR,
|
||||
CRVUSD_USDT_POOL,
|
||||
1,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -270,8 +346,14 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 100 * 10 ** 9; // 9 decimals
|
||||
deal(WTAO_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1, ALICE);
|
||||
bytes memory data = _getData(
|
||||
WTAO_ADDR,
|
||||
WSTTAO_ADDR,
|
||||
WSTTAO_WTAO_POOL,
|
||||
1,
|
||||
ALICE,
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
@@ -284,7 +366,8 @@ contract CurveExecutorTest is Test, Constants {
|
||||
address tokenOut,
|
||||
address pool,
|
||||
uint8 poolType,
|
||||
address receiver
|
||||
address receiver,
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) internal view returns (bytes memory data) {
|
||||
(int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool);
|
||||
data = abi.encodePacked(
|
||||
@@ -295,7 +378,7 @@ contract CurveExecutorTest is Test, Constants {
|
||||
uint8(uint256(uint128(i))),
|
||||
uint8(uint256(uint128(j))),
|
||||
true,
|
||||
TokenTransfer.TransferType.NONE,
|
||||
transferType,
|
||||
receiver
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "../TestUtils.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 {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.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));
|
||||
|
||||
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
|
||||
NATIVE_TOKEN_ADDRESS, // tokenIn
|
||||
USDC_ADDR, // tokenOut
|
||||
@@ -82,7 +82,7 @@ contract EkuboExecutorTest is Constants, TestUtils {
|
||||
uint256 ethBalanceBeforeExecutor = address(executor).balance;
|
||||
|
||||
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
|
||||
USDC_ADDR, // tokenIn
|
||||
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
|
||||
function testMultiHopSwap() public {
|
||||
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
|
||||
NATIVE_TOKEN_ADDRESS, // tokenIn
|
||||
USDC_ADDR, // tokenOut of 1st swap
|
||||
|
||||
@@ -17,7 +17,7 @@ contract MaverickV2ExecutorExposed is MaverickV2Executor {
|
||||
IERC20 tokenIn,
|
||||
address target,
|
||||
address receiver,
|
||||
TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
@@ -43,14 +43,14 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
||||
GHO_ADDR,
|
||||
GHO_USDC_POOL,
|
||||
address(2),
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
(
|
||||
IERC20 tokenIn,
|
||||
address target,
|
||||
address receiver,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = maverickV2Exposed.decodeParams(params);
|
||||
|
||||
assertEq(address(tokenIn), GHO_ADDR);
|
||||
@@ -58,7 +58,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
||||
assertEq(receiver, address(2));
|
||||
assertEq(
|
||||
uint8(transferType),
|
||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
||||
GHO_ADDR,
|
||||
GHO_USDC_POOL,
|
||||
BOB,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
deal(GHO_ADDR, address(maverickV2Exposed), amountIn);
|
||||
@@ -98,7 +98,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
||||
IERC20 tokenIn,
|
||||
address pool,
|
||||
address receiver,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = maverickV2Exposed.decodeParams(protocolData);
|
||||
|
||||
assertEq(address(tokenIn), GHO_ADDR);
|
||||
@@ -106,7 +106,7 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
||||
assertEq(receiver, BOB);
|
||||
assertEq(
|
||||
uint8(transferType),
|
||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "../TestUtils.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 {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
|
||||
contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
||||
constructor(
|
||||
@@ -23,7 +23,7 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
)
|
||||
{
|
||||
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;
|
||||
|
||||
UniswapV2ExecutorExposed uniswapV2Exposed;
|
||||
@@ -60,7 +60,6 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
UniswapV2ExecutorExposed pancakeswapV2Exposed;
|
||||
IERC20 WETH = IERC20(WETH_ADDR);
|
||||
IERC20 DAI = IERC20(DAI_ADDR);
|
||||
IAllowanceTransfer permit2;
|
||||
|
||||
function setUp() public {
|
||||
uint256 forkBlock = 17323404;
|
||||
@@ -80,7 +79,6 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
PERMIT2_ADDRESS,
|
||||
25
|
||||
);
|
||||
permit2 = IAllowanceTransfer(PERMIT2_ADDRESS);
|
||||
}
|
||||
|
||||
function testDecodeParams() public view {
|
||||
@@ -89,7 +87,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address(2),
|
||||
address(3),
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
(
|
||||
@@ -97,7 +95,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = uniswapV2Exposed.decodeParams(params);
|
||||
|
||||
assertEq(address(tokenIn), WETH_ADDR);
|
||||
@@ -105,8 +103,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
assertEq(receiver, address(3));
|
||||
assertEq(zeroForOne, false);
|
||||
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,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||
@@ -173,59 +171,6 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
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 {
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
@@ -235,7 +180,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
WETH_DAI_POOL,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.NONE)
|
||||
RestrictTransferFrom.TransferType.None
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(this), amountIn);
|
||||
@@ -248,27 +193,29 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
|
||||
function testDecodeIntegration() public view {
|
||||
bytes memory protocolData =
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010000";
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010001";
|
||||
|
||||
(
|
||||
IERC20 tokenIn,
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = uniswapV2Exposed.decodeParams(protocolData);
|
||||
|
||||
assertEq(address(tokenIn), WETH_ADDR);
|
||||
assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640);
|
||||
assertEq(receiver, 0x0000000000000000000000000000000000000001);
|
||||
assertEq(zeroForOne, false);
|
||||
// TRANSFER = 0
|
||||
assertEq(0, uint8(transferType));
|
||||
assertEq(
|
||||
uint8(transferType),
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
}
|
||||
|
||||
function testSwapIntegration() public {
|
||||
bytes memory protocolData =
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0000";
|
||||
loadCallDataFromFile("test_encode_uniswap_v2");
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||
@@ -287,7 +234,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
fakePool,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||
@@ -307,7 +254,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
USDC_MAG7_POOL,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);
|
||||
|
||||
@@ -22,7 +22,7 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
||||
address receiver,
|
||||
address target,
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
@@ -71,7 +71,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address(2),
|
||||
address(3),
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
(
|
||||
@@ -81,7 +81,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address receiver,
|
||||
address target,
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) = uniswapV3Exposed.decodeData(data);
|
||||
|
||||
assertEq(tokenIn, WETH_ADDR);
|
||||
@@ -92,7 +92,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
assertEq(zeroForOne, false);
|
||||
assertEq(
|
||||
uint8(transferType),
|
||||
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address(this),
|
||||
DAI_WETH_USV3,
|
||||
zeroForOne,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
|
||||
@@ -150,7 +150,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
WETH_ADDR,
|
||||
DAI_ADDR,
|
||||
poolFee,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
address(uniswapV3Exposed)
|
||||
);
|
||||
uint256 dataOffset = 3; // some offset
|
||||
@@ -184,7 +184,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address(this),
|
||||
fakePool,
|
||||
zeroForOne,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
|
||||
RestrictTransferFrom.TransferType.Transfer
|
||||
);
|
||||
|
||||
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);
|
||||
@@ -197,7 +197,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
address receiver,
|
||||
address target,
|
||||
bool zero2one,
|
||||
TokenTransfer.TransferType transferType
|
||||
RestrictTransferFrom.TransferType transferType
|
||||
) internal view returns (bytes memory) {
|
||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||
return abi.encodePacked(
|
||||
|
||||
@@ -4,7 +4,6 @@ pragma solidity ^0.8.26;
|
||||
import "../../src/executors/UniswapV4Executor.sol";
|
||||
import "../TestUtils.sol";
|
||||
import "./UniswapV4Utils.sol";
|
||||
import "@src/executors/TokenTransfer.sol";
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
@@ -22,7 +21,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver,
|
||||
UniswapV4Pool[] memory pools
|
||||
)
|
||||
@@ -53,8 +52,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
int24 tickSpacing1 = 60;
|
||||
uint24 pool2Fee = 1000;
|
||||
int24 tickSpacing2 = -10;
|
||||
TokenTransfer.TransferType transferType =
|
||||
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||
@@ -70,14 +67,19 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
});
|
||||
|
||||
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 tokenOut,
|
||||
bool zeroForOneDecoded,
|
||||
TokenTransfer.TransferType transferTypeDecoded,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
||||
) = uniswapV4Exposed.decodeData(data);
|
||||
@@ -85,7 +87,10 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
assertEq(tokenIn, USDE_ADDR);
|
||||
assertEq(tokenOut, USDT_ADDR);
|
||||
assertEq(zeroForOneDecoded, zeroForOne);
|
||||
assertEq(uint8(transferTypeDecoded), uint8(transferType));
|
||||
assertEq(
|
||||
uint8(transferType),
|
||||
uint8(RestrictTransferFrom.TransferType.Transfer)
|
||||
);
|
||||
assertEq(receiver, ALICE);
|
||||
assertEq(decodedPools.length, 2);
|
||||
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
|
||||
@@ -115,7 +120,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
@@ -172,7 +177,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
USDE_ADDR,
|
||||
WBTC_ADDR,
|
||||
true,
|
||||
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
|
||||
RestrictTransferFrom.TransferType.Transfer,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ library UniswapV4Utils {
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
bool zeroForOne,
|
||||
UniswapV4Executor.TransferType transferType,
|
||||
RestrictTransferFrom.TransferType transferType,
|
||||
address receiver,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||
) public pure returns (bytes memory) {
|
||||
|
||||
@@ -34,11 +34,12 @@ pub static IN_TRANSFER_REQUIRED_PROTOCOLS: LazyLock<HashSet<&'static str>> = Laz
|
||||
set
|
||||
});
|
||||
|
||||
// The protocols here are a subset of the ones defined in IN_TRANSFER_REQUIRED_PROTOCOLS. The tokens
|
||||
// can not be sent directly from the previous pool into a pool of this protocol. The tokens need to
|
||||
// be sent to the router and only then transferred into the pool. This is the case for uniswap v3
|
||||
// because of the 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.
|
||||
// The protocols here are a subset of the ones defined in IN_TRANSFER_REQUIRED_PROTOCOLS. The in
|
||||
// transfer needs to be performed inside the callback logic. This means, the tokens can not be sent
|
||||
// directly from the previous pool into a pool of this protocol. The tokens need to be sent to the
|
||||
// router and only then transferred into the pool. This is the case for uniswap v3 because of the
|
||||
// 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(|| {
|
||||
let mut set = HashSet::new();
|
||||
set.insert("uniswap_v3");
|
||||
|
||||
@@ -33,6 +33,7 @@ use crate::encoding::{
|
||||
/// * `selector`: String, the selector for the swap function in the router contract
|
||||
/// * `router_address`: Address of the router to be used to execute swaps
|
||||
/// * `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)]
|
||||
pub struct SingleSwapStrategyEncoder {
|
||||
swap_encoder_registry: SwapEncoderRegistry,
|
||||
@@ -40,6 +41,7 @@ pub struct SingleSwapStrategyEncoder {
|
||||
selector: String,
|
||||
router_address: Bytes,
|
||||
transfer_optimization: TransferOptimization,
|
||||
token_in_already_in_router: bool,
|
||||
}
|
||||
|
||||
impl SingleSwapStrategyEncoder {
|
||||
@@ -55,10 +57,10 @@ impl SingleSwapStrategyEncoder {
|
||||
} else {
|
||||
(
|
||||
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 {
|
||||
permit2,
|
||||
selector,
|
||||
@@ -67,10 +69,10 @@ impl SingleSwapStrategyEncoder {
|
||||
transfer_optimization: TransferOptimization::new(
|
||||
chain.native_token()?,
|
||||
chain.wrapped_token()?,
|
||||
permit2_is_active,
|
||||
token_in_already_in_router,
|
||||
router_address,
|
||||
),
|
||||
token_in_already_in_router,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -125,16 +127,16 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
||||
let swap_receiver =
|
||||
if !unwrap { solution.receiver.clone() } else { self.router_address.clone() };
|
||||
|
||||
let transfer_type = self
|
||||
let transfer = self
|
||||
.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 {
|
||||
receiver: swap_receiver.clone(),
|
||||
exact_out: solution.exact_out,
|
||||
router_address: Some(self.router_address.clone()),
|
||||
group_token_in: grouped_swap.token_in.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![];
|
||||
@@ -178,6 +180,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
||||
wrap,
|
||||
unwrap,
|
||||
bytes_to_address(&solution.receiver)?,
|
||||
!self.token_in_already_in_router,
|
||||
swap_data,
|
||||
)
|
||||
.abi_encode()
|
||||
@@ -210,6 +213,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
||||
/// * `sequential_swap_validator`: SequentialSwapValidator, responsible for checking validity of
|
||||
/// sequential swap solutions
|
||||
/// * `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)]
|
||||
pub struct SequentialSwapStrategyEncoder {
|
||||
swap_encoder_registry: SwapEncoderRegistry,
|
||||
@@ -220,6 +224,7 @@ pub struct SequentialSwapStrategyEncoder {
|
||||
wrapped_address: Bytes,
|
||||
sequential_swap_validator: SequentialSwapValidator,
|
||||
transfer_optimization: TransferOptimization,
|
||||
token_in_already_in_router: bool,
|
||||
}
|
||||
|
||||
impl SequentialSwapStrategyEncoder {
|
||||
@@ -235,11 +240,10 @@ impl SequentialSwapStrategyEncoder {
|
||||
} else {
|
||||
(
|
||||
None,
|
||||
"sequentialSwap(uint256,address,address,uint256,bool,bool,address,bytes)"
|
||||
"sequentialSwap(uint256,address,address,uint256,bool,bool,address,bool,bytes)"
|
||||
.to_string(),
|
||||
)
|
||||
};
|
||||
let permit2_is_active = permit2.is_some();
|
||||
Ok(Self {
|
||||
permit2,
|
||||
selector,
|
||||
@@ -251,10 +255,10 @@ impl SequentialSwapStrategyEncoder {
|
||||
transfer_optimization: TransferOptimization::new(
|
||||
chain.native_token()?,
|
||||
chain.wrapped_token()?,
|
||||
permit2_is_active,
|
||||
token_in_already_in_router,
|
||||
router_address,
|
||||
),
|
||||
token_in_already_in_router,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -311,9 +315,10 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
||||
.transfer_optimization
|
||||
.get_receiver(solution.receiver.clone(), next_swap)?;
|
||||
next_in_between_swap_optimization_allowed = next_swap_optimization;
|
||||
let transfer_type = self
|
||||
|
||||
let transfer = self
|
||||
.transfer_optimization
|
||||
.get_transfer_type(
|
||||
.get_transfers(
|
||||
grouped_swap.clone(),
|
||||
solution.given_token.clone(),
|
||||
wrap,
|
||||
@@ -325,7 +330,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
||||
router_address: Some(self.router_address.clone()),
|
||||
group_token_in: grouped_swap.token_in.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![];
|
||||
@@ -374,6 +379,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
||||
wrap,
|
||||
unwrap,
|
||||
bytes_to_address(&solution.receiver)?,
|
||||
!self.token_in_already_in_router,
|
||||
encoded_swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
@@ -406,6 +412,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
||||
/// solutions
|
||||
/// * `router_address`: Address of the router to be used to execute swaps
|
||||
/// * `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)]
|
||||
pub struct SplitSwapStrategyEncoder {
|
||||
swap_encoder_registry: SwapEncoderRegistry,
|
||||
@@ -416,6 +423,7 @@ pub struct SplitSwapStrategyEncoder {
|
||||
split_swap_validator: SplitSwapValidator,
|
||||
router_address: Bytes,
|
||||
transfer_optimization: TransferOptimization,
|
||||
token_in_already_in_router: bool,
|
||||
}
|
||||
|
||||
impl SplitSwapStrategyEncoder {
|
||||
@@ -431,11 +439,10 @@ impl SplitSwapStrategyEncoder {
|
||||
} else {
|
||||
(
|
||||
None,
|
||||
"splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)"
|
||||
"splitSwap(uint256,address,address,uint256,bool,bool,uint256,address,bool,bytes)"
|
||||
.to_string(),
|
||||
)
|
||||
};
|
||||
let permit2_is_active = permit2.is_some();
|
||||
Ok(Self {
|
||||
permit2,
|
||||
selector,
|
||||
@@ -447,10 +454,10 @@ impl SplitSwapStrategyEncoder {
|
||||
transfer_optimization: TransferOptimization::new(
|
||||
chain.native_token()?,
|
||||
chain.wrapped_token()?,
|
||||
permit2_is_active,
|
||||
token_in_already_in_router,
|
||||
router_address,
|
||||
),
|
||||
token_in_already_in_router,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -553,16 +560,16 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
||||
} else {
|
||||
self.router_address.clone()
|
||||
};
|
||||
let transfer_type = self
|
||||
let transfer = self
|
||||
.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 {
|
||||
receiver: swap_receiver.clone(),
|
||||
exact_out: solution.exact_out,
|
||||
router_address: Some(self.router_address.clone()),
|
||||
group_token_in: grouped_swap.token_in.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![];
|
||||
@@ -621,6 +628,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
||||
unwrap,
|
||||
U256::from(tokens_len),
|
||||
bytes_to_address(&solution.receiver)?,
|
||||
!self.token_in_already_in_router,
|
||||
encoded_swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
@@ -750,7 +758,7 @@ mod tests {
|
||||
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
||||
let expected_input = [
|
||||
"30ace1b1", // Function selector
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount out
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||
&expected_min_amount_encoded, // min amount out
|
||||
@@ -772,7 +780,7 @@ mod tests {
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"02", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
"0000000000000000000000000000", // padding
|
||||
));
|
||||
let hex_calldata = encode(&calldata);
|
||||
@@ -839,7 +847,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
||||
let expected_input = [
|
||||
"20144a07", // Function selector
|
||||
"5c4b639c", // Function selector
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||
@@ -847,7 +855,8 @@ mod tests {
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000001", // transfer from needed
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
||||
|
||||
// Swap data
|
||||
@@ -856,7 +865,7 @@ mod tests {
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"01", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
"0000000000000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
@@ -921,7 +930,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let expected_min_amount_encoded = hex::encode(U256::abi_encode(&expected_min_amount));
|
||||
let expected_input = [
|
||||
"20144a07", // Function selector
|
||||
"5c4b639c", // Function selector
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||
@@ -929,7 +938,8 @@ mod tests {
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // transfer from not needed
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
||||
|
||||
// Swap data
|
||||
@@ -938,7 +948,7 @@ mod tests {
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"00", // transfer type
|
||||
"01", // transfer type Transfer
|
||||
"0000000000000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
@@ -1191,7 +1201,7 @@ mod tests {
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
let expected = String::from(concat!(
|
||||
"e8a980d7", /* function selector */
|
||||
"e21dd0d3", /* function selector */
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
|
||||
@@ -1199,7 +1209,8 @@ mod tests {
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000100", /* length ple
|
||||
"0000000000000000000000000000000000000000000000000000000000000001", /* transfer from needed */
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", /* length ple
|
||||
* encode */
|
||||
"00000000000000000000000000000000000000000000000000000000000000a8",
|
||||
// swap 1
|
||||
@@ -1209,7 +1220,7 @@ mod tests {
|
||||
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
|
||||
"004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool)
|
||||
"00", // zero to one
|
||||
"01", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
// swap 2
|
||||
"0052", // swap length
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
@@ -1217,7 +1228,7 @@ mod tests {
|
||||
"004375dff511095cc5a197a54140a24efef3a416", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
|
||||
"01", // zero to one
|
||||
"05", // transfer type - None
|
||||
"02", // transfer type None
|
||||
"000000000000000000000000000000000000000000000000", // padding
|
||||
));
|
||||
|
||||
@@ -1336,7 +1347,7 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"01", // zero2one
|
||||
"02", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
"0069", // ple encoded swaps
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
@@ -1345,7 +1356,7 @@ mod tests {
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"00", // zero2one
|
||||
"00", // transfer type
|
||||
"01", // transfer type Transfer
|
||||
"00000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
@@ -2062,7 +2073,7 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"01", // zero2one
|
||||
"02", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
"006e", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
@@ -2074,7 +2085,7 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"01", // zero2one
|
||||
"02", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
"0057", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
@@ -2084,7 +2095,7 @@ mod tests {
|
||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id,
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"00", // transfer type
|
||||
"01", // transfer type Transfer
|
||||
"00000000000000" // padding
|
||||
]
|
||||
.join("");
|
||||
@@ -2224,7 +2235,7 @@ mod tests {
|
||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"01", // zero2one
|
||||
"02", // transfer type
|
||||
"00", // transfer type TransferFrom
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
@@ -2236,7 +2247,7 @@ mod tests {
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"00", // zero2one
|
||||
"00", // transfer type
|
||||
"01", // transfer type Transfer
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
@@ -2248,7 +2259,7 @@ mod tests {
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"00", // zero2one
|
||||
"00", // transfer type
|
||||
"01", // transfer type Transfer
|
||||
"00000000000000" // padding
|
||||
]
|
||||
.join("");
|
||||
@@ -2625,7 +2636,7 @@ mod tests {
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
|
||||
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
|
||||
"00", // zero2one
|
||||
"02", // transfer type (transfer to router)
|
||||
"00", // transfer type TransferFrom
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
// First pool params
|
||||
"0000000000000000000000000000000000000000", // intermediary token (ETH)
|
||||
|
||||
@@ -16,7 +16,6 @@ use crate::encoding::{
|
||||
pub struct TransferOptimization {
|
||||
native_token: Bytes,
|
||||
wrapped_token: Bytes,
|
||||
permit2: bool,
|
||||
token_in_already_in_router: bool,
|
||||
router_address: Bytes,
|
||||
}
|
||||
@@ -25,69 +24,58 @@ impl TransferOptimization {
|
||||
pub fn new(
|
||||
native_token: Bytes,
|
||||
wrapped_token: Bytes,
|
||||
permit2: bool,
|
||||
token_in_already_in_router: bool,
|
||||
router_address: Bytes,
|
||||
) -> Self {
|
||||
TransferOptimization {
|
||||
native_token,
|
||||
wrapped_token,
|
||||
permit2,
|
||||
token_in_already_in_router,
|
||||
router_address,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the transfer method that should be used for the given swap and solution.
|
||||
pub fn get_transfer_type(
|
||||
/// Returns the transfer type that should be used for the current transfer.
|
||||
pub fn get_transfers(
|
||||
&self,
|
||||
swap: SwapGroup,
|
||||
given_token: Bytes,
|
||||
wrap: bool,
|
||||
in_between_swap_optimization: bool,
|
||||
) -> TransferType {
|
||||
let is_first_swap = swap.token_in == given_token;
|
||||
let in_transfer_required: bool =
|
||||
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 {
|
||||
// Funds are already in router. All protocols currently take care of native transfers.
|
||||
TransferType::None
|
||||
} else if (swap.token_in == self.wrapped_token) && wrap {
|
||||
// Wrapping already happened in the router so we can just use a normal transfer.
|
||||
TransferType::TransferToProtocol
|
||||
// Wrapping already happened in the router so, we just do a normal transfer.
|
||||
TransferType::Transfer
|
||||
} else if is_first_swap {
|
||||
if in_transfer_required {
|
||||
if self.token_in_already_in_router {
|
||||
// Transfer from router to pool.
|
||||
TransferType::TransferToProtocol
|
||||
} else if self.permit2 {
|
||||
// Transfer from swapper to pool using permit2.
|
||||
TransferType::TransferPermit2ToProtocol
|
||||
TransferType::Transfer
|
||||
} else {
|
||||
// Transfer from swapper to pool.
|
||||
TransferType::TransferFromToProtocol
|
||||
// Transfer from swapper to pool
|
||||
TransferType::TransferFrom
|
||||
}
|
||||
// in transfer is not necessary for these protocols. Only make a transfer if the
|
||||
// tokens are not already in the router
|
||||
// in transfer is not necessary for these protocols. Only make a transfer from the
|
||||
// swapper to the router if the tokens are not already in the router
|
||||
} else if !self.token_in_already_in_router {
|
||||
if self.permit2 {
|
||||
// Transfer from swapper to router using permit2.
|
||||
TransferType::TransferPermit2ToRouter
|
||||
} else {
|
||||
// Transfer from swapper to router.
|
||||
TransferType::TransferFromToRouter
|
||||
}
|
||||
// Transfer from swapper to router using.
|
||||
TransferType::TransferFrom
|
||||
} else {
|
||||
TransferType::None
|
||||
}
|
||||
// all other swaps
|
||||
// all other swaps that not the first one
|
||||
} else if !in_transfer_required || in_between_swap_optimization {
|
||||
// funds should already be in the router or in the next pool
|
||||
TransferType::None
|
||||
} else {
|
||||
TransferType::TransferToProtocol
|
||||
TransferType::Transfer
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,146 +143,63 @@ mod tests {
|
||||
Bytes::from("0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_swap_transfer_from_permit2() {
|
||||
#[rstest]
|
||||
// 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
|
||||
let swap = SwapGroup {
|
||||
let swaps = vec![Swap {
|
||||
component: ProtocolComponent {
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
token_in: weth(),
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: swap_token_in.clone(),
|
||||
token_out: dai(),
|
||||
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 {
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
token_in: weth(),
|
||||
protocol_system: protocol,
|
||||
token_in: swap_token_in,
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
swaps: vec![],
|
||||
swaps,
|
||||
};
|
||||
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::TransferFromToProtocol);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_first_swap_native() {
|
||||
// The swap token is the same as the given token, and it's the native token.
|
||||
// No transfer action is needed.
|
||||
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);
|
||||
let optimization =
|
||||
TransferOptimization::new(eth(), weth(), token_in_already_in_router, router_address());
|
||||
let transfer = optimization.get_transfers(
|
||||
swap.clone(),
|
||||
given_token,
|
||||
wrap,
|
||||
in_between_swap_optimization,
|
||||
);
|
||||
assert_eq!(transfer, expected_transfer);
|
||||
}
|
||||
|
||||
fn receiver() -> Bytes {
|
||||
@@ -319,7 +224,7 @@ mod tests {
|
||||
#[case] expected_receiver: Bytes,
|
||||
#[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() {
|
||||
None
|
||||
|
||||
@@ -592,7 +592,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_encode_uniswap_v2() {
|
||||
let usv2_pool = ProtocolComponent {
|
||||
id: String::from("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"),
|
||||
id: String::from("0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11"),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -605,12 +605,12 @@ mod tests {
|
||||
split: 0f64,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
receiver: Bytes::from("0x0000000000000000000000000000000000000001"),
|
||||
receiver: Bytes::from("0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e"), // BOB
|
||||
exact_out: false,
|
||||
router_address: Some(Bytes::zero(20)),
|
||||
group_token_in: token_in.clone(),
|
||||
group_token_out: token_out.clone(),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
let encoder = UniswapV2SwapEncoder::new(
|
||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||
@@ -628,15 +628,16 @@ mod tests {
|
||||
// in token
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
// component id
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11",
|
||||
// receiver
|
||||
"0000000000000000000000000000000000000001",
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type (transfer)
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"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)),
|
||||
group_token_in: token_in.clone(),
|
||||
group_token_out: token_out.clone(),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
let encoder = UniswapV3SwapEncoder::new(
|
||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||
@@ -695,8 +696,8 @@ mod tests {
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type (transfer)
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"01",
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -759,8 +760,8 @@ mod tests {
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
// approval needed
|
||||
"01",
|
||||
// transfer type
|
||||
"05"
|
||||
// transfer type None
|
||||
"02"
|
||||
))
|
||||
);
|
||||
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_out: token_out.clone(),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
let encoder = UniswapV4SwapEncoder::new(
|
||||
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
|
||||
@@ -826,8 +827,8 @@ mod tests {
|
||||
"dac17f958d2ee523a2206206994597c13d831ec7",
|
||||
// zero for one
|
||||
"01",
|
||||
// transfer type
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"01",
|
||||
// receiver
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||
// pool params:
|
||||
@@ -875,7 +876,7 @@ mod tests {
|
||||
group_token_in: group_token_in.clone(),
|
||||
// Token out is the same as the group token out
|
||||
group_token_out: token_out.clone(),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
|
||||
let encoder = UniswapV4SwapEncoder::new(
|
||||
@@ -918,7 +919,7 @@ mod tests {
|
||||
router_address: Some(router_address.clone()),
|
||||
group_token_in: usde_address.clone(),
|
||||
group_token_out: wbtc_address.clone(),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
|
||||
// Setup - First sequence: USDE -> USDT
|
||||
@@ -996,8 +997,8 @@ mod tests {
|
||||
"2260fac5e5542a773aa44fbcfedf7c193bc2c599",
|
||||
// zero for one
|
||||
"01",
|
||||
// transfer type
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"01",
|
||||
// receiver
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||
// pool params:
|
||||
@@ -1053,7 +1054,7 @@ mod tests {
|
||||
group_token_out: token_out.clone(),
|
||||
exact_out: false,
|
||||
router_address: Some(Bytes::default()),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
|
||||
let encoder =
|
||||
@@ -1069,8 +1070,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
hex_swap,
|
||||
concat!(
|
||||
// transfer type
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"01",
|
||||
// receiver
|
||||
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
|
||||
// group token in
|
||||
@@ -1099,7 +1100,7 @@ mod tests {
|
||||
group_token_out: group_token_out.clone(),
|
||||
exact_out: false,
|
||||
router_address: Some(Bytes::default()),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
|
||||
let first_swap = Swap {
|
||||
@@ -1149,8 +1150,8 @@ mod tests {
|
||||
combined_hex,
|
||||
// transfer type
|
||||
concat!(
|
||||
// transfer type
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"01",
|
||||
// receiver
|
||||
"ca4f73fe97d0b987a0d12b39bbd562c779bab6f6",
|
||||
// group token in
|
||||
@@ -1332,10 +1333,10 @@ mod tests {
|
||||
"01",
|
||||
// approval needed
|
||||
"01",
|
||||
// transfer type
|
||||
"05",
|
||||
// transfer type None
|
||||
"02",
|
||||
// receiver,
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -1403,10 +1404,10 @@ mod tests {
|
||||
"00",
|
||||
// approval needed
|
||||
"01",
|
||||
// transfer type
|
||||
"05",
|
||||
// transfer type None
|
||||
"02",
|
||||
// receiver
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -1484,10 +1485,10 @@ mod tests {
|
||||
"01",
|
||||
// approval needed
|
||||
"01",
|
||||
// transfer type
|
||||
"05",
|
||||
// transfer type None
|
||||
"02",
|
||||
// receiver
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e"
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -1516,7 +1517,7 @@ mod tests {
|
||||
router_address: Some(Bytes::default()),
|
||||
group_token_in: token_in.clone(),
|
||||
group_token_out: token_out.clone(),
|
||||
transfer_type: TransferType::TransferToProtocol,
|
||||
transfer_type: TransferType::Transfer,
|
||||
};
|
||||
let encoder = MaverickV2SwapEncoder::new(
|
||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||
@@ -1539,8 +1540,8 @@ mod tests {
|
||||
"14Cf6D2Fe3E1B326114b07d22A6F6bb59e346c67",
|
||||
// receiver
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
// transfer from router to protocol
|
||||
"00",
|
||||
// transfer true
|
||||
"01",
|
||||
))
|
||||
.to_lowercase()
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ use tycho_common::Bytes;
|
||||
use crate::encoding::{
|
||||
errors::EncodingError,
|
||||
evm::{
|
||||
constants::GROUPABLE_PROTOCOLS,
|
||||
constants::{GROUPABLE_PROTOCOLS, IN_TRANSFER_REQUIRED_PROTOCOLS},
|
||||
group_swaps::group_swaps,
|
||||
strategy_encoder::strategy_encoders::{
|
||||
SequentialSwapStrategyEncoder, SingleSwapStrategyEncoder, SplitSwapStrategyEncoder,
|
||||
@@ -273,13 +273,20 @@ impl TychoExecutorEncoder {
|
||||
|
||||
let mut grouped_protocol_data: Vec<u8> = vec![];
|
||||
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 {
|
||||
receiver: receiver.clone(),
|
||||
exact_out: solution.exact_out,
|
||||
router_address: None,
|
||||
group_token_in: grouped_swap.token_in.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())?;
|
||||
grouped_protocol_data.extend(protocol_data);
|
||||
@@ -461,7 +468,7 @@ mod tests {
|
||||
Bytes::from_str("0x3ede3eca2a72b3aecc820e955b36f38437d01395").unwrap()
|
||||
);
|
||||
// single swap selector
|
||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07");
|
||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "5c4b639c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -486,7 +493,7 @@ mod tests {
|
||||
let transactions = transactions.unwrap();
|
||||
assert_eq!(transactions.len(), 1);
|
||||
// single swap selector
|
||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "20144a07");
|
||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "5c4b639c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -533,7 +540,7 @@ mod tests {
|
||||
assert_eq!(transactions.len(), 1);
|
||||
assert_eq!(transactions[0].value, eth_amount_in);
|
||||
// sequential swap selector
|
||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e8a980d7");
|
||||
assert_eq!(&hex::encode(transactions[0].clone().data)[..8], "e21dd0d3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1059,8 +1066,8 @@ mod tests {
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type
|
||||
"00",
|
||||
// transfer true
|
||||
"01",
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -1147,8 +1154,8 @@ mod tests {
|
||||
"6982508145454ce325ddbe47a25d4ec3d2311933",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type
|
||||
"00",
|
||||
// transfer type Transfer
|
||||
"01",
|
||||
// receiver
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2",
|
||||
// first pool intermediary token (ETH)
|
||||
|
||||
@@ -96,27 +96,6 @@ pub struct Transaction {
|
||||
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.
|
||||
///
|
||||
/// # Fields
|
||||
@@ -127,6 +106,7 @@ pub enum TransferType {
|
||||
/// solution does not require router address.
|
||||
/// * `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.
|
||||
/// * `transfer`: Type of transfer to be performed. See `TransferType` for more details.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EncodingContext {
|
||||
pub receiver: Bytes,
|
||||
@@ -137,6 +117,21 @@ pub struct EncodingContext {
|
||||
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)]
|
||||
pub struct Chain {
|
||||
pub id: u64,
|
||||
|
||||
Reference in New Issue
Block a user