Skip to content

Commit

Permalink
Decode posm params in calldata
Browse files Browse the repository at this point in the history
  • Loading branch information
hensha256 committed Jul 30, 2024
1 parent a96a8f6 commit e5e2db9
Show file tree
Hide file tree
Showing 27 changed files with 138 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_empty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
47271
47690
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_empty_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
47088
47508
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_nonEmpty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
130139
130555
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_nonEmpty_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
123060
123476
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151223
150859
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
142375
142011
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151223
150859
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decreaseLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
116766
116402
Original file line number Diff line number Diff line change
@@ -1 +1 @@
109375
109084
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decrease_burnEmpty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135178
135328
Original file line number Diff line number Diff line change
@@ -1 +1 @@
127917
128067
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129482
129118
Original file line number Diff line number Diff line change
@@ -1 +1 @@
152726
152337
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134609
134220
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135432
135050
Original file line number Diff line number Diff line change
@@ -1 +1 @@
171588
171206
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
372827
372374
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
337610
337157
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_nativeWithSweep.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
344548
344095
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickLower.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
315509
315056
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
316151
315698
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
241733
241280
Original file line number Diff line number Diff line change
@@ -1 +1 @@
321527
321074
Original file line number Diff line number Diff line change
@@ -1 +1 @@
417163
416750
52 changes: 29 additions & 23 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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 {CalldataDecoder} from "./libraries/CalldataDecoder.sol";

contract PositionManager is
IPositionManager,
Expand All @@ -39,6 +40,7 @@ contract PositionManager is
using StateLibrary for IPoolManager;
using TransientStateLibrary for IPoolManager;
using SafeCast for uint256;
using CalldataDecoder for bytes;

/// @dev The ID of the next token that will be minted. Skips 0
uint256 public nextTokenId = 1;
Expand Down Expand Up @@ -92,22 +94,22 @@ contract PositionManager is
return _getLocker();
}

/// @param params is an encoding of uint256 tokenId, PositionConfig memory config, uint256 liquidity, bytes hookData
/// @param params is an encoding of uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes hookData
/// @dev Calling increase with 0 liquidity will credit the caller with any underlying fees of the position
function _increase(bytes memory params) internal {
(uint256 tokenId, PositionConfig memory config, uint256 liquidity, bytes memory hookData) =
abi.decode(params, (uint256, PositionConfig, uint256, bytes));
function _increase(bytes calldata params) internal {
(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) =
params.decodeModifyLiquidityParams();

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);
}

/// @param params is an encoding of uint256 tokenId, PositionConfig memory config, uint256 liquidity, bytes hookData
/// @param params is an encoding of uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes hookData
/// @dev Calling decrease with 0 liquidity will credit the caller with any underlying fees of the position
function _decrease(bytes memory params) internal {
(uint256 tokenId, PositionConfig memory config, uint256 liquidity, bytes memory hookData) =
abi.decode(params, (uint256, PositionConfig, uint256, bytes));
function _decrease(bytes calldata params) internal {
(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) =
params.decodeModifyLiquidityParams();

if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender());
if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId);
Expand All @@ -116,10 +118,10 @@ contract PositionManager is
BalanceDelta liquidityDelta = _modifyLiquidity(config, -(liquidity.toInt256()), bytes32(tokenId), hookData);
}

/// @param params is an encoding of PositionConfig memory config, uint256 liquidity, address recipient, bytes hookData where recipient is the receiver / owner of the ERC721
function _mint(bytes memory params) internal {
(PositionConfig memory config, uint256 liquidity, address owner, bytes memory hookData) =
abi.decode(params, (PositionConfig, uint256, address, bytes));
/// @param params is an encoding of PositionConfig calldata config, uint256 liquidity, address recipient, bytes hookData where recipient is the receiver / owner of the ERC721
function _mint(bytes calldata params) internal {
(PositionConfig calldata config, uint256 liquidity, address owner, bytes calldata hookData) =
params.decodeMintParams();

// mint receipt token
uint256 tokenId;
Expand All @@ -136,8 +138,11 @@ contract PositionManager is
}

/// @param params is an encoding of the Currency to close
function _close(bytes memory params) internal {
(Currency currency) = abi.decode(params, (Currency));
function _close(bytes calldata params) internal {
Currency currency;
assembly ("memory-safe") {
currency := calldataload(params.offset)
}
// this address has applied all deltas on behalf of the user/owner
// it is safe to close this entire delta because of slippage checks throughout the batched calls.
int256 currencyDelta = poolManager.currencyDelta(address(this), currency);
Expand All @@ -154,11 +159,10 @@ contract PositionManager is
}
}

/// @param params is an encoding of uint256 tokenId, PositionConfig memory config, bytes hookData
/// @param params is an encoding of uint256 tokenId, PositionConfig calldata config, bytes hookData
/// @dev this is overloaded with ERC721Permit._burn
function _burn(bytes memory params) internal {
(uint256 tokenId, PositionConfig memory config, bytes memory hookData) =
abi.decode(params, (uint256, PositionConfig, bytes));
function _burn(bytes calldata params) internal {
(uint256 tokenId, PositionConfig calldata config, bytes calldata hookData) = params.decodeBurnParams();

if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender());
if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId);
Expand All @@ -175,10 +179,12 @@ contract PositionManager is
_burn(tokenId);
}

