Skip to content
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

Use packed stack-based version of Slot0 structure #613

Merged
merged 23 commits into from
May 17, 2024

Conversation

0xVolosnikov
Copy link
Contributor

This pull request does not relate to any issue. In my opinion, it is more convenient to discuss this change if you have an already written implementation in a pull request.

Description of changes

The slot0 structure by design fits into one storage slot. However, when using the memory version of this structure, each field occupies a separate memory slot. In addition, the memory structure takes up more space on the solidity "stack".

The changes I propose allows to read this structure onto the stack and operate with the fields of this structure directly on the stack. As a result, the amount of memory used is reduced, which a little bit reduces gas costs and bytecode size.

Since the changes are more or less significant, I would first like to hear the opinion of the community and maintainers regarding the proposal to use a structure on the stack before adding tests and so on.

src/PoolManager.sol Outdated Show resolved Hide resolved
src/PoolManager.sol Outdated Show resolved Hide resolved
src/libraries/Pool.sol Outdated Show resolved Hide resolved
src/libraries/Pool.sol Outdated Show resolved Hide resolved
src/types/Slot0.sol Outdated Show resolved Hide resolved
src/types/Slot0.sol Outdated Show resolved Hide resolved
src/types/Slot0.sol Outdated Show resolved Hide resolved
src/types/Slot0.sol Outdated Show resolved Hide resolved
src/PoolManager.sol Outdated Show resolved Hide resolved
src/PoolManager.sol Outdated Show resolved Hide resolved
@snreynolds
Copy link
Member

Btw in general, I do really like this change and it would be great to get tests I think! cc @hensha256

0xVolosnikov and others added 4 commits May 14, 2024 21:07
Co-authored-by: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com>
Co-authored-by: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com>
Co-authored-by: Shuhui Luo <107524008+shuhuiluo@users.noreply.github.com>
uint24 protocolFee;
// used for the lp fee, either static at initialize or dynamic via hook
uint24 lpFee;
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you maybe just also add a comment that we dont use a struct so that we get the benefits of a packed structure when we reference slot0 in memory/stack

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

using Slot0Library for Slot0 global;

library Slot0Library {
uint160 private constant UINT160_MASK = 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this not just 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ?

Copy link
Contributor Author

@0xVolosnikov 0xVolosnikov May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compiler treats it as an incorrectly formatted address literal and is really angry about it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could just change it to type(uint160).max? That feels more reliable anyway as you dont need to check you have the right number of Fs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could just change it to type(uint160).max?

Only direct number constants can be used in assembly. We can replace it with type(uin160).max but it will be a bit messier

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah damn, annoying

src/types/Slot0.sol Show resolved Hide resolved
src/libraries/Pool.sol Outdated Show resolved Hide resolved
src/types/Slot0.sol Outdated Show resolved Hide resolved
Copy link
Contributor

@hensha256 hensha256 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally really like this! Any chance of some tests?
Particularly a fuzz test that takes in the 4 arguments, and calls set on all 4, and then get on all 4, and check the extracted values are the same as the inputs.

Plus a test that UINT160_MASK == type(uint160).max in case anyone ever edits it 😏


library Slot0Library {
uint160 internal constant UINT160_MASK = 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
uint24 internal constant INT24_MASK = 0xFFFFFF;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INT24_MASK can be removed since it is equal to UINT24_MASK

@0xVolosnikov
Copy link
Contributor Author

Added tests

test/types/Slot0.t.sol Outdated Show resolved Hide resolved
@hensha256
Copy link
Contributor

@snreynolds anything else you wanna see before we merge?

src/types/Slot0.sol Outdated Show resolved Hide resolved
src/PoolManager.sol Outdated Show resolved Hide resolved
Copy link
Contributor

@hensha256 hensha256 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 final nit, plus you need to handle merge conflicts (sorry we're merging lots today!). Then we can merge!

state.feeGrowthGlobalX128 = zeroForOne ? self.feeGrowthGlobal0X128 : self.feeGrowthGlobal1X128;
state.liquidity = liquidityStart;

// if the beforeSwap hook returned a valid fee override, use that as the LP fee, otherwise load from storage
slot0Start.lpFee =
params.lpFeeOverride.isOverride() ? params.lpFeeOverride.removeOverrideAndValidate() : slot0Start.lpFee;
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice thank you!

@hensha256 hensha256 merged commit 285b53e into Uniswap:main May 17, 2024
5 of 6 checks passed
@0xVolosnikov 0xVolosnikov deleted the isomorphic-slot0 branch May 17, 2024 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants