Skip to content

Commit

Permalink
more QuoteExactInput tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ConjunctiveNormalForm committed Nov 15, 2023
1 parent a69c782 commit 4f9519f
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 92 deletions.
24 changes: 0 additions & 24 deletions contracts/lens/Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -236,30 +236,6 @@ contract Quoter is IQuoter {
}
}

/*
struct PathKey {
Currency intermediateCurrency;
uint24 fee;
int24 tickSpacing;
IHooks hooks;
bytes hookData;
}
struct ExactInputSingleParams {
PoolKey poolKey;
bool zeroForOne;
address recipient;
uint128 amountIn;
uint160 sqrtPriceLimitX96;
bytes hookData;
}
struct IPoolManager.SwapParams {
bool zeroForOne;
int256 amountSpecified;
uint160 sqrtPriceLimitX96;
}
*/
function _quoteExactInputSingle(ExactInputSingleParams memory params)
private
returns (BalanceDelta deltas, uint160 sqrtPriceX96After, int24 tickAfter)
Expand Down
210 changes: 142 additions & 68 deletions test/Quoter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {SafeCast} from "@uniswap/v4-core/contracts/libraries/SafeCast.sol";
import {Deployers} from "@uniswap/v4-core/test/foundry-tests/utils/Deployers.sol";
import {IHooks} from "@uniswap/v4-core/contracts/interfaces/IHooks.sol";
import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol";
import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
import {PoolManager} from "@uniswap/v4-core/contracts/PoolManager.sol";
import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
Expand All @@ -21,6 +22,7 @@ import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol";

contract QuoterTest is Test, Deployers {
using SafeCast for *;
using PoolIdLibrary for PoolKey;

// Min tick for full range with tick spacing of 60
int24 internal constant MIN_TICK = -887220;
Expand All @@ -47,9 +49,12 @@ contract QuoterTest is Test, Deployers {
quoter = new Quoter(address(manager));
positionManager = new PoolModifyPositionTest(manager);

token0 = new MockERC20("Test0", "0", 18);
// salts are chose so that address(token0) < address(token2) && address(1) < address(token2)
bytes32 salt1 = "ffff";
bytes32 salt2 = "gm";
token0 = new MockERC20{salt: salt1}("Test0", "0", 18);
token0.mint(address(this), 2 ** 128);
token1 = new MockERC20("Test1", "1", 18);
token1 = new MockERC20{salt: salt2}("Test1", "1", 18);
token1.mint(address(this), 2 ** 128);
token2 = new MockERC20("Test2", "2", 18);
token2.mint(address(this), 2 ** 128);
Expand All @@ -62,27 +67,6 @@ contract QuoterTest is Test, Deployers {
setupPoolMultiplePositions(key02);
}

function testQuoter_quoteExactInputSingle_zeroForOne_SinglePosition() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 992054607780215625;

ExactInputSingleParams memory params = ExactInputSingleParams({
poolKey: key01,
zeroForOne: true,
recipient: address(this),
amountIn: uint128(amountIn),
sqrtPriceLimitX96: 0,
hookData: ZERO_BYTES
});

(int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed) =
quoter.quoteExactInputSingle(params);

assertEq(uint128(-deltaAmounts[1]), expectedAmountOut);
assertEq(sqrtPriceX96After, 78835169195823159145205102899);
assertEq(initializedTicksCrossed, 0);
}

function testQuoter_quoteExactInputSingle_ZeroForOne_MultiplePositions() public {
uint256 amountIn = 10000;
uint256 expectedAmountOut = 9871;
Expand Down Expand Up @@ -127,48 +111,6 @@ contract QuoterTest is Test, Deployers {
assertEq(initializedTicksCrossed, 2);
}

function testQuoter_quoteExactInput_1hop_SinglePosition() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 992054607780215625;

tokenPath.push(token0);
tokenPath.push(token1);

ExactInputParams memory params = getExactInputParams(tokenPath, amountIn);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

assertEq(uint128(-deltaAmounts[1]), expectedAmountOut);
assertEq(sqrtPriceX96AfterList[0], 78835169195823159145205102899);
assertEq(initializedTicksCrossedList[0], 0);
}

function testQuoter_quoteExactInput_2Hops_0TickCrossed() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 984211133872795298;

tokenPath.push(token0);
tokenPath.push(token1);
tokenPath.push(token2);
ExactInputParams memory params = getExactInputParams(tokenPath, amountIn);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

assertEq(uint128(-deltaAmounts[2]), expectedAmountOut);
assertEq(sqrtPriceX96AfterList[0], 78835169195823159145205102899);
assertEq(sqrtPriceX96AfterList[1], 79619976852750192506445279985);
assertEq(initializedTicksCrossedList[0], 0);
assertEq(initializedTicksCrossedList[1], 0);
}

function testQuoter_quoteExactInput_0to2_2TicksCrossed() public {
tokenPath.push(token0);
tokenPath.push(token2);
Expand Down Expand Up @@ -252,10 +194,124 @@ contract QuoterTest is Test, Deployers {
) = quoter.quoteExactInput(params);

assertEq(uint128(-deltaAmounts[1]), 8);
assertEq(sqrtPriceX96AfterList[0], 79227483487511329217250071027);
assertEq(sqrtPriceX96AfterList[0], 79227817515327498931091950511);
assertEq(initializedTicksCrossedList[0], 1);
}

