From e51e16b09c240be704d3ee17dfcdd16802dcd197 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Wed, 31 Jul 2024 18:41:14 -0400 Subject: [PATCH] compiling --- .../BaseActionsRouter_mock10commands.snap | 2 +- .../PositionManager_burn_empty.snap | 2 +- .../PositionManager_burn_empty_native.snap | 2 +- .../PositionManager_burn_nonEmpty.snap | 2 +- .../PositionManager_burn_nonEmpty_native.snap | 2 +- .forge-snapshots/PositionManager_collect.snap | 2 +- .../PositionManager_collect_native.snap | 2 +- .../PositionManager_collect_sameRange.snap | 2 +- .../PositionManager_decreaseLiquidity.snap | 2 +- ...itionManager_decreaseLiquidity_native.snap | 2 +- .../PositionManager_decrease_burnEmpty.snap | 2 +- ...tionManager_decrease_burnEmpty_native.snap | 2 +- ...nager_decrease_sameRange_allLiquidity.snap | 2 +- ...sitionManager_increaseLiquidity_erc20.snap | 2 +- ...itionManager_increaseLiquidity_native.snap | 2 +- ...crease_autocompoundExactUnclaimedFees.snap | 2 +- ...increase_autocompoundExcessFeesCredit.snap | 2 +- .forge-snapshots/PositionManager_mint.snap | 2 +- .../PositionManager_mint_native.snap | 2 +- .../PositionManager_mint_nativeWithSweep.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 +- ...tionManager_multicall_initialize_mint.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/PositionManager.sol | 66 +++++++++++++------ src/base/Notifier.sol | 53 +++++++++++++++ src/base/StakingNotifier.sol | 49 -------------- src/interfaces/IPositionManager.sol | 4 +- src/interfaces/IStakingSubscriber.sol | 12 ---- src/interfaces/ISubscriber.sol | 12 ++++ src/libraries/PositionConfig.sol | 50 +++++++++++++- test/libraries/PositionConfig.t.sol | 2 + test/mocks/StakingSubscriber.sol | 22 +++---- 58 files changed, 223 insertions(+), 145 deletions(-) create mode 100644 src/base/Notifier.sol delete mode 100644 src/base/StakingNotifier.sol delete mode 100644 src/interfaces/IStakingSubscriber.sol create mode 100644 src/interfaces/ISubscriber.sol diff --git a/.forge-snapshots/BaseActionsRouter_mock10commands.snap b/.forge-snapshots/BaseActionsRouter_mock10commands.snap index 9bb199962..283c59f21 100644 --- a/.forge-snapshots/BaseActionsRouter_mock10commands.snap +++ b/.forge-snapshots/BaseActionsRouter_mock10commands.snap @@ -1 +1 @@ -62960 \ No newline at end of file +34844 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_empty.snap b/.forge-snapshots/PositionManager_burn_empty.snap index 637bc1f07..263b6f21f 100644 --- a/.forge-snapshots/PositionManager_burn_empty.snap +++ b/.forge-snapshots/PositionManager_burn_empty.snap @@ -1 +1 @@ -46864 \ No newline at end of file +14995 \ 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 122463b6a..263b6f21f 100644 --- a/.forge-snapshots/PositionManager_burn_empty_native.snap +++ b/.forge-snapshots/PositionManager_burn_empty_native.snap @@ -1 +1 @@ -46681 \ No newline at end of file +14995 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty.snap b/.forge-snapshots/PositionManager_burn_nonEmpty.snap index 78556cf92..a172fbdbf 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty.snap @@ -1 +1 @@ -132224 \ No newline at end of file +48191 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_burn_nonEmpty_native.snap b/.forge-snapshots/PositionManager_burn_nonEmpty_native.snap index 6329ffb5a..0a65de8f5 100644 --- a/.forge-snapshots/PositionManager_burn_nonEmpty_native.snap +++ b/.forge-snapshots/PositionManager_burn_nonEmpty_native.snap @@ -1 +1 @@ -125145 \ No newline at end of file +51899 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect.snap b/.forge-snapshots/PositionManager_collect.snap index 0bcdd3dc0..68284cda1 100644 --- a/.forge-snapshots/PositionManager_collect.snap +++ b/.forge-snapshots/PositionManager_collect.snap @@ -1 +1 @@ -152889 \ No newline at end of file +72860 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_native.snap b/.forge-snapshots/PositionManager_collect_native.snap index 3fca37bf6..c18dbcb6d 100644 --- a/.forge-snapshots/PositionManager_collect_native.snap +++ b/.forge-snapshots/PositionManager_collect_native.snap @@ -1 +1 @@ -144041 \ No newline at end of file +76568 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_collect_sameRange.snap b/.forge-snapshots/PositionManager_collect_sameRange.snap index 0bcdd3dc0..68284cda1 100644 --- a/.forge-snapshots/PositionManager_collect_sameRange.snap +++ b/.forge-snapshots/PositionManager_collect_sameRange.snap @@ -1 +1 @@ -152889 \ No newline at end of file +72860 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity.snap b/.forge-snapshots/PositionManager_decreaseLiquidity.snap index 07620f5d5..a10b643c3 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity.snap @@ -1 +1 @@ -118432 \ No newline at end of file +40307 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap index bf0f5aaec..b60788553 100644 --- a/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_decreaseLiquidity_native.snap @@ -1 +1 @@ -110708 \ No newline at end of file +44015 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap index 7feacdc19..b52ba08b3 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty.snap @@ -1 +1 @@ -136102 \ No newline at end of file +50159 \ 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 ad7d951c6..32612df1a 100644 --- a/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap +++ b/.forge-snapshots/PositionManager_decrease_burnEmpty_native.snap @@ -1 +1 @@ -128841 \ No newline at end of file +53867 \ 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 6772976dc..d65421090 100644 --- a/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap +++ b/.forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap @@ -1 +1 @@ -131148 \ No newline at end of file +38623 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20.snap index 0647cc747..19d574153 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_erc20.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20.snap @@ -1 +1 @@ -154374 \ No newline at end of file +48545 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap index 229e81480..f2e3f1f27 100644 --- a/.forge-snapshots/PositionManager_increaseLiquidity_native.snap +++ b/.forge-snapshots/PositionManager_increaseLiquidity_native.snap @@ -1 +1 @@ -136174 \ No newline at end of file +46901 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap index d6b384f93..98a6716b6 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap @@ -1 +1 @@ -137095 \ No newline at end of file +65984 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap index 860f27944..0ae9ad4ea 100644 --- a/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap +++ b/.forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap @@ -1 +1 @@ -173251 \ No newline at end of file +77916 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint.snap b/.forge-snapshots/PositionManager_mint.snap index 2df70fcd8..11d436f04 100644 --- a/.forge-snapshots/PositionManager_mint.snap +++ b/.forge-snapshots/PositionManager_mint.snap @@ -1 +1 @@ -374409 \ No newline at end of file +344624 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_native.snap b/.forge-snapshots/PositionManager_mint_native.snap index 4322f052d..bbda2822e 100644 --- a/.forge-snapshots/PositionManager_mint_native.snap +++ b/.forge-snapshots/PositionManager_mint_native.snap @@ -1 +1 @@ -339109 \ No newline at end of file +309780 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep.snap index c70b99e30..3f6d4cc42 100644 --- a/.forge-snapshots/PositionManager_mint_nativeWithSweep.snap +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep.snap @@ -1 +1 @@ -347739 \ No newline at end of file +317494 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap index 839fcaa41..081c437cf 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickLower.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickLower.snap @@ -1 +1 @@ -317091 \ No newline at end of file +255406 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap index 2a0691d0a..51eeba6bc 100644 --- a/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap +++ b/.forge-snapshots/PositionManager_mint_onSameTickUpper.snap @@ -1 +1 @@ -317733 \ No newline at end of file +260048 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_sameRange.snap b/.forge-snapshots/PositionManager_mint_sameRange.snap index bb99e63f9..4f78a103e 100644 --- a/.forge-snapshots/PositionManager_mint_sameRange.snap +++ b/.forge-snapshots/PositionManager_mint_sameRange.snap @@ -1 +1 @@ -243315 \ No newline at end of file +160730 \ 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 d6415c90c..4259a02ea 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -372583 \ No newline at end of file +325892 \ 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 0893f4944..a4d7d5297 100644 --- a/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap +++ b/.forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap @@ -1 +1 @@ -323109 \ No newline at end of file +260624 \ 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 f82d06fe0..2b1104900 100644 --- a/.forge-snapshots/PositionManager_multicall_initialize_mint.snap +++ b/.forge-snapshots/PositionManager_multicall_initialize_mint.snap @@ -1 +1 @@ -418855 \ No newline at end of file +386334 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap index 24c9822b3..3553f17aa 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap @@ -1 +1 @@ -121090 \ No newline at end of file +94942 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap index 24ccfd9d2..e22d08e23 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap @@ -1 +1 @@ -120257 \ No newline at end of file +94109 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap index f891c6dd6..25f0e2eab 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap @@ -1 +1 @@ -129129 \ No newline at end of file +102501 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap index f6834076b..75a5babf4 100644 --- a/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap @@ -1 +1 @@ -135959 \ No newline at end of file +109331 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops.snap b/.forge-snapshots/V4Router_ExactIn2Hops.snap index e70fa1364..823baf73a 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops.snap @@ -1 +1 @@ -187311 \ No newline at end of file +159499 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap index 69edacf10..03058cc19 100644 --- a/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap @@ -1 +1 @@ -179274 \ No newline at end of file +151942 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops.snap b/.forge-snapshots/V4Router_ExactIn3Hops.snap index 6de237e2a..42c2568e5 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops.snap @@ -1 +1 @@ -238692 \ No newline at end of file +209672 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap index 33ade7d18..01528178f 100644 --- a/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap @@ -1 +1 @@ -230679 \ No newline at end of file +202115 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle.snap b/.forge-snapshots/V4Router_ExactInputSingle.snap index 2e3423fd5..3c20382f4 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle.snap @@ -1 +1 @@ -134717 \ No newline at end of file +108241 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap index b7011dc25..dd2e65892 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap @@ -1 +1 @@ -119848 \ No newline at end of file +93852 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap index cdff580ea..317d7ecc3 100644 --- a/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap @@ -1 +1 @@ -118993 \ No newline at end of file +93009 \ 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 77e59bce3..99a3bf61c 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap @@ -1 +1 @@ -126893 \ No newline at end of file +100553 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap index f276517ca..49e23222a 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap @@ -1 +1 @@ -121098 \ No newline at end of file +94758 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap index efacec379..e5f2e3a72 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap @@ -1 +1 @@ -129970 \ No newline at end of file +103150 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap index bd7e8a652..30d7c602a 100644 --- a/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap +++ b/.forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap @@ -1 +1 @@ -134771 \ No newline at end of file +107951 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops.snap b/.forge-snapshots/V4Router_ExactOut2Hops.snap index be849ee54..4c5ba57f6 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops.snap @@ -1 +1 @@ -186732 \ No newline at end of file +158728 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap index 1ae42da18..7327ea8f2 100644 --- a/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap @@ -1 +1 @@ -183655 \ No newline at end of file +156131 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops.snap b/.forge-snapshots/V4Router_ExactOut3Hops.snap index 9883a9323..f6d9014d3 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops.snap @@ -1 +1 @@ -238737 \ No newline at end of file +209525 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap index f55c5a60d..e45d9ab27 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap @@ -1 +1 @@ -235684 \ No newline at end of file +206928 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap index 4301df865..09411ad16 100644 --- a/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap @@ -1 +1 @@ -229889 \ No newline at end of file +201133 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle.snap b/.forge-snapshots/V4Router_ExactOutputSingle.snap index ef03db550..558ce33b8 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle.snap @@ -1 +1 @@ -133251 \ No newline at end of file +106775 \ 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 d31682704..4716df79d 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap @@ -1 +1 @@ -125373 \ No newline at end of file +99377 \ No newline at end of file diff --git a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap index 78729eea9..87b7c22f8 100644 --- a/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap +++ b/.forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap @@ -1 +1 @@ -119636 \ No newline at end of file +93652 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index 3b97a565c..01411104e 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -24,7 +24,7 @@ import {DeltaResolver} from "./base/DeltaResolver.sol"; import {PositionConfig, PositionConfigLibrary} from "./libraries/PositionConfig.sol"; import {BaseActionsRouter} from "./base/BaseActionsRouter.sol"; import {Actions} from "./libraries/Actions.sol"; -import {StakingNotifier, StakingConfig} from "./base/StakingNotifier.sol"; +import {Notifier} from "./base/Notifier.sol"; import {CalldataDecoder} from "./libraries/CalldataDecoder.sol"; contract PositionManager is @@ -35,12 +35,12 @@ contract PositionManager is DeltaResolver, ReentrancyLock, BaseActionsRouter, - StakingNotifier + Notifier { using SafeTransferLib for *; using CurrencyLibrary for Currency; using PoolIdLibrary for PoolKey; - using PositionConfigLibrary for PositionConfig; + using PositionConfigLibrary for *; using StateLibrary for IPoolManager; using TransientStateLibrary for IPoolManager; using SafeCast for uint256; @@ -50,13 +50,13 @@ contract PositionManager is uint256 public nextTokenId = 1; /// @inheritdoc IPositionManager - mapping(uint256 tokenId => bytes32 configId) public positionConfigs; + mapping(uint256 tokenId => bytes32 config) public positionConfigs; IAllowanceTransfer public immutable permit2; - constructor(IPoolManager _poolManager, IAllowanceTransfer _permit2, uint256 _stakingGasLimit) + constructor(IPoolManager _poolManager, IAllowanceTransfer _permit2, uint256 _subscriberGasLimit) BaseActionsRouter(_poolManager) - StakingNotifier(_stakingGasLimit) + Notifier(_subscriberGasLimit) ERC721Permit("Uniswap V4 Positions NFT", "UNI-V4-POSM", "1") { permit2 = _permit2; @@ -67,6 +67,16 @@ contract PositionManager is _; } + modifier onlyIfApproved(address sender, uint256 tokenId) { + if (!_isApprovedOrOwner(sender, tokenId)) revert NotApproved(sender); + _; + } + + modifier onlyValidConfig(uint256 tokenId, PositionConfig calldata config) { + if (positionConfigs.getConfigId(tokenId) != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); + _; + } + /// @param unlockData is an encoding of actions, params, and currencies /// @param deadline is the timestamp at which the unlockData will no longer be valid function modifyLiquidities(bytes calldata unlockData, uint256 deadline) @@ -78,6 +88,25 @@ contract PositionManager is _executeActions(unlockData); } + function subscribe(uint256 tokenId, PositionConfig calldata config, address subscriber) + external + onlyIfApproved(msg.sender, tokenId) + onlyValidConfig(tokenId, config) + { + if (positionConfigs.getConfigId(tokenId) != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); + _subscribe(tokenId, config, subscriber); + positionConfigs.setSubscribe(tokenId); + } + + function unsubscribe(uint256 tokenId, PositionConfig calldata config) + external + onlyIfApproved(msg.sender, tokenId) + { + if (positionConfigs.getConfigId(tokenId) != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); + _unsubscribe(tokenId, config); + positionConfigs.setUnsubscribe(tokenId); + } + function _handleAction(uint256 action, bytes calldata params) internal override { if (action == Actions.INCREASE_LIQUIDITY) { (uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) = @@ -116,8 +145,8 @@ contract PositionManager is /// @dev Calling increase with 0 liquidity will credit the caller with any underlying fees of the position function _increase(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) internal + onlyValidConfig(tokenId, config) { - if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); // Note: The tokenId is used as the salt for this position, so every minted position has unique storage in the pool manager. BalanceDelta liquidityDelta = _modifyLiquidity(config, liquidity.toInt256(), bytes32(tokenId), hookData); } @@ -125,10 +154,9 @@ contract PositionManager is /// @dev Calling decrease with 0 liquidity will credit the caller with any underlying fees of the position function _decrease(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) internal + onlyIfApproved(_msgSender(), tokenId) + onlyValidConfig(tokenId, config) { - if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender()); - if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); - // Note: the tokenId is used as the salt. BalanceDelta liquidityDelta = _modifyLiquidity(config, -(liquidity.toInt256()), bytes32(tokenId), hookData); } @@ -171,9 +199,11 @@ contract PositionManager is } /// @dev this is overloaded with ERC721Permit._burn - function _burn(uint256 tokenId, PositionConfig calldata config, bytes calldata hookData) internal { - if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender()); - if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); + function _burn(uint256 tokenId, PositionConfig calldata config, bytes calldata hookData) + internal + onlyIfApproved(_msgSender(), tokenId) + onlyValidConfig(tokenId, config) + { uint256 liquidity = uint256(_getPositionLiquidity(config, tokenId)); BalanceDelta liquidityDelta; @@ -204,13 +234,9 @@ contract PositionManager is hookData ); - _notifyModifyLiquidity(uint256(salt), liquidityChange, config); - } - - function stake(uint256 tokenId, StakingConfig calldata stakingConfig, PositionConfig calldata config) external { - if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender()); - if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId); - _notifyStake(tokenId, stakingConfig, config); + if (positionConfigs.getSubscribed(uint256(salt))) { + _notifyModifyLiquidity(uint256(salt), config, liquidityChange); + } } function _getPositionLiquidity(PositionConfig calldata config, uint256 tokenId) diff --git a/src/base/Notifier.sol b/src/base/Notifier.sol new file mode 100644 index 000000000..6ef0c31cb --- /dev/null +++ b/src/base/Notifier.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.24; + +import {ISubscriber} from "../interfaces/ISubscriber.sol"; +import {PositionConfig} from "../libraries/PositionConfig.sol"; + +contract Notifier { + error SubscriberCannotBeNotified(); + error AlreadySubscribed(address subscriber); + + event Subscribed(uint256 tokenId, address subscriber); + event Unsubscribed(uint256 tokenId, address subscriber); + + uint256 private immutable subscriberGasLimit; + ISubscriber private constant NO_SUBSCRIBER = ISubscriber(address(0)); + + mapping(uint256 tokenId => ISubscriber subscriber) public subscriber; + + constructor(uint256 _subscriberGasLimit) { + subscriberGasLimit = _subscriberGasLimit; + } + + function _subscribe(uint256 tokenId, PositionConfig memory config, address newSubscriber) internal { + ISubscriber _subscriber = subscriber[tokenId]; + + if (_subscriber != NO_SUBSCRIBER) revert AlreadySubscribed(address(_subscriber)); + subscriber[tokenId] = ISubscriber(newSubscriber); + + ISubscriber(newSubscriber).notifySubscribe(tokenId, config); + emit Subscribed(tokenId, address(newSubscriber)); + } + + /// @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. + function _unsubscribe(uint256 tokenId, PositionConfig memory config) internal { + ISubscriber _subscriber = subscriber[tokenId]; + + if (gasleft() < subscriberGasLimit) revert SubscriberCannotBeNotified(); + try _subscriber.notifyUnsubscribe{gas: subscriberGasLimit}(tokenId, config) {} catch {} + + delete subscriber[tokenId]; + emit Unsubscribed(tokenId, address(_subscriber)); + } + + function _notifyModifyLiquidity(uint256 tokenId, PositionConfig memory config, int256 liquidityChange) internal { + subscriber[tokenId].notifyModifyLiquidity(tokenId, config, liquidityChange); + } + + function _notifyTransfer(uint256 tokenId, PositionConfig memory config, address previousOwner, address newOwner) + internal + { + subscriber[tokenId].notifyTransfer(tokenId, config, previousOwner, newOwner); + } +} diff --git a/src/base/StakingNotifier.sol b/src/base/StakingNotifier.sol deleted file mode 100644 index c3d8ea0c2..000000000 --- a/src/base/StakingNotifier.sol +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity ^0.8.24; - -import {IStakingSubscriber} from "../interfaces/IStakingSubscriber.sol"; -import {PositionConfig} from "../libraries/PositionConfig.sol"; - -struct StakingConfig { - IStakingSubscriber subscriber; -} - -contract StakingNotifier { - error StakingSubscriberCannotBeNotified(); - - event Staked(uint256 tokenId, address subscriber); - - uint256 private immutable stakingGasLimit; - IStakingSubscriber private constant NO_STAKING_SUBSCRIBER = IStakingSubscriber(address(0)); - - mapping(uint256 tokenId => StakingConfig config) public stakingConfig; - - constructor(uint256 _stakingGasLimit) { - stakingGasLimit = _stakingGasLimit; - } - - function _notifyModifyLiquidity(uint256 tokenId, int256 liquidityChange, PositionConfig memory config) internal { - IStakingSubscriber subscriber = stakingConfig[tokenId].subscriber; - if (subscriber != NO_STAKING_SUBSCRIBER) { - if (gasleft() < stakingGasLimit) revert StakingSubscriberCannotBeNotified(); - subscriber.notifyModifyLiquidity{gas: stakingGasLimit}(tokenId, liquidityChange, config); - } - } - - function _notifyStake(uint256 tokenId, StakingConfig memory _stakingConfig, PositionConfig memory config) - internal - { - stakingConfig[tokenId] = _stakingConfig; - _stakingConfig.subscriber.notifyStake(tokenId, 0, config); - emit Staked(tokenId, address(_stakingConfig.subscriber)); - } - - // TODO - // on transfer, notify subscriber. do we need to reset staking permissions? - // on stake, pass through position currenct liq? - // support unstake functionality - // support hooks auto-enrolling positions in their staking program - // use percentage/fraction for gasLimit - // other gasLimit concerns? - // can we optimize in the no stake case (reduce from 1 SLOAD :/) -} diff --git a/src/interfaces/IPositionManager.sol b/src/interfaces/IPositionManager.sol index ebf0b4825..7f6f20c02 100644 --- a/src/interfaces/IPositionManager.sol +++ b/src/interfaces/IPositionManager.sol @@ -11,7 +11,9 @@ interface IPositionManager { /// @notice Maps the ERC721 tokenId to a configId, which is a keccak256 hash of the position's pool key, and range (tickLower, tickUpper) /// Enforces that a minted ERC721 token is tied to one range on one pool. /// @param tokenId the ERC721 tokenId, assigned at mint - /// @return configId the hash of the position's poolkey, tickLower, and tickUpper + /// @return configId a truncated hash of the position's poolkey, tickLower, and tickUpper and a reserved upper bit for the isSubscribed flag + /// @dev the highest bit of the configId is used to signal if the position is subscribed + /// and the lower bits contain the truncated hash of the PositionConfig function positionConfigs(uint256 tokenId) external view returns (bytes32 configId); /// @notice Batches many liquidity modification calls to pool manager diff --git a/src/interfaces/IStakingSubscriber.sol b/src/interfaces/IStakingSubscriber.sol deleted file mode 100644 index 60b9621bd..000000000 --- a/src/interfaces/IStakingSubscriber.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; - -import {PositionConfig} from "../libraries/PositionConfig.sol"; - -interface IStakingSubscriber { - function notifyStake(uint256 tokenId, uint256 liquidity, PositionConfig memory config) external; - function notifyUnstake(uint256 tokenId, PositionConfig memory config) external; - function notifyModifyLiquidity(uint256 tokenId, int256 liquidityChange, PositionConfig memory config) external; - function notifyTransfer(uint256 tokenId, address previousOwner, address newOwner, PositionConfig memory config) - external; -} diff --git a/src/interfaces/ISubscriber.sol b/src/interfaces/ISubscriber.sol new file mode 100644 index 000000000..f68a3e970 --- /dev/null +++ b/src/interfaces/ISubscriber.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import {PositionConfig} from "../libraries/PositionConfig.sol"; + +interface ISubscriber { + function notifySubscribe(uint256 tokenId, PositionConfig memory config) external; + function notifyUnsubscribe(uint256 tokenId, PositionConfig memory config) external; + function notifyModifyLiquidity(uint256 tokenId, PositionConfig memory config, int256 liquidityChange) external; + function notifyTransfer(uint256 tokenId, PositionConfig memory config, address previousOwner, address newOwner) + external; +} diff --git a/src/libraries/PositionConfig.sol b/src/libraries/PositionConfig.sol index d3bd8e240..93fbca7f9 100644 --- a/src/libraries/PositionConfig.sol +++ b/src/libraries/PositionConfig.sol @@ -3,15 +3,59 @@ pragma solidity ^0.8.24; import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; -// A PositionConfig is the input for creating and modifying a Position in core, set per tokenId +// A PositionConfig is the input for creating and modifying a Position in core, whos truncated hash is set per tokenId struct PositionConfig { PoolKey poolKey; int24 tickLower; int24 tickUpper; } -/// @notice Library for computing the configId given a PositionConfig +/// @notice Library to get and set the PositionConfigId and subscriber status for a given tokenId library PositionConfigLibrary { + using PositionConfigLibrary for PositionConfig; + + bytes32 constant MASK_UPPER_BIT = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + bytes32 constant DIRTY_UPPER_BIT = 0x8000000000000000000000000000000000000000000000000000000000000000; + + /// @notice returns the truncated hash of the PositionConfig for a given tokenId + function getConfigId(mapping(uint256 => bytes32) storage positionConfigs, uint256 tokenId) + internal + view + returns (bytes32 configId) + { + bytes32 _config = positionConfigs[tokenId]; + configId = _config & MASK_UPPER_BIT; + } + + function setConfigId( + mapping(uint256 => bytes32) storage positionConfigs, + uint256 tokenId, + PositionConfig calldata config + ) internal { + positionConfigs[tokenId] = config.toId(); + } + + function setSubscribe(mapping(uint256 => bytes32) storage positionConfigs, uint256 tokenId) internal { + bytes32 _config = positionConfigs[tokenId]; + positionConfigs[tokenId] = _config | DIRTY_UPPER_BIT; + } + + function setUnsubscribe(mapping(uint256 => bytes32) storage positionConfigs, uint256 tokenId) internal { + bytes32 _config = positionConfigs[tokenId]; + positionConfigs[tokenId] = _config & MASK_UPPER_BIT; + } + + function getSubscribed(mapping(uint256 => bytes32) storage positionConfigs, uint256 tokenId) + internal + view + returns (bool subscribed) + { + bytes32 _config = positionConfigs[tokenId]; + assembly ("memory-safe") { + subscribed := shr(255, _config) + } + } + function toId(PositionConfig calldata config) internal pure returns (bytes32 id) { // id = keccak256(abi.encodePacked(currency0, currency1, fee, tickSpacing, hooks, tickLower, tickUpper))) assembly ("memory-safe") { @@ -24,7 +68,7 @@ library PositionConfigLibrary { mstore(add(fmp, 0x14), calldataload(add(config, 0x20))) // currency1: [0x20, 0x34) mstore(fmp, calldataload(config)) // currency0: [0x0c, 0x20) - id := keccak256(add(fmp, 0x0c), 0x48) // len is 72 bytes + id := shr(1, keccak256(add(fmp, 0x0c), 0x48)) // len is 72 bytes, truncate upper bit of the hash // now clean the memory we used mstore(add(fmp, 0x40), 0) // fmp+0x40 held hooks (14 bytes), tickLower, tickUpper diff --git a/test/libraries/PositionConfig.t.sol b/test/libraries/PositionConfig.t.sol index 1eeedc181..4fbfb684a 100644 --- a/test/libraries/PositionConfig.t.sol +++ b/test/libraries/PositionConfig.t.sol @@ -19,6 +19,8 @@ contract PositionConfigTest is Test { config.tickUpper ) ); + // the id is shifted over 1 + expectedId = expectedId >> 1; assertEq(expectedId, config.toId()); } } diff --git a/test/mocks/StakingSubscriber.sol b/test/mocks/StakingSubscriber.sol index 0d31b27c1..c57ab17b1 100644 --- a/test/mocks/StakingSubscriber.sol +++ b/test/mocks/StakingSubscriber.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; -import {IStakingSubscriber} from "../../src/interfaces/IStakingSubscriber.sol"; +import {ISubscriber} from "../../src/interfaces/ISubscriber.sol"; import {PositionConfig} from "../../src/libraries/PositionConfig.sol"; import {PositionManager} from "../../src/PositionManager.sol"; /// @notice A staking subscriber contract that ingests updates from the v4 position manager -contract StakingSubscriber is IStakingSubscriber { +contract StakingSubscriber is ISubscriber { PositionManager posm; error NotAuthorizedNotifer(address sender); @@ -22,27 +22,27 @@ contract StakingSubscriber is IStakingSubscriber { _; } - // liquidity param? in case there is already liquidity in a position that is now being staked? - // owner is lookup able - function notifyStake(uint256 tokenId, uint256 liquidity, PositionConfig memory config) external onlyByPosm { + function notifySubscribe(uint256 tokenId, PositionConfig memory config) external view onlyByPosm { revert NotImplemented(); } - function notifyModifyLiquidity(uint256 tokenId, int256 liquidityChange, PositionConfig memory config) - external - onlyByPosm - { + function notifyUnsubscribe(uint256 tokenId, PositionConfig memory config) external view onlyByPosm { revert NotImplemented(); } - function notifyTransfer(uint256 tokenId, address previousOwner, address newOwner, PositionConfig memory config) + function notifyModifyLiquidity(uint256 tokenId, PositionConfig memory config, int256 liquidityChange) external + view onlyByPosm { revert NotImplemented(); } - function notifyUnstake(uint256 tokenId, PositionConfig memory config) external onlyByPosm { + function notifyTransfer(uint256 tokenId, PositionConfig memory config, address previousOwner, address newOwner) + external + view + onlyByPosm + { revert NotImplemented(); } }