-
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
beforeSwap returns dynamic fee #648
Conversation
Forge code coverage:
|
there's an alternative implementation where it's not as clean, but saves 9 gas lul |
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.
Im a bit torn on this one - it definitely makes the hook callsites more messy, and I don't actually love exposing multiple ways of doing the same thing but it is a significant gas difference if a hook does want to change the fee on every swap...
I actually dont mind this impl now that we still have to check canReturnDelta after the callsite... if that makes sense. Like the way I suggested was cleaner before Alice's 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.
Also torn... its making some other non-standard cases more expensive too sadly
went ahead and made the change because 9 gas 😎 |
* Optimise beforeSwap return fee * add comments
* Optimise beforeSwap return fee * add comments * use parse return lib * add selector, fix comments * rename, optimize --------- Co-authored-by: Alice Henshaw <henshawalice@gmail.com>
Co-authored-by: Alice <34962750+hensha256@users.noreply.github.com>
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.
Few small things!
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 good, the one thing I don't love is that hooks default to return 0 if they dont need to use that fee field EXCEPT if you're a dynamic fee hook and you dont want to override - you shouldn't return 0, you need to return the flag. Feels footgunny but don't have a great workaround
src/libraries/LPFeeLibrary.sol
Outdated
uint24 public constant DYNAMIC_FEE_FLAG = 0x800000; | ||
uint24 public constant BEFORE_SWAP_FEE_OVERRIDE_FLAG = 0x800000; |
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.
If we are going to use the same flag - we can just name this FEE_FLAG
and have it defined once
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.
yeeah i did think that - just wasnt sure if the double naming makes the code more readable in other places
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.
hmm, i think if we want to use one, DYNAMIC_FEE_FLAG
works
used for the poolkey and for fee-overrides, which makes sense to me
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.
consolidating to one constant, we might have 2 redundant functions:
function isDynamicFee(uint24 self) internal pure returns (bool) {
return self & DYNAMIC_FEE_FLAG != 0;
}
/// @notice returns true if the fee has the override flag set (top bit of the uint24)
function isOverride(uint24 self) internal pure returns (bool) {
return self & DYNAMIC_FEE_FLAG != 0;
}
kind of like having isOverride
, feels a lot clearer for
// if the beforeSwap hook returned a valid fee override, use that as the LP fee, otherwise load from storage
uint24 lpFee =
params.lpFeeOverride.isOverride() ? params.lpFeeOverride.removeOverrideAndValidate() : slot0Start.lpFee;
if (!lpFee.isValid()) lpFee = slot0Start.lpFee; | ||
} | ||
uint24 lpFee = | ||
params.lpFeeOverride.isOverride() ? params.lpFeeOverride.removeOverrideAndValidate() : slot0Start.lpFee; |
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.
sooo much better ❤️
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.
🚀
Co-authored-by: Alice <34962750+hensha256@users.noreply.github.com>
Co-authored-by: Alice <34962750+hensha256@users.noreply.github.com>
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.
lfg
Related Issue
Closes #554
Description of changes
Change
beforeSwap
to return auint24
representing a dynamic fee. This improves gas for swaps where the dynamic fee is updated on every swap since it does not rely onupdateDynamicSwapFee
(external call + sstore)The return value is honored i.f.f. the PoolKey has a dynamic fee flag AND the value is less than or equal to the max swap fee (1 million / 100%)
The sentinel value is
type(uint24).max
(or anything greater than 1 million). A swap fee of 0 is valid