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

Decode posm params in calldata #226

Merged
merged 12 commits into from
Jul 31, 2024
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_empty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
47248
46761
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 @@
47066
46579
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_burn_nonEmpty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
130117
129621
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 @@
123039
122543
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151223
149718
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
140870
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
149718
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decreaseLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
116766
115261
Original file line number Diff line number Diff line change
@@ -1 +1 @@
109375
108171
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decrease_burnEmpty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135156
133487
Original file line number Diff line number Diff line change
@@ -1 +1 @@
127895
126226
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129482
127977
Original file line number Diff line number Diff line change
@@ -1 +1 @@
152736
151197
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134536
132997
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135432
133924
Original file line number Diff line number Diff line change
@@ -1 +1 @@
171588
170080
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
372837
371232
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
337537
335932
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_nativeWithSweep.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
346399
344562
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickLower.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
315519
313914
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
316161
314556
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
241743
240138
Original file line number Diff line number Diff line change
@@ -1 +1 @@
371451
369400
Original file line number Diff line number Diff line change
@@ -1 +1 @@
321537
319932
Original file line number Diff line number Diff line change
@@ -1 +1 @@
417173
415608
82 changes: 40 additions & 42 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
import {Position} from "@uniswap/v4-core/src/libraries/Position.sol";
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
import {Position} from "@uniswap/v4-core/src/libraries/Position.sol";
Expand All @@ -23,6 +24,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 @@ -40,6 +42,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 @@ -74,20 +77,30 @@ contract PositionManager is

function _handleAction(uint256 action, bytes calldata params) internal override {
if (action == Actions.INCREASE_LIQUIDITY) {
_increase(params);
(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) =
params.decodeModifyLiquidityParams();
_increase(tokenId, config, liquidity, hookData);
} else if (action == Actions.DECREASE_LIQUIDITY) {
_decrease(params);
(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData) =
params.decodeModifyLiquidityParams();
_decrease(tokenId, config, liquidity, hookData);
} else if (action == Actions.MINT_POSITION) {
_mint(params);
(PositionConfig calldata config, uint256 liquidity, address owner, bytes calldata hookData) =
params.decodeMintParams();
_mint(config, liquidity, owner, hookData);
} else if (action == Actions.CLOSE_CURRENCY) {
_close(params);
Currency currency = params.decodeCurrency();
_close(currency);
} else if (action == Actions.BURN_POSITION) {
// Will automatically decrease liquidity to 0 if the position is not already empty.
_burn(params);
(uint256 tokenId, PositionConfig calldata config, bytes calldata hookData) = params.decodeBurnParams();
_burn(tokenId, config, hookData);
} else if (action == Actions.SETTLE_WITH_BALANCE) {
_settleWithBalance(params);
Currency currency = params.decodeCurrency();
_settleWithBalance(currency);
} else if (action == Actions.SWEEP) {
_sweep(params);
(Currency currency, address to) = params.decodeCurrencyAndAddress();
_sweep(currency, to);
} else {
revert UnsupportedAction(action);
}
Expand All @@ -97,35 +110,29 @@ contract PositionManager is
return _getLocker();
}

/// @param params is an encoding of uint256 tokenId, PositionConfig memory 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(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData)
internal
{
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
/// @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(uint256 tokenId, PositionConfig calldata config, uint256 liquidity, bytes calldata hookData)
internal
{
if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender());
if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId);

// Note: the tokenId is used as the salt.
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));

function _mint(PositionConfig calldata config, uint256 liquidity, address owner, bytes calldata hookData)
internal
{
// mint receipt token
uint256 tokenId;
// tokenId is assigned to current nextTokenId before incrementing it
Expand All @@ -140,9 +147,7 @@ contract PositionManager is
positionConfigs[tokenId] = config.toId();
}

/// @param params is an encoding of the Currency to close
function _close(bytes memory params) internal {
(Currency currency) = abi.decode(params, (Currency));
function _close(Currency currency) internal {
// 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 @@ -156,21 +161,14 @@ contract PositionManager is
}
}

/// @param params is an encoding of Currency
/// @dev uses this addresses balance to settle a negative delta
function _settleWithBalance(bytes memory params) internal {
Currency currency = abi.decode(params, (Currency));

function _settleWithBalance(Currency currency) internal {
// set the payer to this address, performs a transfer.
_settle(currency, address(this), _getFullSettleAmount(currency));
}

/// @param params is an encoding of uint256 tokenId, PositionConfig memory 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(uint256 tokenId, PositionConfig calldata config, bytes calldata hookData) internal {
if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert NotApproved(_msgSender());
if (positionConfigs[tokenId] != config.toId()) revert IncorrectPositionConfigForTokenId(tokenId);
uint256 liquidity = uint256(_getPositionLiquidity(config, tokenId));
Expand All @@ -186,10 +184,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 @@ -202,7 +202,7 @@ contract PositionManager is
);
}

function _getPositionLiquidity(PositionConfig memory config, uint256 tokenId)
function _getPositionLiquidity(PositionConfig calldata config, uint256 tokenId)
internal
view
returns (uint128 liquidity)
Expand All @@ -213,9 +213,7 @@ contract PositionManager is
}

/// @notice Sweeps the entire contract balance of specified currency to the recipient
/// @param params an encoding of Currency, address
function _sweep(bytes calldata params) internal {
(Currency currency, address to) = abi.decode(params, (Currency, address));
function _sweep(Currency currency, address to) internal {
uint256 balance = currency.balanceOfSelf();
if (balance > 0) currency.transfer(to, balance);
}
Expand Down
16 changes: 2 additions & 14 deletions src/V4Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,14 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
}
} else {
if (action == Actions.SETTLE_ALL) {
// equivalent: abi.decode(params, (Currency))
Currency currency;
assembly ("memory-safe") {
currency := calldataload(params.offset)
}

Currency currency = params.decodeCurrency();
uint256 amount = _getFullSettleAmount(currency);

// TODO support address(this) paying too
// TODO should it have a maxAmountOut added slippage protection?
_settle(currency, _msgSender(), amount);
} else if (action == Actions.TAKE_ALL) {
// equivalent: abi.decode(params, (Currency, address))
Currency currency;
address recipient;
assembly ("memory-safe") {
currency := calldataload(params.offset)
recipient := calldataload(add(params.offset, 0x20))
}

(Currency currency, address recipient) = params.decodeCurrencyAndAddress();
uint256 amount = _getFullTakeAmount(currency);

// TODO should _take have a minAmountOut added slippage check?
Expand Down
Loading
Loading