-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
skip calls to hooks when msg.sender is hook contract + test #503
Conversation
src/libraries/Hooks.sol
Outdated
@@ -96,10 +96,12 @@ library Hooks { | |||
|
|||
/// @notice performs a hook call using the given calldata on the given hook | |||
function callHook(IHooks self, bytes memory data) internal { | |||
(bytes4 expectedSelector, bytes4 selector) = _callHook(self, data); | |||
if (msg.sender != address(self)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooh this is an interesting line of code.. address(self) reads like address(this), but is actually checking address(hook)... I feel like I lean towards a rename of callHook(IHooks hook, bytes memory data)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could collapse the if statement by doing
if (msg.sender == address(hook) return;
_callHook()
if(selector != expectedSelector) revert ..
which may be clean? but try it out and see if you like it.. not that opinionated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I like that! Honestly it took me a while to figure out what was what so I think this will make it more clear
src/test/PoolSwapTest.sol
Outdated
@@ -66,9 +66,6 @@ contract PoolSwapTest is Test, PoolTestBase { | |||
(,, uint256 reserveAfter0, int256 deltaAfter0) = _fetchBalances(data.key.currency0, data.sender, address(this)); | |||
(,, uint256 reserveAfter1, int256 deltaAfter1) = _fetchBalances(data.key.currency1, data.sender, address(this)); | |||
|
|||
assertEq(reserveBefore0, reserveAfter0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There could be a swap within the hook making the reserves not equal to each other so I removed it. Also since reservesOf might be removed entirely anyways
src/test/SkipCallsTestHook.sol
Outdated
manager = _manager; | ||
} | ||
|
||
function setFee(uint24 _fee) external { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are unneeded functions i believe for the purpose of this test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ya i needed them since I made the hook with a dynamic fee but ill change that so i dont need these
test/SkipCallsTestHook.t.sol
Outdated
); | ||
} | ||
|
||
function test_beforeSwap_invalidSender() public { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean by invalid_sender
in the test name?
I think this is just testing that the hook's call to beforeSwap doesnt trigger the hook again yes? thus, the count to beforeSwap is 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking more like invalid caller aka the hook, but ill rename it to test_beforeSwap_skipIfCalledByHook()
to make it more clear
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changes look good. @hensha256 brought up a good point that changing away from self diverges from how we do this in other libs (Pool.sol, Position.sol) so I'm actually inclined to change it back... and we can discuss more later. Sorry for back and forth there
test/SkipCallsTestHook.t.sol
Outdated
SkipCallsTestHook impl = new SkipCallsTestHook(); | ||
vm.etch(address(skipCallsTestHook), address(impl).code); | ||
deployFreshManagerAndRouters(); | ||
skipCallsTestHook.setManager(IPoolManager(manager)); | ||
|
||
(currency0, currency1) = deployMintAndApprove2Currencies(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just put all of this in setUp and then do the init/addLiq as needed in each of the test cases? I think it may be a bit easier to follow what exactly is being called to understand the expected count amount. And I dont think the hook address needs to change each time ie all of this can just happen once? Unless Im missing something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so make one hook and turn all flags on? and check that count is total 10 at the end?
src/test/SkipCallsTestHook.sol
Outdated
bytes calldata hookData | ||
) external override returns (bytes4) { | ||
counter++; | ||
_initialize(key, Constants.SQRT_RATIO_1_1, hookData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe overkill but it seems like we are just calling the same function on the pool again (except for this.. this one does initialize).... Maybe instead we actually fuzz the function thats called inside? That way we are testing that no matter which hook callback we are in, any action on the pool called from the hook skips the call? So it could be any of initialize/swap/modifyPositon/donate
test/SkipCallsTestHook.t.sol
Outdated
deploy(skipCallsTestHook); | ||
|
||
MockERC20(Currency.unwrap(key.currency0)).approve(address(skipCallsTestHook), Constants.MAX_UINT256); | ||
MockERC20(Currency.unwrap(key.currency1)).approve(address(skipCallsTestHook), Constants.MAX_UINT256); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert counter is 0 before the call in each of these? that makes it super clear we are expecting a change to counter.. I think you do it below but not here/ i think its missing in some other tests as well
donateRouter.donate(key, 100, 200, abi.encode(address(this))); | ||
assertEq(skipCallsTestHook.counter(), 1); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a test where we call again on the pool and the counter should be 2 but not 4?
Forge code coverage:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generally looking great!! couple of small things but we're nearly there
_fetchBalances(data.key.currency1, data.sender, address(this)); | ||
|
||
require(poolBalanceBefore0 == poolBalanceAfter0, "poolBalanceBefore0 is not equal to poolBalanceAfter0"); | ||
require(poolBalanceBefore1 == poolBalanceAfter1, "poolBalanceBefore1 is not equal to poolBalanceAfter1"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are these being removed in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think its because the hook might do a swap/add liq and settle that is nested. meaning the balance would have changed before the outermost swap settles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep exactly, the hook does its own swap which changes the balance
test/SkipCallsTestHook.t.sol
Outdated
& uint160( | ||
~Hooks.AFTER_INITIALIZE_FLAG & ~Hooks.BEFORE_ADD_LIQUIDITY_FLAG & ~Hooks.AFTER_ADD_LIQUIDITY_FLAG | ||
& ~Hooks.BEFORE_REMOVE_LIQUIDITY_FLAG & ~Hooks.AFTER_REMOVE_LIQUIDITY_FLAG & ~Hooks.BEFORE_SWAP_FLAG | ||
& ~Hooks.AFTER_SWAP_FLAG & ~Hooks.BEFORE_DONATE_FLAG & ~Hooks.AFTER_DONATE_FLAG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so these lines can become
address(
uint160(
uint256(type(uint160).max) & clearAllHookPermisssionsMask | Hooks.AFTER_INITIALIZE_FLAG
)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure why it needs to go via uint256... you could try making clearAllHookPermisssionsMask
a uint160 too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think you commented something similar in #548 which I can do over there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah so much nicer! thank you!!
deploy(skipCallsTestHook); | ||
approveAndAddLiquidity(skipCallsTestHook); | ||
|
||
modifyLiquidityRouter.modifyLiquidity(key, REMOVE_LIQ_PARAMS, abi.encode(address(this))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assertEq(skipCallsTestHook.counter(), 0);
above this line too
test/ERC6909Claims.t.sol
Outdated
@@ -4,6 +4,7 @@ pragma solidity ^0.8.15; | |||
import {Test} from "forge-std/Test.sol"; | |||
import {CurrencyLibrary, Currency} from "../src/types/Currency.sol"; | |||
import {MockERC6909Claims} from "../src/test/MockERC6909Claims.sol"; | |||
import "forge-std/console.sol"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove!
Related Issue
Skip calls to hooks when msg.sender is the hook contract #471
Description of changes
skips calls to hooks when msg.sender is the hook contract + tests