-
Notifications
You must be signed in to change notification settings - Fork 489
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
feat: add reverse mapping for pool key, store tL, tU #310
Conversation
so its like 8k more for mints on the same pool right? which is the "normal" case? |
not sure I can add a test but sounds about right it definitely wont be 40-50K |
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.
despite the massive diff, i quite like this
something about not checking subscriber on mint feels nice, same with maybe making burn only call unsubscribe
src/PositionManager.sol
Outdated
uint256 liquidity, | ||
uint128 amount0Max, | ||
uint128 amount1Max, | ||
bytes calldata hookData | ||
) internal onlyIfApproved(msgSender(), tokenId) onlyValidConfig(tokenId, config) { | ||
) internal onlyIfApproved(msgSender(), tokenId) { | ||
(PositionInfo memory info, PoolKey memory poolKey) = getPoolPositionInfo(tokenId); |
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.
are there gas savings if we dont load the entirety of PositionInfo? we're not using the truncated poolId obviously, and the ticks are just repacked to IPoolManager.ModifyLiquidityParams
something like this could be quite cool
(
PoolKey memory key,
IPoolManager.ModifyLiquidityParams memory liquidityParams,
bool hasSubscriber
) = veryAwesomeFunction(tokenId);
liquidityParams.liquidityDelta = liquidityChange;
theres also ways to pack it further since PoolKey is 528 bits, so we can fit tL/tU/hasSubscriber in the remaining bits of the 3rd word
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.
yeah was thinking the same thing.. I think I'm actually happy with it now that I have a version where the PositionInfo is packed (uint256).. since its the minimum we can basically return
src/libraries/PositionConfig.sol
Outdated
@@ -3,33 +3,9 @@ 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, whose truncated hash is set per tokenId | |||
// A PositionConfig is the input for creating and modifying a Position in core |
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.
Keeping this for now to reduce merge conflicts
later can move to test utils
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.
woudl rather delete now that we arent using it
src/PositionManager.sol
Outdated
function _positionConfigs(uint256 tokenId) internal view override returns (PositionConfigId storage) { | ||
return positionConfigs[tokenId]; | ||
} | ||
mapping(uint256 tokenId => PackedPositionInfo info) public positionInfo; |
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.
now that its packed maybe worth having this internal and exposing a getter that returns the elements individually?
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.
hm I dont feel strongly about it. For offchain, a simple sdk helper can dissect it. and onchain someone can just import the PositionInfoLibrary?
But if you prefer I can add
test/libraries/CalldataDecoder.t.sol
Outdated
assertEq(amount0Min, _amount0Min); | ||
assertEq(amount1Min, _amount1Min); | ||
} | ||
|
||
// TODO: fix stack too deep here |
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.
is it fixed now?
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.
yes i just removed that comment! thanks
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.
very clean work per usual 😌
reminder: consider SB-86, hasSubscriber should revert if the token does not exist stance: probably ugly to enforce, and adds gas. BUT should be natspec'd in hasSubscriber function |
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.
some CEI violations in _mint / _burn
https://github.com/spearbit-audits/review-uniswap-v4/issues/93
src/PositionManager.sol
Outdated
bytes25 poolId = info.poolId(); | ||
// Store the poolKey if it is not already stored. | ||
// On UniswapV4, the minimum tick spacing is 1, which means that if the tick spacing is 0, the pool key has not been set. | ||
if (poolKeys[poolId].tickSpacing == 0) { | ||
poolKeys[poolId] = poolKey; | ||
} |
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.
let's do this write prior to _modifyLiquidity
for CEI anyway (the hook still has access to tick range and poolKey regardless of CEI)
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 yeah that makes sense
src/PositionManager.sol
Outdated
delete positionConfigs[tokenId]; | ||
positionInfo[tokenId] = PositionInfoLibrary.EMPTY_POSITION_INFO; | ||
// Burn the token. | ||
_burn(tokenId); |
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.
thinking this logic should run prior to _modifyLiquidity
for CEI
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.
solmate _burn might be save to leave it, but positionInfo may want to happen before?
info = info.setSubscribe(); | ||
assertEq(info.hasSubscriber(), true); | ||
assertEq(info.tickLower(), tickLower); | ||
assertEq(info.tickUpper(), tickUpper); | ||
assertEq(info.poolId(), bytes25(PoolId.unwrap(poolKey.toId()))); |
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.
library itself looks good, but as an insane person we should assert that the tickLower/tickUpper/poolId is NOT changed by .setSubscribe
i.e. asserting that the info data is the same before/after .setSubscribe
src/PositionManager.sol
Outdated
// fee delta can be ignored as this is a new position | ||
(BalanceDelta liquidityDelta,) = | ||
_modifyLiquidity(info, poolKey, liquidity.toInt256(), bytes32(tokenId), hookData); | ||
(liquidityDelta).validateMaxIn(amount0Max, amount1Max); |
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.
(liquidityDelta).validateMaxIn(amount0Max, amount1Max); | |
liquidityDelta.validateMaxIn(amount0Max, amount1Max); |
src/PositionManager.sol
Outdated
liquidityDelta: liquidityChange, | ||
salt: salt | ||
}), | ||
hookData | ||
); | ||
|
||
if (positionConfigs[uint256(salt)].hasSubscriber()) { | ||
_notifyModifyLiquidity(uint256(salt), config, liquidityChange, feesAccrued); | ||
// TODO: Audit issue for burn, decide if we want to keep this and also unsubscribe. |
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
motivation was to have better interface standardization for ERC721s
(functions dont require PositionConfig to be passed in)
I personally was against this for gas reasons (mint is 40-50K more expensive) but that should go down with mints on the same pool, and overhead for other ops is around 4-5K.