From 74caaa6acf1bf112d6f07350e9abab6ffcd57910 Mon Sep 17 00:00:00 2001 From: diana Date: Wed, 16 Oct 2024 15:49:57 -0400 Subject: [PATCH 01/31] Bips library (#367) * update core and add bips library * format * tests * format again --- ...anager_burn_nonEmpty_native_withClose.snap | 2 +- ...ger_burn_nonEmpty_native_withTakePair.snap | 2 +- ...sitionManager_burn_nonEmpty_withClose.snap | 2 +- ...ionManager_burn_nonEmpty_withTakePair.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- ...onManager_decreaseLiquidity_withClose.snap | 2 +- ...anager_decreaseLiquidity_withTakePair.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- .../PositionManager_decrease_take_take.snap | 2 +- ...ger_increaseLiquidity_erc20_withClose.snap | 2 +- ...ncreaseLiquidity_erc20_withSettlePair.snap | 2 +- ...itionManager_increaseLiquidity_native.snap | 2 +- ...increase_autocompoundExcessFeesCredit.snap | 2 +- ...ger_increase_autocompound_clearExcess.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- ...anager_mint_nativeWithSweep_withClose.snap | 2 +- ...r_mint_nativeWithSweep_withSettlePair.snap | 2 +- .../PositionManager_mint_onSameTickLower.snap | 2 +- .../PositionManager_mint_onSameTickUpper.snap | 2 +- .../PositionManager_mint_sameRange.snap | 2 +- ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...anager_mint_warmedPool_differentRange.snap | 2 +- .../PositionManager_mint_withClose.snap | 2 +- .../PositionManager_mint_withSettlePair.snap | 2 +- ...tionManager_multicall_initialize_mint.snap | 2 +- .../PositionManager_permit_twice.snap | 2 +- lib/v4-core | 2 +- src/V4Router.sol | 2 +- src/libraries/BipsLibrary.sol | 17 +++++++ test/libraries/BipsLibrary.t.sol | 51 +++++++++++++++++++ test/router/Payments.t.sol | 2 +- 37 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 src/libraries/BipsLibrary.sol create mode 100644 test/libraries/BipsLibrary.t.sol diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 5345a8daa..9e62ab4df 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125574 \ No newline at end of file +125584 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 068dd4562..33aa7739e 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125021 \ No newline at end of file +125031 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 2ffdbdf14..6a3bb39f1 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132427 \ No newline at end of file +132446 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 81149d950..62abe7a17 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -131874 \ No newline at end of file +131893 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index e6d5ff3e3..83e0e3d6d 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146282 \ No newline at end of file +146294 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index fb052d005..ab27c01ba 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -154848 \ No newline at end of file +154872 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index fb052d005..ab27c01ba 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -154848 \ No newline at end of file +154872 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 8be5e73cc..47b66e440 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154169 \ No newline at end of file +154193 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index 5f7d954cc..e13e87a38 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -111971 \ No newline at end of file +111980 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index f069ca36d..f5f1f8b29 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119729 \ No newline at end of file +119753 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 7f1848a60..e4b3cfdee 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119050 \ No newline at end of file +119074 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index fce34ecdc..31c3a99ce 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135224 \ No newline at end of file +135243 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 90c8a0d42..5cbd7cccc 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128371 \ No newline at end of file +128380 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index 017e8a133..af29b36e3 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132416 \ No newline at end of file +132440 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index c3381b75e..9497d424d 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120305 \ No newline at end of file +120329 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index 8800975f5..df7539ba9 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -159033 \ No newline at end of file +159057 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index 4abbe118f..d62921d36 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -157973 \ No newline at end of file +157997 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 37c589b6e..5224273f7 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -140860 \ No newline at end of file +140872 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index 8b02aa231..d9726ba2c 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177340 \ No newline at end of file +177364 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 01851753c..21e55c88e 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148016 \ No newline at end of file +148040 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index a62444fa7..742cc68e6 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -364721 \ No newline at end of file +364745 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 71b95dabb..7c56236a2 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -373244 \ No newline at end of file +373268 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index 1883afaae..822d688b2 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -372467 \ No newline at end of file +372491 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 36461286f..ccfdb51fc 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317569 \ No newline at end of file +317617 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index ff59c2650..9f9a6b773 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318239 \ No newline at end of file +318287 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index 74ca2bf71..ccc454ddc 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243808 \ No newline at end of file +243856 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index e394e5e8e..23648cc90 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -418988 \ No newline at end of file +419060 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index 9b34b9e5d..cedd06147 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323600 \ No newline at end of file +323648 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index 5c7354cd5..cf0292c96 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -420122 \ No newline at end of file +420170 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index f18f3a75c..549b6841d 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419180 \ No newline at end of file +419228 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 06443a11d..b51b3f660 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -463927 \ No newline at end of file +455975 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_permit_twice.snap b/.forge-snapshots/PositionManager_permit_twice.snap index d650ccbd7..379f96111 100644 --- a/.forge-snapshots/PositionManager_permit_twice.snap +++ b/.forge-snapshots/PositionManager_permit_twice.snap @@ -1 +1 @@ -44876 \ No newline at end of file +44852 \ No newline at end of file diff --git a/lib/v4-core b/lib/v4-core index 88482f7dc..3afa83a0e 160000 --- a/lib/v4-core +++ b/lib/v4-core @@ -1 +1 @@ -Subproject commit 88482f7dc4356a7c395e199e454d50dc960bb6e7 +Subproject commit 3afa83a0e3790edb0d6d9e2289555f8e1dce211e diff --git a/src/V4Router.sol b/src/V4Router.sol index 0aaf77155..282ab77c7 100644 --- a/src/V4Router.sol +++ b/src/V4Router.sol @@ -7,7 +7,6 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; -import {BipsLibrary} from "@uniswap/v4-core/src/libraries/BipsLibrary.sol"; import {PathKey, PathKeyLibrary} from "./libraries/PathKey.sol"; import {CalldataDecoder} from "./libraries/CalldataDecoder.sol"; @@ -16,6 +15,7 @@ import {BaseActionsRouter} from "./base/BaseActionsRouter.sol"; import {DeltaResolver} from "./base/DeltaResolver.sol"; import {Actions} from "./libraries/Actions.sol"; import {ActionConstants} from "./libraries/ActionConstants.sol"; +import {BipsLibrary} from "./libraries/BipsLibrary.sol"; /// @title UniswapV4Router /// @notice Abstract contract that contains all internal logic needed for routing through Uniswap v4 pools diff --git a/src/libraries/BipsLibrary.sol b/src/libraries/BipsLibrary.sol new file mode 100644 index 000000000..219232e25 --- /dev/null +++ b/src/libraries/BipsLibrary.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// @title For calculating a percentage of an amount, using bips +library BipsLibrary { + uint256 internal constant BPS_DENOMINATOR = 10_000; + + /// @notice emitted when an invalid percentage is provided + error InvalidBips(); + + /// @param amount The total amount to calculate a percentage of + /// @param bips The percentage to calculate, in bips + function calculatePortion(uint256 amount, uint256 bips) internal pure returns (uint256) { + if (bips > BPS_DENOMINATOR) revert InvalidBips(); + return (amount * bips) / BPS_DENOMINATOR; + } +} diff --git a/test/libraries/BipsLibrary.t.sol b/test/libraries/BipsLibrary.t.sol new file mode 100644 index 000000000..02cc67d71 --- /dev/null +++ b/test/libraries/BipsLibrary.t.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "forge-std/Test.sol"; +import {BipsLibrary} from "../../src/libraries/BipsLibrary.sol"; + +contract BipsLibraryTest is Test { + using BipsLibrary for uint256; + + // The block gas limit set in foundry config is 300_000_000 (300M) for testing purposes + uint256 BLOCK_GAS_LIMIT; + + function setUp() public { + BLOCK_GAS_LIMIT = block.gaslimit; + } + + function test_fuzz_calculatePortion(uint256 amount, uint256 bips) public { + amount = bound(amount, 0, uint256(type(uint128).max)); + if (bips > BipsLibrary.BPS_DENOMINATOR) { + vm.expectRevert(BipsLibrary.InvalidBips.selector); + amount.calculatePortion(bips); + } else { + assertEq(amount.calculatePortion(bips), amount * bips / BipsLibrary.BPS_DENOMINATOR); + } + } + + function test_fuzz_gasLimit(uint256 bips) public { + if (bips > BipsLibrary.BPS_DENOMINATOR) { + vm.expectRevert(BipsLibrary.InvalidBips.selector); + block.gaslimit.calculatePortion(bips); + } else { + assertEq(block.gaslimit.calculatePortion(bips), BLOCK_GAS_LIMIT * bips / BipsLibrary.BPS_DENOMINATOR); + } + } + + function test_gasLimit_100_percent() public view { + assertEq(block.gaslimit, block.gaslimit.calculatePortion(10_000)); + } + + function test_gasLimit_1_percent() public view { + // 100 bps = 1% + // 1% of 30M is 300K + assertEq(BLOCK_GAS_LIMIT / 100, block.gaslimit.calculatePortion(100)); + } + + function test_gasLimit_1BP() public view { + // 1bp is 0.01% + // 0.01% of 30M is 300 + assertEq(BLOCK_GAS_LIMIT / 10000, block.gaslimit.calculatePortion(1)); + } +} diff --git a/test/router/Payments.t.sol b/test/router/Payments.t.sol index 8f96a4085..3b1b2c328 100644 --- a/test/router/Payments.t.sol +++ b/test/router/Payments.t.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.19; import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; -import {BipsLibrary} from "@uniswap/v4-core/src/libraries/BipsLibrary.sol"; import {IV4Router} from "../../src/interfaces/IV4Router.sol"; import {RoutingTestHelpers} from "../shared/RoutingTestHelpers.sol"; import {Plan, Planner} from "../shared/Planner.sol"; import {Actions} from "../../src/libraries/Actions.sol"; import {ActionConstants} from "../../src/libraries/ActionConstants.sol"; +import {BipsLibrary} from "../../src/libraries/BipsLibrary.sol"; contract PaymentsTests is RoutingTestHelpers, GasSnapshot { using CurrencyLibrary for Currency; From dd76ef0fc94bac93cd40e57b01c9395f54bb924c Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:04:34 -0400 Subject: [PATCH 02/31] add interface for immutable state (#368) --- src/base/ImmutableState.sol | 5 +++-- src/interfaces/IImmutableState.sol | 10 ++++++++++ src/interfaces/IPositionManager.sol | 3 ++- src/interfaces/IV4Router.sol | 3 ++- 4 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 src/interfaces/IImmutableState.sol diff --git a/src/base/ImmutableState.sol b/src/base/ImmutableState.sol index 8e30f1a4b..9f9cf0687 100644 --- a/src/base/ImmutableState.sol +++ b/src/base/ImmutableState.sol @@ -2,11 +2,12 @@ pragma solidity ^0.8.0; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; +import {IImmutableState} from "../interfaces/IImmutableState.sol"; /// @title Immutable State /// @notice A collection of immutable state variables, commonly used across multiple contracts -contract ImmutableState { - /// @notice The Uniswap v4 PoolManager contract +contract ImmutableState is IImmutableState { + /// @inheritdoc IImmutableState IPoolManager public immutable poolManager; constructor(IPoolManager _poolManager) { diff --git a/src/interfaces/IImmutableState.sol b/src/interfaces/IImmutableState.sol new file mode 100644 index 000000000..32e20573a --- /dev/null +++ b/src/interfaces/IImmutableState.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; + +/// @title Interface for ImmutableState +interface IImmutableState { + /// @notice The Uniswap v4 PoolManager contract + function poolManager() external view returns (IPoolManager); +} diff --git a/src/interfaces/IPositionManager.sol b/src/interfaces/IPositionManager.sol index 616b51ccb..fbdfdd5c2 100644 --- a/src/interfaces/IPositionManager.sol +++ b/src/interfaces/IPositionManager.sol @@ -5,10 +5,11 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {PositionInfo} from "../libraries/PositionInfoLibrary.sol"; import {INotifier} from "./INotifier.sol"; +import {IImmutableState} from "./IImmutableState.sol"; /// @title IPositionManager /// @notice Interface for the PositionManager contract -interface IPositionManager is INotifier { +interface IPositionManager is INotifier, IImmutableState { /// @notice Thrown when the caller is not approved to modify a position error NotApproved(address caller); /// @notice Thrown when the block.timestamp exceeds the user-provided deadline diff --git a/src/interfaces/IV4Router.sol b/src/interfaces/IV4Router.sol index 13ed4775f..9c0812444 100644 --- a/src/interfaces/IV4Router.sol +++ b/src/interfaces/IV4Router.sol @@ -4,10 +4,11 @@ pragma solidity ^0.8.0; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; import {PathKey} from "../libraries/PathKey.sol"; +import {IImmutableState} from "./IImmutableState.sol"; /// @title IV4Router /// @notice Interface containing all the structs and errors for different v4 swap types -interface IV4Router { +interface IV4Router is IImmutableState { /// @notice Emitted when an exactInput swap does not receive its minAmountOut error V4TooLittleReceived(uint256 minAmountOutReceived, uint256 amountReceived); /// @notice Emitted when an exactOutput is asked for more than its maxAmountIn From fd0488f9ca46fb81d786df02e50b2f5c76e35250 Mon Sep 17 00:00:00 2001 From: diana Date: Thu, 17 Oct 2024 16:28:24 -0400 Subject: [PATCH 03/31] Pashov M-01 fix hook address (#370) --- src/libraries/SVG.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/SVG.sol b/src/libraries/SVG.sol index dea00e663..d592f7a84 100644 --- a/src/libraries/SVG.sol +++ b/src/libraries/SVG.sol @@ -346,7 +346,7 @@ library SVG { string memory tickLowerStr = tickToString(tickLower); string memory tickUpperStr = tickToString(tickUpper); uint256 str1length = bytes(tokenId).length + 4; - string memory hookSlice = string(abi.encodePacked(substring(hookStr, 0, 5), "...", substring(hookStr, 37, 40))); + string memory hookSlice = string(abi.encodePacked(substring(hookStr, 0, 5), "...", substring(hookStr, 39, 42))); uint256 str2length = bytes(hookSlice).length + 5; uint256 str3length = bytes(tickLowerStr).length + 10; uint256 str4length = bytes(tickUpperStr).length + 10; From 40c9260745657193f99c8db85653a95f76ff40ed Mon Sep 17 00:00:00 2001 From: diana Date: Thu, 17 Oct 2024 17:13:53 -0400 Subject: [PATCH 04/31] Pashov L-07 do not revert if value not uint8 (#375) --- .forge-snapshots/positionDescriptor bytecode size.snap | 2 +- src/libraries/SafeCurrencyMetadata.sol | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index ec121d73b..702b832f5 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31065 \ No newline at end of file +31074 \ No newline at end of file diff --git a/src/libraries/SafeCurrencyMetadata.sol b/src/libraries/SafeCurrencyMetadata.sol index f4d7cf276..029244aa3 100644 --- a/src/libraries/SafeCurrencyMetadata.sol +++ b/src/libraries/SafeCurrencyMetadata.sol @@ -41,7 +41,10 @@ library SafeCurrencyMetadata { return 0; } if (data.length == 32) { - return abi.decode(data, (uint8)); + uint256 decimals = abi.decode(data, (uint256)); + if (decimals <= type(uint8).max) { + return uint8(decimals); + } } return 0; } From 0c162a0cec2bf9184ce97e19f710fbc657ae7a5a Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Thu, 17 Oct 2024 20:41:05 -0400 Subject: [PATCH 05/31] Remove sqrtpricelimit from v4 router (#365) * remove sqrtpricelimit from v4 router * add comment about sqrtpricelimit --------- Co-authored-by: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> --- ...p_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...eFromCaller_takeAllToSpecifiedAddress.snap | 2 +- ..._settleWithBalance_takeAllToMsgSender.snap | 2 +- ...WithBalance_takeAllToSpecifiedAddress.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .../V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .../V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .../V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .../V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .../V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .../V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle.snap | 2 +- .../V4Router_ExactInputSingle_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle_nativeOut.snap | 2 +- ...Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .../V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .../V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .../V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .../V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .../V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .../V4Router_ExactOutputSingle.snap | 2 +- ...r_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOutputSingle_nativeOut.snap | 2 +- src/V4Router.sol | 42 +++++------------- src/interfaces/IV4Router.sol | 2 - test/libraries/CalldataDecoder.t.sol | 2 - test/router/Payments.gas.t.sol | 8 ++-- test/router/Payments.t.sol | 18 ++++---- test/router/V4Router.gas.t.sol | 12 ++--- test/router/V4Router.t.sol | 44 +++++++++---------- 35 files changed, 79 insertions(+), 105 deletions(-) diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index 2cd533eed..63e482c1a 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129854 \ No newline at end of file +129601 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index 89faf94ce..1be91a8be 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131905 \ No newline at end of file +131664 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index 55ac6b3ac..e3d47b59c 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -124110 \ No newline at end of file +123869 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index 00e673a8c..e8e1e8fae 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -124252 \ No newline at end of file +124011 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index fb87573dc..0528d9874 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7148 \ No newline at end of file +7037 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index bc9d99894..2a724576f 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -115722 \ No newline at end of file +115708 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index 764f3bbb0..3afc230ee 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -116043 \ No newline at end of file +116029 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index 40990e3ce..94d611dee 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -124861 \ No newline at end of file +124847 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index a38c964a3..01a3e91e0 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -130584 \ No newline at end of file +130570 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index 208b10238..9620022fb 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -185439 \ No newline at end of file +185411 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index 2862d64cc..a7d527920 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -170577 \ No newline at end of file +170549 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index c44d7bb06..aecf0666e 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -240297 \ No newline at end of file +240255 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index e98fcba77..3ea0d0bf6 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -225435 \ No newline at end of file +225393 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index 2cd533eed..63e482c1a 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -129854 \ No newline at end of file +129601 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index 5e5c5b3ba..d9151a237 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -114992 \ No newline at end of file +114739 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index f36fa4504..e039a25da 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -115282 \ No newline at end of file +115028 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index 9c6beb911..5e64389a5 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -121985 \ No newline at end of file +121971 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index adfd51ab4..4e7b78af5 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -117107 \ No newline at end of file +117093 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index 7692da738..59f0e6917 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -125925 \ No newline at end of file +125911 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 93703d01e..5e7fe01cd 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -129870 \ No newline at end of file +129856 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index abfba6e58..87c5e7044 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -183787 \ No newline at end of file +183759 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index f236e20d6..d15e6c894 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -175902 \ No newline at end of file +175874 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index cfb3e8279..5df7f78e5 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -237735 \ No newline at end of file +237693 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index c30911016..72b7efd5e 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -229850 \ No newline at end of file +229808 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 575b9ea9f..810acacb8 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -217090 \ No newline at end of file +217048 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index 5de03712a..1fb8a61af 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -129140 \ No newline at end of file +128884 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index 6120543a0..cd9382b3d 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -121255 \ No newline at end of file +120999 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index b7b122f53..a14cba0fa 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -116452 \ No newline at end of file +116195 \ No newline at end of file diff --git a/src/V4Router.sol b/src/V4Router.sol index 282ab77c7..4f69a702b 100644 --- a/src/V4Router.sol +++ b/src/V4Router.sol @@ -90,9 +90,8 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { amountIn = _getFullCredit(params.zeroForOne ? params.poolKey.currency0 : params.poolKey.currency1).toUint128(); } - uint128 amountOut = _swap( - params.poolKey, params.zeroForOne, -int256(uint256(amountIn)), params.sqrtPriceLimitX96, params.hookData - ).toUint128(); + uint128 amountOut = + _swap(params.poolKey, params.zeroForOne, -int256(uint256(amountIn)), params.hookData).toUint128(); if (amountOut < params.amountOutMinimum) revert V4TooLittleReceived(params.amountOutMinimum, amountOut); } @@ -110,7 +109,7 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { pathKey = params.path[i]; (PoolKey memory poolKey, bool zeroForOne) = pathKey.getPoolAndSwapDirection(currencyIn); // The output delta will always be positive, except for when interacting with certain hook pools - amountOut = _swap(poolKey, zeroForOne, -int256(uint256(amountIn)), 0, pathKey.hookData).toUint128(); + amountOut = _swap(poolKey, zeroForOne, -int256(uint256(amountIn)), pathKey.hookData).toUint128(); amountIn = amountOut; currencyIn = pathKey.intermediateCurrency; @@ -127,17 +126,7 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { _getFullDebt(params.zeroForOne ? params.poolKey.currency1 : params.poolKey.currency0).toUint128(); } uint128 amountIn = ( - uint256( - -int256( - _swap( - params.poolKey, - params.zeroForOne, - int256(uint256(amountOut)), - params.sqrtPriceLimitX96, - params.hookData - ) - ) - ) + uint256(-int256(_swap(params.poolKey, params.zeroForOne, int256(uint256(amountOut)), params.hookData))) ).toUint128(); if (amountIn > params.amountInMaximum) revert V4TooMuchRequested(params.amountInMaximum, amountIn); } @@ -159,9 +148,8 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { pathKey = params.path[i - 1]; (PoolKey memory poolKey, bool oneForZero) = pathKey.getPoolAndSwapDirection(currencyOut); // The output delta will always be negative, except for when interacting with certain hook pools - amountIn = ( - uint256(-int256(_swap(poolKey, !oneForZero, int256(uint256(amountOut)), 0, pathKey.hookData))) - ).toUint128(); + amountIn = (uint256(-int256(_swap(poolKey, !oneForZero, int256(uint256(amountOut)), pathKey.hookData)))) + .toUint128(); amountOut = amountIn; currencyOut = pathKey.intermediateCurrency; @@ -170,22 +158,16 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { } } - function _swap( - PoolKey memory poolKey, - bool zeroForOne, - int256 amountSpecified, - uint160 sqrtPriceLimitX96, - bytes calldata hookData - ) private returns (int128 reciprocalAmount) { + function _swap(PoolKey memory poolKey, bool zeroForOne, int256 amountSpecified, bytes calldata hookData) + private + returns (int128 reciprocalAmount) + { + // for protection of exactOut swaps, sqrtPriceLimit is not exposed as a feature in this contract unchecked { BalanceDelta delta = poolManager.swap( poolKey, IPoolManager.SwapParams( - zeroForOne, - amountSpecified, - sqrtPriceLimitX96 == 0 - ? (zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1) - : sqrtPriceLimitX96 + zeroForOne, amountSpecified, zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1 ), hookData ); diff --git a/src/interfaces/IV4Router.sol b/src/interfaces/IV4Router.sol index 9c0812444..a24ae9a9d 100644 --- a/src/interfaces/IV4Router.sol +++ b/src/interfaces/IV4Router.sol @@ -20,7 +20,6 @@ interface IV4Router is IImmutableState { bool zeroForOne; uint128 amountIn; uint128 amountOutMinimum; - uint160 sqrtPriceLimitX96; bytes hookData; } @@ -38,7 +37,6 @@ interface IV4Router is IImmutableState { bool zeroForOne; uint128 amountOut; uint128 amountInMaximum; - uint160 sqrtPriceLimitX96; bytes hookData; } diff --git a/test/libraries/CalldataDecoder.t.sol b/test/libraries/CalldataDecoder.t.sol index 0a3fc7375..c41122ebc 100644 --- a/test/libraries/CalldataDecoder.t.sol +++ b/test/libraries/CalldataDecoder.t.sol @@ -103,7 +103,6 @@ contract CalldataDecoderTest is Test { assertEq(swapParams.zeroForOne, _swapParams.zeroForOne); assertEq(swapParams.amountIn, _swapParams.amountIn); assertEq(swapParams.amountOutMinimum, _swapParams.amountOutMinimum); - assertEq(swapParams.sqrtPriceLimitX96, _swapParams.sqrtPriceLimitX96); assertEq(swapParams.hookData, _swapParams.hookData); _assertEq(swapParams.poolKey, _swapParams.poolKey); } @@ -128,7 +127,6 @@ contract CalldataDecoderTest is Test { assertEq(swapParams.zeroForOne, _swapParams.zeroForOne); assertEq(swapParams.amountOut, _swapParams.amountOut); assertEq(swapParams.amountInMaximum, _swapParams.amountInMaximum); - assertEq(swapParams.sqrtPriceLimitX96, _swapParams.sqrtPriceLimitX96); assertEq(swapParams.hookData, _swapParams.hookData); _assertEq(swapParams.poolKey, _swapParams.poolKey); } diff --git a/test/router/Payments.gas.t.sol b/test/router/Payments.gas.t.sol index 9717fdad0..2e42a9366 100644 --- a/test/router/Payments.gas.t.sol +++ b/test/router/Payments.gas.t.sol @@ -22,7 +22,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { function test_gas_swap_settleFromCaller_takeAllToSpecifiedAddress() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, MAX_SETTLE_AMOUNT)); @@ -36,7 +36,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { function test_gas_swap_settleFromCaller_takeAllToMsgSender() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(key0.currency0, key0.currency1)); @@ -49,7 +49,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { function test_gas_swap_settleWithBalance_takeAllToSpecifiedAddress() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); // seed the router with tokens key0.currency0.transfer(address(router), amountIn); @@ -66,7 +66,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { function test_gas_swap_settleWithBalance_takeAllToMsgSender() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); // seed the router with tokens key0.currency0.transfer(address(router), amountIn); diff --git a/test/router/Payments.t.sol b/test/router/Payments.t.sol index 3b1b2c328..29442f9cd 100644 --- a/test/router/Payments.t.sol +++ b/test/router/Payments.t.sol @@ -26,7 +26,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(key0.currency0, key0.currency1)); @@ -54,7 +54,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { function test_exactIn_settleAll_revertsSlippage() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, amountIn - 1)); @@ -69,7 +69,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, MAX_SETTLE_AMOUNT)); @@ -87,7 +87,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 expectedAmountIn = 1008049273448486163; IV4Router.ExactOutputSingleParams memory params = - IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), 0, bytes("")); + IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, expectedAmountIn - 1)); @@ -105,7 +105,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 expectedAmountIn = 1008049273448486163; IV4Router.ExactOutputSingleParams memory params = - IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), 0, bytes("")); + IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, MAX_SETTLE_AMOUNT)); @@ -121,7 +121,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 expectedAmountIn = 1008049273448486163; IV4Router.ExactOutputSingleParams memory params = - IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), 0, bytes("")); + IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, expectedAmountIn)); @@ -135,7 +135,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); // seed the router with tokens key0.currency0.transfer(address(router), amountIn); @@ -169,7 +169,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); // take 15 bips to Bob @@ -205,7 +205,7 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { function test_settle_takePortion_reverts() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); // bips is larger than maximum bips diff --git a/test/router/V4Router.gas.t.sol b/test/router/V4Router.gas.t.sol index 8d3eac922..c49f96dcf 100644 --- a/test/router/V4Router.gas.t.sol +++ b/test/router/V4Router.gas.t.sol @@ -31,7 +31,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, ActionConstants.MSG_SENDER); @@ -107,7 +107,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(nativeKey, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(nativeKey, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(nativeKey.currency0, nativeKey.currency1, ActionConstants.MSG_SENDER); @@ -120,7 +120,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(nativeKey, false, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(nativeKey, false, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(nativeKey.currency1, nativeKey.currency0, ActionConstants.MSG_SENDER); @@ -196,7 +196,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot { uint256 amountOut = 1 ether; IV4Router.ExactOutputSingleParams memory params = - IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), type(uint128).max, 0, bytes("")); + IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), type(uint128).max, bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, ActionConstants.MSG_SENDER); @@ -272,7 +272,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot { uint256 amountOut = 1 ether; IV4Router.ExactOutputSingleParams memory params = - IV4Router.ExactOutputSingleParams(nativeKey, true, uint128(amountOut), type(uint128).max, 0, bytes("")); + IV4Router.ExactOutputSingleParams(nativeKey, true, uint128(amountOut), type(uint128).max, bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(nativeKey.currency0, nativeKey.currency1, ActionConstants.MSG_SENDER); @@ -285,7 +285,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot { uint256 amountOut = 1 ether; IV4Router.ExactOutputSingleParams memory params = - IV4Router.ExactOutputSingleParams(nativeKey, false, uint128(amountOut), type(uint128).max, 0, bytes("")); + IV4Router.ExactOutputSingleParams(nativeKey, false, uint128(amountOut), type(uint128).max, bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(nativeKey.currency1, nativeKey.currency0, ActionConstants.MSG_SENDER); diff --git a/test/router/V4Router.t.sol b/test/router/V4Router.t.sol index e32da0529..0c74e0046 100644 --- a/test/router/V4Router.t.sol +++ b/test/router/V4Router.t.sol @@ -28,9 +28,8 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; // min amount out of 1 higher than the actual amount out - IV4Router.ExactInputSingleParams memory params = IV4Router.ExactInputSingleParams( - key0, true, uint128(amountIn), uint128(expectedAmountOut + 1), 0, bytes("") - ); + IV4Router.ExactInputSingleParams memory params = + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), uint128(expectedAmountOut + 1), bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, ActionConstants.MSG_SENDER); @@ -46,7 +45,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); (uint256 inputBalanceBefore, uint256 outputBalanceBefore, uint256 inputBalanceAfter, uint256 outputBalanceAfter) @@ -64,7 +63,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); @@ -92,7 +91,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); @@ -120,7 +119,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, expectedAmountOut * 12 / 10)); @@ -153,7 +152,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, false, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, false, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); (uint256 inputBalanceBefore, uint256 outputBalanceBefore, uint256 inputBalanceAfter, uint256 outputBalanceAfter) @@ -282,7 +281,7 @@ contract V4RouterTest is RoutingTestHelpers { // amount in of 0 to show it should use the open delta IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, ActionConstants.OPEN_DELTA, 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(key0, true, ActionConstants.OPEN_DELTA, 0, bytes("")); plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, ActionConstants.CONTRACT_BALANCE, false)); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); @@ -314,7 +313,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountOut = 992054607780215625; IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(nativeKey, true, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(nativeKey, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); @@ -334,7 +333,7 @@ contract V4RouterTest is RoutingTestHelpers { // native output means we need !zeroForOne IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(nativeKey, false, uint128(amountIn), 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(nativeKey, false, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); @@ -450,7 +449,7 @@ contract V4RouterTest is RoutingTestHelpers { // amount in of 0 to show it should use the open delta IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(nativeKey, true, ActionConstants.OPEN_DELTA, 0, 0, bytes("")); + IV4Router.ExactInputSingleParams(nativeKey, true, ActionConstants.OPEN_DELTA, 0, bytes("")); plan = plan.add(Actions.SETTLE, abi.encode(nativeKey.currency0, ActionConstants.CONTRACT_BALANCE, false)); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); @@ -481,9 +480,8 @@ contract V4RouterTest is RoutingTestHelpers { uint256 amountOut = 1 ether; uint256 expectedAmountIn = 1008049273448486163; - IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams( - key0, true, uint128(amountOut), uint128(expectedAmountIn - 1), 0, bytes("") - ); + IV4Router.ExactOutputSingleParams memory params = + IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn - 1), bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, ActionConstants.MSG_SENDER); @@ -498,9 +496,8 @@ contract V4RouterTest is RoutingTestHelpers { uint256 amountOut = 1 ether; uint256 expectedAmountIn = 1008049273448486163; - IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams( - key0, true, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("") - ); + IV4Router.ExactOutputSingleParams memory params = + IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn + 1), bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); @@ -518,9 +515,8 @@ contract V4RouterTest is RoutingTestHelpers { uint256 amountOut = 1 ether; uint256 expectedAmountIn = 1008049273448486163; - IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams( - key0, false, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("") - ); + IV4Router.ExactOutputSingleParams memory params = + IV4Router.ExactOutputSingleParams(key0, false, uint128(amountOut), uint128(expectedAmountIn + 1), bytes("")); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); @@ -538,7 +534,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountIn = 1008049273448486163; IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams( - key0, true, ActionConstants.OPEN_DELTA, uint128(expectedAmountIn + 1), 0, bytes("") + key0, true, ActionConstants.OPEN_DELTA, uint128(expectedAmountIn + 1), bytes("") ); plan = plan.add(Actions.TAKE, abi.encode(key0.currency1, ActionConstants.ADDRESS_THIS, 1 ether)); @@ -709,7 +705,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountIn = 1008049273448486163; IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams( - nativeKey, true, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("") + nativeKey, true, uint128(amountOut), uint128(expectedAmountIn + 1), bytes("") ); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); @@ -729,7 +725,7 @@ contract V4RouterTest is RoutingTestHelpers { uint256 expectedAmountIn = 1008049273448486163; IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams( - nativeKey, false, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("") + nativeKey, false, uint128(amountOut), uint128(expectedAmountIn + 1), bytes("") ); plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params)); From d084d9b1f4c3e8c71c67d6e495383841f6ed5b8a Mon Sep 17 00:00:00 2001 From: diana Date: Thu, 24 Oct 2024 14:56:16 -0400 Subject: [PATCH 06/31] Pashov L-01 display No Hook instead of the zero address (#372) --- .forge-snapshots/positionDescriptor bytecode size.snap | 2 +- src/libraries/Descriptor.sol | 2 +- src/libraries/SVG.sol | 4 +++- test/PositionDescriptor.t.sol | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 702b832f5..d2ccf4869 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31074 \ No newline at end of file +31236 \ No newline at end of file diff --git a/src/libraries/Descriptor.sol b/src/libraries/Descriptor.sol index 527e7bd8b..918ca5a8a 100644 --- a/src/libraries/Descriptor.sol +++ b/src/libraries/Descriptor.sol @@ -54,7 +54,7 @@ library Descriptor { escapeQuotes(params.baseCurrencySymbol), addressToString(Currency.unwrap(params.quoteCurrency)), addressToString(Currency.unwrap(params.baseCurrency)), - addressToString(params.hooks), + params.hooks == address(0) ? "No Hook" : addressToString(params.hooks), feeToPercentString(params.fee) ); string memory image = Base64.encode(bytes(generateSVGImage(params))); diff --git a/src/libraries/SVG.sol b/src/libraries/SVG.sol index d592f7a84..90733ddc4 100644 --- a/src/libraries/SVG.sol +++ b/src/libraries/SVG.sol @@ -346,7 +346,9 @@ library SVG { string memory tickLowerStr = tickToString(tickLower); string memory tickUpperStr = tickToString(tickUpper); uint256 str1length = bytes(tokenId).length + 4; - string memory hookSlice = string(abi.encodePacked(substring(hookStr, 0, 5), "...", substring(hookStr, 39, 42))); + string memory hookSlice = hook == address(0) + ? "No Hook" + : string(abi.encodePacked(substring(hookStr, 0, 5), "...", substring(hookStr, 39, 42))); uint256 str2length = bytes(hookSlice).length + 5; uint256 str3length = bytes(tickLowerStr).length + 10; uint256 str4length = bytes(tickUpperStr).length + 10; diff --git a/test/PositionDescriptor.t.sol b/test/PositionDescriptor.t.sol index dabe83930..87835fcbd 100644 --- a/test/PositionDescriptor.t.sol +++ b/test/PositionDescriptor.t.sol @@ -122,7 +122,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot { assertEq(token.name, "Uniswap - 0.3% - TEST/TEST - 1.0060<>1.0121"); assertEq( token.description, - unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\nTEST Address: 0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\nTEST Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nHook Address: 0x0000000000000000000000000000000000000000\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." + unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\nTEST Address: 0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\nTEST Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nHook Address: No Hook\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." ); } From 1b50ca2eef30b088fd76657a22fb6b4300db13b3 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Thu, 24 Oct 2024 21:09:48 +0100 Subject: [PATCH 07/31] return early for amount=0 (#383) * return early for amount=0 * add back natspec * update snapshots * optimize close --- .../Payments_swap_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...ments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap | 2 +- .../Payments_swap_settleWithBalance_takeAllToMsgSender.snap | 2 +- ...ents_swap_settleWithBalance_takeAllToSpecifiedAddress.snap | 2 +- .../PositionManager_burn_nonEmpty_native_withClose.snap | 2 +- .../PositionManager_burn_nonEmpty_native_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap | 2 +- .../PositionManager_burn_nonEmpty_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_collect_native.snap | 2 +- .forge-snapshots/PositionManager_collect_sameRange.snap | 2 +- .forge-snapshots/PositionManager_collect_withClose.snap | 2 +- .forge-snapshots/PositionManager_collect_withTakePair.snap | 2 +- .../PositionManager_decreaseLiquidity_native.snap | 2 +- .../PositionManager_decreaseLiquidity_withClose.snap | 2 +- .../PositionManager_decreaseLiquidity_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_decrease_burnEmpty.snap | 2 +- .../PositionManager_decrease_burnEmpty_native.snap | 2 +- .../PositionManager_decrease_sameRange_allLiquidity.snap | 2 +- .forge-snapshots/PositionManager_decrease_take_take.snap | 2 +- .../PositionManager_increaseLiquidity_erc20_withClose.snap | 2 +- ...ositionManager_increaseLiquidity_erc20_withSettlePair.snap | 2 +- .../PositionManager_increaseLiquidity_native.snap | 2 +- ...PositionManager_increase_autocompoundExcessFeesCredit.snap | 2 +- .forge-snapshots/PositionManager_mint_native.snap | 2 +- .../PositionManager_mint_nativeWithSweep_withClose.snap | 2 +- .../PositionManager_mint_nativeWithSweep_withSettlePair.snap | 2 +- .forge-snapshots/PositionManager_mint_onSameTickLower.snap | 2 +- .forge-snapshots/PositionManager_mint_onSameTickUpper.snap | 2 +- .forge-snapshots/PositionManager_mint_sameRange.snap | 2 +- .../PositionManager_mint_settleWithBalance_sweep.snap | 2 +- .../PositionManager_mint_warmedPool_differentRange.snap | 2 +- .forge-snapshots/PositionManager_mint_withClose.snap | 2 +- .forge-snapshots/PositionManager_mint_withSettlePair.snap | 2 +- .../PositionManager_multicall_initialize_mint.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOutputSingle.snap | 2 +- .../V4Router_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap | 2 +- src/PositionManager.sol | 2 +- src/base/DeltaResolver.sol | 4 ++++ 60 files changed, 63 insertions(+), 59 deletions(-) diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index 63e482c1a..2fb484c41 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129601 \ No newline at end of file +129642 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index 1be91a8be..ff128171f 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131664 \ No newline at end of file +131705 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index e3d47b59c..7703a32a4 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -123869 \ No newline at end of file +123910 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index e8e1e8fae..0830d9291 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -124011 \ No newline at end of file +124052 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 9e62ab4df..5ad0da0a9 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125584 \ No newline at end of file +125624 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 33aa7739e..030a3e444 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125031 \ No newline at end of file +125106 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 6a3bb39f1..5c745f939 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132446 \ No newline at end of file +132486 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 62abe7a17..9bb02f5c0 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -131893 \ No newline at end of file +131968 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 83e0e3d6d..1396b4fbf 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146294 \ No newline at end of file +146344 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index ab27c01ba..ecf3a285b 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -154872 \ No newline at end of file +154922 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index ab27c01ba..ecf3a285b 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -154872 \ No newline at end of file +154922 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 47b66e440..22d50eafd 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154193 \ No newline at end of file +154287 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index e13e87a38..1a2e6b277 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -111980 \ No newline at end of file +112020 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index f5f1f8b29..f52a7effa 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119753 \ No newline at end of file +119803 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index e4b3cfdee..11fddf420 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119074 \ No newline at end of file +119168 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 31c3a99ce..95a005d38 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135243 \ No newline at end of file +135283 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 5cbd7cccc..588100f58 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128380 \ No newline at end of file +128420 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index af29b36e3..d467feba8 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132440 \ No newline at end of file +132490 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index 9497d424d..0b9cd698f 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120329 \ No newline at end of file +120423 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index df7539ba9..974deb9ef 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -159057 \ No newline at end of file +159083 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index d62921d36..1cafe695d 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -157997 \ No newline at end of file +158035 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 5224273f7..7647c22bb 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -140872 \ No newline at end of file +140898 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index d9726ba2c..76da88df2 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177364 \ No newline at end of file +177414 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index 742cc68e6..fef9a7fb9 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -364745 \ No newline at end of file +364771 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 7c56236a2..42f3e8cd0 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -373268 \ No newline at end of file +373294 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index 822d688b2..1423455fa 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -372491 \ No newline at end of file +372529 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index ccfdb51fc..8521dbe72 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317617 \ No newline at end of file +317643 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index 9f9a6b773..afd46945e 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318287 \ No newline at end of file +318313 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index ccc454ddc..ab86eec55 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243856 \ No newline at end of file +243882 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 23648cc90..301b01af6 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -419060 \ No newline at end of file +419098 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index cedd06147..2610fc39f 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323648 \ No newline at end of file +323674 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index cf0292c96..57b8c920a 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -420170 \ No newline at end of file +420196 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index 549b6841d..3171f9750 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419228 \ No newline at end of file +419266 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index b51b3f660..124c6a1eb 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455975 \ No newline at end of file +456001 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index 0528d9874..9c58b9822 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7037 \ No newline at end of file +7063 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index 2a724576f..a3d9bfc1c 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -115708 \ No newline at end of file +115753 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index 3afc230ee..f637e5fe3 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -116029 \ No newline at end of file +116070 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index 94d611dee..f2476e2f5 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -124847 \ No newline at end of file +124888 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index 01a3e91e0..690eed057 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -130570 \ No newline at end of file +130611 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index 9620022fb..beee482b3 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -185411 \ No newline at end of file +185452 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index a7d527920..36622c521 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -170549 \ No newline at end of file +170594 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index aecf0666e..c55ea7d8f 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -240255 \ No newline at end of file +240296 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index 3ea0d0bf6..0758ae8f8 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -225393 \ No newline at end of file +225438 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index 63e482c1a..2fb484c41 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -129601 \ No newline at end of file +129642 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index d9151a237..a86696807 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -114739 \ No newline at end of file +114784 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index e039a25da..d8315aecd 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -115028 \ No newline at end of file +115069 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index 5e64389a5..0b08fa2fc 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -121971 \ No newline at end of file +122016 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index 4e7b78af5..b1d78c0e5 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -117093 \ No newline at end of file +117134 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index 59f0e6917..6202f067e 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -125911 \ No newline at end of file +125952 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 5e7fe01cd..1c782b16c 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -129856 \ No newline at end of file +129897 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index 87c5e7044..ff527d262 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -183759 \ No newline at end of file +183800 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index d15e6c894..75b2b47c6 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -175874 \ No newline at end of file +175919 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index 5df7f78e5..1ed797a75 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -237693 \ No newline at end of file +237734 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index 72b7efd5e..209ae5058 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -229808 \ No newline at end of file +229853 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 810acacb8..50495b292 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -217048 \ No newline at end of file +217089 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index 1fb8a61af..178defb90 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -128884 \ No newline at end of file +128925 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index cd9382b3d..c7076c469 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -120999 \ No newline at end of file +121044 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index a14cba0fa..a21b83f78 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -116195 \ No newline at end of file +116236 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index d5721e346..ca3012ee3 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -363,7 +363,7 @@ contract PositionManager is if (currencyDelta < 0) { // Casting is safe due to limits on the total supply of a pool _settle(currency, caller, uint256(-currencyDelta)); - } else if (currencyDelta > 0) { + } else { _take(currency, caller, uint256(currencyDelta)); } } diff --git a/src/base/DeltaResolver.sol b/src/base/DeltaResolver.sol index ccde3d4d5..57261bd8e 100644 --- a/src/base/DeltaResolver.sol +++ b/src/base/DeltaResolver.sol @@ -21,7 +21,9 @@ abstract contract DeltaResolver is ImmutableState { /// @param currency Currency to take /// @param recipient Address to receive the currency /// @param amount Amount to take + /// @dev Returns early if the amount is 0 function _take(Currency currency, address recipient, uint256 amount) internal { + if (amount == 0) return; poolManager.take(currency, recipient, amount); } @@ -30,7 +32,9 @@ abstract contract DeltaResolver is ImmutableState { /// @param currency Currency to settle /// @param payer Address of the payer /// @param amount Amount to send + /// @dev Returns early if the amount is 0 function _settle(Currency currency, address payer, uint256 amount) internal { + if (amount == 0) return; if (currency.isAddressZero()) { poolManager.settle{value: amount}(); } else { From 01ddf3ac186dcdf2ced3f88a7114e2323f4521da Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Thu, 24 Oct 2024 21:49:52 +0100 Subject: [PATCH 08/31] Add wrap, unwrap functionality (#369) * add wrap unwrap * checkpoint * fix addresses * remove test * eth-weth update * comments * add decode fuzz test * fmt * wrap tests * unwrap tests * use amount * final comments * update comment * test naming update --------- Co-authored-by: dianakocsis Co-authored-by: marktoda --- .../PositionManager_burn_empty.snap | 2 +- .../PositionManager_burn_empty_native.snap | 2 +- ...anager_burn_nonEmpty_native_withClose.snap | 2 +- ...ger_burn_nonEmpty_native_withTakePair.snap | 2 +- ...sitionManager_burn_nonEmpty_withClose.snap | 2 +- ...ionManager_burn_nonEmpty_withTakePair.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- ...onManager_decreaseLiquidity_withClose.snap | 2 +- ...anager_decreaseLiquidity_withTakePair.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- .../PositionManager_decrease_take_take.snap | 2 +- ...ger_increaseLiquidity_erc20_withClose.snap | 2 +- ...ncreaseLiquidity_erc20_withSettlePair.snap | 2 +- ...itionManager_increaseLiquidity_native.snap | 2 +- ...crease_autocompoundExactUnclaimedFees.snap | 2 +- ...increase_autocompoundExcessFeesCredit.snap | 2 +- ...ger_increase_autocompound_clearExcess.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- ...anager_mint_nativeWithSweep_withClose.snap | 2 +- ...r_mint_nativeWithSweep_withSettlePair.snap | 2 +- .../PositionManager_mint_onSameTickLower.snap | 2 +- .../PositionManager_mint_onSameTickUpper.snap | 2 +- .../PositionManager_mint_sameRange.snap | 2 +- ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...anager_mint_warmedPool_differentRange.snap | 2 +- .../PositionManager_mint_withClose.snap | 2 +- .../PositionManager_mint_withSettlePair.snap | 2 +- ...tionManager_multicall_initialize_mint.snap | 2 +- .../PositionManager_permit_twice.snap | 2 +- .../PositionManager_unsubscribe.snap | 2 +- script/DeployPosm.s.sol | 4 +- src/PositionManager.sol | 19 +- src/base/DeltaResolver.sol | 28 ++ src/base/NativeWrapper.sol | 34 ++ src/interfaces/external/IWETH9.sol | 13 + src/libraries/Actions.sol | 6 +- src/libraries/CalldataDecoder.sol | 7 + test/PositionDescriptor.t.sol | 2 +- test/libraries/CalldataDecoder.t.sol | 7 + test/mocks/MockCalldataDecoder.sol | 4 + .../PositionManager.modifyLiquidities.t.sol | 377 ++++++++++++++++++ test/shared/PosmTestSetup.sol | 24 +- 48 files changed, 553 insertions(+), 44 deletions(-) create mode 100644 src/base/NativeWrapper.sol create mode 100644 src/interfaces/external/IWETH9.sol diff --git a/.forge-snapshots/PositionManager_burn_empty.snap b/.forge-snapshots/PositionManager_burn_empty.snap index 0e85ca4a1..949dd08ae 100644 --- a/.forge-snapshots/PositionManager_burn_empty.snap +++ b/.forge-snapshots/PositionManager_burn_empty.snap @@ -1 +1 @@ -50446 \ No newline at end of file +50481 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty_native.snap b/.forge-snapshots/PositionManager_burn_empty_native.snap index 0e85ca4a1..949dd08ae 100644 --- a/.forge-snapshots/PositionManager_burn_empty_native.snap +++ b/.forge-snapshots/PositionManager_burn_empty_native.snap @@ -1 +1 @@ -50446 \ No newline at end of file +50481 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 5ad0da0a9..c3bc574ea 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125624 \ No newline at end of file +125659 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 030a3e444..e33592341 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125106 \ No newline at end of file +125141 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 5c745f939..54b474eb3 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132486 \ No newline at end of file +132521 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 9bb02f5c0..8bbf4b071 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -131968 \ No newline at end of file +132004 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 1396b4fbf..85355e350 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146344 \ No newline at end of file +146388 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index ecf3a285b..1a7e51e0a 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -154922 \ No newline at end of file +154966 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index ecf3a285b..1a7e51e0a 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -154922 \ No newline at end of file +154966 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 22d50eafd..e1639e55e 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154287 \ No newline at end of file +154331 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index 1a2e6b277..4db04993e 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -112020 \ No newline at end of file +112056 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index f52a7effa..0d683313e 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119803 \ No newline at end of file +119847 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 11fddf420..8e8a2c64b 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119168 \ No newline at end of file +119212 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 95a005d38..99fb79393 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135283 \ No newline at end of file +135318 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 588100f58..ef0e4aafa 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128420 \ No newline at end of file +128456 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index d467feba8..651fb4408 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132490 \ No newline at end of file +132534 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index 0b9cd698f..84049ea50 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120423 \ No newline at end of file +120467 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index 974deb9ef..f237a3eac 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -159083 \ No newline at end of file +159127 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index 1cafe695d..7055ac3b2 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -158035 \ No newline at end of file +158079 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 7647c22bb..b4db755ef 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -140898 \ No newline at end of file +140942 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index 770899b46..b6d9ed62f 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -136359 \ No newline at end of file +136403 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index 76da88df2..40fa41627 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177414 \ No newline at end of file +177458 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 21e55c88e..7becdebb3 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148040 \ No newline at end of file +148084 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index fef9a7fb9..0c393410e 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -364771 \ No newline at end of file +364815 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 42f3e8cd0..1ab4ab47f 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -373294 \ No newline at end of file +373334 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index 1423455fa..64d0360e5 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -372529 \ No newline at end of file +372569 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 8521dbe72..b941b6e08 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317643 \ No newline at end of file +317687 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index afd46945e..d9ef5ca04 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318313 \ No newline at end of file +318357 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index ab86eec55..91240b8cd 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243882 \ No newline at end of file +243926 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 301b01af6..79e218a84 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -419098 \ No newline at end of file +419134 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index 2610fc39f..f8eb13001 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323674 \ No newline at end of file +323718 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index 57b8c920a..b7e3ad993 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -420196 \ No newline at end of file +420240 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index 3171f9750..eedfce3e3 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419266 \ No newline at end of file +419310 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 124c6a1eb..66493802d 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -456001 \ No newline at end of file +456088 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_permit_twice.snap b/.forge-snapshots/PositionManager_permit_twice.snap index 379f96111..d650ccbd7 100644 --- a/.forge-snapshots/PositionManager_permit_twice.snap +++ b/.forge-snapshots/PositionManager_permit_twice.snap @@ -1 +1 @@ -44852 \ No newline at end of file +44876 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_unsubscribe.snap b/.forge-snapshots/PositionManager_unsubscribe.snap index 0151c604d..c0f309cf8 100644 --- a/.forge-snapshots/PositionManager_unsubscribe.snap +++ b/.forge-snapshots/PositionManager_unsubscribe.snap @@ -1 +1 @@ -59238 \ No newline at end of file +59260 \ No newline at end of file diff --git a/script/DeployPosm.s.sol b/script/DeployPosm.s.sol index 5bbb6184c..e3a20758d 100644 --- a/script/DeployPosm.s.sol +++ b/script/DeployPosm.s.sol @@ -10,6 +10,7 @@ import {PositionManager} from "../src/PositionManager.sol"; import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; import {IPositionDescriptor} from "../src/interfaces/IPositionDescriptor.sol"; import {PositionDescriptor} from "../src/PositionDescriptor.sol"; +import {IWETH9} from "../src/interfaces/external/IWETH9.sol"; contract DeployPosmTest is Script { function setUp() public {} @@ -30,7 +31,8 @@ contract DeployPosmTest is Script { IPoolManager(poolManager), IAllowanceTransfer(permit2), unsubscribeGasLimit, - IPositionDescriptor(address(positionDescriptor)) + IPositionDescriptor(address(positionDescriptor)), + IWETH9(wrappedNative) ); console2.log("PositionManager", address(posm)); diff --git a/src/PositionManager.sol b/src/PositionManager.sol index ca3012ee3..0a67a9d53 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.26; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; -import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; +import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {Position} from "@uniswap/v4-core/src/libraries/Position.sol"; @@ -26,6 +26,8 @@ import {CalldataDecoder} from "./libraries/CalldataDecoder.sol"; import {Permit2Forwarder} from "./base/Permit2Forwarder.sol"; import {SlippageCheck} from "./libraries/SlippageCheck.sol"; import {PositionInfo, PositionInfoLibrary} from "./libraries/PositionInfoLibrary.sol"; +import {NativeWrapper} from "./base/NativeWrapper.sol"; +import {IWETH9} from "./interfaces/external/IWETH9.sol"; // 444444444 // 444444444444 444444 @@ -102,7 +104,8 @@ contract PositionManager is ReentrancyLock, BaseActionsRouter, Notifier, - Permit2Forwarder + Permit2Forwarder, + NativeWrapper { using PoolIdLibrary for PoolKey; using StateLibrary for IPoolManager; @@ -126,12 +129,14 @@ contract PositionManager is IPoolManager _poolManager, IAllowanceTransfer _permit2, uint256 _unsubscribeGasLimit, - IPositionDescriptor _tokenDescriptor + IPositionDescriptor _tokenDescriptor, + IWETH9 _weth9 ) BaseActionsRouter(_poolManager) Permit2Forwarder(_permit2) ERC721Permit_v4("Uniswap v4 Positions NFT", "UNI-V4-POSM") Notifier(_unsubscribeGasLimit) + NativeWrapper(_weth9) { tokenDescriptor = _tokenDescriptor; } @@ -242,6 +247,14 @@ contract PositionManager is (Currency currency, address to) = params.decodeCurrencyAndAddress(); _sweep(currency, _mapRecipient(to)); return; + } else if (action == Actions.WRAP) { + uint256 amount = params.decodeUint256(); + _wrap(_mapWrapUnwrapAmount(CurrencyLibrary.ADDRESS_ZERO, amount, Currency.wrap(address(WETH9)))); + return; + } else if (action == Actions.UNWRAP) { + uint256 amount = params.decodeUint256(); + _unwrap(_mapWrapUnwrapAmount(Currency.wrap(address(WETH9)), amount, CurrencyLibrary.ADDRESS_ZERO)); + return; } } revert UnsupportedAction(action); diff --git a/src/base/DeltaResolver.sol b/src/base/DeltaResolver.sol index 57261bd8e..85fd12124 100644 --- a/src/base/DeltaResolver.sol +++ b/src/base/DeltaResolver.sol @@ -16,6 +16,8 @@ abstract contract DeltaResolver is ImmutableState { error DeltaNotPositive(Currency currency); /// @notice Emitted trying to take a negative delta. error DeltaNotNegative(Currency currency); + /// @notice Emitted when the contract does not have enough balance to wrap or unwrap. + error InsufficientBalance(); /// @notice Take an amount of currency out of the PoolManager /// @param currency Currency to take @@ -91,4 +93,30 @@ abstract contract DeltaResolver is ImmutableState { return amount; } } + + /// @notice Calculates the sanitized amount before wrapping/unwrapping. + /// @param inputCurrency The currency, either native or wrapped native, that this contract holds + /// @param amount The amount to wrap or unwrap. Can be CONTRACT_BALANCE, OPEN_DELTA or a specific amount + /// @param outputCurrency The currency after the wrap/unwrap that the user may owe a balance in on the poolManager + function _mapWrapUnwrapAmount(Currency inputCurrency, uint256 amount, Currency outputCurrency) + internal + view + returns (uint256) + { + // if wrapping, the balance in this contract is in ETH + // if unwrapping, the balance in this contract is in WETH + uint256 balance = inputCurrency.balanceOf(address(this)); + if (amount == ActionConstants.CONTRACT_BALANCE) { + // return early to avoid unnecessary balance check + return balance; + } + if (amount == ActionConstants.OPEN_DELTA) { + // if wrapping, the open currency on the PoolManager is WETH. + // if unwrapping, the open currency on the PoolManager is ETH. + // note that we use the DEBT amount. Positive deltas can be taken and then wrapped. + amount = _getFullDebt(outputCurrency); + } + if (amount > balance) revert InsufficientBalance(); + return amount; + } } diff --git a/src/base/NativeWrapper.sol b/src/base/NativeWrapper.sol new file mode 100644 index 000000000..ef6a3f2a2 --- /dev/null +++ b/src/base/NativeWrapper.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {IWETH9} from "../interfaces/external/IWETH9.sol"; +import {ActionConstants} from "../libraries/ActionConstants.sol"; +import {ImmutableState} from "./ImmutableState.sol"; + +/// @title Native Wrapper +/// @notice Used for wrapping and unwrapping native +abstract contract NativeWrapper is ImmutableState { + /// @notice The address for WETH9 + IWETH9 public immutable WETH9; + + /// @notice Thrown when an unexpected address sends ETH to this contract + error InvalidEthSender(); + + constructor(IWETH9 _weth9) { + WETH9 = _weth9; + } + + /// @dev The amount should already be <= the current balance in this contract. + function _wrap(uint256 amount) internal { + if (amount > 0) WETH9.deposit{value: amount}(); + } + + /// @dev The amount should already be <= the current balance in this contract. + function _unwrap(uint256 amount) internal { + if (amount > 0) WETH9.withdraw(amount); + } + + receive() external payable { + if (msg.sender != address(WETH9) && msg.sender != address(poolManager)) revert InvalidEthSender(); + } +} diff --git a/src/interfaces/external/IWETH9.sol b/src/interfaces/external/IWETH9.sol new file mode 100644 index 000000000..37c3be8ea --- /dev/null +++ b/src/interfaces/external/IWETH9.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/// @title Interface for WETH9 +interface IWETH9 is IERC20 { + /// @notice Deposit ether to get wrapped ether + function deposit() external payable; + + /// @notice Withdraw wrapped ether to get ether + function withdraw(uint256) external; +} diff --git a/src/libraries/Actions.sol b/src/libraries/Actions.sol index 49d3e04f1..16a8ce8c9 100644 --- a/src/libraries/Actions.sol +++ b/src/libraries/Actions.sol @@ -33,8 +33,10 @@ library Actions { uint256 constant CLOSE_CURRENCY = 0x17; uint256 constant CLEAR_OR_TAKE = 0x18; uint256 constant SWEEP = 0x19; + uint256 constant WRAP = 0x20; + uint256 constant UNWRAP = 0x21; // minting/burning 6909s to close deltas - uint256 constant MINT_6909 = 0x20; - uint256 constant BURN_6909 = 0x21; + uint256 constant MINT_6909 = 0x22; + uint256 constant BURN_6909 = 0x23; } diff --git a/src/libraries/CalldataDecoder.sol b/src/libraries/CalldataDecoder.sol index 00cf6e33e..a14f3a34e 100644 --- a/src/libraries/CalldataDecoder.sol +++ b/src/libraries/CalldataDecoder.sol @@ -241,6 +241,13 @@ library CalldataDecoder { } } + /// @dev equivalent to: abi.decode(params, (uint256)) in calldata + function decodeUint256(bytes calldata params) internal pure returns (uint256 amount) { + assembly ("memory-safe") { + amount := calldataload(params.offset) + } + } + /// @dev equivalent to: abi.decode(params, (Currency, uint256, bool)) in calldata function decodeCurrencyUint256AndBool(bytes calldata params) internal diff --git a/test/PositionDescriptor.t.sol b/test/PositionDescriptor.t.sol index 87835fcbd..bc991e7bf 100644 --- a/test/PositionDescriptor.t.sol +++ b/test/PositionDescriptor.t.sol @@ -122,7 +122,7 @@ contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot { assertEq(token.name, "Uniswap - 0.3% - TEST/TEST - 1.0060<>1.0121"); assertEq( token.description, - unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\nTEST Address: 0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\nTEST Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nHook Address: No Hook\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." + unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nTEST Address: 0xf62849f9a0b5bf2913b396098f7c7019b51a820a\nTEST Address: 0xc7183455a4c133ae270771860664b6b7ec320bb1\nHook Address: No Hook\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." ); } diff --git a/test/libraries/CalldataDecoder.t.sol b/test/libraries/CalldataDecoder.t.sol index c41122ebc..de1006678 100644 --- a/test/libraries/CalldataDecoder.t.sol +++ b/test/libraries/CalldataDecoder.t.sol @@ -232,6 +232,13 @@ contract CalldataDecoderTest is Test { assertEq(amount, _amount); } + function test_fuzz_decodeUint256(uint256 _amount) public { + bytes memory params = abi.encode(_amount); + uint256 amount = decoder.decodeUint256(params); + + assertEq(amount, _amount); + } + function _assertEq(PathKey[] memory path1, PathKey[] memory path2) internal pure { assertEq(path1.length, path2.length); for (uint256 i = 0; i < path1.length; i++) { diff --git a/test/mocks/MockCalldataDecoder.sol b/test/mocks/MockCalldataDecoder.sol index e25d8ec71..c61db4afa 100644 --- a/test/mocks/MockCalldataDecoder.sol +++ b/test/mocks/MockCalldataDecoder.sol @@ -136,4 +136,8 @@ contract MockCalldataDecoder { { return params.decodeCurrencyAddressAndUint256(); } + + function decodeUint256(bytes calldata params) external pure returns (uint256) { + return params.decodeUint256(); + } } diff --git a/test/position-managers/PositionManager.modifyLiquidities.t.sol b/test/position-managers/PositionManager.modifyLiquidities.t.sol index e71c121fe..c805dd271 100644 --- a/test/position-managers/PositionManager.modifyLiquidities.t.sol +++ b/test/position-managers/PositionManager.modifyLiquidities.t.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.24; import "forge-std/Test.sol"; +import {IERC20} from "forge-std/interfaces/IERC20.sol"; + import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; @@ -13,8 +15,11 @@ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; import {Position} from "@uniswap/v4-core/src/libraries/Position.sol"; import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; +import {LiquidityAmounts} from "@uniswap/v4-core/test/utils/LiquidityAmounts.sol"; +import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; import {IPositionManager} from "../../src/interfaces/IPositionManager.sol"; +import {IMulticall_v4} from "../../src/interfaces/IMulticall_v4.sol"; import {ReentrancyLock} from "../../src/base/ReentrancyLock.sol"; import {Actions} from "../../src/libraries/Actions.sol"; import {PositionManager} from "../../src/PositionManager.sol"; @@ -23,10 +28,16 @@ import {PositionConfig} from "../shared/PositionConfig.sol"; import {LiquidityFuzzers} from "../shared/fuzz/LiquidityFuzzers.sol"; import {Planner, Plan} from "../shared/Planner.sol"; import {PosmTestSetup} from "../shared/PosmTestSetup.sol"; +import {ActionConstants} from "../../src/libraries/ActionConstants.sol"; +import {Planner, Plan} from "../shared/Planner.sol"; +import {DeltaResolver} from "../../src/base/DeltaResolver.sol"; + +import "forge-std/console2.sol"; contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityFuzzers { using StateLibrary for IPoolManager; using PoolIdLibrary for PoolKey; + using Planner for Plan; PoolId poolId; address alice; @@ -34,6 +45,8 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF address bob; PositionConfig config; + PositionConfig wethConfig; + PositionConfig nativeConfig; function setUp() public { (alice, alicePK) = makeAddrAndKey("ALICE"); @@ -54,8 +67,23 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF seedBalance(address(hookModifyLiquidities)); (key, poolId) = initPool(currency0, currency1, IHooks(hookModifyLiquidities), 3000, SQRT_PRICE_1_1); + initWethPool(currency1, IHooks(address(0)), 3000, SQRT_PRICE_1_1); + + seedWeth(address(this)); + approvePosmCurrency(Currency.wrap(address(_WETH9))); + + nativeKey = PoolKey(CurrencyLibrary.ADDRESS_ZERO, currency1, 3000, 60, IHooks(address(0))); + manager.initialize(nativeKey, SQRT_PRICE_1_1); config = PositionConfig({poolKey: key, tickLower: -60, tickUpper: 60}); + wethConfig = PositionConfig({ + poolKey: wethKey, + tickLower: TickMath.minUsableTick(wethKey.tickSpacing), + tickUpper: TickMath.maxUsableTick(wethKey.tickSpacing) + }); + nativeConfig = PositionConfig({poolKey: nativeKey, tickLower: -120, tickUpper: 120}); + + vm.deal(address(this), 1000 ether); } /// @dev minting liquidity without approval is allowable @@ -308,4 +336,353 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF ); lpm.modifyLiquidities(calls, _deadline); } + + function test_wrap_mint_usingContractBalance() public { + // weth-currency1 pool initialized as wethKey + // input: eth, currency1 + // modifyLiquidities call to mint liquidity weth and currency1 + // 1 _wrap with contract balance + // 2 _mint + // 3 _settle weth where the payer is the contract + // 4 _close currency1, payer is caller + // 5 _sweep weth since eth was entirely wrapped + + uint256 balanceEthBefore = address(this).balance; + uint256 balance1Before = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + uint256 tokenId = lpm.nextTokenId(); + + uint128 liquidityAmount = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(wethConfig.tickLower), + TickMath.getSqrtPriceAtTick(wethConfig.tickUpper), + 100 ether, + 100 ether + ); + + Plan memory planner = Planner.init(); + planner.add(Actions.WRAP, abi.encode(ActionConstants.CONTRACT_BALANCE)); + planner.add( + Actions.MINT_POSITION, + abi.encode( + wethConfig.poolKey, + wethConfig.tickLower, + wethConfig.tickUpper, + liquidityAmount, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + + // weth9 payer is the contract + planner.add(Actions.SETTLE, abi.encode(address(_WETH9), ActionConstants.OPEN_DELTA, false)); + // other currency can close normally + planner.add(Actions.CLOSE_CURRENCY, abi.encode(currency1)); + // we wrapped the full contract balance so we sweep back in the wrapped currency + planner.add(Actions.SWEEP, abi.encode(address(_WETH9), ActionConstants.MSG_SENDER)); + bytes memory actions = planner.encode(); + + // Overestimate eth amount. + lpm.modifyLiquidities{value: 102 ether}(actions, _deadline); + + uint256 balanceEthAfter = address(this).balance; + uint256 balance1After = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + + // The full eth amount was "spent" because some was wrapped into weth and refunded. + assertApproxEqAbs(balanceEthBefore - balanceEthAfter, 102 ether, 1 wei); + assertApproxEqAbs(balance1Before - balance1After, 100 ether, 1 wei); + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), liquidityAmount); + assertEq(_WETH9.balanceOf(address(lpm)), 0); + assertEq(address(lpm).balance, 0); + } + + function test_wrap_mint_openDelta() public { + // weth-currency1 pool initialized as wethKey + // input: eth, currency1 + // modifyLiquidities call to mint liquidity weth and currency1 + // 1 _mint + // 2 _wrap with open delta + // 3 _settle weth where the payer is the contract + // 4 _close currency1, payer is caller + // 5 _sweep eth since only the open delta amount was wrapped + + uint256 balanceEthBefore = address(this).balance; + uint256 balance1Before = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + uint256 tokenId = lpm.nextTokenId(); + + uint128 liquidityAmount = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(wethConfig.tickLower), + TickMath.getSqrtPriceAtTick(wethConfig.tickUpper), + 100 ether, + 100 ether + ); + + Plan memory planner = Planner.init(); + + planner.add( + Actions.MINT_POSITION, + abi.encode( + wethConfig.poolKey, + wethConfig.tickLower, + wethConfig.tickUpper, + liquidityAmount, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + + planner.add(Actions.WRAP, abi.encode(ActionConstants.OPEN_DELTA)); + + // weth9 payer is the contract + planner.add(Actions.SETTLE, abi.encode(address(_WETH9), ActionConstants.OPEN_DELTA, false)); + // other currency can close normally + planner.add(Actions.CLOSE_CURRENCY, abi.encode(currency1)); + // we wrapped the open delta balance so we sweep back in the native currency + planner.add(Actions.SWEEP, abi.encode(CurrencyLibrary.ADDRESS_ZERO, ActionConstants.MSG_SENDER)); + bytes memory actions = planner.encode(); + + lpm.modifyLiquidities{value: 102 ether}(actions, _deadline); + + uint256 balanceEthAfter = address(this).balance; + uint256 balance1After = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + + // Approx 100 eth was spent because the extra 2 were refunded. + assertApproxEqAbs(balanceEthBefore - balanceEthAfter, 100 ether, 1 wei); + assertApproxEqAbs(balance1Before - balance1After, 100 ether, 1 wei); + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), liquidityAmount); + assertEq(_WETH9.balanceOf(address(lpm)), 0); + assertEq(address(lpm).balance, 0); + } + + function test_wrap_mint_usingExactAmount() public { + // weth-currency1 pool initialized as wethKey + // input: eth, currency1 + // modifyLiquidities call to mint liquidity weth and currency1 + // 1 _wrap with an amount + // 2 _mint + // 3 _settle weth where the payer is the contract + // 4 _close currency1, payer is caller + // 5 _sweep weth since eth was entirely wrapped + + uint256 balanceEthBefore = address(this).balance; + uint256 balance1Before = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + uint256 tokenId = lpm.nextTokenId(); + + uint128 liquidityAmount = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(wethConfig.tickLower), + TickMath.getSqrtPriceAtTick(wethConfig.tickUpper), + 100 ether, + 100 ether + ); + + Plan memory planner = Planner.init(); + planner.add(Actions.WRAP, abi.encode(100 ether)); + planner.add( + Actions.MINT_POSITION, + abi.encode( + wethConfig.poolKey, + wethConfig.tickLower, + wethConfig.tickUpper, + liquidityAmount, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + + // weth9 payer is the contract + planner.add(Actions.SETTLE, abi.encode(address(_WETH9), ActionConstants.OPEN_DELTA, false)); + // other currency can close normally + planner.add(Actions.CLOSE_CURRENCY, abi.encode(currency1)); + // we wrapped all 100 eth so we sweep back in the wrapped currency for safety measure + planner.add(Actions.SWEEP, abi.encode(address(_WETH9), ActionConstants.MSG_SENDER)); + bytes memory actions = planner.encode(); + + lpm.modifyLiquidities{value: 100 ether}(actions, _deadline); + + uint256 balanceEthAfter = address(this).balance; + uint256 balance1After = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + + // The full eth amount was "spent" because some was wrapped into weth and refunded. + assertApproxEqAbs(balanceEthBefore - balanceEthAfter, 100 ether, 1 wei); + assertApproxEqAbs(balance1Before - balance1After, 100 ether, 1 wei); + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), liquidityAmount); + assertEq(_WETH9.balanceOf(address(lpm)), 0); + assertEq(address(lpm).balance, 0); + } + + function test_wrap_mint_revertsInsufficientBalance() public { + // 1 _wrap with more eth than is sent in + + Plan memory planner = Planner.init(); + // Wrap more eth than what is sent in. + planner.add(Actions.WRAP, abi.encode(101 ether)); + + bytes memory actions = planner.encode(); + + vm.expectRevert(DeltaResolver.InsufficientBalance.selector); + lpm.modifyLiquidities{value: 100 ether}(actions, _deadline); + } + + function test_unwrap_usingContractBalance() public { + // weth-currency1 pool + // output: eth, currency1 + // modifyLiquidities call to mint liquidity weth and currency1 + // 1 _burn + // 2 _take where the weth is sent to the lpm contract + // 3 _take where currency1 is sent to the msg sender + // 4 _unwrap using contract balance + // 5 _sweep where eth is sent to msg sender + uint256 tokenId = lpm.nextTokenId(); + + uint128 liquidityAmount = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(wethConfig.tickLower), + TickMath.getSqrtPriceAtTick(wethConfig.tickUpper), + 100 ether, + 100 ether + ); + + bytes memory actions = getMintEncoded(wethConfig, liquidityAmount, address(this), ZERO_BYTES); + lpm.modifyLiquidities(actions, _deadline); + + assertEq(lpm.getPositionLiquidity(tokenId), liquidityAmount); + + uint256 balanceEthBefore = address(this).balance; + uint256 balance1Before = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + + Plan memory planner = Planner.init(); + planner.add( + Actions.BURN_POSITION, abi.encode(tokenId, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) + ); + // take the weth to the position manager to be unwrapped + planner.add(Actions.TAKE, abi.encode(address(_WETH9), ActionConstants.ADDRESS_THIS, ActionConstants.OPEN_DELTA)); + planner.add( + Actions.TAKE, + abi.encode(address(Currency.unwrap(currency1)), ActionConstants.MSG_SENDER, ActionConstants.OPEN_DELTA) + ); + planner.add(Actions.UNWRAP, abi.encode(ActionConstants.CONTRACT_BALANCE)); + planner.add(Actions.SWEEP, abi.encode(CurrencyLibrary.ADDRESS_ZERO, ActionConstants.MSG_SENDER)); + + actions = planner.encode(); + + lpm.modifyLiquidities(actions, _deadline); + + uint256 balanceEthAfter = address(this).balance; + uint256 balance1After = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + + assertApproxEqAbs(balanceEthAfter - balanceEthBefore, 100 ether, 1 wei); + assertApproxEqAbs(balance1After - balance1Before, 100 ether, 1 wei); + assertEq(lpm.getPositionLiquidity(tokenId), 0); + assertEq(_WETH9.balanceOf(address(lpm)), 0); + assertEq(address(lpm).balance, 0); + } + + function test_unwrap_openDelta_reinvest() public { + // weth-currency1 pool rolls half to eth-currency1 pool + // output: eth, currency1 + // modifyLiquidities call to mint liquidity weth and currency1 + // 1 _burn (weth-currency1) + // 2 _take where the weth is sent to the lpm contract + // 4 _mint to an eth pool + // 4 _unwrap using open delta (pool managers ETH balance) + // 3 _take where leftover currency1 is sent to the msg sender + // 5 _settle eth open delta + // 5 _sweep leftover weth + + uint256 tokenId = lpm.nextTokenId(); + + uint128 liquidityAmount = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(wethConfig.tickLower), + TickMath.getSqrtPriceAtTick(wethConfig.tickUpper), + 100 ether, + 100 ether + ); + + bytes memory actions = getMintEncoded(wethConfig, liquidityAmount, address(this), ZERO_BYTES); + lpm.modifyLiquidities(actions, _deadline); + + assertEq(lpm.getPositionLiquidity(tokenId), liquidityAmount); + + uint256 balanceEthBefore = address(this).balance; + uint256 balance1Before = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + uint256 balanceWethBefore = _WETH9.balanceOf(address(this)); + + uint128 newLiquidityAmount = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(nativeConfig.tickLower), + TickMath.getSqrtPriceAtTick(nativeConfig.tickUpper), + 50 ether, + 50 ether + ); + + Plan memory planner = Planner.init(); + planner.add( + Actions.BURN_POSITION, abi.encode(tokenId, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) + ); + // take the weth to the position manager to be unwrapped + planner.add(Actions.TAKE, abi.encode(address(_WETH9), ActionConstants.ADDRESS_THIS, ActionConstants.OPEN_DELTA)); + planner.add( + Actions.MINT_POSITION, + abi.encode( + nativeConfig.poolKey, + nativeConfig.tickLower, + nativeConfig.tickUpper, + newLiquidityAmount, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + planner.add(Actions.UNWRAP, abi.encode(ActionConstants.OPEN_DELTA)); + // pay the eth + planner.add(Actions.SETTLE, abi.encode(CurrencyLibrary.ADDRESS_ZERO, ActionConstants.OPEN_DELTA, false)); + // take the leftover currency1 + planner.add( + Actions.TAKE, + abi.encode(address(Currency.unwrap(currency1)), ActionConstants.MSG_SENDER, ActionConstants.OPEN_DELTA) + ); + planner.add(Actions.SWEEP, abi.encode(address(_WETH9), ActionConstants.MSG_SENDER)); + + actions = planner.encode(); + + lpm.modifyLiquidities(actions, _deadline); + + uint256 balanceEthAfter = address(this).balance; + uint256 balance1After = IERC20(Currency.unwrap(currency1)).balanceOf(address(this)); + uint256 balanceWethAfter = _WETH9.balanceOf(address(this)); + + // Eth balance should not change. + assertEq(balanceEthAfter, balanceEthBefore); + // Only half of the original liquidity was reinvested. + assertApproxEqAbs(balance1After - balance1Before, 50 ether, 1 wei); + assertApproxEqAbs(balanceWethAfter - balanceWethBefore, 50 ether, 1 wei); + assertEq(lpm.getPositionLiquidity(tokenId), 0); + assertEq(_WETH9.balanceOf(address(lpm)), 0); + assertEq(address(lpm).balance, 0); + } + + function test_unwrap_revertsInsufficientBalance() public { + // 1 _unwrap with more than is in the contract + + Plan memory planner = Planner.init(); + // unwraps more eth than what is in the contract + planner.add(Actions.UNWRAP, abi.encode(101 ether)); + + bytes memory actions = planner.encode(); + + vm.expectRevert(DeltaResolver.InsufficientBalance.selector); + lpm.modifyLiquidities(actions, _deadline); + } } diff --git a/test/shared/PosmTestSetup.sol b/test/shared/PosmTestSetup.sol index 0a79edd17..22e09ed9f 100644 --- a/test/shared/PosmTestSetup.sol +++ b/test/shared/PosmTestSetup.sol @@ -17,6 +17,12 @@ import {HookSavesDelta} from "./HookSavesDelta.sol"; import {HookModifyLiquidities} from "./HookModifyLiquidities.sol"; import {PositionDescriptor} from "../../src/PositionDescriptor.sol"; import {ERC721PermitHash} from "../../src/libraries/ERC721PermitHash.sol"; +import {IWETH9} from "../../src/interfaces/external/IWETH9.sol"; +import {WETH} from "solmate/src/tokens/WETH.sol"; +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; +import {SortTokens} from "@uniswap/v4-core/test/utils/SortTokens.sol"; +import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; +import {PositionConfig} from "../shared/PositionConfig.sol"; /// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic liquidity operations on posm. contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { @@ -26,6 +32,7 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { PositionDescriptor public positionDescriptor; HookSavesDelta hook; address hookAddr = address(uint160(Hooks.AFTER_ADD_LIQUIDITY_FLAG | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG)); + IWETH9 public _WETH9 = IWETH9(address(new WETH())); HookModifyLiquidities hookModifyLiquidities; address hookModifyLiquiditiesAddr = address( @@ -35,6 +42,8 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { ) ); + PoolKey wethKey; + function deployPosmHookSavesDelta() public { HookSavesDelta impl = new HookSavesDelta(); vm.etch(hookAddr, address(impl).code); @@ -60,7 +69,7 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { // We use deployPermit2() to prevent having to use via-ir in this repository. permit2 = IAllowanceTransfer(deployPermit2()); positionDescriptor = new PositionDescriptor(poolManager, 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, "ETH"); - lpm = new PositionManager(poolManager, permit2, 100_000, positionDescriptor); + lpm = new PositionManager(poolManager, permit2, 100_000, positionDescriptor, _WETH9); } function seedBalance(address to) internal { @@ -88,6 +97,19 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { vm.stopPrank(); } + function seedWeth(address to) internal { + vm.deal(address(this), STARTING_USER_BALANCE); + _WETH9.deposit{value: STARTING_USER_BALANCE}(); + _WETH9.transfer(to, STARTING_USER_BALANCE); + } + + function initWethPool(Currency currencyB, IHooks hooks, uint24 fee, uint160 sqrtPriceX96) internal { + (Currency _currency0, Currency _currency1) = + SortTokens.sort(MockERC20(address(_WETH9)), MockERC20(Currency.unwrap(currencyB))); + + (wethKey,) = initPool(_currency0, _currency1, hooks, fee, sqrtPriceX96); + } + function permit(uint256 privateKey, uint256 tokenId, address operator, uint256 nonce) internal { bytes32 digest = getDigest(operator, tokenId, 1, block.timestamp + 1); From e601eb43c248ea574e3100c385eedab8d7036fae Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:16:41 +0100 Subject: [PATCH 09/31] check pool manager lock on transfer, subscribe, and unsubscribe (#379) * add lock check * add tests * comment updates * merge --- .../PositionManager_subscribe.snap | 2 +- .../PositionManager_unsubscribe.snap | 2 +- src/PositionManager.sol | 9 ++- src/base/Notifier.sol | 11 ++- src/interfaces/INotifier.sol | 2 + src/interfaces/IPositionManager.sol | 3 + test/mocks/MockReenterHook.sol | 37 +++++++++ .../PositionManager.notifier.t.sol | 81 +++++++++++++++++++ 8 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 test/mocks/MockReenterHook.sol diff --git a/.forge-snapshots/PositionManager_subscribe.snap b/.forge-snapshots/PositionManager_subscribe.snap index e4eada758..b0cbf20ac 100644 --- a/.forge-snapshots/PositionManager_subscribe.snap +++ b/.forge-snapshots/PositionManager_subscribe.snap @@ -1 +1 @@ -84348 \ No newline at end of file +88168 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_unsubscribe.snap b/.forge-snapshots/PositionManager_unsubscribe.snap index c0f309cf8..9bf5d6467 100644 --- a/.forge-snapshots/PositionManager_unsubscribe.snap +++ b/.forge-snapshots/PositionManager_unsubscribe.snap @@ -1 +1 @@ -59260 \ No newline at end of file +63080 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index 0a67a9d53..428fb4b71 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -158,6 +158,12 @@ contract PositionManager is _; } + /// @notice Enforces that the PoolManager is locked. + modifier onlyIfPoolManagerLocked() override { + if (poolManager.isUnlocked()) revert PoolManagerMustBeLocked(); + _; + } + function tokenURI(uint256 tokenId) public view override returns (string memory) { return IPositionDescriptor(tokenDescriptor).tokenURI(this, tokenId); } @@ -444,7 +450,8 @@ contract PositionManager is } /// @dev overrides solmate transferFrom in case a notification to subscribers is needed - function transferFrom(address from, address to, uint256 id) public virtual override { + /// @dev will revert if pool manager is locked + function transferFrom(address from, address to, uint256 id) public virtual override onlyIfPoolManagerLocked { super.transferFrom(from, to, id); if (positionInfo[id].hasSubscriber()) _notifyTransfer(id, from, to); } diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index 558e85b7f..2965e5743 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -29,6 +29,9 @@ abstract contract Notifier is INotifier { /// @param tokenId the tokenId of the position modifier onlyIfApproved(address caller, uint256 tokenId) virtual; + /// @notice Enforces that the PoolManager is locked. + modifier onlyIfPoolManagerLocked() virtual; + function _setUnsubscribed(uint256 tokenId) internal virtual; function _setSubscribed(uint256 tokenId) internal virtual; @@ -37,6 +40,7 @@ abstract contract Notifier is INotifier { function subscribe(uint256 tokenId, address newSubscriber, bytes calldata data) external payable + onlyIfPoolManagerLocked onlyIfApproved(msg.sender, tokenId) { ISubscriber _subscriber = subscriber[tokenId]; @@ -56,7 +60,12 @@ abstract contract Notifier is INotifier { } /// @inheritdoc INotifier - function unsubscribe(uint256 tokenId) external payable onlyIfApproved(msg.sender, tokenId) { + function unsubscribe(uint256 tokenId) + external + payable + onlyIfPoolManagerLocked + onlyIfApproved(msg.sender, tokenId) + { _unsubscribe(tokenId); } diff --git a/src/interfaces/INotifier.sol b/src/interfaces/INotifier.sol index d6cca9083..3eefba3c5 100644 --- a/src/interfaces/INotifier.sol +++ b/src/interfaces/INotifier.sol @@ -36,6 +36,7 @@ interface INotifier { /// @param data caller-provided data that's forwarded to the subscriber contract /// @dev Calling subscribe when a position is already subscribed will revert /// @dev payable so it can be multicalled with NATIVE related actions + /// @dev will revert if pool manager is locked function subscribe(uint256 tokenId, address newSubscriber, bytes calldata data) external payable; /// @notice Removes the subscriber from receiving notifications for a respective position @@ -43,6 +44,7 @@ interface INotifier { /// @dev Callers must specify a high gas limit (remaining gas should be higher than unsubscriberGasLimit) such that the subscriber can be notified /// @dev payable so it can be multicalled with NATIVE related actions /// @dev Must always allow a user to unsubscribe. In the case of a malicious subscriber, a user can always unsubscribe safely, ensuring liquidity is always modifiable. + /// @dev will revert if pool manager is locked function unsubscribe(uint256 tokenId) external payable; /// @notice Returns and determines the maximum allowable gas-used for notifying unsubscribe diff --git a/src/interfaces/IPositionManager.sol b/src/interfaces/IPositionManager.sol index fbdfdd5c2..53a2efbee 100644 --- a/src/interfaces/IPositionManager.sol +++ b/src/interfaces/IPositionManager.sol @@ -14,6 +14,9 @@ interface IPositionManager is INotifier, IImmutableState { error NotApproved(address caller); /// @notice Thrown when the block.timestamp exceeds the user-provided deadline error DeadlinePassed(uint256 deadline); + /// @notice Thrown when calling transfer, subscribe, or unsubscribe when the PoolManager is unlocked. + /// @dev This is to prevent hooks from being able to trigger notifications at the same time the position is being modified. + error PoolManagerMustBeLocked(); /// @notice Unlocks Uniswap v4 PoolManager and batches actions for modifying liquidity /// @dev This is the standard entrypoint for the PositionManager diff --git a/test/mocks/MockReenterHook.sol b/test/mocks/MockReenterHook.sol new file mode 100644 index 000000000..e6d6f2db5 --- /dev/null +++ b/test/mocks/MockReenterHook.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; +import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; +import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; +import {BaseTestHooks} from "@uniswap/v4-core/src/test/BaseTestHooks.sol"; +import {PositionManager} from "../../src/PositionManager.sol"; + +contract MockReenterHook is BaseTestHooks { + PositionManager posm; + + function beforeAddLiquidity( + address, + PoolKey calldata, + IPoolManager.ModifyLiquidityParams calldata, + bytes calldata functionSelector + ) external override returns (bytes4) { + if (functionSelector.length == 0) { + return this.beforeAddLiquidity.selector; + } + (bytes4 selector, address owner, uint256 tokenId) = abi.decode(functionSelector, (bytes4, address, uint256)); + + if (selector == posm.transferFrom.selector) { + posm.transferFrom(owner, address(this), tokenId); + } else if (selector == posm.subscribe.selector) { + posm.subscribe(tokenId, address(this), ""); + } else if (selector == posm.unsubscribe.selector) { + posm.unsubscribe(tokenId); + } + return this.beforeAddLiquidity.selector; + } + + function setPosm(PositionManager _posm) external { + posm = _posm; + } +} diff --git a/test/position-managers/PositionManager.notifier.t.sol b/test/position-managers/PositionManager.notifier.t.sol index 391446a84..74acc7d06 100644 --- a/test/position-managers/PositionManager.notifier.t.sol +++ b/test/position-managers/PositionManager.notifier.t.sol @@ -9,6 +9,7 @@ import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; import {PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; import {BalanceDelta, toBalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; +import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; import {PosmTestSetup} from "../shared/PosmTestSetup.sol"; import {MockSubscriber} from "../mocks/MockSubscriber.sol"; @@ -20,6 +21,7 @@ import {Actions} from "../../src/libraries/Actions.sol"; import {INotifier} from "../../src/interfaces/INotifier.sol"; import {MockReturnDataSubscriber, MockRevertSubscriber} from "../mocks/MockBadSubscribers.sol"; import {PositionInfoLibrary, PositionInfo} from "../../src/libraries/PositionInfoLibrary.sol"; +import {MockReenterHook} from "../mocks/MockReenterHook.sol"; contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { using PoolIdLibrary for PoolKey; @@ -31,10 +33,13 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { MockReturnDataSubscriber badSubscriber; PositionConfig config; MockRevertSubscriber revertSubscriber; + MockReenterHook reenterHook; address alice = makeAddr("ALICE"); address bob = makeAddr("BOB"); + PositionConfig reenterConfig; + function setUp() public { deployFreshManagerAndRouters(); deployMintAndApprove2Currencies(); @@ -49,6 +54,17 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { revertSubscriber = new MockRevertSubscriber(lpm); config = PositionConfig({poolKey: key, tickLower: -300, tickUpper: 300}); + // set the reenter hook + MockReenterHook impl = new MockReenterHook(); + address hookAddr = payable(address(uint160(Hooks.BEFORE_ADD_LIQUIDITY_FLAG))); + vm.etch(hookAddr, address(impl).code); + reenterHook = MockReenterHook(hookAddr); + reenterHook.setPosm(lpm); + + PoolKey memory reenterKey = PoolKey(currency0, currency1, 3000, 60, IHooks(reenterHook)); + manager.initialize(reenterKey, SQRT_PRICE_1_1); + reenterConfig = PositionConfig({poolKey: reenterKey, tickLower: -60, tickUpper: 60}); + // TODO: Test NATIVE poolKey } @@ -647,4 +663,69 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { assertEq(sub.notifyUnsubscribeCount(), beforeUnsubCount + 1); } } + + function test_unsubscribe_reverts_PoolManagerMustBeLocked() public { + uint256 tokenId = lpm.nextTokenId(); + mint(reenterConfig, 10e18, address(this), ZERO_BYTES); + + bytes memory hookData = abi.encode(lpm.unsubscribe.selector, address(this), tokenId); + bytes memory actions = getMintEncoded(reenterConfig, 10e18, address(this), hookData); + + // approve hook as it should not revert because it does not have permissions + lpm.approve(address(reenterHook), tokenId); + // subscribe as it should not revert because there is no subscriber + lpm.subscribe(tokenId, address(sub), ZERO_BYTES); + + // should revert since the pool manager is unlocked + vm.expectRevert( + abi.encodeWithSelector( + Hooks.Wrap__FailedHookCall.selector, + address(reenterHook), + abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector) + ) + ); + lpm.modifyLiquidities(actions, _deadline); + } + + function test_subscribe_reverts_PoolManagerMustBeLocked() public { + uint256 tokenId = lpm.nextTokenId(); + mint(reenterConfig, 10e18, address(this), ZERO_BYTES); + + bytes memory hookData = abi.encode(lpm.subscribe.selector, address(this), tokenId); + bytes memory actions = getMintEncoded(reenterConfig, 10e18, address(this), hookData); + + // approve hook as it should not revert because it does not have permissions + lpm.approve(address(reenterHook), tokenId); + + // should revert since the pool manager is unlocked + vm.expectRevert( + abi.encodeWithSelector( + Hooks.Wrap__FailedHookCall.selector, + address(reenterHook), + abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector) + ) + ); + lpm.modifyLiquidities(actions, _deadline); + } + + function test_transferFrom_reverts_PoolManagerMustBeLocked() public { + uint256 tokenId = lpm.nextTokenId(); + mint(reenterConfig, 10e18, address(this), ZERO_BYTES); + + bytes memory hookData = abi.encode(lpm.transferFrom.selector, address(this), tokenId); + bytes memory actions = getMintEncoded(reenterConfig, 10e18, address(this), hookData); + + // approve hook as it should not revert because it does not have permissions + lpm.approve(address(reenterHook), tokenId); + + // should revert since the pool manager is unlocked + vm.expectRevert( + abi.encodeWithSelector( + Hooks.Wrap__FailedHookCall.selector, + address(reenterHook), + abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector) + ) + ); + lpm.modifyLiquidities(actions, _deadline); + } } From 825b20a931177893573e1f318dab12d3acf9ee39 Mon Sep 17 00:00:00 2001 From: diana Date: Mon, 28 Oct 2024 15:32:51 -0400 Subject: [PATCH 10/31] Pashov L-05 add more special characters to escape (#374) * Pashov L-05 add more special characters to escape * fix bytecode snapshot --- .../positionDescriptor bytecode size.snap | 2 +- src/libraries/Descriptor.sol | 36 ++++++++++--------- test/libraries/Descriptor.t.sol | 23 +++++++----- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index d2ccf4869..a23dd2344 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31236 \ No newline at end of file +31443 \ No newline at end of file diff --git a/src/libraries/Descriptor.sol b/src/libraries/Descriptor.sol index 918ca5a8a..b3d5ef296 100644 --- a/src/libraries/Descriptor.sol +++ b/src/libraries/Descriptor.sol @@ -45,13 +45,13 @@ library Descriptor { function constructTokenURI(ConstructTokenURIParams memory params) internal pure returns (string memory) { string memory name = generateName(params, feeToPercentString(params.fee)); string memory descriptionPartOne = generateDescriptionPartOne( - escapeQuotes(params.quoteCurrencySymbol), - escapeQuotes(params.baseCurrencySymbol), + escapeSpecialCharacters(params.quoteCurrencySymbol), + escapeSpecialCharacters(params.baseCurrencySymbol), addressToString(params.poolManager) ); string memory descriptionPartTwo = generateDescriptionPartTwo( params.tokenId.toString(), - escapeQuotes(params.baseCurrencySymbol), + escapeSpecialCharacters(params.baseCurrencySymbol), addressToString(Currency.unwrap(params.quoteCurrency)), addressToString(Currency.unwrap(params.baseCurrency)), params.hooks == address(0) ? "No Hook" : addressToString(params.hooks), @@ -81,23 +81,23 @@ library Descriptor { ); } - /// @notice Escapes double quotes in a string if they are present - function escapeQuotes(string memory symbol) internal pure returns (string memory) { + /// @notice Escapes special characters in a string if they are present + function escapeSpecialCharacters(string memory symbol) internal pure returns (string memory) { bytes memory symbolBytes = bytes(symbol); - uint8 quotesCount = 0; - // count the amount of double quotes (") in the symbol + uint8 specialCharCount = 0; + // count the amount of double quotes, form feeds, new lines, carriage returns, or tabs in the symbol for (uint8 i = 0; i < symbolBytes.length; i++) { - if (symbolBytes[i] == '"') { - quotesCount++; + if (isSpecialCharacter(symbolBytes[i])) { + specialCharCount++; } } - if (quotesCount > 0) { - // create a new bytes array with enough space to hold the original bytes plus space for the backslashes to escape the quotes - bytes memory escapedBytes = new bytes(symbolBytes.length + quotesCount); + if (specialCharCount > 0) { + // create a new bytes array with enough space to hold the original bytes plus space for the backslashes to escape the special characters + bytes memory escapedBytes = new bytes(symbolBytes.length + specialCharCount); uint256 index; for (uint8 i = 0; i < symbolBytes.length; i++) { - // add a '\' before any double quotes - if (symbolBytes[i] == '"') { + // add a '\' before any double quotes, form feeds, new lines, carriage returns, or tabs + if (isSpecialCharacter(symbolBytes[i])) { escapedBytes[index++] = "\\"; } // copy each byte from original string to the new array @@ -186,9 +186,9 @@ library Descriptor { "Uniswap - ", feeTier, " - ", - escapeQuotes(params.quoteCurrencySymbol), + escapeSpecialCharacters(params.quoteCurrencySymbol), "/", - escapeQuotes(params.baseCurrencySymbol), + escapeSpecialCharacters(params.baseCurrencySymbol), " - ", tickToDecimalString( !params.flipRatio ? params.tickLower : params.tickUpper, @@ -503,6 +503,10 @@ library Descriptor { } } + function isSpecialCharacter(bytes1 b) private pure returns (bool) { + return b == '"' || b == "\u000c" || b == "\n" || b == "\r" || b == "\t"; + } + function scale(uint256 n, uint256 inMn, uint256 inMx, uint256 outMn, uint256 outMx) private pure diff --git a/test/libraries/Descriptor.t.sol b/test/libraries/Descriptor.t.sol index e191c5a5e..2f3d5fd80 100644 --- a/test/libraries/Descriptor.t.sol +++ b/test/libraries/Descriptor.t.sol @@ -39,15 +39,20 @@ contract DescriptorTest is Test { ); } - function test_escapeQuotes_succeeds() public pure { - assertEq(Descriptor.escapeQuotes(""), ""); - assertEq(Descriptor.escapeQuotes("a"), "a"); - assertEq(Descriptor.escapeQuotes("abc"), "abc"); - assertEq(Descriptor.escapeQuotes("a\"bc"), "a\\\"bc"); - assertEq(Descriptor.escapeQuotes("a\"b\"c"), "a\\\"b\\\"c"); - assertEq(Descriptor.escapeQuotes("a\"b\"c\""), "a\\\"b\\\"c\\\""); - assertEq(Descriptor.escapeQuotes("\"a\"b\"c\""), "\\\"a\\\"b\\\"c\\\""); - assertEq(Descriptor.escapeQuotes("\"a\"b\"c\"\""), "\\\"a\\\"b\\\"c\\\"\\\""); + function test_escapeSpecialCharacters_succeeds() public pure { + assertEq(Descriptor.escapeSpecialCharacters(""), ""); + assertEq(Descriptor.escapeSpecialCharacters("a"), "a"); + assertEq(Descriptor.escapeSpecialCharacters("abc"), "abc"); + assertEq(Descriptor.escapeSpecialCharacters("a\"bc"), "a\\\"bc"); + assertEq(Descriptor.escapeSpecialCharacters("a\"b\"c"), "a\\\"b\\\"c"); + assertEq(Descriptor.escapeSpecialCharacters("a\"b\"c\""), "a\\\"b\\\"c\\\""); + assertEq(Descriptor.escapeSpecialCharacters("\"a\"b\"c\""), "\\\"a\\\"b\\\"c\\\""); + assertEq(Descriptor.escapeSpecialCharacters("\"a\"b\"c\"\""), "\\\"a\\\"b\\\"c\\\"\\\""); + + assertEq(Descriptor.escapeSpecialCharacters("a\rbc"), "a\\\rbc"); + assertEq(Descriptor.escapeSpecialCharacters("a\nbc"), "a\\\nbc"); + assertEq(Descriptor.escapeSpecialCharacters("a\tbc"), "a\\\tbc"); + assertEq(Descriptor.escapeSpecialCharacters("a\u000cbc"), "a\\\u000cbc"); } function test_tickToDecimalString_withTickSpacing10() public pure { From 126cca6ce604cf940e8f1ac4dccabba938d0e41a Mon Sep 17 00:00:00 2001 From: diana Date: Tue, 29 Oct 2024 17:08:22 -0400 Subject: [PATCH 11/31] Pashov L-06 limit symbol length (#376) * Pashov L-06 * change max length to 12 instead of 6 * test file * format * fix bytecode * comment --- .../positionDescriptor bytecode size.snap | 2 +- src/libraries/SafeCurrencyMetadata.sol | 18 ++++++++++++++++++ test/libraries/SafeCurrencyMetadata.t.sol | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 test/libraries/SafeCurrencyMetadata.t.sol diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index a23dd2344..6f097d735 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31443 \ No newline at end of file +31619 \ No newline at end of file diff --git a/src/libraries/SafeCurrencyMetadata.sol b/src/libraries/SafeCurrencyMetadata.sol index 029244aa3..b220bf290 100644 --- a/src/libraries/SafeCurrencyMetadata.sol +++ b/src/libraries/SafeCurrencyMetadata.sol @@ -11,6 +11,8 @@ import {AddressStringUtil} from "./AddressStringUtil.sol"; library SafeCurrencyMetadata { using CurrencyLibrary for Currency; + uint8 constant MAX_SYMBOL_LENGTH = 12; + /// @notice attempts to extract the token symbol. if it does not implement symbol, returns a symbol derived from the address /// @param currency The currency /// @param nativeLabel The native label @@ -25,6 +27,9 @@ library SafeCurrencyMetadata { // fallback to 6 uppercase hex of address return addressToSymbol(currencyAddress); } + if (bytes(symbol).length > MAX_SYMBOL_LENGTH) { + return truncateSymbol(symbol); + } return symbol; } @@ -92,4 +97,17 @@ library SafeCurrencyMetadata { } return ""; } + + /// @notice truncates the symbol to the MAX_SYMBOL_LENGTH + /// @dev assumes the string is already longer than MAX_SYMBOL_LENGTH (or the same) + /// @param str the symbol + /// @return the truncated symbol + function truncateSymbol(string memory str) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory truncatedBytes = new bytes(MAX_SYMBOL_LENGTH); + for (uint256 i = 0; i < MAX_SYMBOL_LENGTH; i++) { + truncatedBytes[i] = strBytes[i]; + } + return string(truncatedBytes); + } } diff --git a/test/libraries/SafeCurrencyMetadata.t.sol b/test/libraries/SafeCurrencyMetadata.t.sol new file mode 100644 index 000000000..15f6e0f5d --- /dev/null +++ b/test/libraries/SafeCurrencyMetadata.t.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "forge-std/Test.sol"; +import {SafeCurrencyMetadata} from "../../src/libraries/SafeCurrencyMetadata.sol"; + +contract SafeCurrencyMetadataTest is Test { + function test_truncateSymbol_succeeds() public pure { + // 12 characters + assertEq(SafeCurrencyMetadata.truncateSymbol("123456789012"), "123456789012"); + // 13 characters + assertEq(SafeCurrencyMetadata.truncateSymbol("1234567890123"), "123456789012"); + // 14 characters + assertEq(SafeCurrencyMetadata.truncateSymbol("12345678901234"), "123456789012"); + } +} From 1a21920085fc712ca745361bf397e8a7be25dc1c Mon Sep 17 00:00:00 2001 From: diana Date: Thu, 31 Oct 2024 18:44:23 -0400 Subject: [PATCH 12/31] Pashov L-04 display Native instead of the zero address (#373) * Pashov L-04 display Native instead of the zero address * add test for native * erc20 -> address * format * another test * revert name change * more reversions * last one --- .../positionDescriptor bytecode size.snap | 2 +- src/PositionDescriptor.sol | 9 +- src/libraries/Descriptor.sol | 33 ++- src/libraries/SVG.sol | 1 - src/libraries/SafeCurrencyMetadata.sol | 29 +-- test/PositionDescriptor.t.sol | 222 +++++++++++++++++- test/libraries/SVG.t.sol | 7 + 7 files changed, 262 insertions(+), 41 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 6f097d735..4babbfb1b 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31619 \ No newline at end of file +31728 \ No newline at end of file diff --git a/src/PositionDescriptor.sol b/src/PositionDescriptor.sol index 7cf39d943..7f1ac799b 100644 --- a/src/PositionDescriptor.sol +++ b/src/PositionDescriptor.sol @@ -54,14 +54,17 @@ contract PositionDescriptor is IPositionDescriptor { } (, int24 tick,,) = poolManager.getSlot0(poolKey.toId()); + address currency0 = Currency.unwrap(poolKey.currency0); + address currency1 = Currency.unwrap(poolKey.currency1); + // If possible, flip currencies to get the larger currency as the base currency, so that the price (quote/base) is more readable // flip if currency0 priority is greater than currency1 priority - bool _flipRatio = flipRatio(Currency.unwrap(poolKey.currency0), Currency.unwrap(poolKey.currency1)); + bool _flipRatio = flipRatio(currency0, currency1); // If not flipped, quote currency is currency1, base currency is currency0 // If flipped, quote currency is currency0, base currency is currency1 - Currency quoteCurrency = !_flipRatio ? poolKey.currency1 : poolKey.currency0; - Currency baseCurrency = !_flipRatio ? poolKey.currency0 : poolKey.currency1; + address quoteCurrency = !_flipRatio ? currency1 : currency0; + address baseCurrency = !_flipRatio ? currency0 : currency1; return Descriptor.constructTokenURI( Descriptor.ConstructTokenURIParams({ diff --git a/src/libraries/Descriptor.sol b/src/libraries/Descriptor.sol index b3d5ef296..ba261f850 100644 --- a/src/libraries/Descriptor.sol +++ b/src/libraries/Descriptor.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; import {FullMath} from "@uniswap/v4-core/src/libraries/FullMath.sol"; import {LPFeeLibrary} from "@uniswap/v4-core/src/libraries/LPFeeLibrary.sol"; @@ -23,8 +22,8 @@ library Descriptor { struct ConstructTokenURIParams { uint256 tokenId; - Currency quoteCurrency; - Currency baseCurrency; + address quoteCurrency; + address baseCurrency; string quoteCurrencySymbol; string baseCurrencySymbol; uint8 quoteCurrencyDecimals; @@ -52,8 +51,8 @@ library Descriptor { string memory descriptionPartTwo = generateDescriptionPartTwo( params.tokenId.toString(), escapeSpecialCharacters(params.baseCurrencySymbol), - addressToString(Currency.unwrap(params.quoteCurrency)), - addressToString(Currency.unwrap(params.baseCurrency)), + params.quoteCurrency == address(0) ? "Native" : addressToString(params.quoteCurrency), + params.baseCurrency == address(0) ? "Native" : addressToString(params.baseCurrency), params.hooks == address(0) ? "No Hook" : addressToString(params.hooks), feeToPercentString(params.fee) ); @@ -462,8 +461,8 @@ library Descriptor { /// @return svg The SVG image as a string function generateSVGImage(ConstructTokenURIParams memory params) internal pure returns (string memory svg) { SVG.SVGParams memory svgParams = SVG.SVGParams({ - quoteCurrency: addressToString(Currency.unwrap(params.quoteCurrency)), - baseCurrency: addressToString(Currency.unwrap(params.baseCurrency)), + quoteCurrency: addressToString(params.quoteCurrency), + baseCurrency: addressToString(params.baseCurrency), hooks: params.hooks, quoteCurrencySymbol: params.quoteCurrencySymbol, baseCurrencySymbol: params.baseCurrencySymbol, @@ -473,16 +472,16 @@ library Descriptor { tickSpacing: params.tickSpacing, overRange: overRange(params.tickLower, params.tickUpper, params.tickCurrent), tokenId: params.tokenId, - color0: currencyToColorHex(params.quoteCurrency.toId(), 136), - color1: currencyToColorHex(params.baseCurrency.toId(), 136), - color2: currencyToColorHex(params.quoteCurrency.toId(), 0), - color3: currencyToColorHex(params.baseCurrency.toId(), 0), - x1: scale(getCircleCoord(params.quoteCurrency.toId(), 16, params.tokenId), 0, 255, 16, 274), - y1: scale(getCircleCoord(params.baseCurrency.toId(), 16, params.tokenId), 0, 255, 100, 484), - x2: scale(getCircleCoord(params.quoteCurrency.toId(), 32, params.tokenId), 0, 255, 16, 274), - y2: scale(getCircleCoord(params.baseCurrency.toId(), 32, params.tokenId), 0, 255, 100, 484), - x3: scale(getCircleCoord(params.quoteCurrency.toId(), 48, params.tokenId), 0, 255, 16, 274), - y3: scale(getCircleCoord(params.baseCurrency.toId(), 48, params.tokenId), 0, 255, 100, 484) + color0: currencyToColorHex(uint256(uint160(params.quoteCurrency)), 136), + color1: currencyToColorHex(uint256(uint160(params.baseCurrency)), 136), + color2: currencyToColorHex(uint256(uint160(params.quoteCurrency)), 0), + color3: currencyToColorHex(uint256(uint160(params.baseCurrency)), 0), + x1: scale(getCircleCoord(uint256(uint160(params.quoteCurrency)), 16, params.tokenId), 0, 255, 16, 274), + y1: scale(getCircleCoord(uint256(uint160(params.baseCurrency)), 16, params.tokenId), 0, 255, 100, 484), + x2: scale(getCircleCoord(uint256(uint160(params.quoteCurrency)), 32, params.tokenId), 0, 255, 16, 274), + y2: scale(getCircleCoord(uint256(uint160(params.baseCurrency)), 32, params.tokenId), 0, 255, 100, 484), + x3: scale(getCircleCoord(uint256(uint160(params.quoteCurrency)), 48, params.tokenId), 0, 255, 16, 274), + y3: scale(getCircleCoord(uint256(uint160(params.baseCurrency)), 48, params.tokenId), 0, 255, 100, 484) }); return SVG.generateSVG(svgParams); diff --git a/src/libraries/SVG.sol b/src/libraries/SVG.sol index 90733ddc4..2731a6cac 100644 --- a/src/libraries/SVG.sol +++ b/src/libraries/SVG.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; import {BitMath} from "@uniswap/v4-core/src/libraries/BitMath.sol"; import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; diff --git a/src/libraries/SafeCurrencyMetadata.sol b/src/libraries/SafeCurrencyMetadata.sol index b220bf290..cc88ab84c 100644 --- a/src/libraries/SafeCurrencyMetadata.sol +++ b/src/libraries/SafeCurrencyMetadata.sol @@ -2,30 +2,26 @@ pragma solidity ^0.8.0; import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; import {AddressStringUtil} from "./AddressStringUtil.sol"; /// @title SafeCurrencyMetadata /// @notice can produce symbols and decimals from inconsistent or absent ERC20 implementations /// @dev Reference: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/SafeERC20Namer.sol library SafeCurrencyMetadata { - using CurrencyLibrary for Currency; - uint8 constant MAX_SYMBOL_LENGTH = 12; - /// @notice attempts to extract the token symbol. if it does not implement symbol, returns a symbol derived from the address - /// @param currency The currency + /// @notice attempts to extract the currency symbol. if it does not implement symbol, returns a symbol derived from the address + /// @param currency The currency address /// @param nativeLabel The native label - /// @return the token symbol - function currencySymbol(Currency currency, string memory nativeLabel) internal view returns (string memory) { - if (currency.isAddressZero()) { + /// @return the currency symbol + function currencySymbol(address currency, string memory nativeLabel) internal view returns (string memory) { + if (currency == address(0)) { return nativeLabel; } - address currencyAddress = Currency.unwrap(currency); - string memory symbol = callAndParseStringReturn(currencyAddress, IERC20Metadata.symbol.selector); + string memory symbol = callAndParseStringReturn(currency, IERC20Metadata.symbol.selector); if (bytes(symbol).length == 0) { // fallback to 6 uppercase hex of address - return addressToSymbol(currencyAddress); + return addressToSymbol(currency); } if (bytes(symbol).length > MAX_SYMBOL_LENGTH) { return truncateSymbol(symbol); @@ -34,14 +30,13 @@ library SafeCurrencyMetadata { } /// @notice attempts to extract the token decimals, returns 0 if not implemented or not a uint8 - /// @param currency The currency - /// @return the token decimals - function currencyDecimals(Currency currency) internal view returns (uint8) { - if (currency.isAddressZero()) { + /// @param currency The currency address + /// @return the currency decimals + function currencyDecimals(address currency) internal view returns (uint8) { + if (currency == address(0)) { return 18; } - (bool success, bytes memory data) = - Currency.unwrap(currency).staticcall(abi.encodeCall(IERC20Metadata.decimals, ())); + (bool success, bytes memory data) = currency.staticcall(abi.encodeCall(IERC20Metadata.decimals, ())); if (!success) { return 0; } diff --git a/test/PositionDescriptor.t.sol b/test/PositionDescriptor.t.sol index bc991e7bf..4b326814c 100644 --- a/test/PositionDescriptor.t.sol +++ b/test/PositionDescriptor.t.sol @@ -12,9 +12,14 @@ import {PosmTestSetup} from "./shared/PosmTestSetup.sol"; import {ActionConstants} from "../src/libraries/ActionConstants.sol"; import {Base64} from "./base64.sol"; import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; +import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; +import {SafeCurrencyMetadata} from "../src/libraries/SafeCurrencyMetadata.sol"; +import {AddressStringUtil} from "../src/libraries/AddressStringUtil.sol"; +import {Descriptor} from "../src/libraries/Descriptor.sol"; contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot { using Base64 for string; + using CurrencyLibrary for Currency; address public WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address public DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; @@ -119,10 +124,185 @@ contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot { bytes memory data = vm.parseJson(json); Token memory token = abi.decode(data, (Token)); - assertEq(token.name, "Uniswap - 0.3% - TEST/TEST - 1.0060<>1.0121"); + // quote is currency1, base is currency0 + assertFalse(positionDescriptor.flipRatio(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1))); + + string memory symbol0 = SafeCurrencyMetadata.currencySymbol(Currency.unwrap(currency0), nativeCurrencyLabel); + string memory symbol1 = SafeCurrencyMetadata.currencySymbol(Currency.unwrap(currency1), nativeCurrencyLabel); + string memory managerAddress = toHexString(address(manager)); + string memory currency0Address = toHexString(Currency.unwrap(currency0)); + string memory currency1Address = toHexString(Currency.unwrap(currency1)); + string memory id = uintToString(tokenId); + string memory hookAddress = address(key.hooks) == address(0) + ? "No Hook" + : string(abi.encodePacked("0x", toHexString(address(key.hooks)))); + string memory fee = Descriptor.feeToPercentString(key.fee); + string memory tickToDecimal0 = Descriptor.tickToDecimalString( + tickLower, + key.tickSpacing, + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency0)), + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency1)), + false + ); + string memory tickToDecimal1 = Descriptor.tickToDecimalString( + tickUpper, + key.tickSpacing, + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency0)), + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency1)), + false + ); + + assertEq( + token.name, + string( + abi.encodePacked( + "Uniswap - ", fee, " - ", symbol1, "/", symbol0, " - ", tickToDecimal0, "<>", tickToDecimal1 + ) + ) + ); + assertEq( + token.description, + string( + abi.encodePacked( + unicode"This NFT represents a liquidity position in a Uniswap v4 ", + symbol1, + "-", + symbol0, + " pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: ", + managerAddress, + "\n", + symbol1, + " Address: ", + currency1Address, + "\n", + symbol0, + " Address: ", + currency0Address, + "\nHook Address: ", + hookAddress, + "\nFee Tier: ", + fee, + "\nToken ID: ", + id, + "\n\n", + unicode"⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." + ) + ) + ); + } + + function test_native_tokenURI_succeeds() public { + (nativeKey,) = initPool(CurrencyLibrary.ADDRESS_ZERO, currency1, IHooks(address(0)), 3000, SQRT_PRICE_1_1); + int24 tickLower = int24(nativeKey.tickSpacing); + int24 tickUpper = int24(nativeKey.tickSpacing * 2); + uint256 amount0Desired = 100e18; + uint256 amount1Desired = 100e18; + uint256 liquidityToAdd = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(tickLower), + TickMath.getSqrtPriceAtTick(tickUpper), + amount0Desired, + amount1Desired + ); + + PositionConfig memory config = PositionConfig({poolKey: nativeKey, tickLower: tickLower, tickUpper: tickUpper}); + uint256 tokenId = lpm.nextTokenId(); + mintWithNative(SQRT_PRICE_1_1, config, liquidityToAdd, ActionConstants.MSG_SENDER, ZERO_BYTES); + + // The prefix length is calculated by converting the string to bytes and finding its length + uint256 prefixLength = bytes("data:application/json;base64,").length; + + string memory uri = positionDescriptor.tokenURI(lpm, tokenId); + // Convert the uri to bytes + bytes memory uriBytes = bytes(uri); + + // Slice the uri to get only the base64-encoded part + bytes memory base64Part = new bytes(uriBytes.length - prefixLength); + + for (uint256 i = 0; i < base64Part.length; i++) { + base64Part[i] = uriBytes[i + prefixLength]; + } + + // Decode the base64-encoded part + bytes memory decoded = Base64.decode(string(base64Part)); + string memory json = string(decoded); + + // decode json + bytes memory data = vm.parseJson(json); + Token memory token = abi.decode(data, (Token)); + + // quote is currency1, base is currency0 + assertFalse( + positionDescriptor.flipRatio(Currency.unwrap(nativeKey.currency0), Currency.unwrap(nativeKey.currency1)) + ); + + string memory symbol0 = + SafeCurrencyMetadata.currencySymbol(Currency.unwrap(nativeKey.currency0), nativeCurrencyLabel); + string memory symbol1 = + SafeCurrencyMetadata.currencySymbol(Currency.unwrap(nativeKey.currency1), nativeCurrencyLabel); + string memory managerAddress = toHexString(address(manager)); + string memory currency0Address = Currency.unwrap(nativeKey.currency0) == address(0) + ? "Native" + : toHexString(Currency.unwrap(nativeKey.currency0)); + string memory currency1Address = Currency.unwrap(nativeKey.currency1) == address(0) + ? "Native" + : toHexString(Currency.unwrap(nativeKey.currency1)); + string memory id = uintToString(tokenId); + string memory hookAddress = address(nativeKey.hooks) == address(0) + ? "No Hook" + : string(abi.encodePacked("0x", toHexString(address(nativeKey.hooks)))); + string memory fee = Descriptor.feeToPercentString(nativeKey.fee); + string memory tickToDecimal0 = Descriptor.tickToDecimalString( + tickLower, + nativeKey.tickSpacing, + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency0)), + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency1)), + false + ); + string memory tickToDecimal1 = Descriptor.tickToDecimalString( + tickUpper, + nativeKey.tickSpacing, + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency0)), + SafeCurrencyMetadata.currencyDecimals(Currency.unwrap(currency1)), + false + ); + + assertEq( + token.name, + string( + abi.encodePacked( + "Uniswap - ", fee, " - ", symbol1, "/", symbol0, " - ", tickToDecimal0, "<>", tickToDecimal1 + ) + ) + ); assertEq( token.description, - unicode"This NFT represents a liquidity position in a Uniswap v4 TEST-TEST pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: 0x2e234dae75c793f67a35089c9d99245e1c58470b\nTEST Address: 0xf62849f9a0b5bf2913b396098f7c7019b51a820a\nTEST Address: 0xc7183455a4c133ae270771860664b6b7ec320bb1\nHook Address: No Hook\nFee Tier: 0.3%\nToken ID: 1\n\n⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." + string( + abi.encodePacked( + unicode"This NFT represents a liquidity position in a Uniswap v4 ", + symbol1, + "-", + symbol0, + " pool. The owner of this NFT can modify or redeem the position.\n\nPool Manager Address: ", + managerAddress, + "\n", + symbol1, + " Address: ", + currency1Address, + "\n", + symbol0, + " Address: ", + currency0Address, + "\nHook Address: ", + hookAddress, + "\nFee Tier: ", + fee, + "\nToken ID: ", + id, + "\n\n", + unicode"⚠️ DISCLAIMER: Due diligence is imperative when assessing this NFT. Make sure currency addresses match the expected currencies, as currency symbols may be imitated." + ) + ) ); } @@ -147,4 +327,42 @@ contract PositionDescriptorTest is Test, PosmTestSetup, GasSnapshot { positionDescriptor.tokenURI(lpm, tokenId + 1); } + + // Helper functions for testing purposes + function toHexString(address account) internal pure returns (string memory) { + return toHexString(uint256(uint160(account)), 20); + } + + // different from AddressStringUtil.toHexString. this one is all lowercase hex and includes the 0x prefix + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + uint8 digit = uint8(value & 0xf); + buffer[i] = digit < 10 ? bytes1(digit + 48) : bytes1(digit + 87); // Lowercase hex (0x61 is 'a' in ASCII) + value >>= 4; + } + require(value == 0, "Hex length insufficient"); + return string(buffer); + } + + function uintToString(uint256 value) internal pure returns (string memory) { + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); + } } diff --git a/test/libraries/SVG.t.sol b/test/libraries/SVG.t.sol index c322483e2..915557cbb 100644 --- a/test/libraries/SVG.t.sol +++ b/test/libraries/SVG.t.sol @@ -47,4 +47,11 @@ contract DescriptorTest is Test { result = SVG.isRare(2, 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB); assertFalse(result); } + + function test_substring_succeeds() public pure { + string memory result = SVG.substring("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 0, 5); + assertEq(result, "0xC02"); + result = SVG.substring("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", 39, 42); + assertEq(result, "Cc2"); + } } From 2768c3d578a5ffeec0bc51abcd8e472cb68f8a93 Mon Sep 17 00:00:00 2001 From: marktoda Date: Thu, 31 Oct 2024 16:40:16 -0700 Subject: [PATCH 13/31] feat: update v4 core (#387) * feat: update v4 core this commit updates v4 core to the latest main and updates custom revert handling to support the latest bubble up * fix: forge-gas-snapshot * fix: version * fix: pm address * fix: review comment * fix: bytecode size --------- Co-authored-by: Alice Henshaw --- .../BaseActionsRouter_mock10commands.snap | 2 +- ...p_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...eFromCaller_takeAllToSpecifiedAddress.snap | 2 +- ..._settleWithBalance_takeAllToMsgSender.snap | 2 +- ...WithBalance_takeAllToSpecifiedAddress.snap | 2 +- .../PositionManager_burn_empty.snap | 2 +- .../PositionManager_burn_empty_native.snap | 2 +- ...anager_burn_nonEmpty_native_withClose.snap | 2 +- ...ger_burn_nonEmpty_native_withTakePair.snap | 2 +- ...sitionManager_burn_nonEmpty_withClose.snap | 2 +- ...ionManager_burn_nonEmpty_withTakePair.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- ...onManager_decreaseLiquidity_withClose.snap | 2 +- ...anager_decreaseLiquidity_withTakePair.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- .../PositionManager_decrease_take_take.snap | 2 +- ...ger_increaseLiquidity_erc20_withClose.snap | 2 +- ...ncreaseLiquidity_erc20_withSettlePair.snap | 2 +- ...itionManager_increaseLiquidity_native.snap | 2 +- ...crease_autocompoundExactUnclaimedFees.snap | 2 +- ...increase_autocompoundExcessFeesCredit.snap | 2 +- ...ger_increase_autocompound_clearExcess.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- ...anager_mint_nativeWithSweep_withClose.snap | 2 +- ...r_mint_nativeWithSweep_withSettlePair.snap | 2 +- .../PositionManager_mint_onSameTickLower.snap | 2 +- .../PositionManager_mint_onSameTickUpper.snap | 2 +- .../PositionManager_mint_sameRange.snap | 2 +- ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...anager_mint_warmedPool_differentRange.snap | 2 +- .../PositionManager_mint_withClose.snap | 2 +- .../PositionManager_mint_withSettlePair.snap | 2 +- ...tionManager_multicall_initialize_mint.snap | 2 +- .../PositionManager_permit_twice.snap | 2 +- ...utSingle_oneForZero_multiplePositions.snap | 2 +- ...utSingle_zeroForOne_multiplePositions.snap | 2 +- .../Quoter_exactOutputSingle_oneForZero.snap | 2 +- .../Quoter_exactOutputSingle_zeroForOne.snap | 2 +- ...er_quoteExactInput_oneHop_1TickLoaded.snap | 2 +- ...oteExactInput_oneHop_initializedAfter.snap | 2 +- ...ExactInput_oneHop_startingInitialized.snap | 2 +- .../Quoter_quoteExactInput_twoHops.snap | 2 +- ...r_quoteExactOutput_oneHop_1TickLoaded.snap | 2 +- ..._quoteExactOutput_oneHop_2TicksLoaded.snap | 2 +- ...teExactOutput_oneHop_initializedAfter.snap | 2 +- ...xactOutput_oneHop_startingInitialized.snap | 2 +- .../Quoter_quoteExactOutput_twoHops.snap | 2 +- ...tateView_extsload_getFeeGrowthGlobals.snap | 2 +- ...StateView_extsload_getFeeGrowthInside.snap | 2 +- .../StateView_extsload_getPositionInfo.snap | 2 +- ...View_extsload_getTickFeeGrowthOutside.snap | 2 +- .../StateView_extsload_getTickInfo.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .../V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .../V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .../V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .../V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .../V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .../V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle.snap | 2 +- .../V4Router_ExactInputSingle_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle_nativeOut.snap | 2 +- ...Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .../V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .../V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .../V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .../V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .../V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .../V4Router_ExactOutputSingle.snap | 2 +- ...r_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOutputSingle_nativeOut.snap | 2 +- .../positionDescriptor bytecode size.snap | 2 +- .gitmodules | 3 ++ lib/forge-gas-snapshot | 1 + lib/v4-core | 2 +- remappings.txt | 4 +- script/01_PoolManager.s.sol | 2 +- src/base/Notifier.sol | 12 +++-- src/interfaces/INotifier.sol | 6 +-- .../PositionManager.modifyLiquidities.t.sol | 31 ++++++++---- .../PositionManager.notifier.t.sol | 49 +++++++++++++------ test/script/DeployPoolManager.t.sol | 2 +- .../DeployPoolMofifyLiquidityTest.t.sol | 2 +- test/script/DeployPoolSwapTest.t.sol | 2 +- 95 files changed, 159 insertions(+), 123 deletions(-) create mode 160000 lib/forge-gas-snapshot diff --git a/.forge-snapshots/BaseActionsRouter_mock10commands.snap b/.forge-snapshots/BaseActionsRouter_mock10commands.snap index 8a065fc31..2f6f033f0 100644 --- a/.forge-snapshots/BaseActionsRouter_mock10commands.snap +++ b/.forge-snapshots/BaseActionsRouter_mock10commands.snap @@ -1 +1 @@ -60677 \ No newline at end of file +60674 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index 2fb484c41..cc61af9f0 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129642 \ No newline at end of file +129438 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index ff128171f..0b3e3049b 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131705 \ No newline at end of file +131502 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index 7703a32a4..3d248d7fd 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -123910 \ No newline at end of file +123707 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index 0830d9291..93b71d538 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -124052 \ No newline at end of file +123849 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty.snap b/.forge-snapshots/PositionManager_burn_empty.snap index 949dd08ae..16a0217a7 100644 --- a/.forge-snapshots/PositionManager_burn_empty.snap +++ b/.forge-snapshots/PositionManager_burn_empty.snap @@ -1 +1 @@ -50481 \ No newline at end of file +50479 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty_native.snap b/.forge-snapshots/PositionManager_burn_empty_native.snap index 949dd08ae..16a0217a7 100644 --- a/.forge-snapshots/PositionManager_burn_empty_native.snap +++ b/.forge-snapshots/PositionManager_burn_empty_native.snap @@ -1 +1 @@ -50481 \ No newline at end of file +50479 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index c3bc574ea..7b256dc71 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125659 \ No newline at end of file +125652 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index e33592341..7c676e270 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125141 \ No newline at end of file +125134 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 54b474eb3..4a700a1c7 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132521 \ No newline at end of file +132512 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 8bbf4b071..b74086572 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -132004 \ No newline at end of file +131994 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 85355e350..de5f92d75 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146388 \ No newline at end of file +146379 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index 1a7e51e0a..2f8946517 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -154966 \ No newline at end of file +154954 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index 1a7e51e0a..2f8946517 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -154966 \ No newline at end of file +154954 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index e1639e55e..8b55bcf18 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154331 \ No newline at end of file +154319 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index 4db04993e..4f47d5cdd 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -112056 \ No newline at end of file +112048 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index 0d683313e..5320c7d05 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119847 \ No newline at end of file +119835 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 8e8a2c64b..690234de4 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119212 \ No newline at end of file +119200 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 99fb79393..1bd57c304 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135318 \ No newline at end of file +135308 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index ef0e4aafa..d1d857dcb 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128456 \ No newline at end of file +128448 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index 651fb4408..99eac1b69 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132534 \ No newline at end of file +132522 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index 84049ea50..07b447cf2 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120467 \ No newline at end of file +120455 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index f237a3eac..571f09c3e 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -159127 \ No newline at end of file +158871 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index 7055ac3b2..f673e9018 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -158079 \ No newline at end of file +157823 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index b4db755ef..109715cd0 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -140942 \ No newline at end of file +140808 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index b6d9ed62f..31cb20d9d 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -136403 \ No newline at end of file +136396 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index 40fa41627..35911ac24 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177458 \ No newline at end of file +177446 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 7becdebb3..8a5e17d06 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148084 \ No newline at end of file +148160 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index 0c393410e..a392537d5 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -364815 \ No newline at end of file +364681 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 1ab4ab47f..012d5b883 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -373334 \ No newline at end of file +373199 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index 64d0360e5..a732cefec 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -372569 \ No newline at end of file +372435 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index b941b6e08..31a541afd 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317687 \ No newline at end of file +317431 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index d9ef5ca04..b634faa2b 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318357 \ No newline at end of file +318101 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index 91240b8cd..302128695 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243926 \ No newline at end of file +243670 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 79e218a84..681c6d513 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -419134 \ No newline at end of file +418878 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index f8eb13001..a1b50bf73 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323718 \ No newline at end of file +323462 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index b7e3ad993..8251054aa 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -420240 \ No newline at end of file +419984 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index eedfce3e3..b425567ac 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419310 \ No newline at end of file +419054 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 66493802d..617f2034a 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -456088 \ No newline at end of file +455828 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_permit_twice.snap b/.forge-snapshots/PositionManager_permit_twice.snap index d650ccbd7..379f96111 100644 --- a/.forge-snapshots/PositionManager_permit_twice.snap +++ b/.forge-snapshots/PositionManager_permit_twice.snap @@ -1 +1 @@ -44876 \ No newline at end of file +44852 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap b/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap index 485e8f0d7..7110b7f43 100644 --- a/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap +++ b/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap @@ -1 +1 @@ -143930 \ No newline at end of file +144020 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap b/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap index f89390d96..fc06cb487 100644 --- a/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap +++ b/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap @@ -1 +1 @@ -149382 \ No newline at end of file +149287 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap b/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap index a40f3f57a..2963a4a55 100644 --- a/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap +++ b/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap @@ -1 +1 @@ -78203 \ No newline at end of file +78196 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap b/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap index 23153115b..d91412911 100644 --- a/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap +++ b/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap @@ -1 +1 @@ -82626 \ No newline at end of file +82546 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap b/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap index a3ea8ad76..8e02b3460 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap @@ -1 +1 @@ -120491 \ No newline at end of file +120406 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap b/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap index 6dcb3b78d..1c2000f84 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap @@ -1 +1 @@ -145414 \ No newline at end of file +145504 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap b/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap index 1f604e115..7cd92e9ff 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap @@ -1 +1 @@ -79437 \ No newline at end of file +79438 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap b/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap index bb203fa98..4753bccff 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap @@ -1 +1 @@ -201179 \ No newline at end of file +201071 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap index e7385875b..1fc92a414 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap @@ -1 +1 @@ -119782 \ No newline at end of file +119672 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap index 14b51340c..958e4261f 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap @@ -1 +1 @@ -149919 \ No newline at end of file +149779 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap index c19a0a13c..764795de4 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap @@ -1 +1 @@ -119850 \ No newline at end of file +119740 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap index c0333d8aa..a2bce2b22 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap @@ -1 +1 @@ -96549 \ No newline at end of file +96472 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap b/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap index 7acf5efcd..40af9508f 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap @@ -1 +1 @@ -200630 \ No newline at end of file +200486 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap b/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap index 98665bfc6..920727d2e 100644 --- a/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap +++ b/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap @@ -1 +1 @@ -2259 \ No newline at end of file +2256 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap b/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap index 7db58ace5..6df672447 100644 --- a/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap +++ b/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap @@ -1 +1 @@ -8003 \ No newline at end of file +7994 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getPositionInfo.snap b/.forge-snapshots/StateView_extsload_getPositionInfo.snap index 4b9661fc9..c173e591f 100644 --- a/.forge-snapshots/StateView_extsload_getPositionInfo.snap +++ b/.forge-snapshots/StateView_extsload_getPositionInfo.snap @@ -1 +1 @@ -2829 \ No newline at end of file +2826 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap b/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap index 6870d0f23..7a03b74c0 100644 --- a/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap +++ b/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap @@ -1 +1 @@ -2546 \ No newline at end of file +2543 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getTickInfo.snap b/.forge-snapshots/StateView_extsload_getTickInfo.snap index cd5ecabca..f538595cb 100644 --- a/.forge-snapshots/StateView_extsload_getTickInfo.snap +++ b/.forge-snapshots/StateView_extsload_getTickInfo.snap @@ -1 +1 @@ -2761 \ No newline at end of file +2758 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index 9c58b9822..1e50a9b94 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7063 \ No newline at end of file +7158 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index a3d9bfc1c..a7a1b3973 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -115753 \ No newline at end of file +115672 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index f637e5fe3..4964df0dd 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -116070 \ No newline at end of file +115929 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index f2476e2f5..173740c95 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -124888 \ No newline at end of file +124744 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index 690eed057..6ce48bb27 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -130611 \ No newline at end of file +130408 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index beee482b3..a3319d6e7 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -185452 \ No newline at end of file +185177 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index 36622c521..a6918e587 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -170594 \ No newline at end of file +170441 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index c55ea7d8f..e19bd392b 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -240296 \ No newline at end of file +239949 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index 0758ae8f8..071043d5f 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -225438 \ No newline at end of file +225213 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index 2fb484c41..cc61af9f0 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -129642 \ No newline at end of file +129438 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index a86696807..9427e2f37 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -114784 \ No newline at end of file +114702 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index d8315aecd..68542c464 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -115069 \ No newline at end of file +114927 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index 0b08fa2fc..32cfd4957 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -122016 \ No newline at end of file +121930 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index b1d78c0e5..b6531ae5c 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -117134 \ No newline at end of file +117002 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index 6202f067e..2e6870e6a 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -125952 \ No newline at end of file +125817 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 1c782b16c..8f03d1be8 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -129897 \ No newline at end of file +129689 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index ff527d262..5cb34654d 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -183800 \ No newline at end of file +183515 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index 75b2b47c6..7629f2c17 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -175919 \ No newline at end of file +175756 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index 1ed797a75..640d8aef7 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -237734 \ No newline at end of file +237372 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index 209ae5058..f377c2903 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -229853 \ No newline at end of file +229613 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 50495b292..d1680afd4 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -217089 \ No newline at end of file +216949 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index 178defb90..1c160394e 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -128925 \ No newline at end of file +128716 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index c7076c469..849ff098d 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -121044 \ No newline at end of file +120957 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index a21b83f78..2619b0057 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -116236 \ No newline at end of file +116103 \ No newline at end of file diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 4babbfb1b..1ee6cee65 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31728 \ No newline at end of file +31847 \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 9d6618d5b..fb9fdc7d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/permit2"] path = lib/permit2 url = https://github.com/Uniswap/permit2 +[submodule "lib/forge-gas-snapshot"] + path = lib/forge-gas-snapshot + url = https://github.com/marktoda/forge-gas-snapshot diff --git a/lib/forge-gas-snapshot b/lib/forge-gas-snapshot new file mode 160000 index 000000000..9fc447c73 --- /dev/null +++ b/lib/forge-gas-snapshot @@ -0,0 +1 @@ +Subproject commit 9fc447c732c89b6dd6352c096042d8d82b44faed diff --git a/lib/v4-core b/lib/v4-core index 3afa83a0e..0a849b181 160000 --- a/lib/v4-core +++ b/lib/v4-core @@ -1 +1 @@ -Subproject commit 3afa83a0e3790edb0d6d9e2289555f8e1dce211e +Subproject commit 0a849b1810210bc523da73399d6ed8e4480fd3f5 diff --git a/remappings.txt b/remappings.txt index e7868fe96..c4f006e70 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,6 +1,6 @@ @uniswap/v4-core/=lib/v4-core/ -forge-gas-snapshot/=lib/v4-core/lib/forge-gas-snapshot/src/ +forge-gas-snapshot/=lib/forge-gas-snapshot/src/ ds-test/=lib/v4-core/lib/forge-std/lib/ds-test/src/ forge-std/=lib/v4-core/lib/forge-std/src/ openzeppelin-contracts/=lib/v4-core/lib/openzeppelin-contracts/ -solmate/=lib/v4-core/lib/solmate/ \ No newline at end of file +solmate/=lib/v4-core/lib/solmate/ diff --git a/script/01_PoolManager.s.sol b/script/01_PoolManager.s.sol index e412add9e..5d4c5b140 100644 --- a/script/01_PoolManager.s.sol +++ b/script/01_PoolManager.s.sol @@ -13,7 +13,7 @@ contract DeployPoolManager is Script { function run() public returns (IPoolManager manager) { vm.startBroadcast(); - manager = new PoolManager(); + manager = new PoolManager(address(this)); console2.log("PoolManager", address(manager)); vm.stopBroadcast(); diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index 2965e5743..8f6b3f022 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -9,7 +9,7 @@ import {PositionInfo} from "../libraries/PositionInfoLibrary.sol"; /// @notice Notifier is used to opt in to sending updates to external contracts about position modifications or transfers abstract contract Notifier is INotifier { - using CustomRevert for bytes4; + using CustomRevert for *; ISubscriber private constant NO_SUBSCRIBER = ISubscriber(address(0)); @@ -53,7 +53,7 @@ abstract contract Notifier is INotifier { bool success = _call(newSubscriber, abi.encodeCall(ISubscriber.notifySubscribe, (tokenId, data))); if (!success) { - Wrap__SubscriptionReverted.selector.bubbleUpAndRevertWith(newSubscriber); + newSubscriber.bubbleUpAndRevertWith(ISubscriber.notifySubscribe.selector, SubscriptionReverted.selector); } emit Subscription(tokenId, newSubscriber); @@ -97,7 +97,9 @@ abstract contract Notifier is INotifier { ); if (!success) { - Wrap__ModifyLiquidityNotificationReverted.selector.bubbleUpAndRevertWith(address(_subscriber)); + address(_subscriber).bubbleUpAndRevertWith( + ISubscriber.notifyModifyLiquidity.selector, ModifyLiquidityNotificationReverted.selector + ); } } @@ -108,7 +110,9 @@ abstract contract Notifier is INotifier { _call(address(_subscriber), abi.encodeCall(ISubscriber.notifyTransfer, (tokenId, previousOwner, newOwner))); if (!success) { - Wrap__TransferNotificationReverted.selector.bubbleUpAndRevertWith(address(_subscriber)); + address(_subscriber).bubbleUpAndRevertWith( + ISubscriber.notifyTransfer.selector, TransferNotificationReverted.selector + ); } } diff --git a/src/interfaces/INotifier.sol b/src/interfaces/INotifier.sol index 3eefba3c5..abf6148c4 100644 --- a/src/interfaces/INotifier.sol +++ b/src/interfaces/INotifier.sol @@ -12,11 +12,11 @@ interface INotifier { /// @notice Thrown when a user specifies a gas limit too low to avoid valid unsubscribe notifications error GasLimitTooLow(); /// @notice Wraps the revert message of the subscriber contract on a reverting subscription - error Wrap__SubscriptionReverted(address subscriber, bytes reason); + error SubscriptionReverted(address subscriber, bytes reason); /// @notice Wraps the revert message of the subscriber contract on a reverting modify liquidity notification - error Wrap__ModifyLiquidityNotificationReverted(address subscriber, bytes reason); + error ModifyLiquidityNotificationReverted(address subscriber, bytes reason); /// @notice Wraps the revert message of the subscriber contract on a reverting transfer notification - error Wrap__TransferNotificationReverted(address subscriber, bytes reason); + error TransferNotificationReverted(address subscriber, bytes reason); /// @notice Thrown when a tokenId already has a subscriber error AlreadySubscribed(uint256 tokenId, address subscriber); diff --git a/test/position-managers/PositionManager.modifyLiquidities.t.sol b/test/position-managers/PositionManager.modifyLiquidities.t.sol index c805dd271..6f422ccf3 100644 --- a/test/position-managers/PositionManager.modifyLiquidities.t.sol +++ b/test/position-managers/PositionManager.modifyLiquidities.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.24; import "forge-std/Test.sol"; import {IERC20} from "forge-std/interfaces/IERC20.sol"; +import {CustomRevert} from "@uniswap/v4-core/src/libraries/CustomRevert.sol"; import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; @@ -239,9 +240,11 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF // should revert because hook is not approved vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(hookModifyLiquidities), - abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)) + IHooks.beforeSwap.selector, + abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); swap(key, true, -1e18, calls); @@ -260,9 +263,11 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF // should revert because hook is not approved vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(hookModifyLiquidities), - abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)) + IHooks.beforeSwap.selector, + abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); swap(key, true, -1e18, calls); @@ -285,9 +290,11 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF // should revert because hook is not approved vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(hookModifyLiquidities), - abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)) + IHooks.beforeSwap.selector, + abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); swap(key, true, -1e18, calls); @@ -306,9 +313,11 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF // should revert because hook is not approved vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(hookModifyLiquidities), - abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)) + IHooks.beforeSwap.selector, + abi.encodeWithSelector(IPositionManager.NotApproved.selector, address(hookModifyLiquidities)), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); swap(key, true, -1e18, calls); @@ -329,9 +338,11 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF // should revert because hook is re-entering modifyLiquiditiesWithoutUnlock vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(hookModifyLiquidities), - abi.encodeWithSelector(ReentrancyLock.ContractLocked.selector) + IHooks.beforeAddLiquidity.selector, + abi.encodeWithSelector(ReentrancyLock.ContractLocked.selector), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); lpm.modifyLiquidities(calls, _deadline); diff --git a/test/position-managers/PositionManager.notifier.t.sol b/test/position-managers/PositionManager.notifier.t.sol index 74acc7d06..3ec0e0c35 100644 --- a/test/position-managers/PositionManager.notifier.t.sol +++ b/test/position-managers/PositionManager.notifier.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.24; import "forge-std/Test.sol"; +import {CustomRevert} from "@uniswap/v4-core/src/libraries/CustomRevert.sol"; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; import {Position} from "@uniswap/v4-core/src/libraries/Position.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; @@ -511,9 +512,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - INotifier.Wrap__SubscriptionReverted.selector, + CustomRevert.WrappedError.selector, address(revertSubscriber), - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifySubscribe") + ISubscriber.notifySubscribe.selector, + abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifySubscribe"), + abi.encodeWithSelector(INotifier.SubscriptionReverted.selector) ) ); lpm.subscribe(tokenId, address(revertSubscriber), ZERO_BYTES); @@ -541,9 +544,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { bytes memory calls = plan.finalizeModifyLiquidityWithSettlePair(config.poolKey); vm.expectRevert( abi.encodeWithSelector( - INotifier.Wrap__ModifyLiquidityNotificationReverted.selector, + CustomRevert.WrappedError.selector, address(revertSubscriber), - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyModifyLiquidity") + ISubscriber.notifyModifyLiquidity.selector, + abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyModifyLiquidity"), + abi.encodeWithSelector(INotifier.ModifyLiquidityNotificationReverted.selector) ) ); lpm.modifyLiquidities(calls, _deadline); @@ -562,9 +567,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - INotifier.Wrap__TransferNotificationReverted.selector, + CustomRevert.WrappedError.selector, address(revertSubscriber), - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer") + ISubscriber.notifyTransfer.selector, + abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer"), + abi.encodeWithSelector(INotifier.TransferNotificationReverted.selector) ) ); lpm.transferFrom(alice, bob, tokenId); @@ -583,9 +590,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - INotifier.Wrap__TransferNotificationReverted.selector, + CustomRevert.WrappedError.selector, address(revertSubscriber), - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer") + ISubscriber.notifyTransfer.selector, + abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer"), + abi.encodeWithSelector(INotifier.TransferNotificationReverted.selector) ) ); lpm.safeTransferFrom(alice, bob, tokenId); @@ -604,9 +613,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { vm.expectRevert( abi.encodeWithSelector( - INotifier.Wrap__TransferNotificationReverted.selector, + CustomRevert.WrappedError.selector, address(revertSubscriber), - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer") + ISubscriber.notifyTransfer.selector, + abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer"), + abi.encodeWithSelector(INotifier.TransferNotificationReverted.selector) ) ); lpm.safeTransferFrom(alice, bob, tokenId, ""); @@ -679,9 +690,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { // should revert since the pool manager is unlocked vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(reenterHook), - abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector) + IHooks.beforeAddLiquidity.selector, + abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); lpm.modifyLiquidities(actions, _deadline); @@ -700,9 +713,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { // should revert since the pool manager is unlocked vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(reenterHook), - abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector) + IHooks.beforeAddLiquidity.selector, + abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); lpm.modifyLiquidities(actions, _deadline); @@ -721,9 +736,11 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { // should revert since the pool manager is unlocked vm.expectRevert( abi.encodeWithSelector( - Hooks.Wrap__FailedHookCall.selector, + CustomRevert.WrappedError.selector, address(reenterHook), - abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector) + IHooks.beforeAddLiquidity.selector, + abi.encodeWithSelector(IPositionManager.PoolManagerMustBeLocked.selector), + abi.encodeWithSelector(Hooks.HookCallFailed.selector) ) ); lpm.modifyLiquidities(actions, _deadline); diff --git a/test/script/DeployPoolManager.t.sol b/test/script/DeployPoolManager.t.sol index fbb7df439..19159c266 100644 --- a/test/script/DeployPoolManager.t.sol +++ b/test/script/DeployPoolManager.t.sol @@ -15,7 +15,7 @@ contract DeployPoolManagerTest is Test { function test_run_poolManager() public { IPoolManager manager = deployer.run(); // Foundry sets a default sender in scripts. - address defaultSender = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; + address defaultSender = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; // Deployer is the owner. assertEq(_getOwner(manager), defaultSender); } diff --git a/test/script/DeployPoolMofifyLiquidityTest.t.sol b/test/script/DeployPoolMofifyLiquidityTest.t.sol index e4c677108..6da02e012 100644 --- a/test/script/DeployPoolMofifyLiquidityTest.t.sol +++ b/test/script/DeployPoolMofifyLiquidityTest.t.sol @@ -14,7 +14,7 @@ contract DeployPoolModifyLiquidityTestTest is Test { IPoolManager manager; function setUp() public { - manager = new PoolManager(); + manager = new PoolManager(address(this)); deployer = new DeployPoolModifyLiquidityTest(); } diff --git a/test/script/DeployPoolSwapTest.t.sol b/test/script/DeployPoolSwapTest.t.sol index 2feb0aaad..de9ca350b 100644 --- a/test/script/DeployPoolSwapTest.t.sol +++ b/test/script/DeployPoolSwapTest.t.sol @@ -14,7 +14,7 @@ contract DeployPoolSwapTestTest is Test { IPoolManager manager; function setUp() public { - manager = new PoolManager(); + manager = new PoolManager(address(this)); deployer = new DeployPoolSwapTest(); } From 0a97fda32ae85d122df4fe9c91a3363e7b1a5800 Mon Sep 17 00:00:00 2001 From: marktoda Date: Fri, 8 Nov 2024 05:50:22 -0800 Subject: [PATCH 14/31] feat: add UniswapV4DeployerCompetition (#117) * feat: add UniswapV4DeployerCompetition this commit adds a contract that creates a competition to generate the vanity address for Uniswap V4. It does so using CREATE2 salts, pre-calculating the address at which the contract will be deployed and applying a score to the address based on its vanity. leading 0's are weighted most heavily, followed by other 0's and 4's. The winner receives an NFT, a bounty, and deployer privileges * add comments * change scoring to discuss * interface plus tests * inheritdoc tags * change scoring algorithm * feat: remove prizes this commit removes the ETH payout, NFT mint, and exclusive deploy rights * feat: add natspec * fix: snaps * feat: improve test * feat: cleanup scoring code * fix: typo * update constructor parameters for pool manager * correct snapshots * Include address in salt * remove console logs * correct test name * More constructor parameters * fix: remove override keywords * fix: remove unused code * fix: use default create2 function signature * feat: remove unused import * fix: remove unused v4Owner variable * fix: add rules to natspec * fix(deployComp): remove bestaddress storage This commit removes the storage variable for bestAddres, calculating it on-the-fly instead. It also just takes the initial `salt = 0` value as a default score-to-beat rather than a sentinel for any salt is allowed as a simplification * fix: minor nits - comparison strictness match comments - unchecked vanity math * snapshot --------- Co-authored-by: dianakocsis Co-authored-by: hensha256 --- .../positionDescriptor bytecode size.snap | 2 +- lib/v4-core | 2 +- src/UniswapV4DeployerCompetition.sol | 85 +++++++++ .../IUniswapV4DeployerCompetition.sol | 25 +++ src/libraries/VanityAddressLib.sol | 97 ++++++++++ test/UniswapV4DeployerCompetition.t.sol | 178 ++++++++++++++++++ test/libraries/VanityAddressLib.t.sol | 101 ++++++++++ .../PositionManager.modifyLiquidities.t.sol | 2 - 8 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 src/UniswapV4DeployerCompetition.sol create mode 100644 src/interfaces/IUniswapV4DeployerCompetition.sol create mode 100644 src/libraries/VanityAddressLib.sol create mode 100644 test/UniswapV4DeployerCompetition.t.sol create mode 100644 test/libraries/VanityAddressLib.t.sol diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 1ee6cee65..4babbfb1b 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31847 \ No newline at end of file +31728 \ No newline at end of file diff --git a/lib/v4-core b/lib/v4-core index 0a849b181..362c9cab7 160000 --- a/lib/v4-core +++ b/lib/v4-core @@ -1 +1 @@ -Subproject commit 0a849b1810210bc523da73399d6ed8e4480fd3f5 +Subproject commit 362c9cab7c03ca1122795aed2e8e118de9ed186e diff --git a/src/UniswapV4DeployerCompetition.sol b/src/UniswapV4DeployerCompetition.sol new file mode 100644 index 000000000..c9af05a65 --- /dev/null +++ b/src/UniswapV4DeployerCompetition.sol @@ -0,0 +1,85 @@ +// SPADIX-License-Identifier: UNLICENSED +pragma solidity 0.8.26; + +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {VanityAddressLib} from "./libraries/VanityAddressLib.sol"; +import {IUniswapV4DeployerCompetition} from "./interfaces/IUniswapV4DeployerCompetition.sol"; + +/// @title UniswapV4DeployerCompetition +/// @notice A contract to crowdsource a salt for the best Uniswap V4 address +contract UniswapV4DeployerCompetition is IUniswapV4DeployerCompetition { + using VanityAddressLib for address; + + /// @dev The salt for the best address found so far + bytes32 public bestAddressSalt; + /// @dev The submitter of the best address found so far + address public bestAddressSubmitter; + + /// @dev The deadline for the competition + uint256 public immutable competitionDeadline; + /// @dev The init code hash of the V4 contract + bytes32 public immutable initCodeHash; + + /// @dev The deployer who can initiate the deployment of the v4 PoolManager, until the exclusive deploy deadline. + /// @dev After this deadline anyone can deploy. + address public immutable deployer; + /// @dev The deadline for exclusive deployment by deployer after deadline + uint256 public immutable exclusiveDeployDeadline; + + constructor( + bytes32 _initCodeHash, + uint256 _competitionDeadline, + address _exclusiveDeployer, + uint256 _exclusiveDeployLength + ) { + initCodeHash = _initCodeHash; + competitionDeadline = _competitionDeadline; + exclusiveDeployDeadline = _competitionDeadline + _exclusiveDeployLength; + deployer = _exclusiveDeployer; + } + + /// @inheritdoc IUniswapV4DeployerCompetition + function updateBestAddress(bytes32 salt) external { + if (block.timestamp > competitionDeadline) { + revert CompetitionOver(block.timestamp, competitionDeadline); + } + + address saltSubAddress = address(bytes20(salt)); + if (saltSubAddress != msg.sender && saltSubAddress != address(0)) revert InvalidSender(salt, msg.sender); + + address newAddress = Create2.computeAddress(salt, initCodeHash); + address _bestAddress = bestAddress(); + if (!newAddress.betterThan(_bestAddress)) { + revert WorseAddress(newAddress, _bestAddress, newAddress.score(), _bestAddress.score()); + } + + bestAddressSalt = salt; + bestAddressSubmitter = msg.sender; + + emit NewAddressFound(newAddress, msg.sender, newAddress.score()); + } + + /// @inheritdoc IUniswapV4DeployerCompetition + function deploy(bytes memory bytecode) external { + if (keccak256(bytecode) != initCodeHash) { + revert InvalidBytecode(); + } + + if (block.timestamp <= competitionDeadline) { + revert CompetitionNotOver(block.timestamp, competitionDeadline); + } + + if (msg.sender != deployer && block.timestamp <= exclusiveDeployDeadline) { + // anyone can deploy after the deadline + revert NotAllowedToDeploy(msg.sender, deployer); + } + + // the owner of the contract must be encoded in the bytecode + Create2.deploy(0, bestAddressSalt, bytecode); + } + + /// @dev returns the best address found so far + function bestAddress() public view returns (address) { + return Create2.computeAddress(bestAddressSalt, initCodeHash); + } +} diff --git a/src/interfaces/IUniswapV4DeployerCompetition.sol b/src/interfaces/IUniswapV4DeployerCompetition.sol new file mode 100644 index 000000000..82959230c --- /dev/null +++ b/src/interfaces/IUniswapV4DeployerCompetition.sol @@ -0,0 +1,25 @@ +// SPADIX-License-Identifier: UNLICENSED +pragma solidity 0.8.26; + +/// @title UniswapV4DeployerCompetition +/// @notice A competition to deploy the UniswapV4 contract with the best address +interface IUniswapV4DeployerCompetition { + event NewAddressFound(address indexed bestAddress, address indexed submitter, uint256 score); + + error InvalidBytecode(); + error CompetitionNotOver(uint256 currentTime, uint256 deadline); + error CompetitionOver(uint256 currentTime, uint256 deadline); + error NotAllowedToDeploy(address sender, address deployer); + error WorseAddress(address newAddress, address bestAddress, uint256 newScore, uint256 bestScore); + error InvalidSender(bytes32 salt, address sender); + + /// @notice Updates the best address if the new address has a better vanity score + /// @param salt The salt to use to compute the new address with CREATE2 + /// @dev The first 20 bytes of the salt must be either address(0) or msg.sender + function updateBestAddress(bytes32 salt) external; + + /// @notice deploys the Uniswap v4 PoolManager contract + /// @param bytecode The bytecode of the Uniswap v4 PoolManager contract + /// @dev The bytecode must match the initCodeHash + function deploy(bytes memory bytecode) external; +} diff --git a/src/libraries/VanityAddressLib.sol b/src/libraries/VanityAddressLib.sol new file mode 100644 index 000000000..ba35b9699 --- /dev/null +++ b/src/libraries/VanityAddressLib.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +/// @title VanityAddressLib +/// @notice A library to score addresses based on their vanity +library VanityAddressLib { + /// @notice Compares two addresses and returns true if the first address has a better vanity score + /// @param first The first address to compare + /// @param second The second address to compare + /// @return better True if the first address has a better vanity score + function betterThan(address first, address second) internal pure returns (bool better) { + return score(first) > score(second); + } + + /// @notice Scores an address based on its vanity + /// @dev Scoring rules: + /// Requirement: The first nonzero nibble must be 4 + /// 10 points for every leading 0 nibble + /// 40 points if the first 4 is followed by 3 more 4s + /// 20 points if the first nibble after the 4 4s is NOT a 4 + /// 20 points if the last 4 nibbles are 4s + /// 1 point for every 4 + /// @param addr The address to score + /// @return calculatedScore The vanity score of the address + function score(address addr) internal pure returns (uint256 calculatedScore) { + // convert the address to bytes for easier parsing + bytes20 addrBytes = bytes20(addr); + + unchecked { + // 10 points per leading zero nibble + uint256 leadingZeroCount = getLeadingNibbleCount(addrBytes, 0, 0); + calculatedScore += (leadingZeroCount * 10); + + // special handling for 4s immediately after leading 0s + uint256 leadingFourCount = getLeadingNibbleCount(addrBytes, leadingZeroCount, 4); + // If the first nonzero nibble is not 4, return 0 + if (leadingFourCount == 0) { + return 0; + } else if (leadingFourCount == 4) { + // 60 points if exactly 4 4s + calculatedScore += 60; + } else if (leadingFourCount > 4) { + // 40 points if more than 4 4s + calculatedScore += 40; + } + + // handling for remaining nibbles + for (uint256 i = 0; i < addrBytes.length * 2; i++) { + uint8 currentNibble = getNibble(addrBytes, i); + + // 1 extra point for any 4 nibbles + if (currentNibble == 4) { + calculatedScore += 1; + } + } + + // If the last 4 nibbles are 4s, add 20 points + if (addrBytes[18] == 0x44 && addrBytes[19] == 0x44) { + calculatedScore += 20; + } + } + } + + /// @notice Returns the number of leading nibbles in an address that match a given value + /// @param addrBytes The address to count the leading zero nibbles in + function getLeadingNibbleCount(bytes20 addrBytes, uint256 startIndex, uint8 comparison) + internal + pure + returns (uint256 count) + { + if (startIndex >= addrBytes.length * 2) { + return count; + } + + for (uint256 i = startIndex; i < addrBytes.length * 2; i++) { + uint8 currentNibble = getNibble(addrBytes, i); + if (currentNibble != comparison) { + return count; + } + count += 1; + } + } + + /// @notice Returns the nibble at a given index in an address + /// @param input The address to get the nibble from + /// @param nibbleIndex The index of the nibble to get + function getNibble(bytes20 input, uint256 nibbleIndex) internal pure returns (uint8 currentNibble) { + uint8 currByte = uint8(input[nibbleIndex / 2]); + if (nibbleIndex % 2 == 0) { + // Get the higher nibble of the byte + currentNibble = currByte >> 4; + } else { + // Get the lower nibble of the byte + currentNibble = currByte & 0x0F; + } + } +} diff --git a/test/UniswapV4DeployerCompetition.t.sol b/test/UniswapV4DeployerCompetition.t.sol new file mode 100644 index 000000000..265d3b6fe --- /dev/null +++ b/test/UniswapV4DeployerCompetition.t.sol @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import {Owned} from "solmate/src/auth/Owned.sol"; +import {Test} from "forge-std/Test.sol"; +import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol"; +import {UniswapV4DeployerCompetition} from "../src/UniswapV4DeployerCompetition.sol"; +import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; +import {VanityAddressLib} from "../src/libraries/VanityAddressLib.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {IUniswapV4DeployerCompetition} from "../src/interfaces/IUniswapV4DeployerCompetition.sol"; + +contract UniswapV4DeployerCompetitionTest is Test { + using VanityAddressLib for address; + + UniswapV4DeployerCompetition competition; + bytes32 initCodeHash; + address deployer; + address v4Owner; + address winner; + address defaultAddress; + uint256 competitionDeadline; + uint256 exclusiveDeployLength = 1 days; + + bytes32 mask20bytes = bytes32(uint256(type(uint96).max)); + + function setUp() public { + competitionDeadline = block.timestamp + 7 days; + v4Owner = makeAddr("V4Owner"); + winner = makeAddr("Winner"); + deployer = makeAddr("Deployer"); + vm.prank(deployer); + initCodeHash = keccak256(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + competition = + new UniswapV4DeployerCompetition(initCodeHash, competitionDeadline, deployer, exclusiveDeployLength); + defaultAddress = Create2.computeAddress(bytes32(0), initCodeHash, address(competition)); + } + + function test_defaultSalt_deploy_succeeds() public { + assertEq(competition.bestAddressSubmitter(), address(0)); + assertEq(competition.bestAddressSalt(), bytes32(0)); + assertEq(competition.bestAddress(), defaultAddress); + + assertEq(defaultAddress.code.length, 0); + vm.warp(competition.competitionDeadline() + 1); + vm.prank(deployer); + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + assertFalse(defaultAddress.code.length == 0); + assertEq(Owned(defaultAddress).owner(), v4Owner); + } + + function test_updateBestAddress_succeeds(bytes32 salt) public { + salt = (salt & mask20bytes) | bytes32(bytes20(winner)); + + assertEq(competition.bestAddressSubmitter(), address(0)); + assertEq(competition.bestAddressSalt(), bytes32(0)); + assertEq(competition.bestAddress(), defaultAddress); + + address newAddress = Create2.computeAddress(salt, initCodeHash, address(competition)); + vm.assume(newAddress.betterThan(defaultAddress)); + + vm.prank(winner); + vm.expectEmit(true, true, true, false, address(competition)); + emit IUniswapV4DeployerCompetition.NewAddressFound(newAddress, winner, VanityAddressLib.score(newAddress)); + competition.updateBestAddress(salt); + assertFalse(competition.bestAddress() == address(0), "best address not set"); + assertEq(competition.bestAddress(), newAddress, "wrong address set"); + assertEq(competition.bestAddressSubmitter(), winner, "wrong submitter set"); + assertEq(competition.bestAddressSalt(), salt, "incorrect salt set"); + address v4Core = competition.bestAddress(); + + assertEq(v4Core.code.length, 0); + vm.warp(competition.competitionDeadline() + 1); + vm.prank(deployer); + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + assertFalse(v4Core.code.length == 0); + assertEq(Owned(v4Core).owner(), v4Owner); + assertEq(address(competition).balance, 0 ether); + } + + function test_updateBestAddress_reverts_CompetitionOver(bytes32 salt) public { + vm.warp(competition.competitionDeadline() + 1); + vm.expectRevert( + abi.encodeWithSelector( + IUniswapV4DeployerCompetition.CompetitionOver.selector, + block.timestamp, + competition.competitionDeadline() + ) + ); + competition.updateBestAddress(salt); + } + + function test_updateBestAddress_reverts_InvalidSigner(bytes32 salt) public { + vm.assume(bytes20(salt) != bytes20(0)); + vm.assume(bytes20(salt) != bytes20(winner)); + + vm.expectRevert(abi.encodeWithSelector(IUniswapV4DeployerCompetition.InvalidSender.selector, salt, winner)); + vm.prank(winner); + competition.updateBestAddress(salt); + } + + function test_updateBestAddress_reverts_WorseAddress(bytes32 salt) public { + vm.assume(salt != bytes32(0)); + salt = (salt & mask20bytes) | bytes32(bytes20(winner)); + + address newAddr = Create2.computeAddress(salt, initCodeHash, address(competition)); + if (!newAddr.betterThan(defaultAddress)) { + vm.expectRevert( + abi.encodeWithSelector( + IUniswapV4DeployerCompetition.WorseAddress.selector, + newAddr, + competition.bestAddress(), + newAddr.score(), + competition.bestAddress().score() + ) + ); + vm.prank(winner); + competition.updateBestAddress(salt); + } else { + vm.prank(winner); + competition.updateBestAddress(salt); + assertEq(competition.bestAddressSubmitter(), winner); + assertEq(competition.bestAddressSalt(), salt); + assertEq(competition.bestAddress(), newAddr); + } + } + + function test_deploy_succeeds(bytes32 salt) public { + salt = (salt & mask20bytes) | bytes32(bytes20(winner)); + + address newAddress = Create2.computeAddress(salt, initCodeHash, address(competition)); + vm.assume(newAddress.betterThan(defaultAddress)); + + vm.prank(winner); + competition.updateBestAddress(salt); + address v4Core = competition.bestAddress(); + + vm.warp(competition.competitionDeadline() + 1); + vm.prank(deployer); + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + assertFalse(v4Core.code.length == 0); + assertEq(Owned(v4Core).owner(), v4Owner); + assertEq(TickMath.MAX_TICK_SPACING, type(int16).max); + } + + function test_deploy_reverts_CompetitionNotOver(uint256 timestamp) public { + vm.assume(timestamp < competition.competitionDeadline()); + vm.warp(timestamp); + vm.expectRevert( + abi.encodeWithSelector( + IUniswapV4DeployerCompetition.CompetitionNotOver.selector, timestamp, competition.competitionDeadline() + ) + ); + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + } + + function test_deploy_reverts_InvalidBytecode() public { + vm.expectRevert(IUniswapV4DeployerCompetition.InvalidBytecode.selector); + vm.prank(deployer); + // set the owner as the winner not the correct owner + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(winner)))); + } + + function test_deploy_reverts_NotAllowedToDeploy() public { + vm.warp(competition.competitionDeadline() + 1); + vm.prank(address(1)); + vm.expectRevert( + abi.encodeWithSelector(IUniswapV4DeployerCompetition.NotAllowedToDeploy.selector, address(1), deployer) + ); + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + } + + function test_deploy_succeeds_afterExcusiveDeployDeadline() public { + vm.warp(competition.exclusiveDeployDeadline() + 1); + vm.prank(address(1)); + competition.deploy(abi.encodePacked(type(PoolManager).creationCode, uint256(uint160(v4Owner)))); + } +} diff --git a/test/libraries/VanityAddressLib.t.sol b/test/libraries/VanityAddressLib.t.sol new file mode 100644 index 000000000..f9ae5474a --- /dev/null +++ b/test/libraries/VanityAddressLib.t.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import {Test} from "forge-std/Test.sol"; +import {VanityAddressLib} from "../../src/libraries/VanityAddressLib.sol"; + +contract VanityAddressLibTest is Test { + function test_fuzz_reasonableScoreNeverReverts(address test) public pure { + uint256 score = VanityAddressLib.score(address(test)); + assertGe(score, 0); + assertLe(score, 444); + } + + function test_scoreAllFours() public pure { + address addr = address(0x4444444444444444444444444444444444444444); + uint256 score = VanityAddressLib.score(addr); + uint256 expected = 100; // 40 + 40 + 20 = 100 + assertEq(score, expected); + } + + function test_scoreLaterFours() public pure { + address addr = address(0x1444444444444444444444444444444444444444); + uint256 score = VanityAddressLib.score(addr); + uint256 expected = 0; // no leading 4 + assertEq(score, expected); + } + + function test_scoreMixed_4() public pure { + address addr = address(0x0044001111111111111111111111111111114114); + // counts first null byte + // counts first leading 4s after that + // does not count future null bytes + // counts 4 nibbles after that + uint256 score = VanityAddressLib.score(addr); + uint256 expected = 24; // 10 * 2 + 2 + 2 = 24 + assertEq(score, expected); + } + + function test_scoreMixed_44() public pure { + address addr = address(0x0044001111111111111111111111111111114444); + // counts first null byte + // counts first leading 4s after that + // does not count future null bytes + // counts 4 nibbles after that + uint256 score = VanityAddressLib.score(addr); + uint256 expected = 46; // 10 * 2 + 6 + 20 = 46 + assertEq(score, expected); + } + + function test_scoreMixed_halfZeroHalf4() public pure { + address addr = address(0x0004111111111111111111111111111111111111); + // counts first null byte + // counts first leading 4s after that + uint256 score = VanityAddressLib.score(addr); + uint256 expected = 31; // 10 * 3 + 1 = 31 + assertEq(score, expected); + } + + function test_scores_succeed() public pure { + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000082)), 0); // 0 + assertEq(VanityAddressLib.score(address(0x0400000000000000000000000000000000000000)), 11); // 10 * 1 + 1 = 11 + assertEq(VanityAddressLib.score(address(0x0044000000000000000000000000000000004444)), 46); // 10 * 2 + 6 + 20 = 46 + assertEq(VanityAddressLib.score(address(0x4444000000000000000000000000000000004444)), 88); // 40 + 20 + 20 + 8 = 88 + assertEq(VanityAddressLib.score(address(0x0044440000000000000000000000000000000044)), 86); // 10 * 2 + 40 + 20 + 6 = 86 + assertEq(VanityAddressLib.score(address(0x0000444400000000000000000000000000004444)), 128); // 10 * 4 + 40 + 20 + 20 + 8 = 128 + assertEq(VanityAddressLib.score(address(0x0040444444444444444444444444444444444444)), 77); // 10 * 2 + 37 + 20 = 77 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000444)), 373); // 10 * 37 + 3 = 373 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000044444444)), 388); // 10 * 32 + 40 + 20 + 8 = 388 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000454444)), 365); // 10 * 34 + 20 + 5 = 365 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000044)), 382); // 10 * 38 + 2 = 382 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000004)), 391); // 10 * 39 + 1 = 391 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000444444)), 406); // 10 * 34 + 40 + 20 + 6 = 406 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000044444)), 415); // 10 * 35 + 40 + 20 + 5 = 415 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000444455)), 404); // 10 * 34 + 40 + 20 + 4 = 404 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000044445)), 414); // 10 * 35 + 40 + 20 + 4 = 414 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000004444)), 444); // 10 * 36 + 40 + 20 + 20 + 4 = 444 + } + + function test_betterThan() public pure { + address addr1 = address(0x0011111111111111111111111111111111111111); // 0 points + address addr2 = address(0x4000111111111111111111111111111111111111); // 1 points + address addr3 = address(0x0000411111111111111111111111111111111111); // 10 * 4 + 1 = 41 points + address addr4 = address(0x0000441111111111111111111111111111111111); // 10 * 4 + 2 = 42 points + address addr5 = address(0x0000440011111111111111111111111111111111); // 10 * 4 + 2 = 42 points + assertTrue(VanityAddressLib.betterThan(addr2, addr1)); // 1 > 0 + assertTrue(VanityAddressLib.betterThan(addr3, addr2)); // 41 > 1 + assertTrue(VanityAddressLib.betterThan(addr3, addr1)); // 41 > 0 + assertTrue(VanityAddressLib.betterThan(addr4, addr3)); // 42 > 41 + assertTrue(VanityAddressLib.betterThan(addr4, addr2)); // 42 > 1 + assertTrue(VanityAddressLib.betterThan(addr4, addr1)); // 42 > 0 + assertFalse(VanityAddressLib.betterThan(addr5, addr4)); // 42 == 42 + assertEq(VanityAddressLib.score(addr5), VanityAddressLib.score(addr4)); // 42 == 42 + assertTrue(VanityAddressLib.betterThan(addr5, addr3)); // 42 > 41 + assertTrue(VanityAddressLib.betterThan(addr5, addr2)); // 42 > 1 + assertTrue(VanityAddressLib.betterThan(addr5, addr1)); // 42 > 0 + + address addr6 = address(0x0000000000000000000000000000000000004444); + address addr7 = address(0x0000000000000000000000000000000000000082); + assertTrue(VanityAddressLib.betterThan(addr6, addr7)); // 10 * 36 + 40 + 20 + 20 + 4 = 444 > 0 + } +} diff --git a/test/position-managers/PositionManager.modifyLiquidities.t.sol b/test/position-managers/PositionManager.modifyLiquidities.t.sol index 6f422ccf3..4e14a733c 100644 --- a/test/position-managers/PositionManager.modifyLiquidities.t.sol +++ b/test/position-managers/PositionManager.modifyLiquidities.t.sol @@ -33,8 +33,6 @@ import {ActionConstants} from "../../src/libraries/ActionConstants.sol"; import {Planner, Plan} from "../shared/Planner.sol"; import {DeltaResolver} from "../../src/base/DeltaResolver.sol"; -import "forge-std/console2.sol"; - contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityFuzzers { using StateLibrary for IPoolManager; using PoolIdLibrary for PoolKey; From 3f295d8435e4f776ea2daeb96ce1bc6d63f33fc7 Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:53:55 +0000 Subject: [PATCH 15/31] Update compiler and pull in core (#392) --- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .forge-snapshots/positionDescriptor bytecode size.snap | 2 +- foundry.toml | 1 + lib/v4-core | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index 1e50a9b94..7d18bd6a5 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7158 \ No newline at end of file +7117 \ No newline at end of file diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 4babbfb1b..b89166c6e 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31728 \ No newline at end of file +31687 \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 381668e8d..c685a490e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -8,6 +8,7 @@ fs_permissions = [{ access = "read-write", path = ".forge-snapshots/"}] evm_version = "cancun" gas_limit = "3000000000" fuzz_runs = 10_000 +bytecode_hash = "none" [profile.debug] via_ir = false diff --git a/lib/v4-core b/lib/v4-core index 362c9cab7..0f17b65aa 160000 --- a/lib/v4-core +++ b/lib/v4-core @@ -1 +1 @@ -Subproject commit 362c9cab7c03ca1122795aed2e8e118de9ed186e +Subproject commit 0f17b65aa61edee384d5129b7ea080f22905faa0 From d767807d357b18bb8d35876b52c0556f1c2b302f Mon Sep 17 00:00:00 2001 From: Daniel Gretzke Date: Tue, 19 Nov 2024 01:41:31 +0700 Subject: [PATCH 16/31] Rename quoter (#394) --- ...eployQuoter.s.sol => DeployV4Quoter.s.sol} | 12 ++-- src/interfaces/{IQuoter.sol => IV4Quoter.sol} | 4 +- src/lens/{Quoter.sol => V4Quoter.sol} | 12 ++-- test/{Quoter.t.sol => V4Quoter.t.sol} | 62 +++++++++---------- 4 files changed, 45 insertions(+), 45 deletions(-) rename script/{DeployQuoter.s.sol => DeployV4Quoter.s.sol} (53%) rename src/interfaces/{IQuoter.sol => IV4Quoter.sol} (98%) rename src/lens/{Quoter.sol => V4Quoter.sol} (96%) rename test/{Quoter.t.sol => V4Quoter.t.sol} (89%) diff --git a/script/DeployQuoter.s.sol b/script/DeployV4Quoter.s.sol similarity index 53% rename from script/DeployQuoter.s.sol rename to script/DeployV4Quoter.s.sol index 501f77611..1c6a8430e 100644 --- a/script/DeployQuoter.s.sol +++ b/script/DeployV4Quoter.s.sol @@ -5,17 +5,17 @@ import "forge-std/console2.sol"; import "forge-std/Script.sol"; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; -import {Quoter} from "../src/lens/Quoter.sol"; +import {V4Quoter} from "../src/lens/V4Quoter.sol"; -contract DeployQuoter is Script { +contract DeployV4Quoter is Script { function setUp() public {} - function run(address poolManager) public returns (Quoter state) { + function run(address poolManager) public returns (V4Quoter state) { vm.startBroadcast(); - // forge script --broadcast --sig 'run(address)' --rpc-url --private-key --verify script/DeployQuoter.s.sol:DeployQuoter - state = new Quoter(IPoolManager(poolManager)); - console2.log("Quoter", address(state)); + // forge script --broadcast --sig 'run(address)' --rpc-url --private-key --verify script/DeployV4Quoter.s.sol:DeployV4Quoter + state = new V4Quoter(IPoolManager(poolManager)); + console2.log("V4Quoter", address(state)); console2.log("PoolManager", address(state.poolManager())); vm.stopBroadcast(); diff --git a/src/interfaces/IQuoter.sol b/src/interfaces/IV4Quoter.sol similarity index 98% rename from src/interfaces/IQuoter.sol rename to src/interfaces/IV4Quoter.sol index 9815d74b7..a8483a894 100644 --- a/src/interfaces/IQuoter.sol +++ b/src/interfaces/IV4Quoter.sol @@ -5,12 +5,12 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; import {PathKey} from "../libraries/PathKey.sol"; -/// @title Quoter Interface +/// @title V4 Quoter Interface /// @notice Supports quoting the delta amounts for exact input or exact output swaps. /// @notice For each pool also tells you the sqrt price of the pool after the swap. /// @dev These functions are not marked view because they rely on calling non-view functions and reverting /// to compute the result. They are also not gas efficient and should not be called on-chain. -interface IQuoter { +interface IV4Quoter { struct QuoteExactSingleParams { PoolKey poolKey; bool zeroForOne; diff --git a/src/lens/Quoter.sol b/src/lens/V4Quoter.sol similarity index 96% rename from src/lens/Quoter.sol rename to src/lens/V4Quoter.sol index fd1597978..1623ff59b 100644 --- a/src/lens/Quoter.sol +++ b/src/lens/V4Quoter.sol @@ -6,18 +6,18 @@ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; -import {IQuoter} from "../interfaces/IQuoter.sol"; +import {IV4Quoter} from "../interfaces/IV4Quoter.sol"; import {PathKey, PathKeyLibrary} from "../libraries/PathKey.sol"; import {QuoterRevert} from "../libraries/QuoterRevert.sol"; import {BaseV4Quoter} from "../base/BaseV4Quoter.sol"; -contract Quoter is IQuoter, BaseV4Quoter { +contract V4Quoter is IV4Quoter, BaseV4Quoter { using PathKeyLibrary for PathKey; using QuoterRevert for *; constructor(IPoolManager _poolManager) BaseV4Quoter(_poolManager) {} - /// @inheritdoc IQuoter + /// @inheritdoc IV4Quoter function quoteExactInputSingle(QuoteExactSingleParams memory params) external returns (uint256 amountOut, uint256 gasEstimate) @@ -31,7 +31,7 @@ contract Quoter is IQuoter, BaseV4Quoter { } } - /// @inheritdoc IQuoter + /// @inheritdoc IV4Quoter function quoteExactInput(QuoteExactParams memory params) external returns (uint256 amountOut, uint256 gasEstimate) @@ -45,7 +45,7 @@ contract Quoter is IQuoter, BaseV4Quoter { } } - /// @inheritdoc IQuoter + /// @inheritdoc IV4Quoter function quoteExactOutputSingle(QuoteExactSingleParams memory params) external returns (uint256 amountIn, uint256 gasEstimate) @@ -59,7 +59,7 @@ contract Quoter is IQuoter, BaseV4Quoter { } } - /// @inheritdoc IQuoter + /// @inheritdoc IV4Quoter function quoteExactOutput(QuoteExactParams memory params) external returns (uint256 amountIn, uint256 gasEstimate) diff --git a/test/Quoter.t.sol b/test/V4Quoter.t.sol similarity index 89% rename from test/Quoter.t.sol rename to test/V4Quoter.t.sol index 2dc1c8540..26b62d102 100644 --- a/test/Quoter.t.sol +++ b/test/V4Quoter.t.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {PathKey} from "../src/libraries/PathKey.sol"; -import {IQuoter} from "../src/interfaces/IQuoter.sol"; -import {Quoter} from "../src/lens/Quoter.sol"; +import {IV4Quoter} from "../src/interfaces/IV4Quoter.sol"; +import {V4Quoter} from "../src/lens/V4Quoter.sol"; import {BaseV4Quoter} from "../src/base/BaseV4Quoter.sol"; import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; @@ -40,7 +40,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { uint256 internal constant CONTROLLER_GAS_LIMIT = 500000; - Quoter quoter; + V4Quoter quoter; PoolModifyLiquidityTest positionManager; @@ -56,7 +56,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function setUp() public { deployFreshManagerAndRouters(); - quoter = new Quoter(IPoolManager(manager)); + quoter = new V4Quoter(IPoolManager(manager)); positionManager = new PoolModifyLiquidityTest(manager); // salts are chosen so that address(token0) < address(token1) && address(token1) < address(token2) @@ -86,7 +86,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { uint256 expectedAmountOut = 9871; (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInputSingle( - IQuoter.QuoteExactSingleParams({ + IV4Quoter.QuoteExactSingleParams({ poolKey: key02, zeroForOne: true, exactAmount: uint128(amountIn), @@ -105,7 +105,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { uint256 expectedAmountOut = 9871; (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInputSingle( - IQuoter.QuoteExactSingleParams({ + IV4Quoter.QuoteExactSingleParams({ poolKey: key02, zeroForOne: false, exactAmount: uint128(amountIn), @@ -122,7 +122,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactInput_0to2_2TicksLoaded() public { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -137,7 +137,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { // 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. - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 6200); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 6200); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -152,7 +152,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { // The swap amount is set such that the active tick after the swap is -60. // -60 is an initialized tick for this pool. We check that we don't count it. - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 4000); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 4000); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -166,7 +166,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactInput_0to2_0TickLoaded_startingNotInitialized() public { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -179,7 +179,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { setupPoolWithZeroTickInitialized(key02); tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -191,7 +191,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactInput_2to0_2TicksLoaded() public { tokenPath.push(token2); tokenPath.push(token0); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -206,7 +206,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { // 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. - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 6250); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 6250); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -221,7 +221,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { setupPoolWithZeroTickInitialized(key02); tokenPath.push(token2); tokenPath.push(token0); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 200); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 200); // Tick 0 initialized. Tick after = 1 (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -237,7 +237,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactInput_2to0_0TickLoaded_startingNotInitialized() public { tokenPath.push(token2); tokenPath.push(token0); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 103); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 103); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -249,7 +249,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactInput_2to1() public { tokenPath.push(token2); tokenPath.push(token1); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); assertGt(gasEstimate, 50000); @@ -261,7 +261,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token0); tokenPath.push(token2); tokenPath.push(token1); - IQuoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); + IV4Quoter.QuoteExactParams memory params = getExactInputParams(tokenPath, 10000); (uint256 amountOut, uint256 gasEstimate) = quoter.quoteExactInput(params); @@ -275,7 +275,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactOutputSingle_0to1() public { uint256 amountOut = 10000; (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutputSingle( - IQuoter.QuoteExactSingleParams({ + IV4Quoter.QuoteExactSingleParams({ poolKey: key01, zeroForOne: true, exactAmount: uint128(amountOut), @@ -292,7 +292,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactOutputSingle_1to0() public { uint256 amountOut = 10000; (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutputSingle( - IQuoter.QuoteExactSingleParams({ + IV4Quoter.QuoteExactSingleParams({ poolKey: key01, zeroForOne: false, exactAmount: uint128(amountOut), @@ -309,7 +309,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactOutput_0to2_2TicksLoaded() public { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 15000); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 15000); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -323,7 +323,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 6143); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 6143); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -337,7 +337,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 4000); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 4000); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -352,7 +352,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 100); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 100); // Tick 0 initialized. Tick after = 1 (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -367,7 +367,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token0); tokenPath.push(token2); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 10); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 10); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -379,7 +379,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function testQuoter_quoteExactOutput_2to0_2TicksLoaded() public { tokenPath.push(token2); tokenPath.push(token0); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 15000); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 15000); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -392,7 +392,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token2); tokenPath.push(token0); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 6223); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 6223); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -405,7 +405,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token2); tokenPath.push(token0); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 6000); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 6000); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); assertGt(gasEstimate, 50000); @@ -417,7 +417,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token2); tokenPath.push(token1); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 9871); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 9871); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -431,7 +431,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { tokenPath.push(token2); tokenPath.push(token1); - IQuoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 9745); + IV4Quoter.QuoteExactParams memory params = getExactOutputParams(tokenPath, 9745); (uint256 amountIn, uint256 gasEstimate) = quoter.quoteExactOutput(params); @@ -548,7 +548,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function getExactInputParams(MockERC20[] memory _tokenPath, uint256 amountIn) internal pure - returns (IQuoter.QuoteExactParams memory params) + returns (IV4Quoter.QuoteExactParams memory params) { PathKey[] memory path = new PathKey[](_tokenPath.length - 1); for (uint256 i = 0; i < _tokenPath.length - 1; i++) { @@ -563,7 +563,7 @@ contract QuoterTest is Test, Deployers, GasSnapshot { function getExactOutputParams(MockERC20[] memory _tokenPath, uint256 amountOut) internal pure - returns (IQuoter.QuoteExactParams memory params) + returns (IV4Quoter.QuoteExactParams memory params) { PathKey[] memory path = new PathKey[](_tokenPath.length - 1); for (uint256 i = _tokenPath.length - 1; i > 0; i--) { From 8acce8b3aa19cfe0dbfa7084e0ddfeb734973a40 Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:36:35 +0000 Subject: [PATCH 17/31] Remove SETTLE_TAKE_PAIR command (#371) --- ...p_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...eFromCaller_takeAllToSpecifiedAddress.snap | 2 +- ..._settleWithBalance_takeAllToMsgSender.snap | 2 +- ...WithBalance_takeAllToSpecifiedAddress.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .../V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .../V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .../V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .../V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .../V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .../V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle.snap | 2 +- .../V4Router_ExactInputSingle_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle_nativeOut.snap | 2 +- ...Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .../V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .../V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .../V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .../V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .../V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .../V4Router_ExactOutputSingle.snap | 2 +- ...r_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOutputSingle_nativeOut.snap | 2 +- lib/v4-core | 2 +- src/V4Router.sol | 7 +--- src/libraries/Actions.sol | 1 - test/router/Payments.gas.t.sol | 3 +- test/router/Payments.t.sol | 35 +++---------------- test/shared/Planner.sol | 4 ++- 34 files changed, 39 insertions(+), 69 deletions(-) diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index cc61af9f0..cb3a89244 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129438 \ No newline at end of file +129542 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index 0b3e3049b..7274089db 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131502 \ No newline at end of file +131456 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index 3d248d7fd..bce4817b7 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -123707 \ No newline at end of file +123661 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index 93b71d538..b7ad30f41 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -123849 \ No newline at end of file +123803 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index 7d18bd6a5..64b24d8a3 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7117 \ No newline at end of file +7007 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index a7a1b3973..a9a2feec9 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -115672 \ No newline at end of file +117265 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index 4964df0dd..dbf08c802 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -115929 \ No newline at end of file +117522 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index 173740c95..ae7b1c4e1 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -124744 \ No newline at end of file +126337 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index 6ce48bb27..b85186e7e 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -130408 \ No newline at end of file +132001 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index a3319d6e7..e5992b07c 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -185177 \ No newline at end of file +186735 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index a6918e587..17554adca 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -170441 \ No newline at end of file +171999 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index e19bd392b..e42451bad 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -239949 \ No newline at end of file +241519 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index 071043d5f..55f78227b 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -225213 \ No newline at end of file +226783 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index cc61af9f0..78a778cc9 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -129438 \ No newline at end of file +131009 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index 9427e2f37..ba9f8ca68 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -114702 \ No newline at end of file +116273 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index 68542c464..ca42bde59 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -114927 \ No newline at end of file +116498 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index 32cfd4957..f5d88c2f6 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -121930 \ No newline at end of file +123523 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index b6531ae5c..39f69af23 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -117002 \ No newline at end of file +118595 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index 2e6870e6a..de15f8421 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -125817 \ No newline at end of file +127410 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 8f03d1be8..171978b3c 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -129689 \ No newline at end of file +131282 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index 5cb34654d..bcd78abea 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -183515 \ No newline at end of file +185073 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index 7629f2c17..023860526 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -175756 \ No newline at end of file +177314 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index 640d8aef7..c27e36f6d 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -237372 \ No newline at end of file +238942 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index f377c2903..eaf35acac 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -229613 \ No newline at end of file +231183 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index d1680afd4..600109db1 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -216949 \ No newline at end of file +218519 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index 1c160394e..204f362dd 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -128716 \ No newline at end of file +130287 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index 849ff098d..c8d65c56c 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -120957 \ No newline at end of file +122528 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index 2619b0057..eb34179d9 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -116103 \ No newline at end of file +117674 \ No newline at end of file diff --git a/lib/v4-core b/lib/v4-core index 0f17b65aa..b619b6718 160000 --- a/lib/v4-core +++ b/lib/v4-core @@ -1 +1 @@ -Subproject commit 0f17b65aa61edee384d5129b7ea080f22905faa0 +Subproject commit b619b6718e31aa5b4fa0286520c455ceb950276d diff --git a/src/V4Router.sol b/src/V4Router.sol index 4f69a702b..8f2fb194a 100644 --- a/src/V4Router.sol +++ b/src/V4Router.sol @@ -50,12 +50,7 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver { return; } } else { - if (action == Actions.SETTLE_TAKE_PAIR) { - (Currency settleCurrency, Currency takeCurrency) = params.decodeCurrencyPair(); - _settle(settleCurrency, msgSender(), _getFullDebt(settleCurrency)); - _take(takeCurrency, msgSender(), _getFullCredit(takeCurrency)); - return; - } else if (action == Actions.SETTLE_ALL) { + if (action == Actions.SETTLE_ALL) { (Currency currency, uint256 maxAmount) = params.decodeCurrencyAndUint256(); uint256 amount = _getFullDebt(currency); if (amount > maxAmount) revert V4TooMuchRequested(maxAmount, amount); diff --git a/src/libraries/Actions.sol b/src/libraries/Actions.sol index 16a8ce8c9..883eaeecb 100644 --- a/src/libraries/Actions.sol +++ b/src/libraries/Actions.sol @@ -29,7 +29,6 @@ library Actions { uint256 constant TAKE_PORTION = 0x14; uint256 constant TAKE_PAIR = 0x15; - uint256 constant SETTLE_TAKE_PAIR = 0x16; uint256 constant CLOSE_CURRENCY = 0x17; uint256 constant CLEAR_OR_TAKE = 0x18; uint256 constant SWEEP = 0x19; diff --git a/test/router/Payments.gas.t.sol b/test/router/Payments.gas.t.sol index 2e42a9366..6ee98bffc 100644 --- a/test/router/Payments.gas.t.sol +++ b/test/router/Payments.gas.t.sol @@ -39,7 +39,8 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); - plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(key0.currency0, key0.currency1)); + plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, amountIn, true)); + plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, 0)); bytes memory data = plan.encode(); router.executeActions(data); diff --git a/test/router/Payments.t.sol b/test/router/Payments.t.sol index 29442f9cd..cb50c1728 100644 --- a/test/router/Payments.t.sol +++ b/test/router/Payments.t.sol @@ -22,35 +22,6 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { plan = Planner.init(); } - function test_settleTakePair() public { - uint256 amountIn = 1 ether; - uint256 expectedAmountOut = 992054607780215625; - IV4Router.ExactInputSingleParams memory params = - IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); - - plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); - plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(key0.currency0, key0.currency1)); - - uint256 inputBalanceBefore = key0.currency0.balanceOfSelf(); - uint256 outputBalanceBefore = key0.currency1.balanceOfSelf(); - // router is empty before - assertEq(currency0.balanceOf(address(router)), 0); - assertEq(currency1.balanceOf(address(router)), 0); - - bytes memory data = plan.encode(); - router.executeActions(data); - - uint256 inputBalanceAfter = key0.currency0.balanceOfSelf(); - uint256 outputBalanceAfter = key0.currency1.balanceOfSelf(); - - // router is empty - assertEq(currency0.balanceOf(address(router)), 0); - assertEq(currency1.balanceOf(address(router)), 0); - // caller's balance changed by input and output amounts - assertEq(inputBalanceBefore - inputBalanceAfter, amountIn); - assertEq(outputBalanceAfter - outputBalanceBefore, expectedAmountOut); - } - function test_exactIn_settleAll_revertsSlippage() public { uint256 amountIn = 1 ether; IV4Router.ExactInputSingleParams memory params = @@ -172,9 +143,10 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); + plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, amountIn, true)); // take 15 bips to Bob plan = plan.add(Actions.TAKE_PORTION, abi.encode(key0.currency1, bob, 15)); - plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(key0.currency0, key0.currency1)); + plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, 0)); uint256 inputBalanceBefore = key0.currency0.balanceOfSelf(); uint256 outputBalanceBefore = key0.currency1.balanceOfSelf(); @@ -208,9 +180,10 @@ contract PaymentsTests is RoutingTestHelpers, GasSnapshot { IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, bytes("")); plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params)); + plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, amountIn, true)); // bips is larger than maximum bips plan = plan.add(Actions.TAKE_PORTION, abi.encode(key0.currency1, bob, BipsLibrary.BPS_DENOMINATOR + 1)); - plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(key0.currency0, key0.currency1)); + plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, 0)); bytes memory data = plan.encode(); diff --git a/test/shared/Planner.sol b/test/shared/Planner.sol index 979f12151..0d5ca4fc1 100644 --- a/test/shared/Planner.sol +++ b/test/shared/Planner.sol @@ -86,7 +86,9 @@ library Planner { returns (bytes memory) { if (takeRecipient == ActionConstants.MSG_SENDER) { - plan = plan.add(Actions.SETTLE_TAKE_PAIR, abi.encode(inputCurrency, outputCurrency)); + // blindly settling and taking all, without slippage checks, isnt recommended in prod + plan = plan.add(Actions.SETTLE_ALL, abi.encode(inputCurrency, type(uint256).max)); + plan = plan.add(Actions.TAKE_ALL, abi.encode(outputCurrency, 0)); } else { plan = plan.add(Actions.SETTLE, abi.encode(inputCurrency, ActionConstants.OPEN_DELTA, true)); plan = plan.add(Actions.TAKE, abi.encode(outputCurrency, takeRecipient, ActionConstants.OPEN_DELTA)); From b3b7c49dcac21027611f298f819e3e46b3ffdcd5 Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:29:56 +0000 Subject: [PATCH 18/31] Sync before native settle (#364) * add sync to native settle * snapshot --- .../Payments_swap_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...yments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap | 2 +- .../Payments_swap_settleWithBalance_takeAllToMsgSender.snap | 2 +- ...ments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap | 2 +- .../PositionManager_increaseLiquidity_erc20_withClose.snap | 2 +- ...PositionManager_increaseLiquidity_erc20_withSettlePair.snap | 2 +- .forge-snapshots/PositionManager_increaseLiquidity_native.snap | 2 +- .forge-snapshots/PositionManager_mint_native.snap | 2 +- .../PositionManager_mint_nativeWithSweep_withClose.snap | 2 +- .../PositionManager_mint_nativeWithSweep_withSettlePair.snap | 2 +- .forge-snapshots/PositionManager_mint_onSameTickLower.snap | 2 +- .forge-snapshots/PositionManager_mint_onSameTickUpper.snap | 2 +- .forge-snapshots/PositionManager_mint_sameRange.snap | 2 +- .../PositionManager_mint_settleWithBalance_sweep.snap | 2 +- .../PositionManager_mint_warmedPool_differentRange.snap | 2 +- .forge-snapshots/PositionManager_mint_withClose.snap | 2 +- .forge-snapshots/PositionManager_mint_withSettlePair.snap | 2 +- .../PositionManager_multicall_initialize_mint.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOutputSingle.snap | 2 +- .../V4Router_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap | 2 +- src/base/DeltaResolver.sol | 3 ++- 43 files changed, 44 insertions(+), 43 deletions(-) diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index cb3a89244..47625c0d3 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129542 \ No newline at end of file +129534 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index 7274089db..f3484bc7c 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131456 \ No newline at end of file +131448 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index bce4817b7..7d351c872 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -123661 \ No newline at end of file +123653 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index b7ad30f41..113b5817b 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -123803 \ No newline at end of file +123795 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index 571f09c3e..95650a1e8 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -158871 \ No newline at end of file +158857 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index f673e9018..66be8c412 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -157823 \ No newline at end of file +157809 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 109715cd0..e559220c6 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -140808 \ No newline at end of file +142121 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index a392537d5..86b73c4d1 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -364681 \ No newline at end of file +365994 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 012d5b883..bb299253b 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -373199 \ No newline at end of file +374512 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index a732cefec..f3ab1f4e6 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -372435 \ No newline at end of file +373748 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 31a541afd..0aff1998a 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317431 \ No newline at end of file +317417 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index b634faa2b..6a2602583 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318101 \ No newline at end of file +318087 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index 302128695..8c4f5a353 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243670 \ No newline at end of file +243656 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 681c6d513..2d831268b 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -418878 \ No newline at end of file +418864 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index a1b50bf73..d4011d6ca 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323462 \ No newline at end of file +323448 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index 8251054aa..33db8cb92 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -419984 \ No newline at end of file +419970 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index b425567ac..4605a1b60 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419054 \ No newline at end of file +419040 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 617f2034a..79b9364c8 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455828 \ No newline at end of file +455814 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index 64b24d8a3..ff36c2189 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7007 \ No newline at end of file +6929 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index a9a2feec9..89a7062ae 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -117265 \ No newline at end of file +118538 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index dbf08c802..8e073c7bf 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -117522 \ No newline at end of file +117514 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index ae7b1c4e1..8768af82b 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -126337 \ No newline at end of file +126329 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index b85186e7e..857cd65f7 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -132001 \ No newline at end of file +131993 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index e5992b07c..8208b8fdd 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -186735 \ No newline at end of file +186727 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index 17554adca..a8dff7adb 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -171999 \ No newline at end of file +173272 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index e42451bad..8cfcd044b 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -241519 \ No newline at end of file +241511 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index 55f78227b..03156f8ea 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -226783 \ No newline at end of file +228056 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index 78a778cc9..618bac703 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -131009 \ No newline at end of file +131001 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index ba9f8ca68..7b5725f6a 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -116273 \ No newline at end of file +117546 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index ca42bde59..dc2287e05 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -116498 \ No newline at end of file +116490 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index f5d88c2f6..93d27d561 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -123523 \ No newline at end of file +124796 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index 39f69af23..833a13b62 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -118595 \ No newline at end of file +118587 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index de15f8421..4e2d3a67c 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -127410 \ No newline at end of file +127402 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 171978b3c..7c9c6431f 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -131282 \ No newline at end of file +131274 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index bcd78abea..8b726968c 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -185073 \ No newline at end of file +185065 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index 023860526..a1149e4c2 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -177314 \ No newline at end of file +178587 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index c27e36f6d..4180aab4a 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -238942 \ No newline at end of file +238934 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index eaf35acac..31d268292 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -231183 \ No newline at end of file +232456 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 600109db1..0333b3b38 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -218519 \ No newline at end of file +218511 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index 204f362dd..bc9803a5e 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -130287 \ No newline at end of file +130279 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index c8d65c56c..3a68556fa 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -122528 \ No newline at end of file +123801 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index eb34179d9..ea119d57b 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -117674 \ No newline at end of file +117666 \ No newline at end of file diff --git a/src/base/DeltaResolver.sol b/src/base/DeltaResolver.sol index 85fd12124..be7e48e72 100644 --- a/src/base/DeltaResolver.sol +++ b/src/base/DeltaResolver.sol @@ -37,10 +37,11 @@ abstract contract DeltaResolver is ImmutableState { /// @dev Returns early if the amount is 0 function _settle(Currency currency, address payer, uint256 amount) internal { if (amount == 0) return; + + poolManager.sync(currency); if (currency.isAddressZero()) { poolManager.settle{value: amount}(); } else { - poolManager.sync(currency); _pay(currency, payer, amount); poolManager.settle(); } From 58974e36e7c342901d7bca2e50340dfafc03d4ff Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:20:05 +0000 Subject: [PATCH 19/31] Unsubscribe on transfer (#395) * Unsubscribe on transfer * snapshot --- .../PositionManager_subscribe.snap | 2 +- .../PositionManager_unsubscribe.snap | 2 +- .../positionDescriptor bytecode size.snap | 2 +- src/PositionManager.sol | 2 +- src/base/Notifier.sol | 13 --- src/interfaces/ISubscriber.sol | 4 - test/mocks/MockBadSubscribers.sol | 9 -- test/mocks/MockSubscriber.sol | 5 - .../PositionManager.notifier.t.sol | 101 ++++-------------- 9 files changed, 26 insertions(+), 114 deletions(-) diff --git a/.forge-snapshots/PositionManager_subscribe.snap b/.forge-snapshots/PositionManager_subscribe.snap index b0cbf20ac..74ca20b5e 100644 --- a/.forge-snapshots/PositionManager_subscribe.snap +++ b/.forge-snapshots/PositionManager_subscribe.snap @@ -1 +1 @@ -88168 \ No newline at end of file +88124 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_unsubscribe.snap b/.forge-snapshots/PositionManager_unsubscribe.snap index 9bf5d6467..c9bfebd46 100644 --- a/.forge-snapshots/PositionManager_unsubscribe.snap +++ b/.forge-snapshots/PositionManager_unsubscribe.snap @@ -1 +1 @@ -63080 \ No newline at end of file +63036 \ No newline at end of file diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index b89166c6e..29912b341 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31687 \ No newline at end of file +31806 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index 428fb4b71..73253dbf2 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -453,7 +453,7 @@ contract PositionManager is /// @dev will revert if pool manager is locked function transferFrom(address from, address to, uint256 id) public virtual override onlyIfPoolManagerLocked { super.transferFrom(from, to, id); - if (positionInfo[id].hasSubscriber()) _notifyTransfer(id, from, to); + if (positionInfo[id].hasSubscriber()) _unsubscribe(id); } /// @inheritdoc IPositionManager diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index 8f6b3f022..b85d3e6e0 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -103,19 +103,6 @@ abstract contract Notifier is INotifier { } } - function _notifyTransfer(uint256 tokenId, address previousOwner, address newOwner) internal { - ISubscriber _subscriber = subscriber[tokenId]; - - bool success = - _call(address(_subscriber), abi.encodeCall(ISubscriber.notifyTransfer, (tokenId, previousOwner, newOwner))); - - if (!success) { - address(_subscriber).bubbleUpAndRevertWith( - ISubscriber.notifyTransfer.selector, TransferNotificationReverted.selector - ); - } - } - function _call(address target, bytes memory encodedCall) internal returns (bool success) { if (target.code.length == 0) NoCodeSubscriber.selector.revertWith(); assembly ("memory-safe") { diff --git a/src/interfaces/ISubscriber.sol b/src/interfaces/ISubscriber.sol index 1e6f04762..0c410079e 100644 --- a/src/interfaces/ISubscriber.sol +++ b/src/interfaces/ISubscriber.sol @@ -17,8 +17,4 @@ interface ISubscriber { /// @param liquidityChange the change in liquidity on the underlying position /// @param feesAccrued the fees to be collected from the position as a result of the modifyLiquidity call function notifyModifyLiquidity(uint256 tokenId, int256 liquidityChange, BalanceDelta feesAccrued) external; - /// @param tokenId the token ID of the position - /// @param previousOwner address of the old owner - /// @param newOwner address of the new owner - function notifyTransfer(uint256 tokenId, address previousOwner, address newOwner) external; } diff --git a/test/mocks/MockBadSubscribers.sol b/test/mocks/MockBadSubscribers.sol index 28f151823..d6e6e0c39 100644 --- a/test/mocks/MockBadSubscribers.sol +++ b/test/mocks/MockBadSubscribers.sol @@ -12,7 +12,6 @@ contract MockReturnDataSubscriber is ISubscriber { uint256 public notifySubscribeCount; uint256 public notifyUnsubscribeCount; uint256 public notifyModifyLiquidityCount; - uint256 public notifyTransferCount; error NotAuthorizedNotifer(address sender); @@ -48,10 +47,6 @@ contract MockReturnDataSubscriber is ISubscriber { notifyModifyLiquidityCount++; } - function notifyTransfer(uint256, address, address) external onlyByPosm { - notifyTransferCount++; - } - function setReturnDataSize(uint256 _value) external { memPtr = _value; } @@ -90,10 +85,6 @@ contract MockRevertSubscriber is ISubscriber { revert TestRevert("notifyModifyLiquidity"); } - function notifyTransfer(uint256, address, address) external view onlyByPosm { - revert TestRevert("notifyTransfer"); - } - function setRevert(bool _shouldRevert) external { shouldRevert = _shouldRevert; } diff --git a/test/mocks/MockSubscriber.sol b/test/mocks/MockSubscriber.sol index 1e1fda151..ef4c2e86e 100644 --- a/test/mocks/MockSubscriber.sol +++ b/test/mocks/MockSubscriber.sol @@ -12,7 +12,6 @@ contract MockSubscriber is ISubscriber { uint256 public notifySubscribeCount; uint256 public notifyUnsubscribeCount; uint256 public notifyModifyLiquidityCount; - uint256 public notifyTransferCount; int256 public liquidityChange; BalanceDelta public feesAccrued; @@ -45,8 +44,4 @@ contract MockSubscriber is ISubscriber { liquidityChange = _liquidityChange; feesAccrued = _feesAccrued; } - - function notifyTransfer(uint256, address, address) external onlyByPosm { - notifyTransferCount++; - } } diff --git a/test/position-managers/PositionManager.notifier.t.sol b/test/position-managers/PositionManager.notifier.t.sol index 3ec0e0c35..599bfbe15 100644 --- a/test/position-managers/PositionManager.notifier.t.sol +++ b/test/position-managers/PositionManager.notifier.t.sol @@ -215,7 +215,7 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { assertEq(int256(sub.feesAccrued().amount1()), int256(feeRevenue1) - 1 wei); } - function test_notifyTransfer_withTransferFrom_succeeds() public { + function test_transferFrom_unsubscribes() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 100e18, alice, ZERO_BYTES); @@ -231,10 +231,12 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { lpm.transferFrom(alice, bob, tokenId); - assertEq(sub.notifyTransferCount(), 1); + assertEq(sub.notifyUnsubscribeCount(), 1); + assertEq(lpm.positionInfo(tokenId).hasSubscriber(), false); + assertEq(address(lpm.subscriber(tokenId)), address(0)); } - function test_notifyTransfer_withTransferFrom_selfDestruct_revert() public { + function test_transferFrom_unsubscribes_selfDestruct() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 100e18, alice, ZERO_BYTES); @@ -250,11 +252,14 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { // simulate selfdestruct by etching the bytecode to 0 vm.etch(address(sub), ZERO_BYTES); - vm.expectRevert(INotifier.NoCodeSubscriber.selector); + // unsubscribe happens anyway lpm.transferFrom(alice, bob, tokenId); + + assertEq(lpm.positionInfo(tokenId).hasSubscriber(), false); + assertEq(address(lpm.subscriber(tokenId)), address(0)); } - function test_notifyTransfer_withSafeTransferFrom_succeeds() public { + function test_safeTransferFrom_unsubscribes() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 100e18, alice, ZERO_BYTES); @@ -270,10 +275,12 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { lpm.safeTransferFrom(alice, bob, tokenId); - assertEq(sub.notifyTransferCount(), 1); + assertEq(sub.notifyUnsubscribeCount(), 1); + assertEq(lpm.positionInfo(tokenId).hasSubscriber(), false); + assertEq(address(lpm.subscriber(tokenId)), address(0)); } - function test_notifyTransfer_withSafeTransferFrom_selfDestruct_revert() public { + function test_safeTransferFrom_unsubscribes_selfDestruct() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 100e18, alice, ZERO_BYTES); @@ -289,11 +296,14 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { // simulate selfdestruct by etching the bytecode to 0 vm.etch(address(sub), ZERO_BYTES); - vm.expectRevert(INotifier.NoCodeSubscriber.selector); + // unsubscribe happens anyway lpm.safeTransferFrom(alice, bob, tokenId); + + assertEq(lpm.positionInfo(tokenId).hasSubscriber(), false); + assertEq(address(lpm.subscriber(tokenId)), address(0)); } - function test_notifyTransfer_withSafeTransferFromData_succeeds() public { + function test_safeTransferFrom_unsubscribes_withData() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 100e18, alice, ZERO_BYTES); @@ -309,7 +319,9 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { lpm.safeTransferFrom(alice, bob, tokenId, ""); - assertEq(sub.notifyTransferCount(), 1); + assertEq(sub.notifyUnsubscribeCount(), 1); + assertEq(lpm.positionInfo(tokenId).hasSubscriber(), false); + assertEq(address(lpm.subscriber(tokenId)), address(0)); } function test_unsubscribe_succeeds() public { @@ -554,75 +566,6 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { lpm.modifyLiquidities(calls, _deadline); } - function test_notifyTransfer_withTransferFrom_wraps_revert() public { - uint256 tokenId = lpm.nextTokenId(); - mint(config, 100e18, alice, ZERO_BYTES); - - // approve this contract to operate on alices liq - vm.startPrank(alice); - lpm.approve(address(this), tokenId); - vm.stopPrank(); - - lpm.subscribe(tokenId, address(revertSubscriber), ZERO_BYTES); - - vm.expectRevert( - abi.encodeWithSelector( - CustomRevert.WrappedError.selector, - address(revertSubscriber), - ISubscriber.notifyTransfer.selector, - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer"), - abi.encodeWithSelector(INotifier.TransferNotificationReverted.selector) - ) - ); - lpm.transferFrom(alice, bob, tokenId); - } - - function test_notifyTransfer_withSafeTransferFrom_wraps_revert() public { - uint256 tokenId = lpm.nextTokenId(); - mint(config, 100e18, alice, ZERO_BYTES); - - // approve this contract to operate on alices liq - vm.startPrank(alice); - lpm.approve(address(this), tokenId); - vm.stopPrank(); - - lpm.subscribe(tokenId, address(revertSubscriber), ZERO_BYTES); - - vm.expectRevert( - abi.encodeWithSelector( - CustomRevert.WrappedError.selector, - address(revertSubscriber), - ISubscriber.notifyTransfer.selector, - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer"), - abi.encodeWithSelector(INotifier.TransferNotificationReverted.selector) - ) - ); - lpm.safeTransferFrom(alice, bob, tokenId); - } - - function test_notifyTransfer_withSafeTransferFromData_wraps_revert() public { - uint256 tokenId = lpm.nextTokenId(); - mint(config, 100e18, alice, ZERO_BYTES); - - // approve this contract to operate on alices liq - vm.startPrank(alice); - lpm.approve(address(this), tokenId); - vm.stopPrank(); - - lpm.subscribe(tokenId, address(revertSubscriber), ZERO_BYTES); - - vm.expectRevert( - abi.encodeWithSelector( - CustomRevert.WrappedError.selector, - address(revertSubscriber), - ISubscriber.notifyTransfer.selector, - abi.encodeWithSelector(MockRevertSubscriber.TestRevert.selector, "notifyTransfer"), - abi.encodeWithSelector(INotifier.TransferNotificationReverted.selector) - ) - ); - lpm.safeTransferFrom(alice, bob, tokenId, ""); - } - /// @notice burning a position will automatically notify unsubscribe function test_burn_unsubscribe() public { uint256 tokenId = lpm.nextTokenId(); From e5829f6bbd656444bce937a27f4d714b6de82d75 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:09:02 +0000 Subject: [PATCH 20/31] add from amount support (#384) * add from amount support * update gas snaps * add calldata decoder fuzz tests * use open delta * mint from deltas * increase test * use SafeCast * add fuzz test, optimize clear * spearbit comments * fix FOT fuzz test * add license --------- Co-authored-by: marktoda Co-authored-by: Alice Henshaw Co-authored-by: Alice <34962750+hensha256@users.noreply.github.com> --- .../PositionManager_burn_empty.snap | 2 +- .../PositionManager_burn_empty_native.snap | 2 +- ...anager_burn_nonEmpty_native_withClose.snap | 2 +- ...ger_burn_nonEmpty_native_withTakePair.snap | 2 +- ...sitionManager_burn_nonEmpty_withClose.snap | 2 +- ...ionManager_burn_nonEmpty_withTakePair.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- ...onManager_decreaseLiquidity_withClose.snap | 2 +- ...anager_decreaseLiquidity_withTakePair.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- .../PositionManager_decrease_take_take.snap | 2 +- ...ger_increase_autocompound_clearExcess.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- ...anager_mint_nativeWithSweep_withClose.snap | 2 +- ...r_mint_nativeWithSweep_withSettlePair.snap | 2 +- .../PositionManager_mint_onSameTickLower.snap | 2 +- .../PositionManager_mint_onSameTickUpper.snap | 2 +- .../PositionManager_mint_sameRange.snap | 2 +- ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...anager_mint_warmedPool_differentRange.snap | 2 +- .../PositionManager_mint_withClose.snap | 2 +- .../PositionManager_mint_withSettlePair.snap | 2 +- ...tionManager_multicall_initialize_mint.snap | 2 +- src/PositionManager.sol | 71 ++++- src/libraries/Actions.sol | 42 +-- src/libraries/CalldataDecoder.sol | 41 +++ src/libraries/LiquidityAmounts.sol | 75 +++++ test/libraries/CalldataDecoder.t.sol | 40 ++- test/mocks/MockCalldataDecoder.sol | 43 +++ test/mocks/MockFeeOnTransfer.sol | 43 +++ .../PositionManager.modifyLiquidities.t.sol | 272 +++++++++++++++++- test/shared/PosmTestSetup.sol | 13 +- 38 files changed, 644 insertions(+), 54 deletions(-) create mode 100644 src/libraries/LiquidityAmounts.sol create mode 100644 test/mocks/MockFeeOnTransfer.sol diff --git a/.forge-snapshots/PositionManager_burn_empty.snap b/.forge-snapshots/PositionManager_burn_empty.snap index 16a0217a7..2479c9837 100644 --- a/.forge-snapshots/PositionManager_burn_empty.snap +++ b/.forge-snapshots/PositionManager_burn_empty.snap @@ -1 +1 @@ -50479 \ No newline at end of file +50540 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty_native.snap b/.forge-snapshots/PositionManager_burn_empty_native.snap index 16a0217a7..2479c9837 100644 --- a/.forge-snapshots/PositionManager_burn_empty_native.snap +++ b/.forge-snapshots/PositionManager_burn_empty_native.snap @@ -1 +1 @@ -50479 \ No newline at end of file +50540 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 7b256dc71..6cc21bc29 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125652 \ No newline at end of file +125712 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 7c676e270..152039dde 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125134 \ No newline at end of file +125195 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 4a700a1c7..9f4b916f8 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132512 \ No newline at end of file +132572 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index b74086572..84dd6ef48 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -131994 \ No newline at end of file +132055 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index de5f92d75..5b1ce3e4f 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146379 \ No newline at end of file +146402 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index 2f8946517..4cdcba5fe 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -154954 \ No newline at end of file +154977 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index 2f8946517..4cdcba5fe 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -154954 \ No newline at end of file +154977 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 8b55bcf18..338401963 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154319 \ No newline at end of file +154342 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index 4f47d5cdd..eddfbeb8a 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -112048 \ No newline at end of file +112067 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index 5320c7d05..cb0cab2e8 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119835 \ No newline at end of file +119858 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 690234de4..5b8a8ab82 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119200 \ No newline at end of file +119223 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 1bd57c304..c2e430727 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135308 \ No newline at end of file +135388 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index d1d857dcb..46828a493 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128448 \ No newline at end of file +128528 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index 99eac1b69..0d940fbfa 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132522 \ No newline at end of file +132545 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index 07b447cf2..bf7f2b047 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120455 \ No newline at end of file +120478 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 8a5e17d06..85389eb86 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148160 \ No newline at end of file +148210 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index 86b73c4d1..428620b58 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -365994 \ No newline at end of file +366017 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index bb299253b..6669c3da7 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -374512 \ No newline at end of file +374535 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index f3ab1f4e6..d361ccef6 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -373748 \ No newline at end of file +373771 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 0aff1998a..b10c99fe9 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317417 \ No newline at end of file +317440 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index 6a2602583..a10679c13 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318087 \ No newline at end of file +318110 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index 8c4f5a353..c1e9eea41 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243656 \ No newline at end of file +243679 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 2d831268b..1854045d0 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -418864 \ No newline at end of file +418887 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index d4011d6ca..db4e21f2d 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323448 \ No newline at end of file +323471 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index 33db8cb92..c8af8e307 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -419970 \ No newline at end of file +419993 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index 4605a1b60..7d6b55033 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419040 \ No newline at end of file +419063 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 79b9364c8..5c67ca185 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455814 \ No newline at end of file +455837 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index 73253dbf2..58efd722e 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -11,8 +11,9 @@ import {Position} from "@uniswap/v4-core/src/libraries/Position.sol"; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol"; import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; -import {IPositionDescriptor} from "./interfaces/IPositionDescriptor.sol"; +import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; +import {IPositionDescriptor} from "./interfaces/IPositionDescriptor.sol"; import {ERC721Permit_v4} from "./base/ERC721Permit_v4.sol"; import {ReentrancyLock} from "./base/ReentrancyLock.sol"; import {IPositionManager} from "./interfaces/IPositionManager.sol"; @@ -26,6 +27,7 @@ import {CalldataDecoder} from "./libraries/CalldataDecoder.sol"; import {Permit2Forwarder} from "./base/Permit2Forwarder.sol"; import {SlippageCheck} from "./libraries/SlippageCheck.sol"; import {PositionInfo, PositionInfoLibrary} from "./libraries/PositionInfoLibrary.sol"; +import {LiquidityAmounts} from "./libraries/LiquidityAmounts.sol"; import {NativeWrapper} from "./base/NativeWrapper.sol"; import {IWETH9} from "./interfaces/external/IWETH9.sol"; @@ -199,6 +201,11 @@ contract PositionManager is params.decodeModifyLiquidityParams(); _increase(tokenId, liquidity, amount0Max, amount1Max, hookData); return; + } else if (action == Actions.INCREASE_LIQUIDITY_FROM_DELTAS) { + (uint256 tokenId, uint128 amount0Max, uint128 amount1Max, bytes calldata hookData) = + params.decodeIncreaseLiquidityFromDeltasParams(); + _increaseFromDeltas(tokenId, amount0Max, amount1Max, hookData); + return; } else if (action == Actions.DECREASE_LIQUIDITY) { (uint256 tokenId, uint256 liquidity, uint128 amount0Min, uint128 amount1Min, bytes calldata hookData) = params.decodeModifyLiquidityParams(); @@ -217,6 +224,18 @@ contract PositionManager is ) = params.decodeMintParams(); _mint(poolKey, tickLower, tickUpper, liquidity, amount0Max, amount1Max, _mapRecipient(owner), hookData); return; + } else if (action == Actions.MINT_POSITION_FROM_DELTAS) { + ( + PoolKey calldata poolKey, + int24 tickLower, + int24 tickUpper, + uint128 amount0Max, + uint128 amount1Max, + address owner, + bytes calldata hookData + ) = params.decodeMintFromDeltasParams(); + _mintFromDeltas(poolKey, tickLower, tickUpper, amount0Max, amount1Max, _mapRecipient(owner), hookData); + return; } else if (action == Actions.BURN_POSITION) { // Will automatically decrease liquidity to 0 if the position is not already empty. (uint256 tokenId, uint128 amount0Min, uint128 amount1Min, bytes calldata hookData) = @@ -283,6 +302,31 @@ contract PositionManager is (liquidityDelta - feesAccrued).validateMaxIn(amount0Max, amount1Max); } + /// @dev The liquidity delta is derived from open deltas in the pool manager. + function _increaseFromDeltas(uint256 tokenId, uint128 amount0Max, uint128 amount1Max, bytes calldata hookData) + internal + onlyIfApproved(msgSender(), tokenId) + { + (PoolKey memory poolKey, PositionInfo info) = getPoolAndPositionInfo(tokenId); + + (uint160 sqrtPriceX96,,,) = poolManager.getSlot0(poolKey.toId()); + + // Use the credit on the pool manager as the amounts for the mint. + uint256 liquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + TickMath.getSqrtPriceAtTick(info.tickLower()), + TickMath.getSqrtPriceAtTick(info.tickUpper()), + _getFullCredit(poolKey.currency0), + _getFullCredit(poolKey.currency1) + ); + + // Note: The tokenId is used as the salt for this position, so every minted position has unique storage in the pool manager. + (BalanceDelta liquidityDelta, BalanceDelta feesAccrued) = + _modifyLiquidity(info, poolKey, liquidity.toInt256(), bytes32(tokenId), hookData); + // Slippage checks should be done on the principal liquidityDelta which is the liquidityDelta - feesAccrued + (liquidityDelta - feesAccrued).validateMaxIn(amount0Max, amount1Max); + } + /// @dev Calling decrease with 0 liquidity will credit the caller with any underlying fees of the position function _decrease( uint256 tokenId, @@ -335,6 +379,29 @@ contract PositionManager is liquidityDelta.validateMaxIn(amount0Max, amount1Max); } + function _mintFromDeltas( + PoolKey calldata poolKey, + int24 tickLower, + int24 tickUpper, + uint128 amount0Max, + uint128 amount1Max, + address owner, + bytes calldata hookData + ) internal { + (uint160 sqrtPriceX96,,,) = poolManager.getSlot0(poolKey.toId()); + + // Use the credit on the pool manager as the amounts for the mint. + uint256 liquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + TickMath.getSqrtPriceAtTick(tickLower), + TickMath.getSqrtPriceAtTick(tickUpper), + _getFullCredit(poolKey.currency0), + _getFullCredit(poolKey.currency1) + ); + + _mint(poolKey, tickLower, tickUpper, liquidity, amount0Max, amount1Max, owner, hookData); + } + /// @dev this is overloaded with ERC721Permit_v4._burn function _burn(uint256 tokenId, uint128 amount0Min, uint128 amount1Min, bytes calldata hookData) internal @@ -389,8 +456,10 @@ contract PositionManager is /// @dev integrators may elect to forfeit positive deltas with clear /// if the forfeit amount exceeds the user-specified max, the amount is taken instead + /// if there is no credit, no call is made. function _clearOrTake(Currency currency, uint256 amountMax) internal { uint256 delta = _getFullCredit(currency); + if (delta == 0) return; // forfeit the delta if its less than or equal to the user-specified limit if (delta <= amountMax) { diff --git a/src/libraries/Actions.sol b/src/libraries/Actions.sol index 883eaeecb..207a8c7be 100644 --- a/src/libraries/Actions.sol +++ b/src/libraries/Actions.sol @@ -10,32 +10,36 @@ library Actions { uint256 constant DECREASE_LIQUIDITY = 0x01; uint256 constant MINT_POSITION = 0x02; uint256 constant BURN_POSITION = 0x03; + uint256 constant INCREASE_LIQUIDITY_FROM_DELTAS = 0x04; + uint256 constant MINT_POSITION_FROM_DELTAS = 0x05; + // swapping - uint256 constant SWAP_EXACT_IN_SINGLE = 0x04; - uint256 constant SWAP_EXACT_IN = 0x05; - uint256 constant SWAP_EXACT_OUT_SINGLE = 0x06; - uint256 constant SWAP_EXACT_OUT = 0x07; + uint256 constant SWAP_EXACT_IN_SINGLE = 0x06; + uint256 constant SWAP_EXACT_IN = 0x07; + uint256 constant SWAP_EXACT_OUT_SINGLE = 0x08; + uint256 constant SWAP_EXACT_OUT = 0x09; // donate - uint256 constant DONATE = 0x08; + uint256 constant DONATE = 0x0a; // closing deltas on the pool manager // settling - uint256 constant SETTLE = 0x09; - uint256 constant SETTLE_ALL = 0x10; - uint256 constant SETTLE_PAIR = 0x11; + uint256 constant SETTLE = 0x0b; + uint256 constant SETTLE_ALL = 0x0c; + uint256 constant SETTLE_PAIR = 0x0d; // taking - uint256 constant TAKE = 0x12; - uint256 constant TAKE_ALL = 0x13; - uint256 constant TAKE_PORTION = 0x14; - uint256 constant TAKE_PAIR = 0x15; + uint256 constant TAKE = 0x0e; + uint256 constant TAKE_ALL = 0x0f; + uint256 constant TAKE_PORTION = 0x10; + uint256 constant TAKE_PAIR = 0x11; + + uint256 constant CLOSE_CURRENCY = 0x12; + uint256 constant CLEAR_OR_TAKE = 0x13; + uint256 constant SWEEP = 0x14; - uint256 constant CLOSE_CURRENCY = 0x17; - uint256 constant CLEAR_OR_TAKE = 0x18; - uint256 constant SWEEP = 0x19; - uint256 constant WRAP = 0x20; - uint256 constant UNWRAP = 0x21; + uint256 constant WRAP = 0x15; + uint256 constant UNWRAP = 0x16; // minting/burning 6909s to close deltas - uint256 constant MINT_6909 = 0x22; - uint256 constant BURN_6909 = 0x23; + uint256 constant MINT_6909 = 0x17; + uint256 constant BURN_6909 = 0x18; } diff --git a/src/libraries/CalldataDecoder.sol b/src/libraries/CalldataDecoder.sol index a14f3a34e..00eeeb37c 100644 --- a/src/libraries/CalldataDecoder.sol +++ b/src/libraries/CalldataDecoder.sol @@ -86,6 +86,21 @@ library CalldataDecoder { hookData = params.toBytes(4); } + /// @dev equivalent to: abi.decode(params, (uint256, uint128, uint128, bytes)) in calldata + function decodeIncreaseLiquidityFromDeltasParams(bytes calldata params) + internal + pure + returns (uint256 tokenId, uint128 amount0Max, uint128 amount1Max, bytes calldata hookData) + { + assembly ("memory-safe") { + tokenId := calldataload(params.offset) + amount0Max := calldataload(add(params.offset, 0x20)) + amount1Max := calldataload(add(params.offset, 0x40)) + } + + hookData = params.toBytes(3); + } + /// @dev equivalent to: abi.decode(params, (PoolKey, int24, int24, uint256, uint128, uint128, address, bytes)) in calldata function decodeMintParams(bytes calldata params) internal @@ -113,6 +128,32 @@ library CalldataDecoder { hookData = params.toBytes(11); } + /// @dev equivalent to: abi.decode(params, (PoolKey, int24, int24, uint128, uint128, address, bytes)) in calldata + function decodeMintFromDeltasParams(bytes calldata params) + internal + pure + returns ( + PoolKey calldata poolKey, + int24 tickLower, + int24 tickUpper, + uint128 amount0Max, + uint128 amount1Max, + address owner, + bytes calldata hookData + ) + { + assembly ("memory-safe") { + poolKey := params.offset + tickLower := calldataload(add(params.offset, 0xa0)) + tickUpper := calldataload(add(params.offset, 0xc0)) + amount0Max := calldataload(add(params.offset, 0xe0)) + amount1Max := calldataload(add(params.offset, 0x100)) + owner := calldataload(add(params.offset, 0x120)) + } + + hookData = params.toBytes(10); + } + /// @dev equivalent to: abi.decode(params, (uint256, uint128, uint128, bytes)) in calldata function decodeBurnParams(bytes calldata params) internal diff --git a/src/libraries/LiquidityAmounts.sol b/src/libraries/LiquidityAmounts.sol new file mode 100644 index 000000000..d6d2dd96d --- /dev/null +++ b/src/libraries/LiquidityAmounts.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {FullMath} from "@uniswap/v4-core/src/libraries/FullMath.sol"; +import {FixedPoint96} from "@uniswap/v4-core/src/libraries/FixedPoint96.sol"; +import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; + +/// @notice Provides functions for computing liquidity amounts from token amounts and prices +library LiquidityAmounts { + using SafeCast for uint256; + + /// @notice Computes the amount of liquidity received for a given amount of token0 and price range + /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) + /// @param sqrtPriceAX96 A sqrt price representing the first tick boundary + /// @param sqrtPriceBX96 A sqrt price representing the second tick boundary + /// @param amount0 The amount0 being sent in + /// @return liquidity The amount of returned liquidity + function getLiquidityForAmount0(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint256 amount0) + internal + pure + returns (uint128 liquidity) + { + unchecked { + if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96); + uint256 intermediate = FullMath.mulDiv(sqrtPriceAX96, sqrtPriceBX96, FixedPoint96.Q96); + return FullMath.mulDiv(amount0, intermediate, sqrtPriceBX96 - sqrtPriceAX96).toUint128(); + } + } + + /// @notice Computes the amount of liquidity received for a given amount of token1 and price range + /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). + /// @param sqrtPriceAX96 A sqrt price representing the first tick boundary + /// @param sqrtPriceBX96 A sqrt price representing the second tick boundary + /// @param amount1 The amount1 being sent in + /// @return liquidity The amount of returned liquidity + function getLiquidityForAmount1(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint256 amount1) + internal + pure + returns (uint128 liquidity) + { + unchecked { + if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96); + return FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtPriceBX96 - sqrtPriceAX96).toUint128(); + } + } + + /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current + /// pool prices and the prices at the tick boundaries + /// @param sqrtPriceX96 A sqrt price representing the current pool prices + /// @param sqrtPriceAX96 A sqrt price representing the first tick boundary + /// @param sqrtPriceBX96 A sqrt price representing the second tick boundary + /// @param amount0 The amount of token0 being sent in + /// @param amount1 The amount of token1 being sent in + /// @return liquidity The maximum amount of liquidity received + function getLiquidityForAmounts( + uint160 sqrtPriceX96, + uint160 sqrtPriceAX96, + uint160 sqrtPriceBX96, + uint256 amount0, + uint256 amount1 + ) internal pure returns (uint128 liquidity) { + if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96); + + if (sqrtPriceX96 <= sqrtPriceAX96) { + liquidity = getLiquidityForAmount0(sqrtPriceAX96, sqrtPriceBX96, amount0); + } else if (sqrtPriceX96 < sqrtPriceBX96) { + uint128 liquidity0 = getLiquidityForAmount0(sqrtPriceX96, sqrtPriceBX96, amount0); + uint128 liquidity1 = getLiquidityForAmount1(sqrtPriceAX96, sqrtPriceX96, amount1); + + liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; + } else { + liquidity = getLiquidityForAmount1(sqrtPriceAX96, sqrtPriceBX96, amount1); + } + } +} diff --git a/test/libraries/CalldataDecoder.t.sol b/test/libraries/CalldataDecoder.t.sol index de1006678..f772c514e 100644 --- a/test/libraries/CalldataDecoder.t.sol +++ b/test/libraries/CalldataDecoder.t.sol @@ -83,6 +83,28 @@ contract CalldataDecoderTest is Test { assertEq(mintParams.tickUpper, _config.tickUpper); } + function test_fuzz_decodeMintFromDeltasParams( + PositionConfig calldata _config, + uint128 _amount0Max, + uint128 _amount1Max, + address _owner, + bytes calldata _hookData + ) public view { + bytes memory params = abi.encode( + _config.poolKey, _config.tickLower, _config.tickUpper, _amount0Max, _amount1Max, _owner, _hookData + ); + + (MockCalldataDecoder.MintFromDeltasParams memory mintParams) = decoder.decodeMintFromDeltasParams(params); + + _assertEq(mintParams.poolKey, _config.poolKey); + assertEq(mintParams.tickLower, _config.tickLower); + assertEq(mintParams.tickUpper, _config.tickUpper); + assertEq(mintParams.amount0Max, _amount0Max); + assertEq(mintParams.amount1Max, _amount1Max); + assertEq(mintParams.owner, _owner); + assertEq(mintParams.hookData, _hookData); + } + function test_fuzz_decodeSwapExactInParams(IV4Router.ExactInputParams calldata _swapParams) public view { bytes memory params = abi.encode(_swapParams); IV4Router.ExactInputParams memory swapParams = decoder.decodeSwapExactInParams(params); @@ -232,7 +254,23 @@ contract CalldataDecoderTest is Test { assertEq(amount, _amount); } - function test_fuzz_decodeUint256(uint256 _amount) public { + function test_fuzz_decodeIncreaseLiquidityFromAmountsParams( + uint256 _tokenId, + uint128 _amount0Max, + uint128 _amount1Max, + bytes calldata _hookData + ) public view { + bytes memory params = abi.encode(_tokenId, _amount0Max, _amount1Max, _hookData); + + (uint256 tokenId, uint128 amount0Max, uint128 amount1Max, bytes memory hookData) = + decoder.decodeIncreaseLiquidityFromDeltasParams(params); + assertEq(_tokenId, tokenId); + assertEq(_amount0Max, amount0Max); + assertEq(_amount1Max, amount1Max); + assertEq(_hookData, hookData); + } + + function test_fuzz_decodeUint256(uint256 _amount) public view { bytes memory params = abi.encode(_amount); uint256 amount = decoder.decodeUint256(params); diff --git a/test/mocks/MockCalldataDecoder.sol b/test/mocks/MockCalldataDecoder.sol index c61db4afa..c4bd803ee 100644 --- a/test/mocks/MockCalldataDecoder.sol +++ b/test/mocks/MockCalldataDecoder.sol @@ -22,6 +22,16 @@ contract MockCalldataDecoder { bytes hookData; } + struct MintFromDeltasParams { + PoolKey poolKey; + int24 tickLower; + int24 tickUpper; + uint128 amount0Max; + uint128 amount1Max; + address owner; + bytes hookData; + } + function decodeActionsRouterParams(bytes calldata params) external pure @@ -137,6 +147,39 @@ contract MockCalldataDecoder { return params.decodeCurrencyAddressAndUint256(); } + function decodeIncreaseLiquidityFromDeltasParams(bytes calldata params) + external + pure + returns (uint256 tokenId, uint128 amount0Max, uint128 amount1Max, bytes calldata hookData) + { + return params.decodeIncreaseLiquidityFromDeltasParams(); + } + + function decodeMintFromDeltasParams(bytes calldata params) + external + pure + returns (MintFromDeltasParams memory mintParams) + { + ( + PoolKey memory poolKey, + int24 tickLower, + int24 tickUpper, + uint128 amount0Max, + uint128 amount1Max, + address owner, + bytes memory hookData + ) = params.decodeMintFromDeltasParams(); + return MintFromDeltasParams({ + poolKey: poolKey, + tickLower: tickLower, + tickUpper: tickUpper, + amount0Max: amount0Max, + amount1Max: amount1Max, + owner: owner, + hookData: hookData + }); + } + function decodeUint256(bytes calldata params) external pure returns (uint256) { return params.decodeUint256(); } diff --git a/test/mocks/MockFeeOnTransfer.sol b/test/mocks/MockFeeOnTransfer.sol new file mode 100644 index 000000000..1150a777d --- /dev/null +++ b/test/mocks/MockFeeOnTransfer.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.20; + +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; +import {IPositionManager} from "../../src/interfaces/IPositionManager.sol"; +import {BipsLibrary} from "../../src/libraries/BipsLibrary.sol"; + +contract MockFOT is MockERC20 { + using BipsLibrary for uint256; + + IPositionManager immutable posm; + + uint256 public bips; + + constructor(IPositionManager _posm) MockERC20("FOT Token", "FOT", 18) { + posm = _posm; + } + + function setFee(uint256 amountInBips) public { + bips = amountInBips; + } + + function transferFrom(address from, address to, uint256 amount) public override returns (bool) { + uint256 allowed = allowance[from][msg.sender]; + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // bips% fee on the recipient + uint256 amountAfterFee = amount - amount.calculatePortion(bips); + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amountAfterFee; + } + + emit Transfer(from, to, amount); + + return true; + } +} diff --git a/test/position-managers/PositionManager.modifyLiquidities.t.sol b/test/position-managers/PositionManager.modifyLiquidities.t.sol index 4e14a733c..664758616 100644 --- a/test/position-managers/PositionManager.modifyLiquidities.t.sol +++ b/test/position-managers/PositionManager.modifyLiquidities.t.sol @@ -18,6 +18,9 @@ import {Position} from "@uniswap/v4-core/src/libraries/Position.sol"; import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; import {LiquidityAmounts} from "@uniswap/v4-core/test/utils/LiquidityAmounts.sol"; import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; +import {Pool} from "@uniswap/v4-core/src/libraries/Pool.sol"; + +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {IPositionManager} from "../../src/interfaces/IPositionManager.sol"; import {IMulticall_v4} from "../../src/interfaces/IMulticall_v4.sol"; @@ -25,6 +28,7 @@ import {ReentrancyLock} from "../../src/base/ReentrancyLock.sol"; import {Actions} from "../../src/libraries/Actions.sol"; import {PositionManager} from "../../src/PositionManager.sol"; import {PositionConfig} from "../shared/PositionConfig.sol"; +import {BipsLibrary} from "../../src/libraries/BipsLibrary.sol"; import {LiquidityFuzzers} from "../shared/fuzz/LiquidityFuzzers.sol"; import {Planner, Plan} from "../shared/Planner.sol"; @@ -32,20 +36,27 @@ import {PosmTestSetup} from "../shared/PosmTestSetup.sol"; import {ActionConstants} from "../../src/libraries/ActionConstants.sol"; import {Planner, Plan} from "../shared/Planner.sol"; import {DeltaResolver} from "../../src/base/DeltaResolver.sol"; +import {MockFOT} from "../mocks/MockFeeOnTransfer.sol"; contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityFuzzers { using StateLibrary for IPoolManager; using PoolIdLibrary for PoolKey; using Planner for Plan; + using BipsLibrary for uint256; PoolId poolId; address alice; uint256 alicePK; address bob; + PoolKey fotKey; + PositionConfig config; PositionConfig wethConfig; PositionConfig nativeConfig; + PositionConfig fotConfig; + + MockERC20 fotToken; function setUp() public { (alice, alicePK) = makeAddrAndKey("ALICE"); @@ -66,7 +77,7 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF seedBalance(address(hookModifyLiquidities)); (key, poolId) = initPool(currency0, currency1, IHooks(hookModifyLiquidities), 3000, SQRT_PRICE_1_1); - initWethPool(currency1, IHooks(address(0)), 3000, SQRT_PRICE_1_1); + wethKey = initPoolUnsorted(Currency.wrap(address(_WETH9)), currency1, IHooks(address(0)), 3000, SQRT_PRICE_1_1); seedWeth(address(this)); approvePosmCurrency(Currency.wrap(address(_WETH9))); @@ -83,6 +94,11 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF nativeConfig = PositionConfig({poolKey: nativeKey, tickLower: -120, tickUpper: 120}); vm.deal(address(this), 1000 ether); + + fotToken = new MockFOT(lpm); + approvePosmCurrency(Currency.wrap(address(fotToken))); + seedToken(fotToken, address(this)); + fotKey = initPoolUnsorted(Currency.wrap(address(fotToken)), currency1, IHooks(address(0)), 3000, SQRT_PRICE_1_1); } /// @dev minting liquidity without approval is allowable @@ -694,4 +710,258 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF vm.expectRevert(DeltaResolver.InsufficientBalance.selector); lpm.modifyLiquidities(actions, _deadline); } + + function test_mintFromDeltas_fot() public { + // Use a 1% fee. + MockFOT(address(fotToken)).setFee(100); + uint256 tokenId = lpm.nextTokenId(); + + uint256 fotBalanceBefore = Currency.wrap(address(fotToken)).balanceOf(address(this)); + + uint256 amountAfterTransfer = 990e18; + uint256 amountToSendFot = 1000e18; + + (uint256 amount0, uint256 amount1) = fotKey.currency0 == Currency.wrap(address(fotToken)) + ? (amountToSendFot, amountAfterTransfer) + : (amountAfterTransfer, amountToSendFot); + + // Calculcate the expected liquidity from the amounts after the transfer. They are the same for both currencies. + uint256 expectedLiquidity = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(LIQUIDITY_PARAMS.tickLower), + TickMath.getSqrtPriceAtTick(LIQUIDITY_PARAMS.tickUpper), + amountAfterTransfer, + amountAfterTransfer + ); + + Plan memory planner = Planner.init(); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, amount0, true)); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, amount1, true)); + planner.add( + Actions.MINT_POSITION_FROM_DELTAS, + abi.encode( + fotKey, + LIQUIDITY_PARAMS.tickLower, + LIQUIDITY_PARAMS.tickUpper, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + + bytes memory plan = planner.encode(); + + lpm.modifyLiquidities(plan, _deadline); + + uint256 fotBalanceAfter = Currency.wrap(address(fotToken)).balanceOf(address(this)); + + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), expectedLiquidity); + assertEq(fotBalanceBefore - fotBalanceAfter, 1000e18); + } + + function test_increaseFromDeltas() public { + uint128 initialLiquidity = 1000e18; + uint256 tokenId = lpm.nextTokenId(); + fotConfig = PositionConfig({poolKey: fotKey, tickLower: -120, tickUpper: 120}); + + mint(fotConfig, initialLiquidity, address(this), ZERO_BYTES); + + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), initialLiquidity); + + Plan memory planner = Planner.init(); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, 10e18, true)); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, 10e18, true)); + planner.add( + Actions.INCREASE_LIQUIDITY_FROM_DELTAS, + abi.encode(tokenId, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) + ); + + bytes memory actions = planner.encode(); + + lpm.modifyLiquidities(actions, _deadline); + + uint128 newLiquidity = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(fotConfig.tickLower), + TickMath.getSqrtPriceAtTick(fotConfig.tickUpper), + 10e18, + 10e18 + ); + + assertEq(lpm.getPositionLiquidity(tokenId), initialLiquidity + newLiquidity); + } + + function test_increaseFromDeltas_fot() public { + uint128 initialLiquidity = 1000e18; + uint256 tokenId = lpm.nextTokenId(); + fotConfig = PositionConfig({poolKey: fotKey, tickLower: -120, tickUpper: 120}); + + mint(fotConfig, initialLiquidity, address(this), ZERO_BYTES); + + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), initialLiquidity); + + // Use a 1% fee. + MockFOT(address(fotToken)).setFee(100); + + // Set the fee on transfer amount 1% higher. + (uint256 amount0, uint256 amount1) = + fotKey.currency0 == Currency.wrap(address(fotToken)) ? (100e18, 99e18) : (99e19, 100e18); + + Plan memory planner = Planner.init(); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, amount0, true)); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, amount1, true)); + planner.add( + Actions.INCREASE_LIQUIDITY_FROM_DELTAS, + abi.encode(tokenId, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) + ); + + bytes memory actions = planner.encode(); + + lpm.modifyLiquidities(actions, _deadline); + + (uint256 amount0AfterTransfer, uint256 amount1AfterTransfer) = + fotKey.currency0 == Currency.wrap(address(fotToken)) ? (99e18, 100e18) : (100e18, 99e19); + + uint128 newLiquidity = LiquidityAmounts.getLiquidityForAmounts( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(fotConfig.tickLower), + TickMath.getSqrtPriceAtTick(fotConfig.tickUpper), + amount0AfterTransfer, + amount1AfterTransfer + ); + + assertEq(lpm.getPositionLiquidity(tokenId), initialLiquidity + newLiquidity); + } + + function test_fuzz_mintFromDeltas_burn_fot( + uint256 bips, + uint256 amount0, + uint256 amount1, + int24 tickLower, + int24 tickUpper + ) public { + bips = bound(bips, 1, 10_000); + MockFOT(address(fotToken)).setFee(bips); + + tickLower = int24( + bound( + tickLower, + fotKey.tickSpacing * (TickMath.MIN_TICK / fotKey.tickSpacing), + fotKey.tickSpacing * (TickMath.MAX_TICK / fotKey.tickSpacing) + ) + ); + tickUpper = int24( + bound( + tickUpper, + fotKey.tickSpacing * (TickMath.MIN_TICK / fotKey.tickSpacing), + fotKey.tickSpacing * (TickMath.MAX_TICK / fotKey.tickSpacing) + ) + ); + + tickLower = fotKey.tickSpacing * (tickLower / fotKey.tickSpacing); + tickUpper = fotKey.tickSpacing * (tickUpper / fotKey.tickSpacing); + vm.assume(tickUpper > tickLower); + + (uint160 sqrtPriceX96,,,) = manager.getSlot0(fotKey.toId()); + uint128 maxLiquidityPerTick = Pool.tickSpacingToMaxLiquidityPerTick(fotKey.tickSpacing); + + (uint256 maxAmount0, uint256 maxAmount1) = LiquidityAmounts.getAmountsForLiquidity( + sqrtPriceX96, + TickMath.getSqrtPriceAtTick(tickLower), + TickMath.getSqrtPriceAtTick(tickUpper), + maxLiquidityPerTick + ); + + maxAmount0 = maxAmount0 == 0 ? 1 : maxAmount0 > STARTING_USER_BALANCE ? STARTING_USER_BALANCE : maxAmount0; + maxAmount1 = maxAmount1 == 0 ? 1 : maxAmount1 > STARTING_USER_BALANCE ? STARTING_USER_BALANCE : maxAmount1; + amount0 = bound(amount0, 1, maxAmount0); + amount1 = bound(amount1, 1, maxAmount1); + + uint256 tokenId = lpm.nextTokenId(); + + uint256 balance0 = fotKey.currency0.balanceOf(address(this)); + uint256 balance1 = fotKey.currency1.balanceOf(address(this)); + uint256 balance0PM = fotKey.currency0.balanceOf(address(manager)); + uint256 balance1PM = fotKey.currency1.balanceOf(address(manager)); + + Plan memory planner = Planner.init(); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, amount0, true)); + planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, amount1, true)); + planner.add( + Actions.MINT_POSITION_FROM_DELTAS, + abi.encode( + fotKey, + tickLower, + tickUpper, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + // take the excess of each currency + planner.add(Actions.TAKE_PAIR, abi.encode(fotKey.currency0, fotKey.currency1, ActionConstants.MSG_SENDER)); + + bytes memory actions = planner.encode(); + + bool currency0IsFOT = fotKey.currency0 == Currency.wrap(address(fotToken)); + bool positionIsEntirelyInOtherToken = currency0IsFOT + ? tickUpper <= TickMath.getTickAtSqrtPrice(sqrtPriceX96) + : tickLower > TickMath.getTickAtSqrtPrice(sqrtPriceX96); + + if (bips == 10000 && !positionIsEntirelyInOtherToken) { + vm.expectRevert(Position.CannotUpdateEmptyPosition.selector); + lpm.modifyLiquidities(actions, _deadline); + } else { + // MINT FROM DELTAS. + lpm.modifyLiquidities(actions, _deadline); + + uint256 balance0After = fotKey.currency0.balanceOf(address(this)); + uint256 balance1After = fotKey.currency1.balanceOf(address(this)); + uint256 balance0PMAfter = fotKey.currency0.balanceOf(address(manager)); + uint256 balance1PMAfter = fotKey.currency1.balanceOf(address(manager)); + + // Calculate the expected resulting balances used to create liquidity after the fee is applied. + uint256 amountInFOT = currency0IsFOT ? amount0 : amount1; + uint256 expectedFee = amountInFOT.calculatePortion(bips); + (uint256 expected0, uint256 expected1) = currency0IsFOT + ? (balance0 - balance0After - expectedFee, balance1 - balance1After) + : (balance0 - balance0After, balance1 - balance1After - expectedFee); + + assertEq(expected0, balance0PMAfter - balance0PM); + assertEq(expected1, balance1PMAfter - balance1PM); + + // the liquidity that was created is a diff of the balance change + uint128 expectedLiquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + TickMath.getSqrtPriceAtTick(tickLower), + TickMath.getSqrtPriceAtTick(tickUpper), + expected0, + expected1 + ); + + assertEq(lpm.ownerOf(tokenId), address(this)); + assertEq(lpm.getPositionLiquidity(tokenId), expectedLiquidity); + + // BURN. + planner = Planner.init(); + // Note that the slippage does not include the fee from the transfer. + planner.add( + Actions.BURN_POSITION, + abi.encode(tokenId, expected0 == 0 ? 0 : expected0 - 1, expected1 == 0 ? 0 : expected1 - 1, ZERO_BYTES) + ); + + planner.add(Actions.TAKE_PAIR, abi.encode(fotKey.currency0, fotKey.currency1, ActionConstants.MSG_SENDER)); + + actions = planner.encode(); + + lpm.modifyLiquidities(actions, _deadline); + + assertEq(lpm.getPositionLiquidity(tokenId), 0); + } + } } diff --git a/test/shared/PosmTestSetup.sol b/test/shared/PosmTestSetup.sol index 22e09ed9f..bce86b97b 100644 --- a/test/shared/PosmTestSetup.sol +++ b/test/shared/PosmTestSetup.sol @@ -103,11 +103,18 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations { _WETH9.transfer(to, STARTING_USER_BALANCE); } - function initWethPool(Currency currencyB, IHooks hooks, uint24 fee, uint160 sqrtPriceX96) internal { + function seedToken(MockERC20 token, address to) internal { + token.mint(to, STARTING_USER_BALANCE); + } + + function initPoolUnsorted(Currency currencyA, Currency currencyB, IHooks hooks, uint24 fee, uint160 sqrtPriceX96) + internal + returns (PoolKey memory poolKey) + { (Currency _currency0, Currency _currency1) = - SortTokens.sort(MockERC20(address(_WETH9)), MockERC20(Currency.unwrap(currencyB))); + SortTokens.sort(MockERC20(Currency.unwrap(currencyA)), MockERC20(Currency.unwrap(currencyB))); - (wethKey,) = initPool(_currency0, _currency1, hooks, fee, sqrtPriceX96); + (poolKey,) = initPool(_currency0, _currency1, hooks, fee, sqrtPriceX96); } function permit(uint256 privateKey, uint256 tokenId, address operator, uint256 nonce) internal { From 1394ff24c0bdc8ee7a7c23569c8d3452a667996e Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Fri, 22 Nov 2024 19:59:37 +0000 Subject: [PATCH 21/31] Assembly length checks (#396) * length check on fixed length decodes * tests for out of bounds checks * minimal length checks on swap structs --- ...p_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...eFromCaller_takeAllToSpecifiedAddress.snap | 2 +- ..._settleWithBalance_takeAllToMsgSender.snap | 2 +- ...WithBalance_takeAllToSpecifiedAddress.snap | 2 +- ...anager_burn_nonEmpty_native_withClose.snap | 2 +- ...ger_burn_nonEmpty_native_withTakePair.snap | 2 +- ...sitionManager_burn_nonEmpty_withClose.snap | 2 +- ...ionManager_burn_nonEmpty_withTakePair.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- ...onManager_decreaseLiquidity_withClose.snap | 2 +- ...anager_decreaseLiquidity_withTakePair.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- .../PositionManager_decrease_take_take.snap | 2 +- ...ger_increaseLiquidity_erc20_withClose.snap | 2 +- ...ncreaseLiquidity_erc20_withSettlePair.snap | 2 +- ...itionManager_increaseLiquidity_native.snap | 2 +- ...crease_autocompoundExactUnclaimedFees.snap | 2 +- ...increase_autocompoundExcessFeesCredit.snap | 2 +- ...ger_increase_autocompound_clearExcess.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- ...anager_mint_nativeWithSweep_withClose.snap | 2 +- ...r_mint_nativeWithSweep_withSettlePair.snap | 2 +- .../PositionManager_mint_onSameTickLower.snap | 2 +- .../PositionManager_mint_onSameTickUpper.snap | 2 +- .../PositionManager_mint_sameRange.snap | 2 +- ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...anager_mint_warmedPool_differentRange.snap | 2 +- .../PositionManager_mint_withClose.snap | 2 +- .../PositionManager_mint_withSettlePair.snap | 2 +- ...tionManager_multicall_initialize_mint.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .../V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .../V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .../V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .../V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .../V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .../V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle.snap | 2 +- .../V4Router_ExactInputSingle_nativeIn.snap | 2 +- .../V4Router_ExactInputSingle_nativeOut.snap | 2 +- ...Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .../V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .../V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .../V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .../V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .../V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .../V4Router_ExactOutputSingle.snap | 2 +- ...r_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .../V4Router_ExactOutputSingle_nativeOut.snap | 2 +- src/libraries/CalldataDecoder.sol | 60 +++++++++ test/libraries/CalldataDecoder.t.sol | 120 +++++++++++++++++- test/mocks/MockCalldataDecoder.sol | 4 + 63 files changed, 239 insertions(+), 65 deletions(-) diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index 47625c0d3..7dd962cce 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129534 \ No newline at end of file +129705 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index f3484bc7c..361cd159f 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131448 \ No newline at end of file +131634 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index 7d351c872..d55b574af 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -123653 \ No newline at end of file +123813 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index 113b5817b..63b1d146d 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -123795 \ No newline at end of file +123955 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 6cc21bc29..7ec595830 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125712 \ No newline at end of file +125788 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 152039dde..5218895ce 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125195 \ No newline at end of file +125220 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 9f4b916f8..1be09a218 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132572 \ No newline at end of file +132648 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 84dd6ef48..7c6408e36 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -132055 \ No newline at end of file +132080 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 5b1ce3e4f..40f4aecb3 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146402 \ No newline at end of file +146518 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index 4cdcba5fe..3a0b4f707 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -154977 \ No newline at end of file +155093 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index 4cdcba5fe..3a0b4f707 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -154977 \ No newline at end of file +155093 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 338401963..3e9ec783f 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154342 \ No newline at end of file +154396 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index eddfbeb8a..ba0b210d5 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -112067 \ No newline at end of file +112160 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index cb0cab2e8..8f0ff9be1 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119858 \ No newline at end of file +119974 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 5b8a8ab82..323d58aa9 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119223 \ No newline at end of file +119277 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index c2e430727..92d88d4ab 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135388 \ No newline at end of file +135480 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 46828a493..5c195ecc6 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128528 \ No newline at end of file +128620 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index 0d940fbfa..de446de0c 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132545 \ No newline at end of file +132661 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index bf7f2b047..c1f9fc28e 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120478 \ No newline at end of file +120564 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index 95650a1e8..07d41e539 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -158857 \ No newline at end of file +158973 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index 66be8c412..f3733866f 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -157809 \ No newline at end of file +157884 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index e559220c6..43a1de117 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -142121 \ No newline at end of file +142237 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index 31cb20d9d..15b5ab6c2 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -136396 \ No newline at end of file +136418 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index 35911ac24..81df070a8 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177446 \ No newline at end of file +177562 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 85389eb86..3abe5dbd4 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148210 \ No newline at end of file +148338 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index 428620b58..9258b17f6 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -366017 \ No newline at end of file +366111 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 6669c3da7..571f3e49f 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -374535 \ No newline at end of file +374685 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index d361ccef6..9f80774dd 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -373771 \ No newline at end of file +373880 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index b10c99fe9..62bd3d801 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317440 \ No newline at end of file +317534 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index a10679c13..dd8c88a2a 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318110 \ No newline at end of file +318204 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index c1e9eea41..ade21eeba 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243679 \ No newline at end of file +243773 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 1854045d0..7d6b55033 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -418887 \ No newline at end of file +419063 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index db4e21f2d..95c1d7783 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323471 \ No newline at end of file +323565 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index c8af8e307..189188dc8 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -419993 \ No newline at end of file +420087 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index 7d6b55033..eb86505ba 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419063 \ No newline at end of file +419116 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 5c67ca185..74c7eee12 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455837 \ No newline at end of file +455931 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index ff36c2189..2936eb373 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -6929 \ No newline at end of file +7029 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index 89a7062ae..e867cdb13 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -118538 \ No newline at end of file +118724 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index 8e073c7bf..7e9c5fc11 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -117514 \ No newline at end of file +117700 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index 8768af82b..a8bb1df30 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -126329 \ No newline at end of file +126515 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index 857cd65f7..a62dfebff 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -131993 \ No newline at end of file +132179 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index 8208b8fdd..679817245 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -186727 \ No newline at end of file +186913 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index a8dff7adb..d38ed3054 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -173272 \ No newline at end of file +173458 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index 8cfcd044b..1261e3744 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -241511 \ No newline at end of file +241697 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index 03156f8ea..b37ad64b7 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -228056 \ No newline at end of file +228242 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index 618bac703..e3f4d02a3 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -131001 \ No newline at end of file +131187 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index 7b5725f6a..b6786b89a 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -117546 \ No newline at end of file +117732 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index dc2287e05..99644e8ca 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -116490 \ No newline at end of file +116676 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index 93d27d561..1595951f2 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -124796 \ No newline at end of file +124982 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index 833a13b62..d47ed0cd2 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -118587 \ No newline at end of file +118773 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index 4e2d3a67c..cf325d8b8 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -127402 \ No newline at end of file +127588 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 7c9c6431f..0a1f73c46 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -131274 \ No newline at end of file +131460 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index 8b726968c..f175de3fd 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -185065 \ No newline at end of file +185251 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index a1149e4c2..e1584172a 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -178587 \ No newline at end of file +178773 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index 4180aab4a..04caed975 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -238934 \ No newline at end of file +239120 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index 31d268292..3d524adb1 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -232456 \ No newline at end of file +232642 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 0333b3b38..4bb56d44c 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -218511 \ No newline at end of file +218697 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index bc9803a5e..c49961035 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -130279 \ No newline at end of file +130453 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index 3a68556fa..d35479f22 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -123801 \ No newline at end of file +123975 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index ea119d57b..a0a386d2c 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -117666 \ No newline at end of file +117840 \ No newline at end of file diff --git a/src/libraries/CalldataDecoder.sol b/src/libraries/CalldataDecoder.sol index 00eeeb37c..76ecccaa2 100644 --- a/src/libraries/CalldataDecoder.sol +++ b/src/libraries/CalldataDecoder.sol @@ -77,6 +77,10 @@ library CalldataDecoder { returns (uint256 tokenId, uint256 liquidity, uint128 amount0, uint128 amount1, bytes calldata hookData) { assembly ("memory-safe") { + if lt(params.length, 0x80) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } tokenId := calldataload(params.offset) liquidity := calldataload(add(params.offset, 0x20)) amount0 := calldataload(add(params.offset, 0x40)) @@ -177,6 +181,12 @@ library CalldataDecoder { { // ExactInputParams is a variable length struct so we just have to look up its location assembly ("memory-safe") { + // only safety checks for the minimum length, where path is empty + // 0xa0 = 5 * 0x20 -> 3 elements, path offset, and path length 0 + if lt(params.length, 0xa0) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } swapParams := add(params.offset, calldataload(params.offset)) } } @@ -189,6 +199,12 @@ library CalldataDecoder { { // ExactInputSingleParams is a variable length struct so we just have to look up its location assembly ("memory-safe") { + // only safety checks for the minimum length, where hookData is empty + // 0x140 = 10 * 0x20 -> 8 elements, bytes offset, and bytes length 0 + if lt(params.length, 0x140) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } swapParams := add(params.offset, calldataload(params.offset)) } } @@ -201,6 +217,12 @@ library CalldataDecoder { { // ExactOutputParams is a variable length struct so we just have to look up its location assembly ("memory-safe") { + // only safety checks for the minimum length, where path is empty + // 0xa0 = 5 * 0x20 -> 3 elements, path offset, and path length 0 + if lt(params.length, 0xa0) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } swapParams := add(params.offset, calldataload(params.offset)) } } @@ -213,6 +235,12 @@ library CalldataDecoder { { // ExactOutputSingleParams is a variable length struct so we just have to look up its location assembly ("memory-safe") { + // only safety checks for the minimum length, where hookData is empty + // 0x140 = 10 * 0x20 -> 8 elements, bytes offset, and bytes length 0 + if lt(params.length, 0x140) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } swapParams := add(params.offset, calldataload(params.offset)) } } @@ -220,6 +248,10 @@ library CalldataDecoder { /// @dev equivalent to: abi.decode(params, (Currency)) in calldata function decodeCurrency(bytes calldata params) internal pure returns (Currency currency) { assembly ("memory-safe") { + if lt(params.length, 0x20) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency := calldataload(params.offset) } } @@ -227,6 +259,10 @@ library CalldataDecoder { /// @dev equivalent to: abi.decode(params, (Currency, Currency)) in calldata function decodeCurrencyPair(bytes calldata params) internal pure returns (Currency currency0, Currency currency1) { assembly ("memory-safe") { + if lt(params.length, 0x40) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency0 := calldataload(params.offset) currency1 := calldataload(add(params.offset, 0x20)) } @@ -239,6 +275,10 @@ library CalldataDecoder { returns (Currency currency0, Currency currency1, address _address) { assembly ("memory-safe") { + if lt(params.length, 0x60) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency0 := calldataload(params.offset) currency1 := calldataload(add(params.offset, 0x20)) _address := calldataload(add(params.offset, 0x40)) @@ -252,6 +292,10 @@ library CalldataDecoder { returns (Currency currency, address _address) { assembly ("memory-safe") { + if lt(params.length, 0x40) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency := calldataload(params.offset) _address := calldataload(add(params.offset, 0x20)) } @@ -264,6 +308,10 @@ library CalldataDecoder { returns (Currency currency, address _address, uint256 amount) { assembly ("memory-safe") { + if lt(params.length, 0x60) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency := calldataload(params.offset) _address := calldataload(add(params.offset, 0x20)) amount := calldataload(add(params.offset, 0x40)) @@ -277,6 +325,10 @@ library CalldataDecoder { returns (Currency currency, uint256 amount) { assembly ("memory-safe") { + if lt(params.length, 0x40) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency := calldataload(params.offset) amount := calldataload(add(params.offset, 0x20)) } @@ -285,6 +337,10 @@ library CalldataDecoder { /// @dev equivalent to: abi.decode(params, (uint256)) in calldata function decodeUint256(bytes calldata params) internal pure returns (uint256 amount) { assembly ("memory-safe") { + if lt(params.length, 0x20) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } amount := calldataload(params.offset) } } @@ -296,6 +352,10 @@ library CalldataDecoder { returns (Currency currency, uint256 amount, bool boolean) { assembly ("memory-safe") { + if lt(params.length, 0x60) { + mstore(0, SLICE_ERROR_SELECTOR) + revert(0x1c, 4) + } currency := calldataload(params.offset) amount := calldataload(add(params.offset, 0x20)) boolean := calldataload(add(params.offset, 0x40)) diff --git a/test/libraries/CalldataDecoder.t.sol b/test/libraries/CalldataDecoder.t.sol index f772c514e..b2aa2d78b 100644 --- a/test/libraries/CalldataDecoder.t.sol +++ b/test/libraries/CalldataDecoder.t.sol @@ -161,6 +161,18 @@ contract CalldataDecoderTest is Test { assertEq(_address, __address); } + function test_decodeCurrencyAndAddress_outOutBounds() public { + Currency currency = Currency.wrap(address(0x12341234)); + address addy = address(0x23453456); + + bytes memory params = abi.encode(currency, addy); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrencyAndAddress(invalidParams); + } + function test_fuzz_decodeCurrency(Currency _currency) public view { bytes memory params = abi.encode(_currency); (Currency currency) = decoder.decodeCurrency(params); @@ -168,6 +180,17 @@ contract CalldataDecoderTest is Test { assertEq(Currency.unwrap(currency), Currency.unwrap(_currency)); } + function test_decodeCurrency_outOutBounds() public { + Currency currency = Currency.wrap(address(0x12341234)); + + bytes memory params = abi.encode(currency); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrency(invalidParams); + } + function test_fuzz_decodeActionsRouterParams(bytes memory _actions, bytes[] memory _actionParams) public view { bytes memory params = abi.encode(_actions, _actionParams); (bytes memory actions, bytes[] memory actionParams) = decoder.decodeActionsRouterParams(params); @@ -189,11 +212,7 @@ contract CalldataDecoderTest is Test { bytes memory params = abi.encode(_actions, _actionParams); - bytes memory invalidParams = new bytes(params.length - 1); - // dont copy the final byte - for (uint256 i = 0; i < params.length - 2; i++) { - invalidParams[i] = params[i]; - } + bytes memory invalidParams = _removeFinalByte(params); assertEq(invalidParams.length, params.length - 1); @@ -222,6 +241,18 @@ contract CalldataDecoderTest is Test { assertEq(Currency.unwrap(currency1), Currency.unwrap(_currency1)); } + function test_decodeCurrencyPair_outOutBounds() public { + Currency currency = Currency.wrap(address(0x12341234)); + Currency currency2 = Currency.wrap(address(0x56785678)); + + bytes memory params = abi.encode(currency, currency2); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrencyPair(invalidParams); + } + function test_fuzz_decodeCurrencyPairAndAddress(Currency _currency0, Currency _currency1, address __address) public view @@ -234,6 +265,19 @@ contract CalldataDecoderTest is Test { assertEq(_address, __address); } + function test_decodeCurrencyPairAndAddress_outOutBounds() public { + Currency currency = Currency.wrap(address(0x12341234)); + Currency currency2 = Currency.wrap(address(0x56785678)); + address addy = address(0x23453456); + + bytes memory params = abi.encode(currency, currency2, addy); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrencyPairAndAddress(invalidParams); + } + function test_fuzz_decodeCurrencyAddressAndUint256(Currency _currency, address _addr, uint256 _amount) public view @@ -246,6 +290,19 @@ contract CalldataDecoderTest is Test { assertEq(amount, _amount); } + function test_decodeCurrencyAddressAndUint256_outOutBounds() public { + uint256 value = 12345678; + Currency currency = Currency.wrap(address(0x12341234)); + address addy = address(0x67896789); + + bytes memory params = abi.encode(currency, addy, value); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrencyAddressAndUint256(invalidParams); + } + function test_fuzz_decodeCurrencyAndUint256(Currency _currency, uint256 _amount) public view { bytes memory params = abi.encode(_currency, _amount); (Currency currency, uint256 amount) = decoder.decodeCurrencyAndUint256(params); @@ -254,6 +311,18 @@ contract CalldataDecoderTest is Test { assertEq(amount, _amount); } + function test_decodeCurrencyAndUint256_outOutBounds() public { + uint256 value = 12345678; + Currency currency = Currency.wrap(address(0x12341234)); + + bytes memory params = abi.encode(currency, value); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrencyAndUint256(invalidParams); + } + function test_fuzz_decodeIncreaseLiquidityFromAmountsParams( uint256 _tokenId, uint128 _amount0Max, @@ -277,6 +346,39 @@ contract CalldataDecoderTest is Test { assertEq(amount, _amount); } + function test_decodeUint256_outOutBounds() public { + uint256 value = 12345678; + + bytes memory params = abi.encode(value); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeUint256(invalidParams); + } + + function test_fuzz_decodeCurrencyUint256AndBool(Currency _currency, uint256 _amount, bool _boolean) public view { + bytes memory params = abi.encode(_currency, _amount, _boolean); + (Currency currency, uint256 amount, bool boolean) = decoder.decodeCurrencyUint256AndBool(params); + + assertEq(Currency.unwrap(currency), Currency.unwrap(_currency)); + assertEq(amount, _amount); + assertEq(boolean, _boolean); + } + + function test_decodeCurrencyUint256AndBool_outOutBounds() public { + uint256 value = 12345678; + Currency currency = Currency.wrap(address(0x12341234)); + bool boolean = true; + + bytes memory params = abi.encode(currency, value, boolean); + bytes memory invalidParams = _removeFinalByte(params); + assertEq(invalidParams.length, params.length - 1); + + vm.expectRevert(CalldataDecoder.SliceOutOfBounds.selector); + decoder.decodeCurrencyUint256AndBool(invalidParams); + } + function _assertEq(PathKey[] memory path1, PathKey[] memory path2) internal pure { assertEq(path1.length, path2.length); for (uint256 i = 0; i < path1.length; i++) { @@ -295,4 +397,12 @@ contract CalldataDecoderTest is Test { assertEq(key1.tickSpacing, key2.tickSpacing); assertEq(address(key1.hooks), address(key2.hooks)); } + + function _removeFinalByte(bytes memory params) internal pure returns (bytes memory result) { + result = new bytes(params.length - 1); + // dont copy the final byte + for (uint256 i = 0; i < params.length - 2; i++) { + result[i] = params[i]; + } + } } diff --git a/test/mocks/MockCalldataDecoder.sol b/test/mocks/MockCalldataDecoder.sol index c4bd803ee..151b3c247 100644 --- a/test/mocks/MockCalldataDecoder.sol +++ b/test/mocks/MockCalldataDecoder.sol @@ -183,4 +183,8 @@ contract MockCalldataDecoder { function decodeUint256(bytes calldata params) external pure returns (uint256) { return params.decodeUint256(); } + + function decodeCurrencyUint256AndBool(bytes calldata params) external pure returns (Currency, uint256, bool) { + return params.decodeCurrencyUint256AndBool(); + } } From bf39426ed3013470fafbbe9ca1fca162d53d59c5 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Sat, 23 Nov 2024 08:28:33 +0000 Subject: [PATCH 22/31] try-catch-initialize (#397) * try-catch-initialize * add test * fix return value * snapshot --------- Co-authored-by: Alice Henshaw --- ...tionManager_multicall_initialize_mint.snap | 2 +- src/base/PoolInitializer.sol | 8 ++- .../PositionManager.multicall.t.sol | 61 +++++++++++++------ 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 74c7eee12..175d70efb 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455931 \ No newline at end of file +455917 \ No newline at end of file diff --git a/src/base/PoolInitializer.sol b/src/base/PoolInitializer.sol index 445248e18..b409322f2 100644 --- a/src/base/PoolInitializer.sol +++ b/src/base/PoolInitializer.sol @@ -10,9 +10,15 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; /// @dev Enables create pool + mint liquidity in a single transaction with multicall abstract contract PoolInitializer is ImmutableState { /// @notice Initialize a Uniswap v4 Pool + /// @dev If the pool is already initialized, this function will not revert and just return type(int24).max /// @param key the PoolKey of the pool to initialize /// @param sqrtPriceX96 the initial sqrtPriceX96 of the pool + /// @return tick The current tick of the pool function initializePool(PoolKey calldata key, uint160 sqrtPriceX96) external payable returns (int24) { - return poolManager.initialize(key, sqrtPriceX96); + try poolManager.initialize(key, sqrtPriceX96) returns (int24 tick) { + return tick; + } catch { + return type(int24).max; + } } } diff --git a/test/position-managers/PositionManager.multicall.t.sol b/test/position-managers/PositionManager.multicall.t.sol index c70f68b39..087c21027 100644 --- a/test/position-managers/PositionManager.multicall.t.sol +++ b/test/position-managers/PositionManager.multicall.t.sol @@ -133,6 +133,47 @@ contract PositionManagerMulticallTest is Test, Permit2SignatureHelpers, PosmTest assertGt(result.amount1(), 0); } + function test_multicall_initializePool_twice_andMint_succeeds() public { + key = PoolKey({currency0: currency0, currency1: currency1, fee: 0, tickSpacing: 10, hooks: IHooks(address(0))}); + manager.initialize(key, SQRT_PRICE_1_1); + + // Use multicall to initialize the pool again. + bytes[] memory calls = new bytes[](2); + calls[0] = abi.encodeWithSelector(lpm.initializePool.selector, key, SQRT_PRICE_1_1); + + config = PositionConfig({ + poolKey: key, + tickLower: TickMath.minUsableTick(key.tickSpacing), + tickUpper: TickMath.maxUsableTick(key.tickSpacing) + }); + + Plan memory planner = Planner.init(); + planner.add( + Actions.MINT_POSITION, + abi.encode( + config.poolKey, + config.tickLower, + config.tickUpper, + 100e18, + MAX_SLIPPAGE_INCREASE, + MAX_SLIPPAGE_INCREASE, + ActionConstants.MSG_SENDER, + ZERO_BYTES + ) + ); + bytes memory actions = planner.finalizeModifyLiquidityWithClose(config.poolKey); + + calls[1] = abi.encodeWithSelector(IPositionManager.modifyLiquidities.selector, actions, _deadline); + + IMulticall_v4(address(lpm)).multicall(calls); + + // test swap, doesn't revert, showing the mint succeeded even after initialize reverted + int256 amountSpecified = -1e18; + BalanceDelta result = swap(key, true, amountSpecified, ZERO_BYTES); + assertEq(result.amount0(), amountSpecified); + assertGt(result.amount1(), 0); + } + function test_multicall_initializePool_mint_native() public { key = PoolKey({ currency0: CurrencyLibrary.ADDRESS_ZERO, @@ -227,26 +268,6 @@ contract PositionManagerMulticallTest is Test, Permit2SignatureHelpers, PosmTest lpm.multicall(calls); } - // create a pool where tickSpacing is negative - // core's TickSpacingTooSmall(int24) should bubble up through Multicall - function test_multicall_bubbleRevert_core_args() public { - int24 tickSpacing = -10; - key = PoolKey({ - currency0: currency0, - currency1: currency1, - fee: 0, - tickSpacing: tickSpacing, - hooks: IHooks(address(0)) - }); - - // Use multicall to initialize a pool - bytes[] memory calls = new bytes[](1); - calls[0] = abi.encodeWithSelector(PoolInitializer.initializePool.selector, key, SQRT_PRICE_1_1); - - vm.expectRevert(abi.encodeWithSelector(IPoolManager.TickSpacingTooSmall.selector, tickSpacing)); - lpm.multicall(calls); - } - function test_multicall_permitAndDecrease() public { config = PositionConfig({poolKey: key, tickLower: -60, tickUpper: 60}); uint256 liquidityAlice = 1e18; From 4ac5f57a5dab46ba4c818f7b88992a6aca3b6419 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:07:48 +0000 Subject: [PATCH 23/31] use notifyBurn (#399) * use notifyBurn * rename * update bytecode --- .../PositionManager_burn_empty.snap | 2 +- .../PositionManager_burn_empty_native.snap | 2 +- ...anager_burn_nonEmpty_native_withClose.snap | 2 +- ...ger_burn_nonEmpty_native_withTakePair.snap | 2 +- ...sitionManager_burn_nonEmpty_withClose.snap | 2 +- ...ionManager_burn_nonEmpty_withTakePair.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- ...onManager_decreaseLiquidity_withClose.snap | 2 +- ...anager_decreaseLiquidity_withTakePair.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- .../PositionManager_decrease_take_take.snap | 2 +- ...ger_increaseLiquidity_erc20_withClose.snap | 2 +- ...ncreaseLiquidity_erc20_withSettlePair.snap | 2 +- ...itionManager_increaseLiquidity_native.snap | 2 +- ...crease_autocompoundExactUnclaimedFees.snap | 2 +- ...increase_autocompoundExcessFeesCredit.snap | 2 +- ...ger_increase_autocompound_clearExcess.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- ...anager_mint_nativeWithSweep_withClose.snap | 2 +- ...r_mint_nativeWithSweep_withSettlePair.snap | 2 +- .../PositionManager_mint_onSameTickLower.snap | 2 +- .../PositionManager_mint_onSameTickUpper.snap | 2 +- .../PositionManager_mint_sameRange.snap | 2 +- ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...anager_mint_warmedPool_differentRange.snap | 2 +- .../PositionManager_mint_withClose.snap | 2 +- .../PositionManager_mint_withSettlePair.snap | 2 +- ...tionManager_multicall_initialize_mint.snap | 2 +- .../PositionManager_unsubscribe.snap | 2 +- src/PositionManager.sol | 21 +++++++++++++--- src/base/Notifier.sol | 24 +++++++++++++++++++ src/interfaces/INotifier.sol | 2 ++ src/interfaces/ISubscriber.sol | 9 +++++++ test/mocks/MockBadSubscribers.sol | 13 ++++++++++ test/mocks/MockSubscriber.sol | 9 +++++++ .../PositionManager.notifier.t.sol | 9 +++---- 42 files changed, 115 insertions(+), 42 deletions(-) diff --git a/.forge-snapshots/PositionManager_burn_empty.snap b/.forge-snapshots/PositionManager_burn_empty.snap index 2479c9837..fcb819260 100644 --- a/.forge-snapshots/PositionManager_burn_empty.snap +++ b/.forge-snapshots/PositionManager_burn_empty.snap @@ -1 +1 @@ -50540 \ No newline at end of file +50845 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty_native.snap b/.forge-snapshots/PositionManager_burn_empty_native.snap index 2479c9837..fcb819260 100644 --- a/.forge-snapshots/PositionManager_burn_empty_native.snap +++ b/.forge-snapshots/PositionManager_burn_empty_native.snap @@ -1 +1 @@ -50540 \ No newline at end of file +50845 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 7ec595830..9c88356c2 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -125788 \ No newline at end of file +126075 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 5218895ce..0c610d439 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125220 \ No newline at end of file +125508 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 1be09a218..02c6f5867 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132648 \ No newline at end of file +132935 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 7c6408e36..5d1c4b28d 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -132080 \ No newline at end of file +132368 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 40f4aecb3..300b94d21 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146518 \ No newline at end of file +146517 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index 3a0b4f707..9d8c45b66 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -155093 \ No newline at end of file +155092 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index 3a0b4f707..9d8c45b66 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -155093 \ No newline at end of file +155092 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 3e9ec783f..3a772220d 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154396 \ No newline at end of file +154395 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index ba0b210d5..03b97f2fc 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -112160 \ No newline at end of file +112159 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index 8f0ff9be1..48ff8dce8 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119974 \ No newline at end of file +119973 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 323d58aa9..c576e745f 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119277 \ No newline at end of file +119276 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 92d88d4ab..d997832ef 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135480 \ No newline at end of file +135785 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 5c195ecc6..178defb90 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128620 \ No newline at end of file +128925 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index de446de0c..5067e921f 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132661 \ No newline at end of file +132660 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index c1f9fc28e..1704633b9 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120564 \ No newline at end of file +120563 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index 07d41e539..e041bfa5e 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -158973 \ No newline at end of file +158972 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index f3733866f..4218521c0 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -157884 \ No newline at end of file +157883 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 43a1de117..173f0fd14 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -142237 \ No newline at end of file +142236 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index 15b5ab6c2..65400e18f 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -136418 \ No newline at end of file +136417 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index 81df070a8..c100c3a7a 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177562 \ No newline at end of file +177561 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 3abe5dbd4..f780123ba 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148338 \ No newline at end of file +148337 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index 9258b17f6..fd7f97d42 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -366111 \ No newline at end of file +366110 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index 571f3e49f..d51892743 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -374685 \ No newline at end of file +374684 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index 9f80774dd..4bc4b7b3e 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -373880 \ No newline at end of file +373879 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 62bd3d801..1dbf1cac3 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317534 \ No newline at end of file +317533 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index dd8c88a2a..762eabe24 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318204 \ No newline at end of file +318203 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index ade21eeba..79c426297 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243773 \ No newline at end of file +243772 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 7d6b55033..1a107995a 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -419063 \ No newline at end of file +419062 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index 95c1d7783..51af85723 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323565 \ No newline at end of file +323564 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index 189188dc8..3fa2f80f6 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -420087 \ No newline at end of file +420086 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index eb86505ba..530393d35 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419116 \ No newline at end of file +419115 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index 175d70efb..db9aea251 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455917 \ No newline at end of file +455916 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_unsubscribe.snap b/.forge-snapshots/PositionManager_unsubscribe.snap index c9bfebd46..ef5e368eb 100644 --- a/.forge-snapshots/PositionManager_unsubscribe.snap +++ b/.forge-snapshots/PositionManager_unsubscribe.snap @@ -1 +1 @@ -63036 \ No newline at end of file +63058 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index 58efd722e..dfe6e8f01 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -411,20 +411,34 @@ contract PositionManager is uint256 liquidity = uint256(_getLiquidity(tokenId, poolKey, info.tickLower(), info.tickUpper())); + address owner = ownerOf(tokenId); + // Clear the position info. positionInfo[tokenId] = PositionInfoLibrary.EMPTY_POSITION_INFO; // Burn the token. _burn(tokenId); // Can only call modify if there is non zero liquidity. + BalanceDelta feesAccrued; + BalanceDelta liquidityDelta; if (liquidity > 0) { - (BalanceDelta liquidityDelta, BalanceDelta feesAccrued) = - _modifyLiquidity(info, poolKey, -(liquidity.toInt256()), bytes32(tokenId), hookData); + // do not use _modifyLiquidity as we do not need to notify on modification for burns. + (liquidityDelta, feesAccrued) = poolManager.modifyLiquidity( + poolKey, + IPoolManager.ModifyLiquidityParams({ + tickLower: info.tickLower(), + tickUpper: info.tickUpper(), + liquidityDelta: -(liquidity.toInt256()), + salt: bytes32(tokenId) + }), + hookData + ); // Slippage checks should be done on the principal liquidityDelta which is the liquidityDelta - feesAccrued (liquidityDelta - feesAccrued).validateMinOut(amount0Min, amount1Min); } - if (info.hasSubscriber()) _unsubscribe(tokenId); + // deletes then notifies the subscriber + if (info.hasSubscriber()) _removeSubscriberAndNotifyBurn(tokenId, owner, info, liquidity, feesAccrued); } function _settlePair(Currency currency0, Currency currency1) internal { @@ -475,6 +489,7 @@ contract PositionManager is if (balance > 0) currency.transfer(to, balance); } + /// @dev if there is a subscriber attached to the position, this function will notify the subscriber function _modifyLiquidity( PositionInfo info, PoolKey memory poolKey, diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index b85d3e6e0..3b2880532 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -88,6 +88,30 @@ abstract contract Notifier is INotifier { emit Unsubscription(tokenId, address(_subscriber)); } + /// @dev note this function also deletes the subscriber address from the mapping + function _removeSubscriberAndNotifyBurn( + uint256 tokenId, + address owner, + PositionInfo info, + uint256 liquidity, + BalanceDelta feesAccrued + ) internal { + ISubscriber _subscriber = subscriber[tokenId]; + + // remove the subscriber + delete subscriber[tokenId]; + + bool success = _call( + address(_subscriber), abi.encodeCall(ISubscriber.notifyBurn, (tokenId, owner, info, liquidity, feesAccrued)) + ); + + if (!success) { + address(_subscriber).bubbleUpAndRevertWith( + ISubscriber.notifyBurn.selector, BurnNotificationReverted.selector + ); + } + } + function _notifyModifyLiquidity(uint256 tokenId, int256 liquidityChange, BalanceDelta feesAccrued) internal { ISubscriber _subscriber = subscriber[tokenId]; diff --git a/src/interfaces/INotifier.sol b/src/interfaces/INotifier.sol index abf6148c4..9e7d2356c 100644 --- a/src/interfaces/INotifier.sol +++ b/src/interfaces/INotifier.sol @@ -15,6 +15,8 @@ interface INotifier { error SubscriptionReverted(address subscriber, bytes reason); /// @notice Wraps the revert message of the subscriber contract on a reverting modify liquidity notification error ModifyLiquidityNotificationReverted(address subscriber, bytes reason); + /// @notice Wraps the revert message of the subscriber contract on a reverting burn notification + error BurnNotificationReverted(address subscriber, bytes reason); /// @notice Wraps the revert message of the subscriber contract on a reverting transfer notification error TransferNotificationReverted(address subscriber, bytes reason); /// @notice Thrown when a tokenId already has a subscriber diff --git a/src/interfaces/ISubscriber.sol b/src/interfaces/ISubscriber.sol index 0c410079e..e16629985 100644 --- a/src/interfaces/ISubscriber.sol +++ b/src/interfaces/ISubscriber.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; +import {PositionInfo} from "../libraries/PositionInfoLibrary.sol"; /// @notice Interface that a Subscriber contract should implement to receive updates from the v4 position manager interface ISubscriber { @@ -13,6 +14,14 @@ interface ISubscriber { /// @dev Because of EIP-150, solidity may only allocate 63/64 of gasleft() /// @param tokenId the token ID of the position function notifyUnsubscribe(uint256 tokenId) external; + /// @notice Called when a position is burned + /// @param tokenId the token ID of the position + /// @param owner the current owner of the tokenId + /// @param info information about the position + /// @param liquidity the amount of liquidity decreased in the position, may be 0 + /// @param feesAccrued the fees accrued by the position if liquidity was decreased + function notifyBurn(uint256 tokenId, address owner, PositionInfo info, uint256 liquidity, BalanceDelta feesAccrued) + external; /// @param tokenId the token ID of the position /// @param liquidityChange the change in liquidity on the underlying position /// @param feesAccrued the fees to be collected from the position as a result of the modifyLiquidity call diff --git a/test/mocks/MockBadSubscribers.sol b/test/mocks/MockBadSubscribers.sol index d6e6e0c39..0c506926d 100644 --- a/test/mocks/MockBadSubscribers.sol +++ b/test/mocks/MockBadSubscribers.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.20; import {ISubscriber} from "../../src/interfaces/ISubscriber.sol"; import {PositionManager} from "../../src/PositionManager.sol"; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; +import {PositionInfo} from "../../src/libraries/PositionInfoLibrary.sol"; /// @notice A subscriber contract that returns values from the subscriber entrypoints contract MockReturnDataSubscriber is ISubscriber { @@ -47,6 +48,12 @@ contract MockReturnDataSubscriber is ISubscriber { notifyModifyLiquidityCount++; } + function notifyBurn(uint256 tokenId, address owner, PositionInfo info, uint256 liquidity, BalanceDelta feesAccrued) + external + { + return; + } + function setReturnDataSize(uint256 _value) external { memPtr = _value; } @@ -85,6 +92,12 @@ contract MockRevertSubscriber is ISubscriber { revert TestRevert("notifyModifyLiquidity"); } + function notifyBurn(uint256 tokenId, address owner, PositionInfo info, uint256 liquidity, BalanceDelta feesAccrued) + external + { + return; + } + function setRevert(bool _shouldRevert) external { shouldRevert = _shouldRevert; } diff --git a/test/mocks/MockSubscriber.sol b/test/mocks/MockSubscriber.sol index ef4c2e86e..4da187b57 100644 --- a/test/mocks/MockSubscriber.sol +++ b/test/mocks/MockSubscriber.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.20; import {ISubscriber} from "../../src/interfaces/ISubscriber.sol"; import {PositionManager} from "../../src/PositionManager.sol"; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; +import {PositionInfo} from "../../src/libraries/PositionInfoLibrary.sol"; /// @notice A subscriber contract that ingests updates from the v4 position manager contract MockSubscriber is ISubscriber { @@ -12,6 +13,7 @@ contract MockSubscriber is ISubscriber { uint256 public notifySubscribeCount; uint256 public notifyUnsubscribeCount; uint256 public notifyModifyLiquidityCount; + uint256 public notifyBurnCount; int256 public liquidityChange; BalanceDelta public feesAccrued; @@ -44,4 +46,11 @@ contract MockSubscriber is ISubscriber { liquidityChange = _liquidityChange; feesAccrued = _feesAccrued; } + + function notifyBurn(uint256 tokenId, address owner, PositionInfo info, uint256 liquidity, BalanceDelta feesAccrued) + external + onlyByPosm + { + notifyBurnCount++; + } } diff --git a/test/position-managers/PositionManager.notifier.t.sol b/test/position-managers/PositionManager.notifier.t.sol index 599bfbe15..de25bc412 100644 --- a/test/position-managers/PositionManager.notifier.t.sol +++ b/test/position-managers/PositionManager.notifier.t.sol @@ -566,8 +566,8 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { lpm.modifyLiquidities(calls, _deadline); } - /// @notice burning a position will automatically notify unsubscribe - function test_burn_unsubscribe() public { + /// @notice burning a position will automatically notify burn + function test_notifyBurn_succeeds() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 100e18, alice, ZERO_BYTES); @@ -583,12 +583,13 @@ contract PositionManagerNotifierTest is Test, PosmTestSetup, GasSnapshot { assertEq(lpm.positionInfo(tokenId).hasSubscriber(), true); assertEq(sub.notifyUnsubscribeCount(), 0); - // burn the position, causing an unsubscribe + // burn the position, causing a notifyBurn burn(tokenId, config, ZERO_BYTES); // position is now unsubscribed assertEq(lpm.positionInfo(tokenId).hasSubscriber(), false); - assertEq(sub.notifyUnsubscribeCount(), 1); + assertEq(sub.notifyUnsubscribeCount(), 0); + assertEq(sub.notifyBurnCount(), 1); } /// @notice Test that users cannot forcibly avoid unsubscribe logic via gas limits From e75fd8878c70d18234cdf9d0bfeeae6e16713037 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:35:07 +0000 Subject: [PATCH 24/31] update license (#400) * update license * remove gpl * add mit license * update * fix * new line * rename --- LICENSE | 340 +----------------- script/01_PoolManager.s.sol | 2 +- script/02_PoolModifyLiquidityTest.s.sol | 2 +- script/03_PoolSwapTest.s.sol | 2 +- script/DeployPosm.s.sol | 2 +- script/DeployStateView.s.sol | 2 +- script/DeployV4Quoter.s.sol | 2 +- src/PositionDescriptor.sol | 2 +- src/PositionManager.sol | 2 +- src/UniswapV4DeployerCompetition.sol | 2 +- src/V4Router.sol | 2 +- src/base/BaseActionsRouter.sol | 2 +- src/base/BaseV4Quoter.sol | 2 +- src/base/DeltaResolver.sol | 2 +- src/base/ERC721Permit_v4.sol | 2 +- src/base/ImmutableState.sol | 2 +- src/base/Multicall_v4.sol | 2 +- src/base/NativeWrapper.sol | 2 +- src/base/Notifier.sol | 2 +- src/base/Permit2Forwarder.sol | 2 +- src/base/PoolInitializer.sol | 2 +- src/base/ReentrancyLock.sol | 2 +- src/base/SafeCallback.sol | 2 +- src/base/UnorderedNonce.sol | 2 +- src/base/hooks/BaseHook.sol | 2 +- src/interfaces/IERC721Permit_v4.sol | 2 +- src/interfaces/IImmutableState.sol | 2 +- src/interfaces/IMulticall_v4.sol | 2 +- src/interfaces/INotifier.sol | 2 +- src/interfaces/IPositionDescriptor.sol | 2 +- src/interfaces/IPositionManager.sol | 2 +- src/interfaces/ISubscriber.sol | 2 +- .../IUniswapV4DeployerCompetition.sol | 2 +- src/interfaces/IV4Quoter.sol | 2 +- src/interfaces/IV4Router.sol | 2 +- src/interfaces/external/IWETH9.sol | 2 +- src/lens/StateView.sol | 2 +- src/lens/V4Quoter.sol | 2 +- src/libraries/ActionConstants.sol | 2 +- src/libraries/Actions.sol | 2 +- src/libraries/AddressStringUtil.sol | 2 +- src/libraries/BipsLibrary.sol | 2 +- src/libraries/CalldataDecoder.sol | 2 +- src/libraries/CurrencyRatioSortOrder.sol | 2 +- src/libraries/Descriptor.sol | 2 +- src/libraries/ERC721PermitHash.sol | 2 +- src/libraries/HexStrings.sol | 2 +- src/libraries/Locker.sol | 2 +- src/libraries/PathKey.sol | 2 +- src/libraries/PositionConfig.sol | 2 +- src/libraries/PositionConfigId.sol | 2 +- src/libraries/PositionInfoLibrary.sol | 2 +- src/libraries/QuoterRevert.sol | 2 +- src/libraries/SVG.sol | 2 +- src/libraries/SafeCurrencyMetadata.sol | 2 +- src/libraries/SlippageCheck.sol | 2 +- src/libraries/VanityAddressLib.sol | 2 +- test/BaseActionsRouter.t.sol | 2 +- test/DeltaResolver.t.sol | 2 +- test/Multicall.t.sol | 2 +- test/SafeCallback.t.sol | 2 +- test/UnorderedNonce.t.sol | 2 +- test/V4Quoter.t.sol | 2 +- test/mocks/MockBadSubscribers.sol | 2 +- test/mocks/MockBaseActionsRouter.sol | 2 +- test/mocks/MockDeltaResolver.sol | 2 +- test/mocks/MockERC721Permit.sol | 2 +- test/mocks/MockFeeOnTransfer.sol | 2 +- test/mocks/MockMulticall.sol | 2 +- test/mocks/MockSafeCallback.sol | 2 +- test/mocks/MockSubscriber.sol | 2 +- test/mocks/MockUnorderedNonce.sol | 2 +- test/mocks/ReentrantToken.sol | 2 +- test/shared/PositionConfig.sol | 2 +- 74 files changed, 77 insertions(+), 409 deletions(-) diff --git a/LICENSE b/LICENSE index ecbc05937..45956f482 100644 --- a/LICENSE +++ b/LICENSE @@ -1,339 +1,7 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +Copyright 2023 Universal Navigation Inc. - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - Preamble +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. \ No newline at end of file +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/script/01_PoolManager.s.sol b/script/01_PoolManager.s.sol index 5d4c5b140..3d9d570d8 100644 --- a/script/01_PoolManager.s.sol +++ b/script/01_PoolManager.s.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Script.sol"; diff --git a/script/02_PoolModifyLiquidityTest.s.sol b/script/02_PoolModifyLiquidityTest.s.sol index 3e0b75510..a2c4975ed 100644 --- a/script/02_PoolModifyLiquidityTest.s.sol +++ b/script/02_PoolModifyLiquidityTest.s.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {Script} from "forge-std/Script.sol"; diff --git a/script/03_PoolSwapTest.s.sol b/script/03_PoolSwapTest.s.sol index a2da989f9..acd650d25 100644 --- a/script/03_PoolSwapTest.s.sol +++ b/script/03_PoolSwapTest.s.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {Script} from "forge-std/Script.sol"; diff --git a/script/DeployPosm.s.sol b/script/DeployPosm.s.sol index e3a20758d..b87fbea0f 100644 --- a/script/DeployPosm.s.sol +++ b/script/DeployPosm.s.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/console2.sol"; diff --git a/script/DeployStateView.s.sol b/script/DeployStateView.s.sol index b48526bc9..9584099d2 100644 --- a/script/DeployStateView.s.sol +++ b/script/DeployStateView.s.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/console2.sol"; diff --git a/script/DeployV4Quoter.s.sol b/script/DeployV4Quoter.s.sol index 1c6a8430e..7cc61d5f9 100644 --- a/script/DeployV4Quoter.s.sol +++ b/script/DeployV4Quoter.s.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/console2.sol"; diff --git a/src/PositionDescriptor.sol b/src/PositionDescriptor.sol index 7f1ac799b..34910d538 100644 --- a/src/PositionDescriptor.sol +++ b/src/PositionDescriptor.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/PositionManager.sol b/src/PositionManager.sol index dfe6e8f01..f5840999a 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/UniswapV4DeployerCompetition.sol b/src/UniswapV4DeployerCompetition.sol index c9af05a65..deec4177e 100644 --- a/src/UniswapV4DeployerCompetition.sol +++ b/src/UniswapV4DeployerCompetition.sol @@ -1,4 +1,4 @@ -// SPADIX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; diff --git a/src/V4Router.sol b/src/V4Router.sol index 8f2fb194a..e149da215 100644 --- a/src/V4Router.sol +++ b/src/V4Router.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/base/BaseActionsRouter.sol b/src/base/BaseActionsRouter.sol index 56e311906..8cb30f131 100644 --- a/src/base/BaseActionsRouter.sol +++ b/src/base/BaseActionsRouter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/base/BaseV4Quoter.sol b/src/base/BaseV4Quoter.sol index 312cf7d15..52bacdb3f 100644 --- a/src/base/BaseV4Quoter.sol +++ b/src/base/BaseV4Quoter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; diff --git a/src/base/DeltaResolver.sol b/src/base/DeltaResolver.sol index be7e48e72..bd0d39bf0 100644 --- a/src/base/DeltaResolver.sol +++ b/src/base/DeltaResolver.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; diff --git a/src/base/ERC721Permit_v4.sol b/src/base/ERC721Permit_v4.sol index cb074c9c8..e6ded04dd 100644 --- a/src/base/ERC721Permit_v4.sol +++ b/src/base/ERC721Permit_v4.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ERC721} from "solmate/src/tokens/ERC721.sol"; diff --git a/src/base/ImmutableState.sol b/src/base/ImmutableState.sol index 9f9cf0687..708a3d281 100644 --- a/src/base/ImmutableState.sol +++ b/src/base/ImmutableState.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/base/Multicall_v4.sol b/src/base/Multicall_v4.sol index e632270af..e4fb7dacb 100644 --- a/src/base/Multicall_v4.sol +++ b/src/base/Multicall_v4.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IMulticall_v4} from "../interfaces/IMulticall_v4.sol"; diff --git a/src/base/NativeWrapper.sol b/src/base/NativeWrapper.sol index ef6a3f2a2..eb4eba073 100644 --- a/src/base/NativeWrapper.sol +++ b/src/base/NativeWrapper.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IWETH9} from "../interfaces/external/IWETH9.sol"; diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index 3b2880532..3412ea645 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ISubscriber} from "../interfaces/ISubscriber.sol"; diff --git a/src/base/Permit2Forwarder.sol b/src/base/Permit2Forwarder.sol index c90b406a3..d5a749a85 100644 --- a/src/base/Permit2Forwarder.sol +++ b/src/base/Permit2Forwarder.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; diff --git a/src/base/PoolInitializer.sol b/src/base/PoolInitializer.sol index b409322f2..fea603402 100644 --- a/src/base/PoolInitializer.sol +++ b/src/base/PoolInitializer.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ImmutableState} from "./ImmutableState.sol"; diff --git a/src/base/ReentrancyLock.sol b/src/base/ReentrancyLock.sol index 29fa3d34f..c1abf028f 100644 --- a/src/base/ReentrancyLock.sol +++ b/src/base/ReentrancyLock.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Locker} from "../libraries/Locker.sol"; diff --git a/src/base/SafeCallback.sol b/src/base/SafeCallback.sol index cda2b4a04..45e1c6bf9 100644 --- a/src/base/SafeCallback.sol +++ b/src/base/SafeCallback.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol"; diff --git a/src/base/UnorderedNonce.sol b/src/base/UnorderedNonce.sol index fc33b63d8..b08b5d92c 100644 --- a/src/base/UnorderedNonce.sol +++ b/src/base/UnorderedNonce.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Unordered Nonce diff --git a/src/base/hooks/BaseHook.sol b/src/base/hooks/BaseHook.sol index c53f9b753..635602a63 100644 --- a/src/base/hooks/BaseHook.sol +++ b/src/base/hooks/BaseHook.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol"; diff --git a/src/interfaces/IERC721Permit_v4.sol b/src/interfaces/IERC721Permit_v4.sol index bc4c7aa06..e15e00bd8 100644 --- a/src/interfaces/IERC721Permit_v4.sol +++ b/src/interfaces/IERC721Permit_v4.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ERC721 with permit diff --git a/src/interfaces/IImmutableState.sol b/src/interfaces/IImmutableState.sol index 32e20573a..83f7cf034 100644 --- a/src/interfaces/IImmutableState.sol +++ b/src/interfaces/IImmutableState.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/interfaces/IMulticall_v4.sol b/src/interfaces/IMulticall_v4.sol index 1d053a97d..07c321b32 100644 --- a/src/interfaces/IMulticall_v4.sol +++ b/src/interfaces/IMulticall_v4.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Multicall_v4 interface diff --git a/src/interfaces/INotifier.sol b/src/interfaces/INotifier.sol index 9e7d2356c..13ded49f3 100644 --- a/src/interfaces/INotifier.sol +++ b/src/interfaces/INotifier.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ISubscriber} from "./ISubscriber.sol"; diff --git a/src/interfaces/IPositionDescriptor.sol b/src/interfaces/IPositionDescriptor.sol index 8c3227324..a1736ceab 100644 --- a/src/interfaces/IPositionDescriptor.sol +++ b/src/interfaces/IPositionDescriptor.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "./IPositionManager.sol"; diff --git a/src/interfaces/IPositionManager.sol b/src/interfaces/IPositionManager.sol index 53a2efbee..86df7bbf9 100644 --- a/src/interfaces/IPositionManager.sol +++ b/src/interfaces/IPositionManager.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; diff --git a/src/interfaces/ISubscriber.sol b/src/interfaces/ISubscriber.sol index e16629985..f2fc94df6 100644 --- a/src/interfaces/ISubscriber.sol +++ b/src/interfaces/ISubscriber.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; diff --git a/src/interfaces/IUniswapV4DeployerCompetition.sol b/src/interfaces/IUniswapV4DeployerCompetition.sol index 82959230c..5bb1a4be1 100644 --- a/src/interfaces/IUniswapV4DeployerCompetition.sol +++ b/src/interfaces/IUniswapV4DeployerCompetition.sol @@ -1,4 +1,4 @@ -// SPADIX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.26; /// @title UniswapV4DeployerCompetition diff --git a/src/interfaces/IV4Quoter.sol b/src/interfaces/IV4Quoter.sol index a8483a894..f502a4f44 100644 --- a/src/interfaces/IV4Quoter.sol +++ b/src/interfaces/IV4Quoter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; diff --git a/src/interfaces/IV4Router.sol b/src/interfaces/IV4Router.sol index a24ae9a9d..f42715aa0 100644 --- a/src/interfaces/IV4Router.sol +++ b/src/interfaces/IV4Router.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; diff --git a/src/interfaces/external/IWETH9.sol b/src/interfaces/external/IWETH9.sol index 37c3be8ea..b8e68b363 100644 --- a/src/interfaces/external/IWETH9.sol +++ b/src/interfaces/external/IWETH9.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/src/lens/StateView.sol b/src/lens/StateView.sol index f361b905a..6527d2f72 100644 --- a/src/lens/StateView.sol +++ b/src/lens/StateView.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; diff --git a/src/lens/V4Quoter.sol b/src/lens/V4Quoter.sol index 1623ff59b..0f6b78648 100644 --- a/src/lens/V4Quoter.sol +++ b/src/lens/V4Quoter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/src/libraries/ActionConstants.sol b/src/libraries/ActionConstants.sol index 914528b02..4c84e11a1 100644 --- a/src/libraries/ActionConstants.sol +++ b/src/libraries/ActionConstants.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Action Constants diff --git a/src/libraries/Actions.sol b/src/libraries/Actions.sol index 207a8c7be..ab34c9c2d 100644 --- a/src/libraries/Actions.sol +++ b/src/libraries/Actions.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice Library to define different pool actions. diff --git a/src/libraries/AddressStringUtil.sol b/src/libraries/AddressStringUtil.sol index 999bc2d95..3add136f8 100644 --- a/src/libraries/AddressStringUtil.sol +++ b/src/libraries/AddressStringUtil.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title AddressStringUtil diff --git a/src/libraries/BipsLibrary.sol b/src/libraries/BipsLibrary.sol index 219232e25..d85486a82 100644 --- a/src/libraries/BipsLibrary.sol +++ b/src/libraries/BipsLibrary.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title For calculating a percentage of an amount, using bips diff --git a/src/libraries/CalldataDecoder.sol b/src/libraries/CalldataDecoder.sol index 76ecccaa2..3c7a800c2 100644 --- a/src/libraries/CalldataDecoder.sol +++ b/src/libraries/CalldataDecoder.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; diff --git a/src/libraries/CurrencyRatioSortOrder.sol b/src/libraries/CurrencyRatioSortOrder.sol index 1f3a719a4..c02d1084f 100644 --- a/src/libraries/CurrencyRatioSortOrder.sol +++ b/src/libraries/CurrencyRatioSortOrder.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title CurrencyRatioSortOrder diff --git a/src/libraries/Descriptor.sol b/src/libraries/Descriptor.sol index ba261f850..327937c8d 100644 --- a/src/libraries/Descriptor.sol +++ b/src/libraries/Descriptor.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol"; diff --git a/src/libraries/ERC721PermitHash.sol b/src/libraries/ERC721PermitHash.sol index a8c9cfc87..3ead157a2 100644 --- a/src/libraries/ERC721PermitHash.sol +++ b/src/libraries/ERC721PermitHash.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library ERC721PermitHash { diff --git a/src/libraries/HexStrings.sol b/src/libraries/HexStrings.sol index d5a323875..714a9c8ef 100644 --- a/src/libraries/HexStrings.sol +++ b/src/libraries/HexStrings.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title HexStrings diff --git a/src/libraries/Locker.sol b/src/libraries/Locker.sol index 713779f16..246b10a96 100644 --- a/src/libraries/Locker.sol +++ b/src/libraries/Locker.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /// @notice This is a temporary library that allows us to use transient storage (tstore/tload) diff --git a/src/libraries/PathKey.sol b/src/libraries/PathKey.sol index b3fa1e7f8..daa2fdd07 100644 --- a/src/libraries/PathKey.sol +++ b/src/libraries/PathKey.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: UNLICENSED +//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; diff --git a/src/libraries/PositionConfig.sol b/src/libraries/PositionConfig.sol index 007e7bb9d..2fd6cd0d6 100644 --- a/src/libraries/PositionConfig.sol +++ b/src/libraries/PositionConfig.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; diff --git a/src/libraries/PositionConfigId.sol b/src/libraries/PositionConfigId.sol index 4e31c760c..e6bdf84d6 100644 --- a/src/libraries/PositionConfigId.sol +++ b/src/libraries/PositionConfigId.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice A configId is set per tokenId diff --git a/src/libraries/PositionInfoLibrary.sol b/src/libraries/PositionInfoLibrary.sol index 981500559..2baba26a1 100644 --- a/src/libraries/PositionInfoLibrary.sol +++ b/src/libraries/PositionInfoLibrary.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; diff --git a/src/libraries/QuoterRevert.sol b/src/libraries/QuoterRevert.sol index bb0eda905..d53ec844d 100644 --- a/src/libraries/QuoterRevert.sol +++ b/src/libraries/QuoterRevert.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ParseBytes} from "@uniswap/v4-core/src/libraries/ParseBytes.sol"; diff --git a/src/libraries/SVG.sol b/src/libraries/SVG.sol index 2731a6cac..03c4236cb 100644 --- a/src/libraries/SVG.sol +++ b/src/libraries/SVG.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; diff --git a/src/libraries/SafeCurrencyMetadata.sol b/src/libraries/SafeCurrencyMetadata.sol index cc88ab84c..e1a4c059c 100644 --- a/src/libraries/SafeCurrencyMetadata.sol +++ b/src/libraries/SafeCurrencyMetadata.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/src/libraries/SlippageCheck.sol b/src/libraries/SlippageCheck.sol index 48700c153..e4c7e960e 100644 --- a/src/libraries/SlippageCheck.sol +++ b/src/libraries/SlippageCheck.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; diff --git a/src/libraries/VanityAddressLib.sol b/src/libraries/VanityAddressLib.sol index ba35b9699..0139aa54d 100644 --- a/src/libraries/VanityAddressLib.sol +++ b/src/libraries/VanityAddressLib.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title VanityAddressLib diff --git a/test/BaseActionsRouter.t.sol b/test/BaseActionsRouter.t.sol index 57ca984fa..0a6bbc76f 100644 --- a/test/BaseActionsRouter.t.sol +++ b/test/BaseActionsRouter.t.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: UNLICENSED +//SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {MockBaseActionsRouter} from "./mocks/MockBaseActionsRouter.sol"; diff --git a/test/DeltaResolver.t.sol b/test/DeltaResolver.t.sol index 61c032038..212939b6f 100644 --- a/test/DeltaResolver.t.sol +++ b/test/DeltaResolver.t.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: UNLICENSED +//SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Test} from "forge-std/Test.sol"; diff --git a/test/Multicall.t.sol b/test/Multicall.t.sol index 8591c2712..83503c005 100644 --- a/test/Multicall.t.sol +++ b/test/Multicall.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Test.sol"; diff --git a/test/SafeCallback.t.sol b/test/SafeCallback.t.sol index fd5157ab3..1e7673227 100644 --- a/test/SafeCallback.t.sol +++ b/test/SafeCallback.t.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: UNLICENSED +//SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "forge-std/Test.sol"; diff --git a/test/UnorderedNonce.t.sol b/test/UnorderedNonce.t.sol index d3939fd24..f7b46b2da 100644 --- a/test/UnorderedNonce.t.sol +++ b/test/UnorderedNonce.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Test.sol"; diff --git a/test/V4Quoter.t.sol b/test/V4Quoter.t.sol index 26b62d102..fc91ce47a 100644 --- a/test/V4Quoter.t.sol +++ b/test/V4Quoter.t.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: UNLICENSED +//SPDX-License-Identifier: MIT pragma solidity ^0.8.20; diff --git a/test/mocks/MockBadSubscribers.sol b/test/mocks/MockBadSubscribers.sol index 0c506926d..d9c99cbbe 100644 --- a/test/mocks/MockBadSubscribers.sol +++ b/test/mocks/MockBadSubscribers.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ISubscriber} from "../../src/interfaces/ISubscriber.sol"; diff --git a/test/mocks/MockBaseActionsRouter.sol b/test/mocks/MockBaseActionsRouter.sol index b7630297e..53b92a24a 100644 --- a/test/mocks/MockBaseActionsRouter.sol +++ b/test/mocks/MockBaseActionsRouter.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; diff --git a/test/mocks/MockDeltaResolver.sol b/test/mocks/MockDeltaResolver.sol index 327f5e1c9..6de67fbb7 100644 --- a/test/mocks/MockDeltaResolver.sol +++ b/test/mocks/MockDeltaResolver.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; diff --git a/test/mocks/MockERC721Permit.sol b/test/mocks/MockERC721Permit.sol index bf3792084..0cd2a7789 100644 --- a/test/mocks/MockERC721Permit.sol +++ b/test/mocks/MockERC721Permit.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ERC721Permit_v4} from "../../src/base/ERC721Permit_v4.sol"; diff --git a/test/mocks/MockFeeOnTransfer.sol b/test/mocks/MockFeeOnTransfer.sol index 1150a777d..7488a5d87 100644 --- a/test/mocks/MockFeeOnTransfer.sol +++ b/test/mocks/MockFeeOnTransfer.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; diff --git a/test/mocks/MockMulticall.sol b/test/mocks/MockMulticall.sol index 38ddaa09e..1bae4d1f0 100644 --- a/test/mocks/MockMulticall.sol +++ b/test/mocks/MockMulticall.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "../../src/base/Multicall_v4.sol"; diff --git a/test/mocks/MockSafeCallback.sol b/test/mocks/MockSafeCallback.sol index 232fbe3c5..4739a1461 100644 --- a/test/mocks/MockSafeCallback.sol +++ b/test/mocks/MockSafeCallback.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; diff --git a/test/mocks/MockSubscriber.sol b/test/mocks/MockSubscriber.sol index 4da187b57..64a167abb 100644 --- a/test/mocks/MockSubscriber.sol +++ b/test/mocks/MockSubscriber.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ISubscriber} from "../../src/interfaces/ISubscriber.sol"; diff --git a/test/mocks/MockUnorderedNonce.sol b/test/mocks/MockUnorderedNonce.sol index 8f3cfc57a..338b8f2d2 100644 --- a/test/mocks/MockUnorderedNonce.sol +++ b/test/mocks/MockUnorderedNonce.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {UnorderedNonce} from "../../src/base/UnorderedNonce.sol"; diff --git a/test/mocks/ReentrantToken.sol b/test/mocks/ReentrantToken.sol index 63cc71ee3..522d76fba 100644 --- a/test/mocks/ReentrantToken.sol +++ b/test/mocks/ReentrantToken.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; diff --git a/test/shared/PositionConfig.sol b/test/shared/PositionConfig.sol index a2ab832bd..1d0a5a5ad 100644 --- a/test/shared/PositionConfig.sol +++ b/test/shared/PositionConfig.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; From 1ba502d0b7fdb3e9d97fac163b29bb72cd884243 Mon Sep 17 00:00:00 2001 From: diana Date: Tue, 26 Nov 2024 04:43:52 +0700 Subject: [PATCH 25/31] bytecode size test + optimizer runs = 1 (#401) * bytecode size test * update snapshots --- .forge-snapshots/BaseActionsRouter_mock10commands.snap | 2 +- .../Payments_swap_settleFromCaller_takeAllToMsgSender.snap | 2 +- ...ments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap | 2 +- .../Payments_swap_settleWithBalance_takeAllToMsgSender.snap | 2 +- ...ents_swap_settleWithBalance_takeAllToSpecifiedAddress.snap | 2 +- .forge-snapshots/PositionManager_burn_empty.snap | 2 +- .forge-snapshots/PositionManager_burn_empty_native.snap | 2 +- .../PositionManager_burn_nonEmpty_native_withClose.snap | 2 +- .../PositionManager_burn_nonEmpty_native_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap | 2 +- .../PositionManager_burn_nonEmpty_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_collect_native.snap | 2 +- .forge-snapshots/PositionManager_collect_sameRange.snap | 2 +- .forge-snapshots/PositionManager_collect_withClose.snap | 2 +- .forge-snapshots/PositionManager_collect_withTakePair.snap | 2 +- .../PositionManager_decreaseLiquidity_native.snap | 2 +- .../PositionManager_decreaseLiquidity_withClose.snap | 2 +- .../PositionManager_decreaseLiquidity_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_decrease_burnEmpty.snap | 2 +- .../PositionManager_decrease_burnEmpty_native.snap | 2 +- .../PositionManager_decrease_sameRange_allLiquidity.snap | 2 +- .forge-snapshots/PositionManager_decrease_take_take.snap | 2 +- .../PositionManager_increaseLiquidity_erc20_withClose.snap | 2 +- ...ositionManager_increaseLiquidity_erc20_withSettlePair.snap | 2 +- .../PositionManager_increaseLiquidity_native.snap | 2 +- ...sitionManager_increase_autocompoundExactUnclaimedFees.snap | 2 +- ...PositionManager_increase_autocompoundExcessFeesCredit.snap | 2 +- .../PositionManager_increase_autocompound_clearExcess.snap | 2 +- .forge-snapshots/PositionManager_mint_native.snap | 2 +- .../PositionManager_mint_nativeWithSweep_withClose.snap | 2 +- .../PositionManager_mint_nativeWithSweep_withSettlePair.snap | 2 +- .forge-snapshots/PositionManager_mint_onSameTickLower.snap | 2 +- .forge-snapshots/PositionManager_mint_onSameTickUpper.snap | 2 +- .forge-snapshots/PositionManager_mint_sameRange.snap | 2 +- .../PositionManager_mint_settleWithBalance_sweep.snap | 2 +- .../PositionManager_mint_warmedPool_differentRange.snap | 2 +- .forge-snapshots/PositionManager_mint_withClose.snap | 2 +- .forge-snapshots/PositionManager_mint_withSettlePair.snap | 2 +- .../PositionManager_multicall_initialize_mint.snap | 2 +- .forge-snapshots/PositionManager_permit.snap | 2 +- .forge-snapshots/PositionManager_permit_secondPosition.snap | 2 +- .forge-snapshots/PositionManager_permit_twice.snap | 2 +- .forge-snapshots/PositionManager_subscribe.snap | 2 +- .forge-snapshots/PositionManager_unsubscribe.snap | 2 +- .../Quoter_exactInputSingle_oneForZero_multiplePositions.snap | 2 +- .../Quoter_exactInputSingle_zeroForOne_multiplePositions.snap | 2 +- .forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap | 2 +- .forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap | 2 +- .../Quoter_quoteExactInput_oneHop_1TickLoaded.snap | 2 +- .../Quoter_quoteExactInput_oneHop_initializedAfter.snap | 2 +- .../Quoter_quoteExactInput_oneHop_startingInitialized.snap | 2 +- .forge-snapshots/Quoter_quoteExactInput_twoHops.snap | 2 +- .../Quoter_quoteExactOutput_oneHop_1TickLoaded.snap | 2 +- .../Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap | 2 +- .../Quoter_quoteExactOutput_oneHop_initializedAfter.snap | 2 +- .../Quoter_quoteExactOutput_oneHop_startingInitialized.snap | 2 +- .forge-snapshots/Quoter_quoteExactOutput_twoHops.snap | 2 +- .forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap | 2 +- .forge-snapshots/StateView_extsload_getFeeGrowthInside.snap | 2 +- .forge-snapshots/StateView_extsload_getLiquidity.snap | 2 +- .forge-snapshots/StateView_extsload_getPositionInfo.snap | 2 +- .forge-snapshots/StateView_extsload_getPositionLiquidity.snap | 2 +- .forge-snapshots/StateView_extsload_getSlot0.snap | 2 +- .forge-snapshots/StateView_extsload_getTickBitmap.snap | 2 +- .../StateView_extsload_getTickFeeGrowthOutside.snap | 2 +- .forge-snapshots/StateView_extsload_getTickInfo.snap | 2 +- .forge-snapshots/StateView_extsload_getTickLiquidity.snap | 2 +- .forge-snapshots/V4Router_Bytecode.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap | 2 +- .forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops.snap | 2 +- .forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops.snap | 2 +- .forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap | 2 +- .forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops.snap | 2 +- .forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap | 2 +- .forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap | 2 +- .forge-snapshots/V4Router_ExactOutputSingle.snap | 2 +- .../V4Router_ExactOutputSingle_nativeIn_sweepETH.snap | 2 +- .forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap | 2 +- .forge-snapshots/positionDescriptor bytecode size.snap | 2 +- .forge-snapshots/positionManager bytecode size.snap | 1 + foundry.toml | 2 +- test/position-managers/PositionManager.gas.t.sol | 4 ++++ 95 files changed, 98 insertions(+), 93 deletions(-) create mode 100644 .forge-snapshots/positionManager bytecode size.snap diff --git a/.forge-snapshots/BaseActionsRouter_mock10commands.snap b/.forge-snapshots/BaseActionsRouter_mock10commands.snap index 2f6f033f0..20e1c5f43 100644 --- a/.forge-snapshots/BaseActionsRouter_mock10commands.snap +++ b/.forge-snapshots/BaseActionsRouter_mock10commands.snap @@ -1 +1 @@ -60674 \ No newline at end of file +61332 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap index 7dd962cce..770caaf99 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap @@ -1 +1 @@ -129705 \ No newline at end of file +132997 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap index 361cd159f..3541eaf39 100644 --- a/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -131634 \ No newline at end of file +134973 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap index d55b574af..e05cffe7d 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap @@ -1 +1 @@ -123813 \ No newline at end of file +127102 \ No newline at end of file diff --git a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap index 63b1d146d..9166a87da 100644 --- a/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap +++ b/.forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap @@ -1 +1 @@ -123955 \ No newline at end of file +127212 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty.snap b/.forge-snapshots/PositionManager_burn_empty.snap index fcb819260..88081af81 100644 --- a/.forge-snapshots/PositionManager_burn_empty.snap +++ b/.forge-snapshots/PositionManager_burn_empty.snap @@ -1 +1 @@ -50845 \ No newline at end of file +51576 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty_native.snap b/.forge-snapshots/PositionManager_burn_empty_native.snap index fcb819260..88081af81 100644 --- a/.forge-snapshots/PositionManager_burn_empty_native.snap +++ b/.forge-snapshots/PositionManager_burn_empty_native.snap @@ -1 +1 @@ -50845 \ No newline at end of file +51576 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap index 9c88356c2..b8ad8f5e7 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap @@ -1 +1 @@ -126075 \ No newline at end of file +128316 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap index 0c610d439..5f7fe3b44 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap @@ -1 +1 @@ -125508 \ No newline at end of file +127696 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap index 02c6f5867..f821b49cb 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap @@ -1 +1 @@ -132935 \ No newline at end of file +135236 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap index 5d1c4b28d..46630b5d9 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap @@ -1 +1 @@ -132368 \ No newline at end of file +134615 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 300b94d21..df2c6fcf5 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -146517 \ No newline at end of file +148593 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index 9d8c45b66..d5f6bc6fb 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -155092 \ No newline at end of file +157242 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index 9d8c45b66..d5f6bc6fb 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -155092 \ No newline at end of file +157242 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index 3a772220d..a7d8032c6 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -154395 \ No newline at end of file +156478 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index 03b97f2fc..15e513a00 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -112159 \ No newline at end of file +114183 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index 48ff8dce8..b13b88cd8 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -119973 \ No newline at end of file +122577 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index c576e745f..627de811d 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -119276 \ No newline at end of file +121813 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index d997832ef..28983a330 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -135785 \ No newline at end of file +138195 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 178defb90..9f6d1c14e 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128925 \ No newline at end of file +131276 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index 5067e921f..397b72af6 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -132660 \ No newline at end of file +135240 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index 1704633b9..25671ee7f 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -120563 \ No newline at end of file +123191 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index e041bfa5e..e20cbceb5 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -158972 \ No newline at end of file +162441 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index 4218521c0..957d69b9f 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -157883 \ No newline at end of file +161305 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 173f0fd14..c00b69785 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -142236 \ No newline at end of file +145318 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index 65400e18f..6ed7545ea 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -136417 \ No newline at end of file +138032 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index c100c3a7a..e08e83c47 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -177561 \ No newline at end of file +180216 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index f780123ba..7d47367c2 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -148337 \ No newline at end of file +150804 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index fd7f97d42..ad9b48fff 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -366110 \ No newline at end of file +369623 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap index d51892743..6d4460fb9 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -1 +1 @@ -374684 \ No newline at end of file +378280 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap index 4bc4b7b3e..351997f8d 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -1 +1 @@ -373879 \ No newline at end of file +377364 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 1dbf1cac3..dcb8d5ae5 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317533 \ No newline at end of file +321205 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index 762eabe24..3a7c7c34a 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -318203 \ No newline at end of file +321875 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index 79c426297..7d8a26862 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243772 \ No newline at end of file +247444 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 1a107995a..4d62f1da1 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -419062 \ No newline at end of file +423280 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap index 51af85723..fcd47aaf3 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323564 \ No newline at end of file +327236 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withClose.snap b/.forge-snapshots/PositionManager_mint_withClose.snap index 3fa2f80f6..59610f85c 100644 --- a/.forge-snapshots/PositionManager_mint_withClose.snap +++ b/.forge-snapshots/PositionManager_mint_withClose.snap @@ -1 +1 @@ -420086 \ No newline at end of file +423986 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap index 530393d35..b3a6480c2 100644 --- a/.forge-snapshots/PositionManager_mint_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -1 +1 @@ -419115 \ No newline at end of file +422936 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap index db9aea251..19380f4f4 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -455916 \ No newline at end of file +460558 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_permit.snap b/.forge-snapshots/PositionManager_permit.snap index 227e327e4..53dd01e77 100644 --- a/.forge-snapshots/PositionManager_permit.snap +++ b/.forge-snapshots/PositionManager_permit.snap @@ -1 +1 @@ -79076 \ No newline at end of file +79259 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_permit_secondPosition.snap b/.forge-snapshots/PositionManager_permit_secondPosition.snap index 31ad61876..ac17c65c1 100644 --- a/.forge-snapshots/PositionManager_permit_secondPosition.snap +++ b/.forge-snapshots/PositionManager_permit_secondPosition.snap @@ -1 +1 @@ -61976 \ No newline at end of file +62159 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_permit_twice.snap b/.forge-snapshots/PositionManager_permit_twice.snap index 379f96111..532d2de91 100644 --- a/.forge-snapshots/PositionManager_permit_twice.snap +++ b/.forge-snapshots/PositionManager_permit_twice.snap @@ -1 +1 @@ -44852 \ No newline at end of file +45035 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_subscribe.snap b/.forge-snapshots/PositionManager_subscribe.snap index 74ca20b5e..f6081d8d7 100644 --- a/.forge-snapshots/PositionManager_subscribe.snap +++ b/.forge-snapshots/PositionManager_subscribe.snap @@ -1 +1 @@ -88124 \ No newline at end of file +88475 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_unsubscribe.snap b/.forge-snapshots/PositionManager_unsubscribe.snap index ef5e368eb..3651ba8a5 100644 --- a/.forge-snapshots/PositionManager_unsubscribe.snap +++ b/.forge-snapshots/PositionManager_unsubscribe.snap @@ -1 +1 @@ -63058 \ No newline at end of file +63253 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap b/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap index 7110b7f43..cb86556e8 100644 --- a/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap +++ b/.forge-snapshots/Quoter_exactInputSingle_oneForZero_multiplePositions.snap @@ -1 +1 @@ -144020 \ No newline at end of file +146317 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap b/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap index fc06cb487..8cf53dc80 100644 --- a/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap +++ b/.forge-snapshots/Quoter_exactInputSingle_zeroForOne_multiplePositions.snap @@ -1 +1 @@ -149287 \ No newline at end of file +151973 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap b/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap index 2963a4a55..2f2aa6ed8 100644 --- a/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap +++ b/.forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap @@ -1 +1 @@ -78196 \ No newline at end of file +80048 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap b/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap index d91412911..9606490a7 100644 --- a/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap +++ b/.forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap @@ -1 +1 @@ -82546 \ No newline at end of file +84626 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap b/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap index 8e02b3460..9aebeeca5 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_oneHop_1TickLoaded.snap @@ -1 +1 @@ -120406 \ No newline at end of file +122994 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap b/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap index 1c2000f84..1a3ae7138 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_oneHop_initializedAfter.snap @@ -1 +1 @@ -145504 \ No newline at end of file +147949 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap b/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap index 7cd92e9ff..1ce389ff1 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_oneHop_startingInitialized.snap @@ -1 +1 @@ -79438 \ No newline at end of file +81420 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap b/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap index 4753bccff..7fe1af46a 100644 --- a/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap +++ b/.forge-snapshots/Quoter_quoteExactInput_twoHops.snap @@ -1 +1 @@ -201071 \ No newline at end of file +205421 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap index 1fc92a414..6233611de 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_1TickLoaded.snap @@ -1 +1 @@ -119672 \ No newline at end of file +122296 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap index 958e4261f..ee524ce0d 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_2TicksLoaded.snap @@ -1 +1 @@ -149779 \ No newline at end of file +152648 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap index 764795de4..f965907ac 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_initializedAfter.snap @@ -1 +1 @@ -119740 \ No newline at end of file +122364 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap index a2bce2b22..f813bc4bc 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_oneHop_startingInitialized.snap @@ -1 +1 @@ -96472 \ No newline at end of file +98875 \ No newline at end of file diff --git a/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap b/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap index 40af9508f..584ea1427 100644 --- a/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap +++ b/.forge-snapshots/Quoter_quoteExactOutput_twoHops.snap @@ -1 +1 @@ -200486 \ No newline at end of file +204897 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap b/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap index 920727d2e..a9e72c33a 100644 --- a/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap +++ b/.forge-snapshots/StateView_extsload_getFeeGrowthGlobals.snap @@ -1 +1 @@ -2256 \ No newline at end of file +2367 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap b/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap index 6df672447..b1b49287a 100644 --- a/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap +++ b/.forge-snapshots/StateView_extsload_getFeeGrowthInside.snap @@ -1 +1 @@ -7994 \ No newline at end of file +8444 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getLiquidity.snap b/.forge-snapshots/StateView_extsload_getLiquidity.snap index a900d0b24..ab57eb1e7 100644 --- a/.forge-snapshots/StateView_extsload_getLiquidity.snap +++ b/.forge-snapshots/StateView_extsload_getLiquidity.snap @@ -1 +1 @@ -1399 \ No newline at end of file +1480 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getPositionInfo.snap b/.forge-snapshots/StateView_extsload_getPositionInfo.snap index c173e591f..0a1ca398f 100644 --- a/.forge-snapshots/StateView_extsload_getPositionInfo.snap +++ b/.forge-snapshots/StateView_extsload_getPositionInfo.snap @@ -1 +1 @@ -2826 \ No newline at end of file +2973 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getPositionLiquidity.snap b/.forge-snapshots/StateView_extsload_getPositionLiquidity.snap index 7f3589da4..8d6430831 100644 --- a/.forge-snapshots/StateView_extsload_getPositionLiquidity.snap +++ b/.forge-snapshots/StateView_extsload_getPositionLiquidity.snap @@ -1 +1 @@ -1651 \ No newline at end of file +1750 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getSlot0.snap b/.forge-snapshots/StateView_extsload_getSlot0.snap index 585cf67a0..466fe4026 100644 --- a/.forge-snapshots/StateView_extsload_getSlot0.snap +++ b/.forge-snapshots/StateView_extsload_getSlot0.snap @@ -1 +1 @@ -1446 \ No newline at end of file +1548 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getTickBitmap.snap b/.forge-snapshots/StateView_extsload_getTickBitmap.snap index 05fd8282c..0e8ebf59f 100644 --- a/.forge-snapshots/StateView_extsload_getTickBitmap.snap +++ b/.forge-snapshots/StateView_extsload_getTickBitmap.snap @@ -1 +1 @@ -1392 \ No newline at end of file +1476 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap b/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap index 7a03b74c0..7c43ea017 100644 --- a/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap +++ b/.forge-snapshots/StateView_extsload_getTickFeeGrowthOutside.snap @@ -1 +1 @@ -2543 \ No newline at end of file +2672 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getTickInfo.snap b/.forge-snapshots/StateView_extsload_getTickInfo.snap index f538595cb..3582118cc 100644 --- a/.forge-snapshots/StateView_extsload_getTickInfo.snap +++ b/.forge-snapshots/StateView_extsload_getTickInfo.snap @@ -1 +1 @@ -2758 \ No newline at end of file +2896 \ No newline at end of file diff --git a/.forge-snapshots/StateView_extsload_getTickLiquidity.snap b/.forge-snapshots/StateView_extsload_getTickLiquidity.snap index 44e788259..0504b068d 100644 --- a/.forge-snapshots/StateView_extsload_getTickLiquidity.snap +++ b/.forge-snapshots/StateView_extsload_getTickLiquidity.snap @@ -1 +1 @@ -1646 \ No newline at end of file +1748 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_Bytecode.snap b/.forge-snapshots/V4Router_Bytecode.snap index 2936eb373..ec718f71f 100644 --- a/.forge-snapshots/V4Router_Bytecode.snap +++ b/.forge-snapshots/V4Router_Bytecode.snap @@ -1 +1 @@ -7029 \ No newline at end of file +5137 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index e867cdb13..56a7e65e8 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -118724 \ No newline at end of file +121819 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index 7e9c5fc11..cbfeb1a9c 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -117700 \ No newline at end of file +120826 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index a8bb1df30..6bf2eef7d 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -126515 \ No newline at end of file +129715 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index a62dfebff..891422a70 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -132179 \ No newline at end of file +135623 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index 679817245..a7bc469ae 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -186913 \ No newline at end of file +191979 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index d38ed3054..ef0bcd5fe 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -173458 \ No newline at end of file +178175 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index 1261e3744..89acd064f 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -241697 \ No newline at end of file +248385 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index b37ad64b7..a93abe955 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -228242 \ No newline at end of file +234581 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index e3f4d02a3..24fe6dec9 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -131187 \ No newline at end of file +134546 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index b6786b89a..7f06d7f09 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -117732 \ No newline at end of file +120742 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index 99644e8ca..4e26e8532 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -116676 \ No newline at end of file +119714 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap index 1595951f2..1fdaa9cd4 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -124982 \ No newline at end of file +128078 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index d47ed0cd2..5680b0271 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -118773 \ No newline at end of file +121895 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index cf325d8b8..85542b79f 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -127588 \ No newline at end of file +130784 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index 0a1f73c46..a883e8809 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -131460 \ No newline at end of file +134905 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index f175de3fd..eb9099cb8 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -185251 \ No newline at end of file +190319 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index e1584172a..c2de3e9b9 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -178773 \ No newline at end of file +183492 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index 04caed975..ddf200aa9 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -239120 \ No newline at end of file +245811 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index 3d524adb1..583269aea 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -232642 \ No newline at end of file +238984 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 4bb56d44c..0ff3d5c82 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -218697 \ No newline at end of file +224567 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index c49961035..d44e2734a 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -130453 \ No newline at end of file +133809 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap index d35479f22..fc1ac5689 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -123975 \ No newline at end of file +126982 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index a0a386d2c..dacad49f6 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -117840 \ No newline at end of file +120876 \ No newline at end of file diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 29912b341..616fe5514 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -31806 \ No newline at end of file +24177 \ No newline at end of file diff --git a/.forge-snapshots/positionManager bytecode size.snap b/.forge-snapshots/positionManager bytecode size.snap new file mode 100644 index 000000000..6f29cf461 --- /dev/null +++ b/.forge-snapshots/positionManager bytecode size.snap @@ -0,0 +1 @@ +19068 \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index c685a490e..30dff3ef4 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,7 +1,7 @@ [profile.default] out = 'foundry-out' solc_version = '0.8.26' -optimizer_runs = 44444444 +optimizer_runs = 1 via_ir = true ffi = true fs_permissions = [{ access = "read-write", path = ".forge-snapshots/"}] diff --git a/test/position-managers/PositionManager.gas.t.sol b/test/position-managers/PositionManager.gas.t.sol index cf0777483..bf27604f9 100644 --- a/test/position-managers/PositionManager.gas.t.sol +++ b/test/position-managers/PositionManager.gas.t.sol @@ -75,6 +75,10 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { sub = new MockSubscriber(lpm); } + function test_bytecodeSize_positionManager() public { + snapSize("positionManager bytecode size", address(lpm)); + } + function test_gas_mint_withClose() public { Plan memory planner = Planner.init().add( Actions.MINT_POSITION, From c3d3cad414f4ad78f2de515addcb41aed3bfdcd3 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:21:16 +0000 Subject: [PATCH 26/31] remove stale transfer error (#404) --- .forge-snapshots/positionDescriptor bytecode size.snap | 2 +- src/interfaces/INotifier.sol | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 616fe5514..4cdd5179a 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -24177 \ No newline at end of file +24108 \ No newline at end of file diff --git a/src/interfaces/INotifier.sol b/src/interfaces/INotifier.sol index 13ded49f3..a415e27b6 100644 --- a/src/interfaces/INotifier.sol +++ b/src/interfaces/INotifier.sol @@ -17,8 +17,6 @@ interface INotifier { error ModifyLiquidityNotificationReverted(address subscriber, bytes reason); /// @notice Wraps the revert message of the subscriber contract on a reverting burn notification error BurnNotificationReverted(address subscriber, bytes reason); - /// @notice Wraps the revert message of the subscriber contract on a reverting transfer notification - error TransferNotificationReverted(address subscriber, bytes reason); /// @notice Thrown when a tokenId already has a subscriber error AlreadySubscribed(uint256 tokenId, address subscriber); From c71e4b9d12cad2944d3547720f712c8eaa462c4a Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:05:20 +0000 Subject: [PATCH 27/31] use address for subscriber (#405) * use address for subscriber * fix bytecode snap --- .../positionDescriptor bytecode size.snap | 2 +- src/base/Notifier.sol | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 4cdd5179a..616fe5514 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -24108 \ No newline at end of file +24177 \ No newline at end of file diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol index 3412ea645..7e755c660 100644 --- a/src/base/Notifier.sol +++ b/src/base/Notifier.sol @@ -96,32 +96,28 @@ abstract contract Notifier is INotifier { uint256 liquidity, BalanceDelta feesAccrued ) internal { - ISubscriber _subscriber = subscriber[tokenId]; + address _subscriber = address(subscriber[tokenId]); // remove the subscriber delete subscriber[tokenId]; - bool success = _call( - address(_subscriber), abi.encodeCall(ISubscriber.notifyBurn, (tokenId, owner, info, liquidity, feesAccrued)) - ); + bool success = + _call(_subscriber, abi.encodeCall(ISubscriber.notifyBurn, (tokenId, owner, info, liquidity, feesAccrued))); if (!success) { - address(_subscriber).bubbleUpAndRevertWith( - ISubscriber.notifyBurn.selector, BurnNotificationReverted.selector - ); + _subscriber.bubbleUpAndRevertWith(ISubscriber.notifyBurn.selector, BurnNotificationReverted.selector); } } function _notifyModifyLiquidity(uint256 tokenId, int256 liquidityChange, BalanceDelta feesAccrued) internal { - ISubscriber _subscriber = subscriber[tokenId]; + address _subscriber = address(subscriber[tokenId]); bool success = _call( - address(_subscriber), - abi.encodeCall(ISubscriber.notifyModifyLiquidity, (tokenId, liquidityChange, feesAccrued)) + _subscriber, abi.encodeCall(ISubscriber.notifyModifyLiquidity, (tokenId, liquidityChange, feesAccrued)) ); if (!success) { - address(_subscriber).bubbleUpAndRevertWith( + _subscriber.bubbleUpAndRevertWith( ISubscriber.notifyModifyLiquidity.selector, ModifyLiquidityNotificationReverted.selector ); } From 1d92e95d7c187ddd639176bdc6380ff4963b65a6 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:03:59 +0000 Subject: [PATCH 28/31] fix: move variable (#407) --- src/PositionManager.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PositionManager.sol b/src/PositionManager.sol index f5840999a..f9dbd2e38 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -420,8 +420,8 @@ contract PositionManager is // Can only call modify if there is non zero liquidity. BalanceDelta feesAccrued; - BalanceDelta liquidityDelta; if (liquidity > 0) { + BalanceDelta liquidityDelta; // do not use _modifyLiquidity as we do not need to notify on modification for burns. (liquidityDelta, feesAccrued) = poolManager.modifyLiquidity( poolKey, From d6b0bd059092b5492a52e2ecc472e349cfd9c7c0 Mon Sep 17 00:00:00 2001 From: diana Date: Mon, 2 Dec 2024 14:25:18 -0500 Subject: [PATCH 29/31] unnecessary line of code (#408) * unnecessary line of code * forge clean --- .forge-snapshots/positionDescriptor bytecode size.snap | 2 +- src/PositionDescriptor.sol | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.forge-snapshots/positionDescriptor bytecode size.snap b/.forge-snapshots/positionDescriptor bytecode size.snap index 616fe5514..60d759c40 100644 --- a/.forge-snapshots/positionDescriptor bytecode size.snap +++ b/.forge-snapshots/positionDescriptor bytecode size.snap @@ -1 +1 @@ -24177 \ No newline at end of file +24110 \ No newline at end of file diff --git a/src/PositionDescriptor.sol b/src/PositionDescriptor.sol index 34910d538..021cbd5e5 100644 --- a/src/PositionDescriptor.sol +++ b/src/PositionDescriptor.sol @@ -118,8 +118,6 @@ contract PositionDescriptor is IPositionDescriptor { return CurrencyRatioSortOrder.DENOMINATOR_MORE; } else if (currency == WBTC) { return CurrencyRatioSortOrder.DENOMINATOR_MOST; - } else { - return 0; } } return 0; From 05ede298e04a44a4dfa8beb04d4b3d121b127e68 Mon Sep 17 00:00:00 2001 From: Alice <34962750+hensha256@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:54:42 +0000 Subject: [PATCH 30/31] remove unnecessary length check (#406) * remove unnecessary length check * comments for clarity --------- Co-authored-by: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> --- .forge-snapshots/PositionManager_collect_native.snap | 2 +- .forge-snapshots/PositionManager_collect_sameRange.snap | 2 +- .forge-snapshots/PositionManager_collect_withClose.snap | 2 +- .../PositionManager_collect_withTakePair.snap | 2 +- .../PositionManager_decreaseLiquidity_native.snap | 2 +- .../PositionManager_decreaseLiquidity_withClose.snap | 2 +- .../PositionManager_decreaseLiquidity_withTakePair.snap | 2 +- .forge-snapshots/PositionManager_decrease_burnEmpty.snap | 2 +- .../PositionManager_decrease_burnEmpty_native.snap | 2 +- .../PositionManager_decrease_sameRange_allLiquidity.snap | 2 +- .forge-snapshots/PositionManager_decrease_take_take.snap | 2 +- ...ositionManager_increaseLiquidity_erc20_withClose.snap | 2 +- ...onManager_increaseLiquidity_erc20_withSettlePair.snap | 2 +- .../PositionManager_increaseLiquidity_native.snap | 2 +- ...nManager_increase_autocompoundExactUnclaimedFees.snap | 2 +- ...ionManager_increase_autocompoundExcessFeesCredit.snap | 2 +- ...ositionManager_increase_autocompound_clearExcess.snap | 2 +- .forge-snapshots/positionManager bytecode size.snap | 2 +- src/libraries/CalldataDecoder.sol | 9 +++++---- 19 files changed, 23 insertions(+), 22 deletions(-) diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index df2c6fcf5..86f965291 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -148593 \ No newline at end of file +148571 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index d5f6bc6fb..e2b8005b9 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -157242 \ No newline at end of file +157220 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withClose.snap b/.forge-snapshots/PositionManager_collect_withClose.snap index d5f6bc6fb..e2b8005b9 100644 --- a/.forge-snapshots/PositionManager_collect_withClose.snap +++ b/.forge-snapshots/PositionManager_collect_withClose.snap @@ -1 +1 @@ -157242 \ No newline at end of file +157220 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_withTakePair.snap b/.forge-snapshots/PositionManager_collect_withTakePair.snap index a7d8032c6..ccb34392b 100644 --- a/.forge-snapshots/PositionManager_collect_withTakePair.snap +++ b/.forge-snapshots/PositionManager_collect_withTakePair.snap @@ -1 +1 @@ -156478 \ No newline at end of file +156456 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index 15e513a00..c2b5120a1 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -114183 \ No newline at end of file +114165 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap index b13b88cd8..bdea68d3c 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap @@ -1 +1 @@ -122577 \ No newline at end of file +122555 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap index 627de811d..8c20e971e 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap @@ -1 +1 @@ -121813 \ No newline at end of file +121791 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 28983a330..dbd7a9ac1 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -138195 \ No newline at end of file +138177 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap index 9f6d1c14e..4622f7b48 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -131276 \ No newline at end of file +131258 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap index 397b72af6..105b30011 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -135240 \ No newline at end of file +135218 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_take_take.snap b/.forge-snapshots/PositionManager_decrease_take_take.snap index 25671ee7f..a34b498cd 100644 --- a/.forge-snapshots/PositionManager_decrease_take_take.snap +++ b/.forge-snapshots/PositionManager_decrease_take_take.snap @@ -1 +1 @@ -123191 \ No newline at end of file +123169 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap index e20cbceb5..0c144b4d2 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap @@ -1 +1 @@ -162441 \ No newline at end of file +162419 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap index 957d69b9f..5b88c6213 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -1 +1 @@ -161305 \ No newline at end of file +161283 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index c00b69785..dd90e5a55 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -145318 \ No newline at end of file +145296 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index 6ed7545ea..6312e8ddf 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -138032 \ No newline at end of file +138010 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index e08e83c47..cf908d5cf 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -180216 \ No newline at end of file +180194 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap index 7d47367c2..c9779d027 100644 --- a/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap +++ b/.forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap @@ -1 +1 @@ -150804 \ No newline at end of file +150782 \ No newline at end of file diff --git a/.forge-snapshots/positionManager bytecode size.snap b/.forge-snapshots/positionManager bytecode size.snap index 6f29cf461..404029b94 100644 --- a/.forge-snapshots/positionManager bytecode size.snap +++ b/.forge-snapshots/positionManager bytecode size.snap @@ -1 +1 @@ -19068 \ No newline at end of file +19060 \ No newline at end of file diff --git a/src/libraries/CalldataDecoder.sol b/src/libraries/CalldataDecoder.sol index 3c7a800c2..496852bdc 100644 --- a/src/libraries/CalldataDecoder.sol +++ b/src/libraries/CalldataDecoder.sol @@ -76,11 +76,8 @@ library CalldataDecoder { pure returns (uint256 tokenId, uint256 liquidity, uint128 amount0, uint128 amount1, bytes calldata hookData) { + // no length check performed, as there is a length check in `toBytes` assembly ("memory-safe") { - if lt(params.length, 0x80) { - mstore(0, SLICE_ERROR_SELECTOR) - revert(0x1c, 4) - } tokenId := calldataload(params.offset) liquidity := calldataload(add(params.offset, 0x20)) amount0 := calldataload(add(params.offset, 0x40)) @@ -96,6 +93,7 @@ library CalldataDecoder { pure returns (uint256 tokenId, uint128 amount0Max, uint128 amount1Max, bytes calldata hookData) { + // no length check performed, as there is a length check in `toBytes` assembly ("memory-safe") { tokenId := calldataload(params.offset) amount0Max := calldataload(add(params.offset, 0x20)) @@ -120,6 +118,7 @@ library CalldataDecoder { bytes calldata hookData ) { + // no length check performed, as there is a length check in `toBytes` assembly ("memory-safe") { poolKey := params.offset tickLower := calldataload(add(params.offset, 0xa0)) @@ -146,6 +145,7 @@ library CalldataDecoder { bytes calldata hookData ) { + // no length check performed, as there is a length check in `toBytes` assembly ("memory-safe") { poolKey := params.offset tickLower := calldataload(add(params.offset, 0xa0)) @@ -164,6 +164,7 @@ library CalldataDecoder { pure returns (uint256 tokenId, uint128 amount0Min, uint128 amount1Min, bytes calldata hookData) { + // no length check performed, as there is a length check in `toBytes` assembly ("memory-safe") { tokenId := calldataload(params.offset) amount0Min := calldataload(add(params.offset, 0x20)) From 24ae83fecbaef75bc53e73645199c09d88e5d76f Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:32:28 +0000 Subject: [PATCH 31/31] actions clarification natspec (#409) * natspec * Update src/libraries/Actions.sol Co-authored-by: Alice <34962750+hensha256@users.noreply.github.com> --------- Co-authored-by: Alice <34962750+hensha256@users.noreply.github.com> --- src/libraries/Actions.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/Actions.sol b/src/libraries/Actions.sol index ab34c9c2d..f87038476 100644 --- a/src/libraries/Actions.sol +++ b/src/libraries/Actions.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; /// @notice Library to define different pool actions. /// @dev These are suggested common commands, however additional commands should be defined as required +/// Some of these actions are not supported in the Router contracts or Position Manager contracts, but are left as they may be helpful commands for other peripheral contracts. library Actions { // pool actions // liquidity actions @@ -18,7 +19,9 @@ library Actions { uint256 constant SWAP_EXACT_IN = 0x07; uint256 constant SWAP_EXACT_OUT_SINGLE = 0x08; uint256 constant SWAP_EXACT_OUT = 0x09; + // donate + // note this is not supported in the position manager or router uint256 constant DONATE = 0x0a; // closing deltas on the pool manager @@ -40,6 +43,7 @@ library Actions { uint256 constant UNWRAP = 0x16; // minting/burning 6909s to close deltas + // note this is not supported in the position manager or router uint256 constant MINT_6909 = 0x17; uint256 constant BURN_6909 = 0x18; }