fix: USV3 encoding/decoding after rebase

- Also do some renamings and comment improvements:
transfer method -> type
- Remove integration tests since we no longer support direct calls to USV3 executor, even for testing.
This commit is contained in:
TAMARA LIPOWSKI
2025-04-14 11:23:08 -04:00
committed by Diana Carvalho
parent 7e98145ad7
commit f3c4128eda
5 changed files with 29 additions and 107 deletions

View File

@@ -5,7 +5,7 @@ import "@interfaces/IExecutor.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
error TokenTransfer__InvalidPermit2();
error TokenTransfer__AddressZero();
contract TokenTransfer {
using SafeERC20 for IERC20;
@@ -25,7 +25,7 @@ contract TokenTransfer {
constructor(address _permit2) {
if (_permit2 == address(0)) {
revert TokenTransfer__InvalidPermit2();
revert TokenTransfer__AddressZero();
}
permit2 = IAllowanceTransfer(_permit2);
}

View File

@@ -11,6 +11,7 @@ error UniswapV3Executor__InvalidDataLength();
error UniswapV3Executor__InvalidFactory();
error UniswapV3Executor__InvalidTarget();
error UniswapV3Executor__InvalidInitCode();
error UniswapV3Executor__InvalidTransferType(uint8 transferType);
contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
using SafeERC20 for IERC20;
@@ -97,12 +98,13 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
address tokenIn = address(bytes20(msgData[132:152]));
require(
uint8(msgData[171]) <= uint8(TransferType.NONE),
"InvalidTransferMethod"
);
TransferType transferType = TransferType(uint8(msgData[171]));
address sender = address(bytes20(msgData[172:192]));
// 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:]);
@@ -168,7 +170,7 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
TransferType transferType
) internal view returns (bytes memory) {
return abi.encodePacked(
tokenIn, tokenOut, fee, uint8(transferType), msg.sender, self
tokenIn, tokenOut, fee, uint8(transferType), msg.sender
);
}

View File

@@ -22,7 +22,7 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
address receiver,
address target,
bool zeroForOne,
TransferType method
TransferType transferType
)
{
return _decodeData(data);
@@ -81,7 +81,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
address receiver,
address target,
bool zeroForOne,
TokenTransfer.TransferType method
TokenTransfer.TransferType transferType
) = uniswapV3Exposed.decodeData(data);
assertEq(tokenIn, WETH_ADDR);
@@ -90,7 +90,9 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
assertEq(receiver, address(2));
assertEq(target, address(3));
assertEq(zeroForOne, false);
assertEq(uint8(method), uint8(TokenTransfer.TransferType.TRANSFER));
assertEq(
uint8(transferType), uint8(TokenTransfer.TransferType.TRANSFER)
);
}
function testDecodeParamsInvalidDataLength() public {
@@ -142,88 +144,6 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
assertEq(finalPoolReserve - initialPoolReserve, amountOwed);
}
function testSwapWithTransfer() public {
uint256 amountIn = 10 ** 18;
deal(WETH_ADDR, address(uniswapV3Exposed), amountIn);
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
bool zeroForOne = false;
bytes memory data = encodeUniswapV3Swap(
WETH_ADDR,
DAI_ADDR,
address(this),
DAI_WETH_USV3,
zeroForOne,
TokenTransfer.TransferType.TRANSFER
);
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
assertGe(amountOut, expAmountOut);
assertEq(IERC20(WETH_ADDR).balanceOf(address(uniswapV3Exposed)), 0);
assertGe(IERC20(DAI_ADDR).balanceOf(address(this)), expAmountOut);
}
function testSwapWithTransferFrom() public {
uint256 amountIn = 10 ** 18;
deal(WETH_ADDR, address(this), amountIn);
IERC20(WETH_ADDR).approve(address(uniswapV3Exposed), amountIn);
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
bool zeroForOne = false;
bytes memory data = encodeUniswapV3Swap(
WETH_ADDR,
DAI_ADDR,
address(this),
DAI_WETH_USV3,
zeroForOne,
TokenTransfer.TransferType.TRANSFERFROM
);
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
assertGe(amountOut, expAmountOut);
assertEq(IERC20(WETH_ADDR).balanceOf(address(uniswapV3Exposed)), 0);
assertGe(IERC20(DAI_ADDR).balanceOf(address(this)), expAmountOut);
}
function testSwapWithPermit2TransferFrom() public {
uint256 amountIn = 10 ** 18;
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
bool zeroForOne = false;
bytes memory data = encodeUniswapV3Swap(
WETH_ADDR,
DAI_ADDR,
address(this),
DAI_WETH_USV3,
zeroForOne,
TokenTransfer.TransferType.TRANSFERPERMIT2
);
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
(
IAllowanceTransfer.PermitSingle memory permitSingle,
bytes memory signature
) = handlePermit2Approval(
WETH_ADDR, address(uniswapV3Exposed), amountIn
);
// Assume the permit2.approve method will be called from the TychoRouter
// Replicate this scenario in this test.
permit2.permit(ALICE, permitSingle, signature);
uint256 amountOut = uniswapV3Exposed.swap(amountIn, data);
vm.stopPrank();
assertGe(amountOut, expAmountOut);
assertEq(IERC20(WETH_ADDR).balanceOf(address(uniswapV3Exposed)), 0);
assertGe(IERC20(DAI_ADDR).balanceOf(address(this)), expAmountOut);
}
function testSwapFailureInvalidTarget() public {
uint256 amountIn = 10 ** 18;
deal(WETH_ADDR, address(uniswapV3Exposed), amountIn);