function testQuoter_quoteExactInput_2to0_2TicksCrossed() public {
tokenPath.push(token2);
tokenPath.push(token0);
ExactInputParams memory params = getExactInputParams(tokenPath, 10000);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

assertEq(-deltaAmounts[1], 9871);
assertEq(sqrtPriceX96AfterList[0], 80001962924147897865541384515);
assertEq(initializedTicksCrossedList[0], 2);
}

function testQuoter_quoteExactInput_2to0_2TicksCrossed_initialiedAfter() public {
tokenPath.push(token2);
tokenPath.push(token0);

// The swap amount is set such that the active tick after the swap is 120.
// 120 is an initialized tick for this pool. We check that we don't count it.
ExactInputParams memory params = getExactInputParams(tokenPath, 6250);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

assertEq(-deltaAmounts[1], 6190);
assertEq(sqrtPriceX96AfterList[0], 79705728824507063507279123685);
assertEq(initializedTicksCrossedList[0], 2);
}

function testQuoter_quoteExactInput_2to0_0TicksCrossed_startingInitialized() public {
setupPoolWithZeroTickInitialized(key02);
tokenPath.push(token2);
tokenPath.push(token0);
ExactInputParams memory params = getExactInputParams(tokenPath, 200);

// Tick 0 initialized. Tick after = 1
(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

assertEq(-deltaAmounts[1], 198);
assertEq(sqrtPriceX96AfterList[0], 79235729830182478001034429156);
assertEq(initializedTicksCrossedList[0], 0);
}

// 2->0 starting not initialized
function testQuoter_quoteExactInput_2to0_0TicksCrossed_startingNotInitialized() public {
tokenPath.push(token2);
tokenPath.push(token0);
ExactInputParams memory params = getExactInputParams(tokenPath, 103);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

assertEq(-deltaAmounts[1], 101);
assertEq(sqrtPriceX96AfterList[0], 79235858216754624215638319723);
assertEq(initializedTicksCrossedList[0], 0);
}

function testQuoter_quoteExactInput_2to1() public {
tokenPath.push(token2);
tokenPath.push(token1);
console.logString("===== testQuoter_quoteExactInput_2to1 ======");
console.logString("Token2: ");
console.logAddress(address(token2));
console.logString("Token1: ");
console.logAddress(address(token1));
ExactInputParams memory params = getExactInputParams(tokenPath, 10000);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);
logDeltas(deltaAmounts);
assertEq(-deltaAmounts[1], 9871);
logSqrtPrices(sqrtPriceX96AfterList);
assertEq(sqrtPriceX96AfterList[0], 80018067294531553039351583520);
assertEq(initializedTicksCrossedList[0], 0);
}

function testQuoter_quoteExactInput_0to2to1() public {
tokenPath.push(token0);
tokenPath.push(token2);
tokenPath.push(token1);
ExactInputParams memory params = getExactInputParams(tokenPath, 10000);

(
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksCrossedList
) = quoter.quoteExactInput(params);

logDeltas(deltaAmounts);
logSqrtPrices(sqrtPriceX96AfterList);

assertEq(-deltaAmounts[2], 9745);
assertEq(sqrtPriceX96AfterList[0], 78461846509168490764501028180);
assertEq(sqrtPriceX96AfterList[1], 80007846861567212939802016351);
assertEq(initializedTicksCrossedList[0], 2);
assertEq(initializedTicksCrossedList[1], 0);
}

function createPoolKey(MockERC20 tokenA, MockERC20 tokenB, address hookAddr)
internal
pure
Expand All @@ -270,7 +326,13 @@ contract QuoterTest is Test, Deployers {
MockERC20(Currency.unwrap(poolKey.currency0)).approve(address(positionManager), type(uint256).max);
MockERC20(Currency.unwrap(poolKey.currency1)).approve(address(positionManager), type(uint256).max);
positionManager.modifyPosition(
poolKey, IPoolManager.ModifyPositionParams(MIN_TICK, MAX_TICK, 200 ether), ZERO_BYTES
poolKey,
IPoolManager.ModifyPositionParams(
MIN_TICK,
MAX_TICK,
calculateLiquidityFromAmounts(SQRT_RATIO_1_1, MIN_TICK, MAX_TICK, 1000000, 1000000).toInt256()
),
ZERO_BYTES
);
}

Expand Down Expand Up @@ -304,7 +366,12 @@ contract QuoterTest is Test, Deployers {
}

function setupPoolWithZeroTickInitialized(PoolKey memory poolKey) internal {
manager.initialize(poolKey, SQRT_RATIO_1_1, ZERO_BYTES);
PoolId poolId = poolKey.toId();
(uint160 sqrtPriceX96,,,) = manager.getSlot0(poolId);
if (sqrtPriceX96 == 0) {
manager.initialize(poolKey, SQRT_RATIO_1_1, ZERO_BYTES);
}

MockERC20(Currency.unwrap(poolKey.currency0)).approve(address(positionManager), type(uint256).max);
MockERC20(Currency.unwrap(poolKey.currency1)).approve(address(positionManager), type(uint256).max);
positionManager.modifyPosition(
Expand Down Expand Up @@ -374,4 +441,11 @@ contract QuoterTest is Test, Deployers {
console.logUint(prices[i]);
}
}

function logDeltas(int128[] memory deltas) private view {
console.logString("=== Delta Amounts ===");
for (uint256 i = 0; i < deltas.length; i++) {
console.logInt(deltas[i]);
}
}
}

0 comments on commit 4f9519f

Please sign in to comment.