diff --git a/.forge-snapshots/FullRangeAddInitialLiquidity.snap b/.forge-snapshots/FullRangeAddInitialLiquidity.snap index 1f949e10..f63e2fbb 100644 --- a/.forge-snapshots/FullRangeAddInitialLiquidity.snap +++ b/.forge-snapshots/FullRangeAddInitialLiquidity.snap @@ -1 +1 @@ -412012 \ No newline at end of file +413016 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeAddLiquidity.snap b/.forge-snapshots/FullRangeAddLiquidity.snap index 2e524b49..b7d2b91f 100644 --- a/.forge-snapshots/FullRangeAddLiquidity.snap +++ b/.forge-snapshots/FullRangeAddLiquidity.snap @@ -1 +1 @@ -206278 \ No newline at end of file +207282 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeFirstSwap.snap b/.forge-snapshots/FullRangeFirstSwap.snap index 57d530e3..47ea1890 100644 --- a/.forge-snapshots/FullRangeFirstSwap.snap +++ b/.forge-snapshots/FullRangeFirstSwap.snap @@ -1 +1 @@ -152057 \ No newline at end of file +153143 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeInitialize.snap b/.forge-snapshots/FullRangeInitialize.snap index b1df71e8..7b6d6e9c 100644 --- a/.forge-snapshots/FullRangeInitialize.snap +++ b/.forge-snapshots/FullRangeInitialize.snap @@ -1 +1 @@ -878152 \ No newline at end of file +879088 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeRemoveLiquidity.snap b/.forge-snapshots/FullRangeRemoveLiquidity.snap index 35f89942..b839fdb4 100644 --- a/.forge-snapshots/FullRangeRemoveLiquidity.snap +++ b/.forge-snapshots/FullRangeRemoveLiquidity.snap @@ -1 +1 @@ -199416 \ No newline at end of file +200439 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap b/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap index a6da1a0d..0138b0f1 100644 --- a/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap +++ b/.forge-snapshots/FullRangeRemoveLiquidityAndRebalance.snap @@ -1 +1 @@ -375677 \ No newline at end of file +380062 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeSecondSwap.snap b/.forge-snapshots/FullRangeSecondSwap.snap index 55489485..cadd0b38 100644 --- a/.forge-snapshots/FullRangeSecondSwap.snap +++ b/.forge-snapshots/FullRangeSecondSwap.snap @@ -1 +1 @@ -109596 \ No newline at end of file +110682 \ No newline at end of file diff --git a/.forge-snapshots/FullRangeSwap.snap b/.forge-snapshots/FullRangeSwap.snap index 14527430..7233e853 100644 --- a/.forge-snapshots/FullRangeSwap.snap +++ b/.forge-snapshots/FullRangeSwap.snap @@ -1 +1 @@ -150064 \ No newline at end of file +151418 \ No newline at end of file diff --git a/.forge-snapshots/TWAMMSubmitOrder.snap b/.forge-snapshots/TWAMMSubmitOrder.snap index e5ad5591..7cdc684f 100644 --- a/.forge-snapshots/TWAMMSubmitOrder.snap +++ b/.forge-snapshots/TWAMMSubmitOrder.snap @@ -1 +1 @@ -124175 \ No newline at end of file +123914 \ No newline at end of file diff --git a/contracts/BaseHook.sol b/contracts/BaseHook.sol index e80880e7..8d463807 100644 --- a/contracts/BaseHook.sol +++ b/contracts/BaseHook.sol @@ -60,15 +60,11 @@ abstract contract BaseHook is IHooks { } } - function beforeInitialize(address, PoolKey calldata, uint160) external virtual returns (bytes4) { + function beforeInitialize(address, PoolKey calldata, uint160, bytes calldata) external virtual returns (bytes4) { revert HookNotImplemented(); } - function afterInitialize(address, PoolKey calldata, uint160, int24) external virtual returns (bytes4) { - revert HookNotImplemented(); - } - - function beforeModifyPosition(address, PoolKey calldata, IPoolManager.ModifyPositionParams calldata) + function afterInitialize(address, PoolKey calldata, uint160, int24, bytes calldata) external virtual returns (bytes4) @@ -76,7 +72,7 @@ abstract contract BaseHook is IHooks { revert HookNotImplemented(); } - function afterModifyPosition(address, PoolKey calldata, IPoolManager.ModifyPositionParams calldata, BalanceDelta) + function beforeModifyPosition(address, PoolKey calldata, IPoolManager.ModifyPositionParams calldata, bytes calldata) external virtual returns (bytes4) @@ -84,7 +80,17 @@ abstract contract BaseHook is IHooks { revert HookNotImplemented(); } - function beforeSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata) + function afterModifyPosition( + address, + PoolKey calldata, + IPoolManager.ModifyPositionParams calldata, + BalanceDelta, + bytes calldata + ) external virtual returns (bytes4) { + revert HookNotImplemented(); + } + + function beforeSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, bytes calldata) external virtual returns (bytes4) @@ -92,7 +98,7 @@ abstract contract BaseHook is IHooks { revert HookNotImplemented(); } - function afterSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, BalanceDelta) + function afterSwap(address, PoolKey calldata, IPoolManager.SwapParams calldata, BalanceDelta, bytes calldata) external virtual returns (bytes4) @@ -100,11 +106,19 @@ abstract contract BaseHook is IHooks { revert HookNotImplemented(); } - function beforeDonate(address, PoolKey calldata, uint256, uint256) external virtual returns (bytes4) { + function beforeDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) + external + virtual + returns (bytes4) + { revert HookNotImplemented(); } - function afterDonate(address, PoolKey calldata, uint256, uint256) external virtual returns (bytes4) { + function afterDonate(address, PoolKey calldata, uint256, uint256, bytes calldata) + external + virtual + returns (bytes4) + { revert HookNotImplemented(); } } diff --git a/contracts/hooks/examples/FullRange.sol b/contracts/hooks/examples/FullRange.sol index 4ca7904c..45a4b820 100644 --- a/contracts/hooks/examples/FullRange.sol +++ b/contracts/hooks/examples/FullRange.sol @@ -37,6 +37,8 @@ contract FullRange is BaseHook, ILockCallback { error ExpiredPastDeadline(); error TooMuchSlippage(); + bytes internal constant ZERO_BYTES = bytes(""); + /// @dev Min tick for full range with tick spacing of 60 int24 internal constant MIN_TICK = -887220; /// @dev Max tick for full range with tick spacing of 60 @@ -188,7 +190,11 @@ contract FullRange is BaseHook, ILockCallback { erc20.burn(msg.sender, params.liquidity); } - function beforeInitialize(address, PoolKey calldata key, uint160) external override returns (bytes4) { + function beforeInitialize(address, PoolKey calldata key, uint160, bytes calldata) + external + override + returns (bytes4) + { if (key.tickSpacing != 60) revert TickSpacingNotDefault(); PoolId poolId = key.toId(); @@ -211,18 +217,18 @@ contract FullRange is BaseHook, ILockCallback { return FullRange.beforeInitialize.selector; } - function beforeModifyPosition(address sender, PoolKey calldata, IPoolManager.ModifyPositionParams calldata) - external - view - override - returns (bytes4) - { + function beforeModifyPosition( + address sender, + PoolKey calldata, + IPoolManager.ModifyPositionParams calldata, + bytes calldata + ) external view override returns (bytes4) { if (sender != address(this)) revert SenderMustBeHook(); return FullRange.beforeModifyPosition.selector; } - function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata) + function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata) external override returns (bytes4) @@ -285,7 +291,7 @@ contract FullRange is BaseHook, ILockCallback { ); params.liquidityDelta = -(liquidityToRemove.toInt256()); - delta = poolManager.modifyPosition(key, params); + delta = poolManager.modifyPosition(key, params, ZERO_BYTES); pool.hasAccruedFees = false; } @@ -302,7 +308,7 @@ contract FullRange is BaseHook, ILockCallback { delta = _removeLiquidity(data.key, data.params); _takeDeltas(data.sender, data.key, delta); } else { - delta = poolManager.modifyPosition(data.key, data.params); + delta = poolManager.modifyPosition(data.key, data.params, ZERO_BYTES); _settleDeltas(data.sender, data.key, delta); } return abi.encode(delta); @@ -316,7 +322,8 @@ contract FullRange is BaseHook, ILockCallback { tickLower: MIN_TICK, tickUpper: MAX_TICK, liquidityDelta: -(poolManager.getLiquidity(poolId).toInt256()) - }) + }), + ZERO_BYTES ); uint160 newSqrtPriceX96 = ( @@ -333,7 +340,8 @@ contract FullRange is BaseHook, ILockCallback { zeroForOne: newSqrtPriceX96 < sqrtPriceX96, amountSpecified: MAX_INT, sqrtPriceLimitX96: newSqrtPriceX96 - }) + }), + ZERO_BYTES ); uint128 liquidity = LiquidityAmounts.getLiquidityForAmounts( @@ -350,13 +358,14 @@ contract FullRange is BaseHook, ILockCallback { tickLower: MIN_TICK, tickUpper: MAX_TICK, liquidityDelta: liquidity.toInt256() - }) + }), + ZERO_BYTES ); // Donate any "dust" from the sqrtRatio change as fees uint128 donateAmount0 = uint128(-balanceDelta.amount0() - balanceDeltaAfter.amount0()); uint128 donateAmount1 = uint128(-balanceDelta.amount1() - balanceDeltaAfter.amount1()); - poolManager.donate(key, donateAmount0, donateAmount1); + poolManager.donate(key, donateAmount0, donateAmount1, ZERO_BYTES); } } diff --git a/contracts/hooks/examples/GeomeanOracle.sol b/contracts/hooks/examples/GeomeanOracle.sol index dcdf5076..a2572f73 100644 --- a/contracts/hooks/examples/GeomeanOracle.sol +++ b/contracts/hooks/examples/GeomeanOracle.sol @@ -73,7 +73,7 @@ contract GeomeanOracle is BaseHook { }); } - function beforeInitialize(address, PoolKey calldata key, uint160) + function beforeInitialize(address, PoolKey calldata key, uint160, bytes calldata) external view override @@ -87,7 +87,7 @@ contract GeomeanOracle is BaseHook { return GeomeanOracle.beforeInitialize.selector; } - function afterInitialize(address, PoolKey calldata key, uint160, int24) + function afterInitialize(address, PoolKey calldata key, uint160, int24, bytes calldata) external override poolManagerOnly @@ -110,12 +110,12 @@ contract GeomeanOracle is BaseHook { ); } - function beforeModifyPosition(address, PoolKey calldata key, IPoolManager.ModifyPositionParams calldata params) - external - override - poolManagerOnly - returns (bytes4) - { + function beforeModifyPosition( + address, + PoolKey calldata key, + IPoolManager.ModifyPositionParams calldata params, + bytes calldata + ) external override poolManagerOnly returns (bytes4) { if (params.liquidityDelta < 0) revert OraclePoolMustLockLiquidity(); int24 maxTickSpacing = poolManager.MAX_TICK_SPACING(); if ( @@ -126,7 +126,7 @@ contract GeomeanOracle is BaseHook { return GeomeanOracle.beforeModifyPosition.selector; } - function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata) + function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata) external override poolManagerOnly diff --git a/contracts/hooks/examples/LimitOrder.sol b/contracts/hooks/examples/LimitOrder.sol index 034f0466..9f305f2a 100644 --- a/contracts/hooks/examples/LimitOrder.sol +++ b/contracts/hooks/examples/LimitOrder.sol @@ -51,6 +51,8 @@ contract LimitOrder is BaseHook { event Withdraw(address indexed owner, Epoch indexed epoch, uint128 liquidity); + bytes internal constant ZERO_BYTES = bytes(""); + Epoch private constant EPOCH_DEFAULT = Epoch.wrap(0); mapping(PoolId => int24) public tickLowerLasts; @@ -114,7 +116,7 @@ contract LimitOrder is BaseHook { return compressed * tickSpacing; } - function afterInitialize(address, PoolKey calldata key, uint160, int24 tick) + function afterInitialize(address, PoolKey calldata key, uint160, int24 tick, bytes calldata) external override poolManagerOnly @@ -124,12 +126,13 @@ contract LimitOrder is BaseHook { return LimitOrder.afterInitialize.selector; } - function afterSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, BalanceDelta) - external - override - poolManagerOnly - returns (bytes4) - { + function afterSwap( + address, + PoolKey calldata key, + IPoolManager.SwapParams calldata params, + BalanceDelta, + bytes calldata + ) external override poolManagerOnly returns (bytes4) { (int24 tickLower, int24 lower, int24 upper) = _getCrossedTicks(key.toId(), key.tickSpacing); if (lower > upper) return LimitOrder.afterSwap.selector; @@ -137,32 +140,36 @@ contract LimitOrder is BaseHook { // order fills are the opposite of swap fills, hence the inversion below bool zeroForOne = !params.zeroForOne; for (; lower <= upper; lower += key.tickSpacing) { - Epoch epoch = getEpoch(key, lower, zeroForOne); - if (!epoch.equals(EPOCH_DEFAULT)) { - EpochInfo storage epochInfo = epochInfos[epoch]; + _fillEpoch(key, lower, zeroForOne); + } - epochInfo.filled = true; + setTickLowerLast(key.toId(), tickLower); + return LimitOrder.afterSwap.selector; + } - (uint256 amount0, uint256 amount1) = abi.decode( - poolManager.lock( - abi.encodeCall(this.lockAcquiredFill, (key, lower, -int256(uint256(epochInfo.liquidityTotal)))) - ), - (uint256, uint256) - ); + function _fillEpoch(PoolKey calldata key, int24 lower, bool zeroForOne) internal { + Epoch epoch = getEpoch(key, lower, zeroForOne); + if (!epoch.equals(EPOCH_DEFAULT)) { + EpochInfo storage epochInfo = epochInfos[epoch]; - unchecked { - epochInfo.token0Total += amount0; - epochInfo.token1Total += amount1; - } + epochInfo.filled = true; - setEpoch(key, lower, zeroForOne, EPOCH_DEFAULT); + (uint256 amount0, uint256 amount1) = abi.decode( + poolManager.lock( + abi.encodeCall(this.lockAcquiredFill, (key, lower, -int256(uint256(epochInfo.liquidityTotal)))) + ), + (uint256, uint256) + ); - emit Fill(epoch, key, lower, zeroForOne); + unchecked { + epochInfo.token0Total += amount0; + epochInfo.token1Total += amount1; } - } - setTickLowerLast(key.toId(), tickLower); - return LimitOrder.afterSwap.selector; + setEpoch(key, lower, zeroForOne, EPOCH_DEFAULT); + + emit Fill(epoch, key, lower, zeroForOne); + } } function _getCrossedTicks(PoolId poolId, int24 tickSpacing) @@ -193,7 +200,8 @@ contract LimitOrder is BaseHook { tickLower: tickLower, tickUpper: tickLower + key.tickSpacing, liquidityDelta: liquidityDelta - }) + }), + ZERO_BYTES ); if (delta.amount0() < 0) poolManager.mint(key.currency0, address(this), amount0 = uint128(-delta.amount0())); @@ -248,7 +256,8 @@ contract LimitOrder is BaseHook { tickLower: tickLower, tickUpper: tickLower + key.tickSpacing, liquidityDelta: liquidityDelta - }) + }), + ZERO_BYTES ); if (delta.amount0() > 0) { @@ -320,7 +329,9 @@ contract LimitOrder is BaseHook { // to prevent this, we allocate all fee revenue to remaining limit order placers, unless this is the last order. if (!removingAllLiquidity) { BalanceDelta deltaFee = poolManager.modifyPosition( - key, IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: 0}) + key, + IPoolManager.ModifyPositionParams({tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: 0}), + ZERO_BYTES ); if (deltaFee.amount0() < 0) { @@ -337,7 +348,8 @@ contract LimitOrder is BaseHook { tickLower: tickLower, tickUpper: tickUpper, liquidityDelta: liquidityDelta - }) + }), + ZERO_BYTES ); if (delta.amount0() < 0) poolManager.take(key.currency0, to, amount0 = uint128(-delta.amount0())); diff --git a/contracts/hooks/examples/TWAMM.sol b/contracts/hooks/examples/TWAMM.sol index 2eeb0688..08d7e026 100644 --- a/contracts/hooks/examples/TWAMM.sol +++ b/contracts/hooks/examples/TWAMM.sol @@ -31,6 +31,8 @@ contract TWAMM is BaseHook, ITWAMM { using PoolGetters for IPoolManager; using TickBitmap for mapping(int16 => uint256); + bytes internal constant ZERO_BYTES = bytes(""); + int256 internal constant MIN_DELTA = -1; bool internal constant ZERO_FOR_ONE = true; bool internal constant ONE_FOR_ZERO = false; @@ -71,7 +73,7 @@ contract TWAMM is BaseHook, ITWAMM { }); } - function beforeInitialize(address, PoolKey calldata key, uint160) + function beforeInitialize(address, PoolKey calldata key, uint160, bytes calldata) external virtual override @@ -83,17 +85,17 @@ contract TWAMM is BaseHook, ITWAMM { return BaseHook.beforeInitialize.selector; } - function beforeModifyPosition(address, PoolKey calldata key, IPoolManager.ModifyPositionParams calldata) - external - override - poolManagerOnly - returns (bytes4) - { + function beforeModifyPosition( + address, + PoolKey calldata key, + IPoolManager.ModifyPositionParams calldata, + bytes calldata + ) external override poolManagerOnly returns (bytes4) { executeTWAMMOrders(key); return BaseHook.beforeModifyPosition.selector; } - function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata) + function beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata, bytes calldata) external override poolManagerOnly @@ -304,7 +306,7 @@ contract TWAMM is BaseHook, ITWAMM { (PoolKey memory key, IPoolManager.SwapParams memory swapParams) = abi.decode(rawData, (PoolKey, IPoolManager.SwapParams)); - BalanceDelta delta = poolManager.swap(key, swapParams); + BalanceDelta delta = poolManager.swap(key, swapParams, ZERO_BYTES); if (swapParams.zeroForOne) { if (delta.amount0() > 0) { diff --git a/contracts/hooks/examples/VolatilityOracle.sol b/contracts/hooks/examples/VolatilityOracle.sol index 2d8a033b..0a7e696d 100644 --- a/contracts/hooks/examples/VolatilityOracle.sol +++ b/contracts/hooks/examples/VolatilityOracle.sol @@ -15,7 +15,11 @@ contract VolatilityOracle is BaseHook, IDynamicFeeManager { uint32 deployTimestamp; - function getFee(PoolKey calldata) external view returns (uint24) { + function getFee(address, PoolKey calldata, IPoolManager.SwapParams calldata, bytes calldata) + external + view + returns (uint24) + { uint24 startingFee = 3000; uint32 lapsed = _blockTimestamp() - deployTimestamp; return startingFee + (uint24(lapsed) * 100) / 60; // 100 bps a minute @@ -43,7 +47,12 @@ contract VolatilityOracle is BaseHook, IDynamicFeeManager { }); } - function beforeInitialize(address, PoolKey calldata key, uint160) external pure override returns (bytes4) { + function beforeInitialize(address, PoolKey calldata key, uint160, bytes calldata) + external + pure + override + returns (bytes4) + { if (!key.fee.isDynamicFee()) revert MustUseDynamicFee(); return VolatilityOracle.beforeInitialize.selector; } diff --git a/lib/v4-core b/lib/v4-core index ff1dc91a..73938802 160000 --- a/lib/v4-core +++ b/lib/v4-core @@ -1 +1 @@ -Subproject commit ff1dc91a496a329ada6c410a7b1b3cd8cf782160 +Subproject commit 73938802cad600beb07bd805cc9883e25bf87261 diff --git a/test/FullRange.t.sol b/test/FullRange.t.sol index 29a4e12a..f558b10a 100644 --- a/test/FullRange.t.sol +++ b/test/FullRange.t.sol @@ -10,7 +10,7 @@ import {PoolManager} from "@uniswap/v4-core/contracts/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"; import {Deployers} from "@uniswap/v4-core/test/foundry-tests/utils/Deployers.sol"; import {MockERC20} from "@uniswap/v4-core/test/foundry-tests/utils/MockERC20.sol"; -import {Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; +import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol"; import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol"; import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModifyPositionTest.sol"; @@ -23,6 +23,7 @@ import {SafeCast} from "@uniswap/v4-core/contracts/libraries/SafeCast.sol"; contract TestFullRange is Test, Deployers, GasSnapshot { using PoolIdLibrary for PoolKey; using SafeCast for uint256; + using CurrencyLibrary for Currency; event Initialize( PoolId indexed poolId, @@ -61,6 +62,9 @@ contract TestFullRange is Test, Deployers, GasSnapshot { MockERC20 token1; MockERC20 token2; + Currency currency0; + Currency currency1; + PoolManager manager; FullRangeImplementation fullRange = FullRangeImplementation( address(uint160(Hooks.BEFORE_INITIALIZE_FLAG | Hooks.BEFORE_MODIFY_POSITION_FLAG | Hooks.BEFORE_SWAP_FLAG)) @@ -80,27 +84,22 @@ contract TestFullRange is Test, Deployers, GasSnapshot { PoolSwapTest swapRouter; function setUp() public { - token0 = new MockERC20("token0", "0", 18); - token1 = new MockERC20("token1", "1", 18); - token2 = new MockERC20("token2", "2", 18); - - token0.mint(address(this), 2 ** 128); - token1.mint(address(this), 2 ** 128); - token2.mint(address(this), 2 ** 128); + token0 = new MockERC20("TestA", "A", 18, 2 ** 128); + token1 = new MockERC20("TestB", "B", 18, 2 ** 128); + token2 = new MockERC20("TestC", "C", 18, 2 ** 128); manager = new PoolManager(500000); FullRangeImplementation impl = new FullRangeImplementation(manager, fullRange); vm.etch(address(fullRange), address(impl).code); - key = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 3000, TICK_SPACING, fullRange); + key = createPoolKey(token0, token1); id = key.toId(); - key2 = PoolKey(Currency.wrap(address(token1)), Currency.wrap(address(token2)), 3000, TICK_SPACING, fullRange); + key2 = createPoolKey(token1, token2); id2 = key.toId(); - keyWithLiq = - PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token2)), 3000, TICK_SPACING, fullRange); + keyWithLiq = createPoolKey(token0, token2); idWithLiq = keyWithLiq.toId(); modifyPositionRouter = new PoolModifyPositionTest(manager); @@ -113,11 +112,11 @@ contract TestFullRange is Test, Deployers, GasSnapshot { token1.approve(address(swapRouter), type(uint256).max); token2.approve(address(swapRouter), type(uint256).max); - manager.initialize(keyWithLiq, SQRT_RATIO_1_1); + manager.initialize(keyWithLiq, SQRT_RATIO_1_1, ZERO_BYTES); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token2), + Currency.unwrap(keyWithLiq.currency0), + Currency.unwrap(keyWithLiq.currency1), 3000, 100 ether, 100 ether, @@ -136,7 +135,7 @@ contract TestFullRange is Test, Deployers, GasSnapshot { emit Initialize(id, testKey.currency0, testKey.currency1, testKey.fee, testKey.tickSpacing, testKey.hooks); snapStart("FullRangeInitialize"); - manager.initialize(testKey, SQRT_RATIO_1_1); + manager.initialize(testKey, SQRT_RATIO_1_1, ZERO_BYTES); snapEnd(); (, address liquidityToken) = fullRange.poolInfo(id); @@ -145,24 +144,28 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_beforeInitialize_RevertsIfWrongSpacing() public { - PoolKey memory wrongKey = - PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 0, TICK_SPACING + 1, fullRange); + PoolKey memory wrongKey = PoolKey(key.currency0, key.currency1, 0, TICK_SPACING + 1, fullRange); vm.expectRevert(FullRange.TickSpacingNotDefault.selector); - manager.initialize(wrongKey, SQRT_RATIO_1_1); + manager.initialize(wrongKey, SQRT_RATIO_1_1, ZERO_BYTES); } function testFullRange_addLiquidity_InitialAddSucceeds() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); - uint256 prevBalance0 = MockERC20(token0).balanceOf(address(this)); - uint256 prevBalance1 = MockERC20(token1).balanceOf(address(this)); - - address token0Addr = address(token0); - address token1Addr = address(token1); + uint256 prevBalance0 = key.currency0.balanceOf(address(this)); + uint256 prevBalance1 = key.currency1.balanceOf(address(this)); FullRange.AddLiquidityParams memory addLiquidityParams = FullRange.AddLiquidityParams( - token0Addr, token1Addr, 3000, 10 ether, 10 ether, 9 ether, 9 ether, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + 10 ether, + 10 ether, + 9 ether, + 9 ether, + address(this), + MAX_DEADLINE ); snapStart("FullRangeAddInitialLiquidity"); @@ -174,33 +177,57 @@ contract TestFullRange is Test, Deployers, GasSnapshot { assertEq(manager.getLiquidity(id), liquidityTokenBal + LOCKED_LIQUIDITY); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 10 ether); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 10 ether); + assertEq(key.currency0.balanceOf(address(this)), prevBalance0 - 10 ether); + assertEq(key.currency1.balanceOf(address(this)), prevBalance1 - 10 ether); assertEq(liquidityTokenBal, 10 ether - LOCKED_LIQUIDITY); assertEq(hasAccruedFees, false); } function testFullRange_addLiquidity_InitialAddFuzz(uint256 amount) public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); if (amount < LOCKED_LIQUIDITY) { vm.expectRevert(FullRange.LiquidityDoesntMeetMinimum.selector); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, amount, amount, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + amount, + amount, + address(this), + MAX_DEADLINE ) ); } else if (amount > MAX_TICK_LIQUIDITY) { vm.expectRevert(); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, amount, amount, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + amount, + amount, + address(this), + MAX_DEADLINE ) ); } else { fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, 0, 0, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + 0, + 0, + address(this), + MAX_DEADLINE ) ); @@ -252,17 +279,16 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_addLiquidity_SwapThenAddSucceeds() public { - PoolKey memory testKey = key; - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); - uint256 prevBalance0 = MockERC20(token0).balanceOf(address(this)); - uint256 prevBalance1 = MockERC20(token1).balanceOf(address(this)); + uint256 prevBalance0 = key.currency0.balanceOf(address(this)); + uint256 prevBalance1 = key.currency1.balanceOf(address(this)); (, address liquidityToken) = fullRange.poolInfo(id); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -277,8 +303,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { assertEq(manager.getLiquidity(id), liquidityTokenBal + LOCKED_LIQUIDITY); assertEq(liquidityTokenBal, 10 ether - LOCKED_LIQUIDITY); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 10 ether); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 10 ether); + assertEq(key.currency0.balanceOf(address(this)), prevBalance0 - 10 ether); + assertEq(key.currency1.balanceOf(address(this)), prevBalance1 - 10 ether); vm.expectEmit(true, true, true, true); emit Swap( @@ -291,18 +317,26 @@ contract TestFullRange is Test, Deployers, GasSnapshot { PoolSwapTest.TestSettings({withdrawTokens: true, settleUsingTransfer: true}); snapStart("FullRangeSwap"); - swapRouter.swap(testKey, params, settings); + swapRouter.swap(key, params, settings); snapEnd(); (bool hasAccruedFees,) = fullRange.poolInfo(id); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 10 ether - 1 ether); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 9093389106119850869); + assertEq(key.currency0.balanceOf(address(this)), prevBalance0 - 10 ether - 1 ether); + assertEq(key.currency1.balanceOf(address(this)), prevBalance1 - 9093389106119850869); assertEq(hasAccruedFees, true); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, 5 ether, 5 ether, 4 ether, 4 ether, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + 5 ether, + 5 ether, + 4 ether, + 4 ether, + address(this), + MAX_DEADLINE ) ); @@ -315,12 +349,12 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_addLiquidity_FailsIfTooMuchSlippage() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -341,8 +375,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { vm.expectRevert(FullRange.TooMuchSlippage.selector); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -356,12 +390,12 @@ contract TestFullRange is Test, Deployers, GasSnapshot { function testFullRange_swap_TwoSwaps() public { PoolKey memory testKey = key; - manager.initialize(testKey, SQRT_RATIO_1_1); + manager.initialize(testKey, SQRT_RATIO_1_1, ZERO_BYTES); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -393,13 +427,13 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_swap_TwoPools() public { - manager.initialize(key, SQRT_RATIO_1_1); - manager.initialize(key2, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); + manager.initialize(key2, SQRT_RATIO_1_1, ZERO_BYTES); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -411,8 +445,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { ); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token1), - address(token2), + Currency.unwrap(key2.currency0), + Currency.unwrap(key2.currency1), 3000, 10 ether, 10 ether, @@ -468,12 +502,12 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_removeLiquidity_InitialRemoveFuzz(uint256 amount) public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 1000 ether, 1000 ether, @@ -491,12 +525,16 @@ contract TestFullRange is Test, Deployers, GasSnapshot { if (amount > UniswapV4ERC20(liquidityToken).balanceOf(address(this))) { vm.expectRevert(); fullRange.removeLiquidity( - FullRange.RemoveLiquidityParams(address(token0), address(token1), 3000, amount, MAX_DEADLINE) + FullRange.RemoveLiquidityParams( + Currency.unwrap(key.currency0), Currency.unwrap(key.currency1), 3000, amount, MAX_DEADLINE + ) ); } else { uint256 prevLiquidityTokenBal = UniswapV4ERC20(liquidityToken).balanceOf(address(this)); fullRange.removeLiquidity( - FullRange.RemoveLiquidityParams(address(token0), address(token1), 3000, amount, MAX_DEADLINE) + FullRange.RemoveLiquidityParams( + Currency.unwrap(key.currency0), Currency.unwrap(key.currency1), 3000, amount, MAX_DEADLINE + ) ); uint256 liquidityTokenBal = UniswapV4ERC20(liquidityToken).balanceOf(address(this)); @@ -516,7 +554,7 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_removeLiquidity_FailsIfNoLiquidity() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); (, address liquidityToken) = fullRange.poolInfo(id); UniswapV4ERC20(liquidityToken).approve(address(fullRange), type(uint256).max); @@ -528,15 +566,15 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_removeLiquidity_SucceedsWithPartial() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); - uint256 prevBalance0 = MockERC20(token0).balanceOf(address(this)); - uint256 prevBalance1 = MockERC20(token1).balanceOf(address(this)); + uint256 prevBalance0 = key.currency0.balanceOfSelf(); + uint256 prevBalance1 = key.currency1.balanceOfSelf(); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -551,13 +589,15 @@ contract TestFullRange is Test, Deployers, GasSnapshot { assertEq(UniswapV4ERC20(liquidityToken).balanceOf(address(this)), 10 ether - LOCKED_LIQUIDITY); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 10 ether); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 10 ether); + assertEq(key.currency0.balanceOfSelf(), prevBalance0 - 10 ether); + assertEq(key.currency1.balanceOfSelf(), prevBalance1 - 10 ether); UniswapV4ERC20(liquidityToken).approve(address(fullRange), type(uint256).max); fullRange.removeLiquidity( - FullRange.RemoveLiquidityParams(address(token0), address(token1), 3000, 5 ether, MAX_DEADLINE) + FullRange.RemoveLiquidityParams( + Currency.unwrap(key.currency0), Currency.unwrap(key.currency1), 3000, 5 ether, MAX_DEADLINE + ) ); (bool hasAccruedFees,) = fullRange.poolInfo(id); @@ -565,21 +605,21 @@ contract TestFullRange is Test, Deployers, GasSnapshot { assertEq(manager.getLiquidity(id), liquidityTokenBal + LOCKED_LIQUIDITY); assertEq(liquidityTokenBal, 5 ether - LOCKED_LIQUIDITY); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 5 ether - 1); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 5 ether - 1); + assertEq(key.currency0.balanceOfSelf(), prevBalance0 - 5 ether - 1); + assertEq(key.currency1.balanceOfSelf(), prevBalance1 - 5 ether - 1); assertEq(hasAccruedFees, false); } function testFullRange_removeLiquidity_DiffRatios() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); - uint256 prevBalance0 = MockERC20(token0).balanceOf(address(this)); - uint256 prevBalance1 = MockERC20(token1).balanceOf(address(this)); + uint256 prevBalance0 = key.currency0.balanceOf(address(this)); + uint256 prevBalance1 = key.currency1.balanceOf(address(this)); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 10 ether, 10 ether, @@ -590,8 +630,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { ) ); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 10 ether); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 10 ether); + assertEq(key.currency0.balanceOf(address(this)), prevBalance0 - 10 ether); + assertEq(key.currency1.balanceOf(address(this)), prevBalance1 - 10 ether); (, address liquidityToken) = fullRange.poolInfo(id); @@ -599,8 +639,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 5 ether, 2.5 ether, @@ -611,23 +651,25 @@ contract TestFullRange is Test, Deployers, GasSnapshot { ) ); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 12.5 ether); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 12.5 ether); + assertEq(key.currency0.balanceOf(address(this)), prevBalance0 - 12.5 ether); + assertEq(key.currency1.balanceOf(address(this)), prevBalance1 - 12.5 ether); assertEq(UniswapV4ERC20(liquidityToken).balanceOf(address(this)), 12.5 ether - LOCKED_LIQUIDITY); UniswapV4ERC20(liquidityToken).approve(address(fullRange), type(uint256).max); fullRange.removeLiquidity( - FullRange.RemoveLiquidityParams(address(token0), address(token1), 3000, 5 ether, MAX_DEADLINE) + FullRange.RemoveLiquidityParams( + Currency.unwrap(key.currency0), Currency.unwrap(key.currency1), 3000, 5 ether, MAX_DEADLINE + ) ); uint256 liquidityTokenBal = UniswapV4ERC20(liquidityToken).balanceOf(address(this)); assertEq(manager.getLiquidity(id), liquidityTokenBal + LOCKED_LIQUIDITY); assertEq(liquidityTokenBal, 7.5 ether - LOCKED_LIQUIDITY); - assertEq(MockERC20(token0).balanceOf(address(this)), prevBalance0 - 7.5 ether - 1); - assertEq(MockERC20(token1).balanceOf(address(this)), prevBalance1 - 7.5 ether - 1); + assertEq(key.currency0.balanceOf(address(this)), prevBalance0 - 7.5 ether - 1); + assertEq(key.currency1.balanceOf(address(this)), prevBalance1 - 7.5 ether - 1); } function testFullRange_removeLiquidity_SwapAndRebalance() public { @@ -658,27 +700,51 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_removeLiquidity_RemoveAllFuzz(uint256 amount) public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); (, address liquidityToken) = fullRange.poolInfo(id); if (amount <= LOCKED_LIQUIDITY) { vm.expectRevert(FullRange.LiquidityDoesntMeetMinimum.selector); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, amount, amount, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + amount, + amount, + address(this), + MAX_DEADLINE ) ); } else if (amount >= MAX_TICK_LIQUIDITY) { vm.expectRevert(); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, amount, amount, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + amount, + amount, + address(this), + MAX_DEADLINE ) ); } else { fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, 0, 0, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + 0, + 0, + address(this), + MAX_DEADLINE ) ); @@ -688,7 +754,13 @@ contract TestFullRange is Test, Deployers, GasSnapshot { uint256 liquidityTokenBal = UniswapV4ERC20(liquidityToken).balanceOf(address(this)); fullRange.removeLiquidity( - FullRange.RemoveLiquidityParams(address(token0), address(token1), 3000, liquidityTokenBal, MAX_DEADLINE) + FullRange.RemoveLiquidityParams( + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + liquidityTokenBal, + MAX_DEADLINE + ) ); assertEq(manager.getLiquidity(id), LOCKED_LIQUIDITY); @@ -713,14 +785,14 @@ contract TestFullRange is Test, Deployers, GasSnapshot { vm.prank(address(2)); token1.approve(address(fullRange), type(uint256).max); - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); (, address liquidityToken) = fullRange.poolInfo(id); // Test contract adds liquidity fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 100 ether, 100 ether, @@ -735,8 +807,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { vm.prank(address(1)); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 100 ether, 100 ether, @@ -751,8 +823,8 @@ contract TestFullRange is Test, Deployers, GasSnapshot { vm.prank(address(2)); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), - address(token1), + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), 3000, 100 ether, 100 ether, @@ -778,7 +850,11 @@ contract TestFullRange is Test, Deployers, GasSnapshot { UniswapV4ERC20(liquidityToken).approve(address(fullRange), type(uint256).max); fullRange.removeLiquidity( FullRange.RemoveLiquidityParams( - address(token0), address(token1), 3000, 300 ether - LOCKED_LIQUIDITY, MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + 300 ether - LOCKED_LIQUIDITY, + MAX_DEADLINE ) ); (hasAccruedFees,) = fullRange.poolInfo(id); @@ -791,27 +867,51 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_removeLiquidity_SwapRemoveAllFuzz(uint256 amount) public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); (, address liquidityToken) = fullRange.poolInfo(id); if (amount <= LOCKED_LIQUIDITY) { vm.expectRevert(FullRange.LiquidityDoesntMeetMinimum.selector); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, amount, amount, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + amount, + amount, + address(this), + MAX_DEADLINE ) ); } else if (amount >= MAX_TICK_LIQUIDITY) { vm.expectRevert(); fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, amount, amount, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + amount, + amount, + address(this), + MAX_DEADLINE ) ); } else { fullRange.addLiquidity( FullRange.AddLiquidityParams( - address(token0), address(token1), 3000, amount, amount, 0, 0, address(this), MAX_DEADLINE + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + amount, + amount, + 0, + 0, + address(this), + MAX_DEADLINE ) ); @@ -832,7 +932,13 @@ contract TestFullRange is Test, Deployers, GasSnapshot { uint256 liquidityTokenBal = UniswapV4ERC20(liquidityToken).balanceOf(address(this)); fullRange.removeLiquidity( - FullRange.RemoveLiquidityParams(address(token0), address(token1), 3000, liquidityTokenBal, MAX_DEADLINE) + FullRange.RemoveLiquidityParams( + Currency.unwrap(key.currency0), + Currency.unwrap(key.currency1), + 3000, + liquidityTokenBal, + MAX_DEADLINE + ) ); assertTrue(manager.getLiquidity(id) <= LOCKED_LIQUIDITY + DUST); @@ -840,12 +946,16 @@ contract TestFullRange is Test, Deployers, GasSnapshot { } function testFullRange_BeforeModifyPositionFailsWithWrongMsgSender() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); vm.expectRevert(FullRange.SenderMustBeHook.selector); - modifyPositionRouter.modifyPosition( key, IPoolManager.ModifyPositionParams({tickLower: MIN_TICK, tickUpper: MAX_TICK, liquidityDelta: 100}) ); } + + function createPoolKey(MockERC20 tokenA, MockERC20 tokenB) internal view returns (PoolKey memory) { + if (address(tokenA) > address(tokenB)) (tokenA, tokenB) = (tokenB, tokenA); + return PoolKey(Currency.wrap(address(tokenA)), Currency.wrap(address(tokenB)), 3000, TICK_SPACING, fullRange); + } } diff --git a/test/GeomeanOracle.t.sol b/test/GeomeanOracle.t.sol index f2adbe64..523498bf 100644 --- a/test/GeomeanOracle.t.sol +++ b/test/GeomeanOracle.t.sol @@ -9,6 +9,7 @@ import {GeomeanOracleImplementation} from "./shared/implementation/GeomeanOracle import {PoolManager} from "@uniswap/v4-core/contracts/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"; import {Deployers} from "@uniswap/v4-core/test/foundry-tests/utils/Deployers.sol"; +import {TokenFixture} from "@uniswap/v4-core/test/foundry-tests/utils/TokenFixture.sol"; import {TestERC20} from "@uniswap/v4-core/contracts/test/TestERC20.sol"; import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol"; @@ -17,7 +18,7 @@ import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol"; import {Oracle} from "../contracts/libraries/Oracle.sol"; import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; -contract TestGeomeanOracle is Test, Deployers { +contract TestGeomeanOracle is Test, Deployers, TokenFixture { using PoolIdLibrary for PoolKey; int24 constant MAX_TICK_SPACING = 32767; @@ -40,8 +41,10 @@ contract TestGeomeanOracle is Test, Deployers { PoolModifyPositionTest modifyPositionRouter; function setUp() public { - token0 = new TestERC20(2**128); - token1 = new TestERC20(2**128); + initializeTokens(); + token0 = TestERC20(Currency.unwrap(currency0)); + token1 = TestERC20(Currency.unwrap(currency1)); + manager = new PoolManager(500000); vm.record(); @@ -56,8 +59,7 @@ contract TestGeomeanOracle is Test, Deployers { } } geomeanOracle.setTime(1); - key = - PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 0, MAX_TICK_SPACING, geomeanOracle); + key = PoolKey(currency0, currency1, 0, MAX_TICK_SPACING, geomeanOracle); id = key.toId(); modifyPositionRouter = new PoolModifyPositionTest(manager); @@ -69,14 +71,15 @@ contract TestGeomeanOracle is Test, Deployers { } function testBeforeInitializeAllowsPoolCreation() public { - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); } function testBeforeInitializeRevertsIfFee() public { vm.expectRevert(GeomeanOracle.OnlyOneOraclePoolAllowed.selector); manager.initialize( PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 1, MAX_TICK_SPACING, geomeanOracle), - SQRT_RATIO_1_1 + SQRT_RATIO_1_1, + ZERO_BYTES ); } @@ -84,12 +87,13 @@ contract TestGeomeanOracle is Test, Deployers { vm.expectRevert(GeomeanOracle.OnlyOneOraclePoolAllowed.selector); manager.initialize( PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 0, 60, geomeanOracle), - SQRT_RATIO_1_1 + SQRT_RATIO_1_1, + ZERO_BYTES ); } function testAfterInitializeState() public { - manager.initialize(key, SQRT_RATIO_2_1); + manager.initialize(key, SQRT_RATIO_2_1, ZERO_BYTES); GeomeanOracle.ObservationState memory observationState = geomeanOracle.getState(key); assertEq(observationState.index, 0); assertEq(observationState.cardinality, 1); @@ -97,7 +101,7 @@ contract TestGeomeanOracle is Test, Deployers { } function testAfterInitializeObservation() public { - manager.initialize(key, SQRT_RATIO_2_1); + manager.initialize(key, SQRT_RATIO_2_1, ZERO_BYTES); Oracle.Observation memory observation = geomeanOracle.getObservation(key, 0); assertTrue(observation.initialized); assertEq(observation.blockTimestamp, 1); @@ -106,7 +110,7 @@ contract TestGeomeanOracle is Test, Deployers { } function testAfterInitializeObserve0() public { - manager.initialize(key, SQRT_RATIO_2_1); + manager.initialize(key, SQRT_RATIO_2_1, ZERO_BYTES); uint32[] memory secondsAgo = new uint32[](1); secondsAgo[0] = 0; (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) = @@ -118,7 +122,7 @@ contract TestGeomeanOracle is Test, Deployers { } function testBeforeModifyPositionNoObservations() public { - manager.initialize(key, SQRT_RATIO_2_1); + manager.initialize(key, SQRT_RATIO_2_1, ZERO_BYTES); modifyPositionRouter.modifyPosition( key, IPoolManager.ModifyPositionParams( @@ -139,7 +143,7 @@ contract TestGeomeanOracle is Test, Deployers { } function testBeforeModifyPositionObservation() public { - manager.initialize(key, SQRT_RATIO_2_1); + manager.initialize(key, SQRT_RATIO_2_1, ZERO_BYTES); geomeanOracle.setTime(3); // advance 2 seconds modifyPositionRouter.modifyPosition( key, @@ -161,7 +165,7 @@ contract TestGeomeanOracle is Test, Deployers { } function testBeforeModifyPositionObservationAndCardinality() public { - manager.initialize(key, SQRT_RATIO_2_1); + manager.initialize(key, SQRT_RATIO_2_1, ZERO_BYTES); geomeanOracle.setTime(3); // advance 2 seconds geomeanOracle.increaseCardinalityNext(key, 2); GeomeanOracle.ObservationState memory observationState = geomeanOracle.getState(key); diff --git a/test/LimitOrder.t.sol b/test/LimitOrder.t.sol index 82f87534..9939c7e2 100644 --- a/test/LimitOrder.t.sol +++ b/test/LimitOrder.t.sol @@ -9,6 +9,7 @@ import {LimitOrderImplementation} from "./shared/implementation/LimitOrderImplem import {PoolManager} from "@uniswap/v4-core/contracts/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol"; import {Deployers} from "@uniswap/v4-core/test/foundry-tests/utils/Deployers.sol"; +import {TokenFixture} from "@uniswap/v4-core/test/foundry-tests/utils/TokenFixture.sol"; import {TestERC20} from "@uniswap/v4-core/contracts/test/TestERC20.sol"; import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol"; @@ -16,7 +17,7 @@ import {PoolSwapTest} from "@uniswap/v4-core/contracts/test/PoolSwapTest.sol"; import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol"; import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; -contract TestLimitOrder is Test, Deployers { +contract TestLimitOrder is Test, Deployers, TokenFixture { using PoolIdLibrary for PoolKey; uint160 constant SQRT_RATIO_10_1 = 250541448375047931186413801569; @@ -31,8 +32,10 @@ contract TestLimitOrder is Test, Deployers { PoolSwapTest swapRouter; function setUp() public { - token0 = new TestERC20(2**128); - token1 = new TestERC20(2**128); + initializeTokens(); + token0 = TestERC20(Currency.unwrap(currency0)); + token1 = TestERC20(Currency.unwrap(currency1)); + manager = new PoolManager(500000); vm.record(); @@ -47,9 +50,9 @@ contract TestLimitOrder is Test, Deployers { } } - key = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 3000, 60, limitOrder); + key = PoolKey(currency0, currency1, 3000, 60, limitOrder); id = key.toId(); - manager.initialize(key, SQRT_RATIO_1_1); + manager.initialize(key, SQRT_RATIO_1_1, ZERO_BYTES); swapRouter = new PoolSwapTest(manager); @@ -66,7 +69,7 @@ contract TestLimitOrder is Test, Deployers { function testGetTickLowerLastWithDifferentPrice() public { PoolKey memory differentKey = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 3000, 61, limitOrder); - manager.initialize(differentKey, SQRT_RATIO_10_1); + manager.initialize(differentKey, SQRT_RATIO_10_1, ZERO_BYTES); assertEq(limitOrder.getTickLowerLast(differentKey.toId()), 22997); } @@ -159,8 +162,8 @@ contract TestLimitOrder is Test, Deployers { uint128 liquidityTotal ) = limitOrder.epochInfos(Epoch.wrap(1)); assertFalse(filled); - assertTrue(CurrencyLibrary.equals(currency0, Currency.wrap(address(token0)))); - assertTrue(CurrencyLibrary.equals(currency1, Currency.wrap(address(token1)))); + assertTrue(currency0 == Currency.wrap(address(token0))); + assertTrue(currency1 == Currency.wrap(address(token1))); assertEq(token0Total, 0); assertEq(token1Total, 0); assertEq(liquidityTotal, liquidity * 2); diff --git a/test/TWAMM.t.sol b/test/TWAMM.t.sol index e92e7bcf..7aef0156 100644 --- a/test/TWAMM.t.sol +++ b/test/TWAMM.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.15; import {Test} from "forge-std/Test.sol"; import {Vm} from "forge-std/Vm.sol"; import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; -import {TestERC20} from "@uniswap/v4-core/contracts/test/TestERC20.sol"; +import {MockERC20} from "@uniswap/v4-core/test/foundry-tests/utils/MockERC20.sol"; import {IERC20Minimal} from "@uniswap/v4-core/contracts/interfaces/external/IERC20Minimal.sol"; import {TWAMMImplementation} from "./shared/implementation/TWAMMImplementation.sol"; import {IHooks} from "@uniswap/v4-core/contracts/interfaces/IHooks.sol"; @@ -16,12 +16,13 @@ import {PoolModifyPositionTest} from "@uniswap/v4-core/contracts/test/PoolModify import {PoolSwapTest} from "@uniswap/v4-core/contracts/test/PoolSwapTest.sol"; import {PoolDonateTest} from "@uniswap/v4-core/contracts/test/PoolDonateTest.sol"; import {Deployers} from "@uniswap/v4-core/test/foundry-tests/utils/Deployers.sol"; +import {TokenFixture} from "@uniswap/v4-core/test/foundry-tests/utils/TokenFixture.sol"; import {CurrencyLibrary, Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; import {TWAMM} from "../contracts/hooks/examples/TWAMM.sol"; import {ITWAMM} from "../contracts/interfaces/ITWAMM.sol"; import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; -contract TWAMMTest is Test, Deployers, GasSnapshot { +contract TWAMMTest is Test, Deployers, TokenFixture, GasSnapshot { using PoolIdLibrary for PoolKey; using CurrencyLibrary for Currency; @@ -53,14 +54,15 @@ contract TWAMMTest is Test, Deployers, GasSnapshot { PoolSwapTest swapRouter; PoolDonateTest donateRouter; address hookAddress; - TestERC20 token0; - TestERC20 token1; + MockERC20 token0; + MockERC20 token1; PoolKey poolKey; PoolId poolId; function setUp() public { - token0 = new TestERC20(2**128); - token1 = new TestERC20(2**128); + initializeTokens(); + token0 = MockERC20(Currency.unwrap(currency0)); + token1 = MockERC20(Currency.unwrap(currency1)); manager = new PoolManager(500000); TWAMMImplementation impl = new TWAMMImplementation(manager, 10_000, twamm); @@ -79,7 +81,7 @@ contract TWAMMTest is Test, Deployers, GasSnapshot { poolKey = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 3000, 60, twamm); poolId = poolKey.toId(); - manager.initialize(poolKey, SQRT_RATIO_1_1); + manager.initialize(poolKey, SQRT_RATIO_1_1, ZERO_BYTES); token0.approve(address(modifyPositionRouter), 100 ether); token1.approve(address(modifyPositionRouter), 100 ether); @@ -96,7 +98,7 @@ contract TWAMMTest is Test, Deployers, GasSnapshot { (PoolKey memory initKey, PoolId initId) = newPoolKeyWithTWAMM(twamm); assertEq(twamm.lastVirtualOrderTimestamp(initId), 0); vm.warp(10000); - manager.initialize(initKey, SQRT_RATIO_1_1); + manager.initialize(initKey, SQRT_RATIO_1_1, ZERO_BYTES); assertEq(twamm.lastVirtualOrderTimestamp(initId), 10000); } @@ -381,8 +383,8 @@ contract TWAMMTest is Test, Deployers, GasSnapshot { assertEq(earningsToken0, orderAmount / 2); assertEq(earningsToken1, orderAmount / 2); - uint256 balance0BeforeTWAMM = TestERC20(Currency.unwrap(poolKey.currency0)).balanceOf(address(twamm)); - uint256 balance1BeforeTWAMM = TestERC20(Currency.unwrap(poolKey.currency1)).balanceOf(address(twamm)); + uint256 balance0BeforeTWAMM = MockERC20(Currency.unwrap(poolKey.currency0)).balanceOf(address(twamm)); + uint256 balance1BeforeTWAMM = MockERC20(Currency.unwrap(poolKey.currency1)).balanceOf(address(twamm)); uint256 balance0BeforeThis = poolKey.currency0.balanceOfSelf(); uint256 balance1BeforeThis = poolKey.currency1.balanceOfSelf(); @@ -396,8 +398,8 @@ contract TWAMMTest is Test, Deployers, GasSnapshot { assertEq(twamm.tokensOwed(poolKey.currency0, address(this)), 0); assertEq(twamm.tokensOwed(poolKey.currency1, address(this)), 0); - uint256 balance0AfterTWAMM = TestERC20(Currency.unwrap(poolKey.currency0)).balanceOf(address(twamm)); - uint256 balance1AfterTWAMM = TestERC20(Currency.unwrap(poolKey.currency1)).balanceOf(address(twamm)); + uint256 balance0AfterTWAMM = MockERC20(Currency.unwrap(poolKey.currency0)).balanceOf(address(twamm)); + uint256 balance1AfterTWAMM = MockERC20(Currency.unwrap(poolKey.currency1)).balanceOf(address(twamm)); uint256 balance0AfterThis = poolKey.currency0.balanceOfSelf(); uint256 balance1AfterThis = poolKey.currency1.balanceOfSelf(); @@ -410,7 +412,7 @@ contract TWAMMTest is Test, Deployers, GasSnapshot { } function newPoolKeyWithTWAMM(IHooks hooks) public returns (PoolKey memory, PoolId) { - TestERC20[] memory tokens = deployTokens(2, 2 ** 255); + MockERC20[] memory tokens = deployTokens(2, 2 ** 255); PoolKey memory key = PoolKey(Currency.wrap(address(tokens[0])), Currency.wrap(address(tokens[1])), 0, 60, hooks); return (key, key.toId()); }