function _modifyLiquidity(PositionConfig memory config, int256 liquidityChange, bytes32 salt, bytes memory hookData)
internal
returns (BalanceDelta liquidityDelta)
{
function _modifyLiquidity(
PositionConfig calldata config,
int256 liquidityChange,
bytes32 salt,
bytes calldata hookData
) internal returns (BalanceDelta liquidityDelta) {
(liquidityDelta,) = poolManager.modifyLiquidity(
config.poolKey,
IPoolManager.ModifyLiquidityParams({
Expand All @@ -191,7 +197,7 @@ contract PositionManager is
);
}

function _getPositionLiquidity(PositionConfig memory config, uint256 tokenId)
function _getPositionLiquidity(PositionConfig calldata config, uint256 tokenId)
internal
view
returns (uint128 liquidity)
Expand Down
80 changes: 80 additions & 0 deletions src/libraries/CalldataDecoder.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import {PositionConfig} from "./PositionConfig.sol";

/// @title Library for abi decoding in calldata
library CalldataDecoder {
using CalldataDecoder for bytes;

error SliceOutOfBounds();

/// @notice equivalent to SliceOutOfBounds.selector
Expand Down Expand Up @@ -40,4 +44,80 @@ library CalldataDecoder {
}
}
}

/// @param params The input bytes string to extract input arrays from
function decodeModifyLiquidityParams(bytes calldata params)
internal
pure
returns (uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData)
{
assembly ("memory-safe") {
tokenId := calldataload(params.offset)
config := add(params.offset, 0x20)
liquidity := calldataload(add(params.offset, 0x100))
}
hookData = params.toBytes(9);
}

/// @param params The input bytes string to extract input arrays from
function decodeMintParams(bytes calldata params)
internal
pure
returns (PositionConfig calldata config, uint256 liquidity, address owner, bytes calldata hookData)
{
assembly ("memory-safe") {
config := params.offset
liquidity := calldataload(add(params.offset, 0xe0))
owner := calldataload(add(params.offset, 0x100))
}
hookData = params.toBytes(9);
}

/// @param params The input bytes string to extract input arrays from
function decodeBurnParams(bytes calldata params)
internal
pure
returns (uint256 tokenId, PositionConfig calldata config, bytes calldata hookData)
{
assembly ("memory-safe") {
tokenId := calldataload(params.offset)
config := add(params.offset, 0x20)
}
hookData = params.toBytes(8);
}

/// @notice Decode the `_arg`-th element in `_bytes` as a dynamic array
/// @dev The decoding of `length` and `offset` is universal,
/// whereas the type declaration of `res` instructs the compiler how to read it.
/// @param _bytes The input bytes string to slice
/// @param _arg The index of the argument to extract
/// @return length Length of the array
/// @return offset Pointer to the data part of the array
function toLengthOffset(bytes calldata _bytes, uint256 _arg)
internal
pure
returns (uint256 length, uint256 offset)
{
uint256 relativeOffset;
assembly ("memory-safe") {
// The offset of the `_arg`-th element is `32 * arg`, which stores the offset of the length pointer.
// shl(5, x) is equivalent to mul(32, x)
let lengthPtr := add(_bytes.offset, calldataload(add(_bytes.offset, shl(5, _arg))))
length := calldataload(lengthPtr)
offset := add(lengthPtr, 0x20)
relativeOffset := sub(offset, _bytes.offset)
}
if (_bytes.length < length + relativeOffset) revert SliceOutOfBounds();
}

/// @notice Decode the `_arg`-th element in `_bytes` as `bytes`
/// @param _bytes The input bytes string to extract a bytes string from
/// @param _arg The index of the argument to extract
function toBytes(bytes calldata _bytes, uint256 _arg) internal pure returns (bytes calldata res) {
(uint256 length, uint256 offset) = toLengthOffset(_bytes, _arg);
assembly ("memory-safe") {
res.length := length
res.offset := offset
}
}
}
7 changes: 5 additions & 2 deletions src/libraries/PositionConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ struct PositionConfig {

/// @notice Library for computing the configId given a PositionConfig
library PositionConfigLibrary {
function toId(PositionConfig memory config) internal pure returns (bytes32 id) {
PoolKey memory poolKey = config.poolKey;
function toId(PositionConfig calldata config) internal pure returns (bytes32 id) {
PoolKey calldata poolKey;
assembly ("memory-safe") {
poolKey := config
}
return keccak256(
abi.encodePacked(
poolKey.currency0,
Expand Down

0 comments on commit e5e2db9

Please sign in to comment.