feat(univ4): Refactor input and handle single swap case
Construct the uniswap v4 specific objects inside the executor The swap test in the executor alone doesn't work anymore because of the callback data prepended to the rest of he calldata --- don't change below this line --- ENG-4222 Took 4 hours 0 minutes Took 40 seconds
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "../../src/executors/UniswapV4Executor.sol";
|
||||
import "./UniswapV4Utils.sol";
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
import {console} from "forge-std/console.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
|
||||
contract UniswapV4ExecutorExposed is UniswapV4Executor {
|
||||
constructor(IPoolManager _poolManager) UniswapV4Executor(_poolManager) {}
|
||||
@@ -16,8 +17,11 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
|
||||
returns (
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
bool isExactInput,
|
||||
uint256 amount
|
||||
uint256 amountOutMin,
|
||||
bool zeroForOne,
|
||||
address callbackExecutor,
|
||||
bytes4 callbackSelector,
|
||||
UniswapV4Pool[] memory pools
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
@@ -40,39 +44,58 @@ contract UniswapV4ExecutorTest is Test, Constants {
|
||||
}
|
||||
|
||||
function testDecodeParams() public view {
|
||||
uint24 expectedPoolFee = 500;
|
||||
uint128 expectedAmount = 100;
|
||||
uint256 minAmountOut = 100;
|
||||
bool zeroForOne = true;
|
||||
uint24 pool1Fee = 500;
|
||||
int24 tickSpacing1 = 60;
|
||||
uint24 pool2Fee = 1000;
|
||||
int24 tickSpacing2 = -10;
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||
pools[0] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: USDT_ADDR,
|
||||
fee: pool1Fee,
|
||||
tickSpacing: tickSpacing1
|
||||
});
|
||||
pools[1] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: USDE_ADDR,
|
||||
fee: pool2Fee,
|
||||
tickSpacing: tickSpacing2
|
||||
});
|
||||
|
||||
bytes memory data = UniswapV4Utils.encodeExactInputSingle(
|
||||
USDE_ADDR, USDT_ADDR, expectedPoolFee, false, 1, expectedAmount
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
minAmountOut,
|
||||
zeroForOne,
|
||||
address(uniswapV4Exposed),
|
||||
SafeCallback.unlockCallback.selector,
|
||||
pools
|
||||
);
|
||||
|
||||
(address tokenIn, address tokenOut, bool isExactInput, uint256 amount) =
|
||||
uniswapV4Exposed.decodeData(data);
|
||||
(
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint256 amountOutMin,
|
||||
bool zeroForOneDecoded,
|
||||
address callbackExecutor,
|
||||
bytes4 callbackSelector,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
|
||||
) = uniswapV4Exposed.decodeData(data);
|
||||
|
||||
assertEq(tokenIn, USDE_ADDR);
|
||||
assertEq(tokenOut, USDT_ADDR);
|
||||
assertTrue(isExactInput);
|
||||
assertEq(amount, expectedAmount);
|
||||
}
|
||||
|
||||
function testSwap() public {
|
||||
uint256 amountIn = 100 ether;
|
||||
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);
|
||||
uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager);
|
||||
uint256 usdeBalanceBeforeSwapExecutor =
|
||||
USDE.balanceOf(address(uniswapV4Exposed));
|
||||
|
||||
bytes memory data = UniswapV4Utils.encodeExactInputSingle(
|
||||
USDE_ADDR, USDT_ADDR, 100, true, 1, uint128(amountIn)
|
||||
);
|
||||
|
||||
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
|
||||
assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn);
|
||||
assertEq(
|
||||
USDE.balanceOf(address(uniswapV4Exposed)),
|
||||
usdeBalanceBeforeSwapExecutor - amountIn
|
||||
);
|
||||
assertTrue(USDT.balanceOf(address(uniswapV4Exposed)) == amountOut);
|
||||
assertEq(amountOutMin, minAmountOut);
|
||||
assertEq(zeroForOneDecoded, zeroForOne);
|
||||
assertEq(callbackExecutor, address(uniswapV4Exposed));
|
||||
assertEq(callbackSelector, SafeCallback.unlockCallback.selector);
|
||||
assertEq(decodedPools.length, 2);
|
||||
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
|
||||
assertEq(decodedPools[0].fee, pool1Fee);
|
||||
assertEq(decodedPools[0].tickSpacing, tickSpacing1);
|
||||
assertEq(decodedPools[1].intermediaryToken, USDE_ADDR);
|
||||
assertEq(decodedPools[1].fee, pool2Fee);
|
||||
assertEq(decodedPools[1].tickSpacing, tickSpacing2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,40 +7,31 @@ library UniswapV4Utils {
|
||||
function encodeExactInputSingle(
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint24 fee,
|
||||
uint256 amountOutMin,
|
||||
bool zeroForOne,
|
||||
uint24 tickSpacing,
|
||||
uint128 amountIn
|
||||
address callbackExecutor,
|
||||
bytes4 callbackSelector,
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools
|
||||
) public pure returns (bytes memory) {
|
||||
PoolKey memory key = PoolKey({
|
||||
currency0: Currency.wrap(zeroForOne ? tokenIn : tokenOut),
|
||||
currency1: Currency.wrap(zeroForOne ? tokenOut : tokenIn),
|
||||
fee: fee,
|
||||
tickSpacing: int24(tickSpacing),
|
||||
hooks: IHooks(address(0))
|
||||
});
|
||||
bytes memory encodedPools;
|
||||
|
||||
bytes memory actions = abi.encodePacked(
|
||||
uint8(Actions.SWAP_EXACT_IN_SINGLE),
|
||||
uint8(Actions.SETTLE_ALL),
|
||||
uint8(Actions.TAKE_ALL)
|
||||
for (uint256 i = 0; i < pools.length; i++) {
|
||||
encodedPools = abi.encodePacked(
|
||||
encodedPools,
|
||||
pools[i].intermediaryToken,
|
||||
bytes3(pools[i].fee),
|
||||
pools[i].tickSpacing
|
||||
);
|
||||
}
|
||||
|
||||
return abi.encodePacked(
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
amountOutMin,
|
||||
zeroForOne,
|
||||
callbackExecutor,
|
||||
bytes4(callbackSelector),
|
||||
encodedPools
|
||||
);
|
||||
|
||||
bytes[] memory params = new bytes[](3);
|
||||
|
||||
params[0] = abi.encode(
|
||||
IV4Router.ExactInputSingleParams({
|
||||
poolKey: key,
|
||||
zeroForOne: zeroForOne,
|
||||
amountIn: amountIn,
|
||||
amountOutMinimum: 0,
|
||||
hookData: bytes("")
|
||||
})
|
||||
);
|
||||
|
||||
params[1] = abi.encode(key.currency0, amountIn);
|
||||
params[2] = abi.encode(key.currency1, 0);
|
||||
|
||||
return abi.encode(actions, params);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user