Merge pull request #281 from propeller-heads/dc/ENG-4804-tycho-encoder-send-sync

fix: Make TychoEncode Send + Sync
This commit is contained in:
dianacarvalho1
2025-10-17 09:22:44 +01:00
committed by GitHub
22 changed files with 173 additions and 145 deletions

View File

@@ -93,9 +93,7 @@ contract TychoRouter is
address indexed token, uint256 amount, address indexed receiver address indexed token, uint256 amount, address indexed receiver
); );
constructor(address _permit2, address weth) constructor(address _permit2, address weth) RestrictTransferFrom(_permit2) {
RestrictTransferFrom(_permit2)
{
if (_permit2 == address(0) || weth == address(0)) { if (_permit2 == address(0) || weth == address(0)) {
revert TychoRouter__AddressZero(); revert TychoRouter__AddressZero();
} }
@@ -808,6 +806,7 @@ contract TychoRouter is
/** /**
* @dev Gets balance of a token for a given address. Supports both native ETH and ERC20 tokens. * @dev Gets balance of a token for a given address. Supports both native ETH and ERC20 tokens.
*/ */
// forgefmt: disable-start
function _balanceOf(address token, address owner) function _balanceOf(address token, address owner)
internal internal
view view
@@ -815,7 +814,7 @@ contract TychoRouter is
{ {
return return
token == address(0) ? owner.balance : IERC20(token).balanceOf(owner); token == address(0) ? owner.balance : IERC20(token).balanceOf(owner);
} }// forgefmt: disable-end
/** /**
* @dev Verifies that the expected amount of output tokens was received by the receiver. * @dev Verifies that the expected amount of output tokens was received by the receiver.

View File

@@ -43,7 +43,12 @@ contract BalancerV3Executor is IExecutor, RestrictTransferFrom, ICallback {
calculatedAmount = abi.decode(abi.decode(result, (bytes)), (uint256)); calculatedAmount = abi.decode(abi.decode(result, (bytes)), (uint256));
} }
function verifyCallback(bytes calldata /*data*/ ) public view { function verifyCallback(
bytes calldata /*data*/
)
public
view
{
if (msg.sender != address(VAULT)) { if (msg.sender != address(VAULT)) {
revert BalancerV3Executor__SenderIsNotVault(msg.sender); revert BalancerV3Executor__SenderIsNotVault(msg.sender);
} }

View File

@@ -29,7 +29,9 @@ contract BebopExecutor is IExecutor, RestrictTransferFrom {
constructor(address _bebopSettlement, address _permit2) constructor(address _bebopSettlement, address _permit2)
RestrictTransferFrom(_permit2) RestrictTransferFrom(_permit2)
{ {
if (_bebopSettlement == address(0)) revert BebopExecutor__ZeroAddress(); if (_bebopSettlement == address(0)) {
revert BebopExecutor__ZeroAddress();
}
bebopSettlement = _bebopSettlement; bebopSettlement = _bebopSettlement;
} }

View File

@@ -55,7 +55,9 @@ contract CurveExecutor is IExecutor, RestrictTransferFrom {
payable payable
returns (uint256) returns (uint256)
{ {
if (data.length != 85) revert CurveExecutor__InvalidDataLength(); if (data.length != 85) {
revert CurveExecutor__InvalidDataLength();
}
( (
address tokenIn, address tokenIn,
@@ -91,13 +93,15 @@ contract CurveExecutor is IExecutor, RestrictTransferFrom {
// crypto or llamma // crypto or llamma
if (tokenIn == nativeToken || tokenOut == nativeToken) { if (tokenIn == nativeToken || tokenOut == nativeToken) {
// slither-disable-next-line arbitrary-send-eth // slither-disable-next-line arbitrary-send-eth
CryptoPoolETH(pool).exchange{value: ethAmount}( CryptoPoolETH(pool)
uint256(int256(i)), uint256(int256(j)), amountIn, 0, true .exchange{
); value: ethAmount
}(uint256(int256(i)), uint256(int256(j)), amountIn, 0, true);
} else { } else {
CryptoPool(pool).exchange( CryptoPool(pool)
uint256(int256(i)), uint256(int256(j)), amountIn, 0 .exchange(
); uint256(int256(i)), uint256(int256(j)), amountIn, 0
);
} }
} }
@@ -149,11 +153,7 @@ contract CurveExecutor is IExecutor, RestrictTransferFrom {
require(msg.sender.code.length != 0); require(msg.sender.code.length != 0);
} }
function _balanceOf(address token) function _balanceOf(address token) internal view returns (uint256 balance) {
internal
view
returns (uint256 balance)
{
balance = token == nativeToken balance = token == nativeToken
? address(this).balance ? address(this).balance
: IERC20(token).balanceOf(address(this)); : IERC20(token).balanceOf(address(this));

View File

@@ -102,15 +102,18 @@ contract EkuboExecutor is
} }
} }
function payCallback(uint256, address /*token*/ ) external coreOnly { function payCallback(
uint256,
address /*token*/
)
external
coreOnly
{
// Without selector and locker id // Without selector and locker id
_payCallback(msg.data[36:]); _payCallback(msg.data[36:]);
} }
function _lock(bytes memory data) function _lock(bytes memory data) internal returns (uint128 swappedAmount) {
internal
returns (uint128 swappedAmount)
{
address target = address(core); address target = address(core);
// slither-disable-next-line assembly // slither-disable-next-line assembly

View File

@@ -67,9 +67,8 @@ contract HashflowExecutor is IExecutor, RestrictTransferFrom {
if (approvalNeeded && quote.baseToken != NATIVE_TOKEN) { if (approvalNeeded && quote.baseToken != NATIVE_TOKEN) {
// slither-disable-next-line unused-return // slither-disable-next-line unused-return
IERC20(quote.baseToken).forceApprove( IERC20(quote.baseToken)
hashflowRouter, type(uint256).max .forceApprove(hashflowRouter, type(uint256).max);
);
} }
uint256 ethValue = 0; uint256 ethValue = 0;

View File

@@ -42,13 +42,13 @@ contract MaverickV2Executor is IExecutor, RestrictTransferFrom {
bool isTokenAIn = pool.tokenA() == tokenIn; bool isTokenAIn = pool.tokenA() == tokenIn;
int32 tickLimit = isTokenAIn ? type(int32).max : type(int32).min; int32 tickLimit = isTokenAIn ? type(int32).max : type(int32).min;
IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool IMaverickV2Pool.SwapParams memory swapParams =
.SwapParams({ IMaverickV2Pool.SwapParams({
amount: givenAmount, amount: givenAmount,
tokenAIn: isTokenAIn, tokenAIn: isTokenAIn,
exactOutput: false, exactOutput: false,
tickLimit: tickLimit tickLimit: tickLimit
}); });
_transfer(target, transferType, address(tokenIn), givenAmount); _transfer(target, transferType, address(tokenIn), givenAmount);

View File

@@ -121,7 +121,9 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom {
int256, /* amount0Delta */ int256, /* amount0Delta */
int256, /* amount1Delta */ int256, /* amount1Delta */
bytes calldata /* data */ bytes calldata /* data */
) external { )
external
{
handleCallback(msg.data); handleCallback(msg.data);
} }

View File

@@ -11,19 +11,23 @@ import {
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol"; import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol";
import { import {
Currency, CurrencyLibrary Currency,
CurrencyLibrary
} from "@uniswap/v4-core/src/types/Currency.sol"; } from "@uniswap/v4-core/src/types/Currency.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol"; import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
import {IUnlockCallback} from import {
"@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol"; IUnlockCallback
import {SafeCast as V4SafeCast} from } from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol";
"@uniswap/v4-core/src/libraries/SafeCast.sol"; import {
import {TransientStateLibrary} from SafeCast as V4SafeCast
"@uniswap/v4-core/src/libraries/TransientStateLibrary.sol"; } from "@uniswap/v4-core/src/libraries/SafeCast.sol";
import {
TransientStateLibrary
} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
import "../RestrictTransferFrom.sol"; import "../RestrictTransferFrom.sol";
import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/Address.sol";
import "../../lib/bytes/LibPrefixLengthEncodedByteArray.sol"; import "../../lib/bytes/LibPrefixLengthEncodedByteArray.sol";
@@ -115,7 +119,9 @@ contract UniswapV4Executor is
PathKey[] memory path = new PathKey[](pools.length); PathKey[] memory path = new PathKey[](pools.length);
for (uint256 i = 0; i < pools.length; i++) { for (uint256 i = 0; i < pools.length; i++) {
path[i] = PathKey({ path[i] = PathKey({
intermediateCurrency: Currency.wrap(pools[i].intermediaryToken), intermediateCurrency: Currency.wrap(
pools[i].intermediaryToken
),
fee: pools[i].fee, fee: pools[i].fee,
tickSpacing: pools[i].tickSpacing, tickSpacing: pools[i].tickSpacing,
hooks: IHooks(pools[i].hook), hooks: IHooks(pools[i].hook),
@@ -305,8 +311,8 @@ contract UniswapV4Executor is
Currency currencyIn = zeroForOne ? poolKey.currency0 : poolKey.currency1; Currency currencyIn = zeroForOne ? poolKey.currency0 : poolKey.currency1;
_settle(currencyIn, amountIn, transferType); _settle(currencyIn, amountIn, transferType);
uint128 amountOut = _swap( uint128 amountOut = _swap(
poolKey, zeroForOne, -int256(uint256(amountIn)), hookData poolKey, zeroForOne, -int256(uint256(amountIn)), hookData
).toUint128(); ).toUint128();
Currency currencyOut = Currency currencyOut =
zeroForOne ? poolKey.currency1 : poolKey.currency0; zeroForOne ? poolKey.currency1 : poolKey.currency0;
@@ -343,11 +349,11 @@ contract UniswapV4Executor is
pathKey.getPoolAndSwapDirection(swapCurrencyIn); pathKey.getPoolAndSwapDirection(swapCurrencyIn);
// The output delta will always be positive, except for when interacting with certain hook pools // The output delta will always be positive, except for when interacting with certain hook pools
amountOut = _swap( amountOut = _swap(
poolKey, poolKey,
zeroForOne, zeroForOne,
-int256(uint256(swapAmountIn)), -int256(uint256(swapAmountIn)),
pathKey.hookData pathKey.hookData
).toUint128(); ).toUint128();
swapAmountIn = amountOut; swapAmountIn = amountOut;
swapCurrencyIn = pathKey.intermediateCurrency; swapCurrencyIn = pathKey.intermediateCurrency;

View File

@@ -37,7 +37,9 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
address _reactor, address _reactor,
address _native_address address _native_address
) { ) {
if (_tychoRouter == address(0)) revert UniswapXFiller__AddressZero(); if (_tychoRouter == address(0)) {
revert UniswapXFiller__AddressZero();
}
if (_reactor == address(0)) revert UniswapXFiller__AddressZero(); if (_reactor == address(0)) revert UniswapXFiller__AddressZero();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
@@ -73,9 +75,8 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
// The TychoRouter will take the input tokens from the filler // The TychoRouter will take the input tokens from the filler
if (tokenInApprovalNeeded) { if (tokenInApprovalNeeded) {
// Native ETH input is not supported by UniswapX // Native ETH input is not supported by UniswapX
IERC20(order.input.token).forceApprove( IERC20(order.input.token)
tychoRouter, type(uint256).max .forceApprove(tychoRouter, type(uint256).max);
);
} }
// slither-disable-next-line low-level-calls // slither-disable-next-line low-level-calls
@@ -125,7 +126,9 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
external external
onlyRole(DEFAULT_ADMIN_ROLE) onlyRole(DEFAULT_ADMIN_ROLE)
{ {
if (receiver == address(0)) revert UniswapXFiller__AddressZero(); if (receiver == address(0)) {
revert UniswapXFiller__AddressZero();
}
for (uint256 i = 0; i < tokens.length; i++) { for (uint256 i = 0; i < tokens.length; i++) {
// slither-disable-next-line calls-loop // slither-disable-next-line calls-loop
@@ -144,7 +147,9 @@ contract UniswapXFiller is AccessControl, IReactorCallback {
external external
onlyRole(DEFAULT_ADMIN_ROLE) onlyRole(DEFAULT_ADMIN_ROLE)
{ {
if (receiver == address(0)) revert UniswapXFiller__AddressZero(); if (receiver == address(0)) {
revert UniswapXFiller__AddressZero();
}
uint256 amount = address(this).balance; uint256 amount = address(this).balance;
if (amount > 0) { if (amount > 0) {

View File

@@ -108,7 +108,8 @@ contract Constants is Test, BaseConstants {
address LDO_POOL = 0x9409280DC1e6D33AB7A8C6EC03e5763FB61772B5; address LDO_POOL = 0x9409280DC1e6D33AB7A8C6EC03e5763FB61772B5;
address CRV_POOL = 0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511; address CRV_POOL = 0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511;
address AAVE_POOL = 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE; address AAVE_POOL = 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE;
address FRAXPYUSD_POOL = address(0xA5588F7cdf560811710A2D82D3C9c99769DB1Dcb); address FRAXPYUSD_POOL =
address(0xA5588F7cdf560811710A2D82D3C9c99769DB1Dcb);
address TRICRYPTO2_POOL = 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46; address TRICRYPTO2_POOL = 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46;
address SUSD_POOL = 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD; address SUSD_POOL = 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD;
address FRAX_USDC_POOL = 0xDcEF968d416a41Cdac0ED8702fAC8128A64241A2; address FRAX_USDC_POOL = 0xDcEF968d416a41Cdac0ED8702fAC8128A64241A2;

View File

@@ -176,17 +176,17 @@ contract GasTest is Commands, Test, Constants {
returns (IAllowanceTransfer.PermitSingle memory, bytes memory) returns (IAllowanceTransfer.PermitSingle memory, bytes memory)
{ {
IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in); IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in);
IAllowanceTransfer.PermitSingle memory permitSingle = IAllowanceTransfer IAllowanceTransfer.PermitSingle memory permitSingle =
.PermitSingle({ IAllowanceTransfer.PermitSingle({
details: IAllowanceTransfer.PermitDetails({ details: IAllowanceTransfer.PermitDetails({
token: tokenIn, token: tokenIn,
amount: uint160(amount_in), amount: uint160(amount_in),
expiration: uint48(block.timestamp + 1 days), expiration: uint48(block.timestamp + 1 days),
nonce: 0 nonce: 0
}), }),
spender: UNIVERSAL_ROUTER, spender: UNIVERSAL_ROUTER,
sigDeadline: block.timestamp + 1 days sigDeadline: block.timestamp + 1 days
}); });
bytes memory signature = signPermit2(permitSingle, ALICE_PK); bytes memory signature = signPermit2(permitSingle, ALICE_PK);
return (permitSingle, signature); return (permitSingle, signature);
@@ -223,8 +223,9 @@ contract GasTest is Commands, Test, Constants {
) )
); );
bytes32 digest = bytes32 digest = keccak256(
keccak256(abi.encodePacked("\x19\x01", domainSeparator, permitHash)); abi.encodePacked("\x19\x01", domainSeparator, permitHash)
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
return abi.encodePacked(r, s, v); return abi.encodePacked(r, s, v);

View File

@@ -2,8 +2,9 @@
pragma solidity ^0.8.26; pragma solidity ^0.8.26;
import {Test} from "forge-std/Test.sol"; import {Test} from "forge-std/Test.sol";
import {LibPrefixLengthEncodedByteArray} from import {
"../lib/bytes/LibPrefixLengthEncodedByteArray.sol"; LibPrefixLengthEncodedByteArray
} from "../lib/bytes/LibPrefixLengthEncodedByteArray.sol";
contract LibPrefixLengthEncodedByteArrayTest is Test { contract LibPrefixLengthEncodedByteArrayTest is Test {
using LibPrefixLengthEncodedByteArray for bytes; using LibPrefixLengthEncodedByteArray for bytes;

View File

@@ -25,17 +25,17 @@ contract Permit2TestHelper is Constants {
uint256 amount_in uint256 amount_in
) internal returns (IAllowanceTransfer.PermitSingle memory, bytes memory) { ) internal returns (IAllowanceTransfer.PermitSingle memory, bytes memory) {
IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in); IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in);
IAllowanceTransfer.PermitSingle memory permitSingle = IAllowanceTransfer IAllowanceTransfer.PermitSingle memory permitSingle =
.PermitSingle({ IAllowanceTransfer.PermitSingle({
details: IAllowanceTransfer.PermitDetails({ details: IAllowanceTransfer.PermitDetails({
token: tokenIn, token: tokenIn,
amount: uint160(amount_in), amount: uint160(amount_in),
expiration: uint48(block.timestamp + 1 days), expiration: uint48(block.timestamp + 1 days),
nonce: 0 nonce: 0
}), }),
spender: spender, spender: spender,
sigDeadline: block.timestamp + 1 days sigDeadline: block.timestamp + 1 days
}); });
bytes memory signature = signPermit2(permitSingle, ALICE_PK); bytes memory signature = signPermit2(permitSingle, ALICE_PK);
return (permitSingle, signature); return (permitSingle, signature);
@@ -78,8 +78,9 @@ contract Permit2TestHelper is Constants {
) )
); );
bytes32 digest = bytes32 digest = keccak256(
keccak256(abi.encodePacked("\x19\x01", domainSeparator, permitHash)); abi.encodePacked("\x19\x01", domainSeparator, permitHash)
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
return abi.encodePacked(r, s, v); return abi.encodePacked(r, s, v);

View File

@@ -183,16 +183,13 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE); vm.startPrank(ALICE);
IAllowanceTransfer.PermitSingle memory emptyPermitSingle = IAllowanceTransfer.PermitSingle memory emptyPermitSingle =
IAllowanceTransfer.PermitSingle({ IAllowanceTransfer.PermitSingle({
details: IAllowanceTransfer.PermitDetails({ details: IAllowanceTransfer.PermitDetails({
token: address(0), token: address(0), amount: 0, expiration: 0, nonce: 0
amount: 0, }),
expiration: 0, spender: address(0),
nonce: 0 sigDeadline: 0
}), });
spender: address(0),
sigDeadline: 0
});
bytes[] memory swaps = new bytes[](2); bytes[] memory swaps = new bytes[](2);
// WETH -> DAI // WETH -> DAI
@@ -219,7 +216,9 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
) )
); );
uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}( uint256 amountOut = tychoRouter.sequentialSwapPermit2{
value: amountIn
}(
amountIn, amountIn,
address(0), address(0),
USDC_ADDR, USDC_ADDR,
@@ -502,8 +501,9 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
// Approve permit2 // Approve permit2
vm.startPrank(ALICE); vm.startPrank(ALICE);
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max); IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
bytes memory callData = bytes memory callData = loadCallDataFromFile(
loadCallDataFromFile("test_sequential_swap_strategy_encoder_unwrap"); "test_sequential_swap_strategy_encoder_unwrap"
);
(bool success,) = tychoRouterAddr.call(callData); (bool success,) = tychoRouterAddr.call(callData);
vm.stopPrank(); vm.stopPrank();

View File

@@ -203,16 +203,13 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE); vm.startPrank(ALICE);
IAllowanceTransfer.PermitSingle memory emptyPermitSingle = IAllowanceTransfer.PermitSingle memory emptyPermitSingle =
IAllowanceTransfer.PermitSingle({ IAllowanceTransfer.PermitSingle({
details: IAllowanceTransfer.PermitDetails({ details: IAllowanceTransfer.PermitDetails({
token: address(0), token: address(0), amount: 0, expiration: 0, nonce: 0
amount: 0, }),
expiration: 0, spender: address(0),
nonce: 0 sigDeadline: 0
}), });
spender: address(0),
sigDeadline: 0
});
bytes memory protocolData = encodeUniswapV2Swap( bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_ADDR,
@@ -225,7 +222,9 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
bytes memory swap = bytes memory swap =
encodeSingleSwap(address(usv2Executor), protocolData); encodeSingleSwap(address(usv2Executor), protocolData);
uint256 amountOut = tychoRouter.singleSwapPermit2{value: amountIn}( uint256 amountOut = tychoRouter.singleSwapPermit2{
value: amountIn
}(
amountIn, amountIn,
address(0), address(0),
DAI_ADDR, DAI_ADDR,
@@ -338,8 +337,9 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE); vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max); IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
bytes memory callData = bytes memory callData = loadCallDataFromFile(
loadCallDataFromFile("test_single_swap_strategy_encoder_no_permit2"); "test_single_swap_strategy_encoder_no_permit2"
);
(bool success,) = tychoRouterAddr.call(callData); (bool success,) = tychoRouterAddr.call(callData);
vm.stopPrank(); vm.stopPrank();

View File

@@ -250,16 +250,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE); vm.startPrank(ALICE);
IAllowanceTransfer.PermitSingle memory emptyPermitSingle = IAllowanceTransfer.PermitSingle memory emptyPermitSingle =
IAllowanceTransfer.PermitSingle({ IAllowanceTransfer.PermitSingle({
details: IAllowanceTransfer.PermitDetails({ details: IAllowanceTransfer.PermitDetails({
token: address(0), token: address(0), amount: 0, expiration: 0, nonce: 0
amount: 0, }),
expiration: 0, spender: address(0),
nonce: 0 sigDeadline: 0
}), });
spender: address(0),
sigDeadline: 0
});
bytes memory protocolData = encodeUniswapV2Swap( bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_ADDR,
WETH_DAI_POOL, WETH_DAI_POOL,
@@ -274,7 +271,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
bytes[] memory swaps = new bytes[](1); bytes[] memory swaps = new bytes[](1);
swaps[0] = swap; swaps[0] = swap;
uint256 amountOut = tychoRouter.splitSwapPermit2{value: amountIn}( uint256 amountOut = tychoRouter.splitSwapPermit2{
value: amountIn
}(
amountIn, amountIn,
address(0), address(0),
DAI_ADDR, DAI_ADDR,

View File

@@ -2,8 +2,9 @@
pragma solidity ^0.8.26; pragma solidity ^0.8.26;
import "../TychoRouterTestSetup.sol"; import "../TychoRouterTestSetup.sol";
import {BalancerV3Executor__InvalidDataLength} from import {
"../../src/executors/BalancerV3Executor.sol"; BalancerV3Executor__InvalidDataLength
} from "../../src/executors/BalancerV3Executor.sol";
contract BalancerV3ExecutorExposed is BalancerV3Executor { contract BalancerV3ExecutorExposed is BalancerV3Executor {
constructor(address _permit2) BalancerV3Executor(_permit2) {} constructor(address _permit2) BalancerV3Executor(_permit2) {}
@@ -31,7 +32,8 @@ contract BalancerV3ExecutorTest is Constants, TestUtils {
address WETH_osETH_pool = address WETH_osETH_pool =
address(0x57c23c58B1D8C3292c15BEcF07c62C5c52457A42); address(0x57c23c58B1D8C3292c15BEcF07c62C5c52457A42);
address osETH_ADDR = address(0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38); address osETH_ADDR = address(0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38);
address waEthWETH_ADDR = address(0x0bfc9d54Fc184518A81162F8fB99c2eACa081202); address waEthWETH_ADDR =
address(0x0bfc9d54Fc184518A81162F8fB99c2eACa081202);
function setUp() public { function setUp() public {
uint256 forkBlock = 22625131; uint256 forkBlock = 22625131;

View File

@@ -7,8 +7,9 @@ import "@src/executors/BebopExecutor.sol";
import {Constants} from "../Constants.sol"; import {Constants} from "../Constants.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Permit2TestHelper} from "../Permit2TestHelper.sol"; import {Permit2TestHelper} from "../Permit2TestHelper.sol";
import {SafeERC20} from import {
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; SafeERC20
} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract BebopExecutorExposed is BebopExecutor { contract BebopExecutorExposed is BebopExecutor {
constructor(address _bebopSettlement, address _permit2) constructor(address _bebopSettlement, address _permit2)
@@ -114,7 +115,7 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
address tokenIn = WETH_ADDR; address tokenIn = WETH_ADDR;
address tokenOut = WBTC_ADDR; address tokenOut = WBTC_ADDR;
RestrictTransferFrom.TransferType transferType = RestrictTransferFrom.TransferType transferType =
RestrictTransferFrom.TransferType.None; RestrictTransferFrom.TransferType.None;
uint8 partialFillOffset = 12; uint8 partialFillOffset = 12;
uint256 amountIn = 1000000000000000000; uint256 amountIn = 1000000000000000000;
bool approvalNeeded = true; bool approvalNeeded = true;
@@ -165,7 +166,7 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
address tokenIn = address(0); address tokenIn = address(0);
address tokenOut = WBTC_ADDR; address tokenOut = WBTC_ADDR;
RestrictTransferFrom.TransferType transferType = RestrictTransferFrom.TransferType transferType =
RestrictTransferFrom.TransferType.None; RestrictTransferFrom.TransferType.None;
uint8 partialFillOffset = 12; uint8 partialFillOffset = 12;
uint256 amountIn = 1000000000000000000; uint256 amountIn = 1000000000000000000;
bool approvalNeeded = false; bool approvalNeeded = false;
@@ -212,7 +213,7 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
address tokenIn = WETH_ADDR; address tokenIn = WETH_ADDR;
address tokenOut = WBTC_ADDR; address tokenOut = WBTC_ADDR;
RestrictTransferFrom.TransferType transferType = RestrictTransferFrom.TransferType transferType =
RestrictTransferFrom.TransferType.None; RestrictTransferFrom.TransferType.None;
uint8 partialFillOffset = 12; uint8 partialFillOffset = 12;
// filling only half of the quote // filling only half of the quote
uint256 amountIn = 1000000000000000000 / 2; uint256 amountIn = 1000000000000000000 / 2;
@@ -264,7 +265,7 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
address tokenIn = USDC_ADDR; address tokenIn = USDC_ADDR;
address tokenOut = ONDO_ADDR; address tokenOut = ONDO_ADDR;
RestrictTransferFrom.TransferType transferType = RestrictTransferFrom.TransferType transferType =
RestrictTransferFrom.TransferType.None; RestrictTransferFrom.TransferType.None;
uint8 partialFillOffset = 2; uint8 partialFillOffset = 2;
// filling only half of the quote // filling only half of the quote
uint256 amountIn = 20000000000; uint256 amountIn = 20000000000;
@@ -318,7 +319,7 @@ contract BebopExecutorTest is Constants, Permit2TestHelper, TestUtils {
address tokenIn = USDC_ADDR; address tokenIn = USDC_ADDR;
address tokenOut = ONDO_ADDR; address tokenOut = ONDO_ADDR;
RestrictTransferFrom.TransferType transferType = RestrictTransferFrom.TransferType transferType =
RestrictTransferFrom.TransferType.None; RestrictTransferFrom.TransferType.None;
uint8 partialFillOffset = 2; uint8 partialFillOffset = 2;
// filling only half of the quote // filling only half of the quote
uint256 amountIn = 20000000000 / 2; uint256 amountIn = 20000000000 / 2;

View File

@@ -31,11 +31,9 @@ contract HashflowUtils is Test {
); );
} }
function encodeRfqtQuoteWithDefaults(IHashflowRouter.RFQTQuote memory quote) function encodeRfqtQuoteWithDefaults(
internal IHashflowRouter.RFQTQuote memory quote
pure ) internal pure returns (bytes memory) {
returns (bytes memory)
{
return return
encodeRfqtQuote(quote, true, RestrictTransferFrom.TransferType.None); encodeRfqtQuote(quote, true, RestrictTransferFrom.TransferType.None);
} }
@@ -183,7 +181,9 @@ contract HashflowExecutorECR20Test is Constants, TestUtils, HashflowUtils {
{ {
return IHashflowRouter.RFQTQuote({ return IHashflowRouter.RFQTQuote({
pool: address(0x5d8853028fbF6a2da43c7A828cc5f691E9456B44), pool: address(0x5d8853028fbF6a2da43c7A828cc5f691E9456B44),
externalAccount: address(0x9bA0CF1588E1DFA905eC948F7FE5104dD40EDa31), externalAccount: address(
0x9bA0CF1588E1DFA905eC948F7FE5104dD40EDa31
),
trader: address(ALICE), trader: address(ALICE),
effectiveTrader: address(ALICE), effectiveTrader: address(ALICE),
baseToken: WETH_ADDR, baseToken: WETH_ADDR,
@@ -243,7 +243,9 @@ contract HashflowExecutorNativeTest is Constants, HashflowUtils {
{ {
return IHashflowRouter.RFQTQuote({ return IHashflowRouter.RFQTQuote({
pool: address(0x713DC4Df480235dBe2fB766E7120Cbd4041Dcb58), pool: address(0x713DC4Df480235dBe2fB766E7120Cbd4041Dcb58),
externalAccount: address(0x111BB8c3542F2B92fb41B8d913c01D3788431111), externalAccount: address(
0x111BB8c3542F2B92fb41B8d913c01D3788431111
),
trader: address(ALICE), trader: address(ALICE),
effectiveTrader: address(ALICE), effectiveTrader: address(ALICE),
baseToken: address(0x0000000000000000000000000000000000000000), baseToken: address(0x0000000000000000000000000000000000000000),

View File

@@ -92,9 +92,7 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup {
additionalValidationData: "" additionalValidationData: ""
}), }),
input: InputToken({ input: InputToken({
token: address(WETH_ADDR), token: address(WETH_ADDR), amount: amountIn, maxAmount: amountIn
amount: amountIn,
maxAmount: amountIn
}), }),
outputs: outputs, outputs: outputs,
sig: "", sig: "",
@@ -132,9 +130,10 @@ contract UniswapXFillerTest is Test, TychoRouterTestSetup {
vm.startPrank(address(0xD213e6F6dCB2DBaC03FA28b893F6dA1BD822e852)); vm.startPrank(address(0xD213e6F6dCB2DBaC03FA28b893F6dA1BD822e852));
// Approve Permit2 // Approve Permit2
IERC20(DAI_ADDR).approve( IERC20(DAI_ADDR)
address(0x000000000022D473030F116dDEE9F6B43aC78BA3), amountIn .approve(
); address(0x000000000022D473030F116dDEE9F6B43aC78BA3), amountIn
);
vm.stopPrank(); vm.stopPrank();
// Tx 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d // Tx 0x005d7b150017ba1b59d2f99395ccae7bda9b739938ade4e509817e32760aaf9d

View File

@@ -25,7 +25,7 @@ use crate::encoding::{
/// Tycho is only responsible for generating the internal swap plan. **The user must encode the /// Tycho is only responsible for generating the internal swap plan. **The user must encode the
/// outer function call arguments themselves** and verify that they enforce correct and secure /// outer function call arguments themselves** and verify that they enforce correct and secure
/// behavior. /// behavior.
pub trait TychoEncoder { pub trait TychoEncoder: Send + Sync {
/// Encodes a list of [`Solution`]s into [`EncodedSolution`]s, which include the function /// Encodes a list of [`Solution`]s into [`EncodedSolution`]s, which include the function
/// signature and internal swap call data. /// signature and internal swap call data.
/// ///