Skip to content

Commit

Permalink
take pair recipient
Browse files Browse the repository at this point in the history
  • Loading branch information
dianakocsis committed Aug 3, 2024
1 parent 1d62f32 commit e682040
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
122431
122739
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129509
129817
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_withTakePair.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149439
149846
Original file line number Diff line number Diff line change
@@ -1 +1 @@
115026
115389
13 changes: 6 additions & 7 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ contract PositionManager is
(Currency currency0, Currency currency1) = params.decodeCurrencyPair();
_settlePair(currency0, currency1);
} else if (action == Actions.TAKE_PAIR) {
(Currency currency0, Currency currency1) = params.decodeCurrencyPair();
_takePair(currency0, currency1);
(Currency currency0, Currency currency1, address to) = params.decodeCurrencyPairAndAddress();
_takePair(currency0, currency1, to);
} else if (action == Actions.SWEEP) {
(Currency currency, address to) = params.decodeCurrencyAndAddress();
_sweep(currency, _mapRecipient(to));
Expand Down Expand Up @@ -274,11 +274,10 @@ contract PositionManager is
_settle(currency1, caller, _getFullDebt(currency1));
}

function _takePair(Currency currency0, Currency currency1) internal {
// the locker is the receiver when taking
address caller = msgSender();
_take(currency0, caller, _getFullCredit(currency0));
_take(currency1, caller, _getFullCredit(currency1));
function _takePair(Currency currency0, Currency currency1, address to) internal {
address recipient = _mapRecipient(to);
_take(currency0, recipient, _getFullCredit(currency0));
_take(currency1, recipient, _getFullCredit(currency1));
}

/// @dev this is overloaded with ERC721Permit._burn
Expand Down
13 changes: 13 additions & 0 deletions src/libraries/CalldataDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ library CalldataDecoder {
}
}

/// @dev equivalent to: abi.decode(params, (Currency, Currency, address)) in calldata
function decodeCurrencyPairAndAddress(bytes calldata params)
internal
pure
returns (Currency currency0, Currency currency1, address _address)
{
assembly ("memory-safe") {
currency0 := calldataload(params.offset)
currency1 := calldataload(add(params.offset, 0x20))
_address := calldataload(add(params.offset, 0x40))
}
}

/// @dev equivalent to: abi.decode(params, (Currency, address)) in calldata
function decodeCurrencyAndAddress(bytes calldata params)
internal
Expand Down
12 changes: 12 additions & 0 deletions test/libraries/CalldataDecoder.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ contract CalldataDecoderTest is Test {
assertEq(Currency.unwrap(currency1), Currency.unwrap(_currency1));
}

function test_fuzz_decodeCurrencyPairAndAddress(Currency _currency0, Currency _currency1, address __address)
public
view
{
bytes memory params = abi.encode(_currency0, _currency1, __address);
(Currency currency0, Currency currency1, address _address) = decoder.decodeCurrencyPairAndAddress(params);

assertEq(Currency.unwrap(currency0), Currency.unwrap(_currency0));
assertEq(Currency.unwrap(currency1), Currency.unwrap(_currency1));
assertEq(_address, __address);
}

function test_fuzz_decodeCurrencyAndUint256(Currency _currency, uint256 _amount) public view {
bytes memory params = abi.encode(_currency, _amount);
(Currency currency, uint256 amount) = decoder.decodeCurrencyAndUint256(params);
Expand Down
8 changes: 8 additions & 0 deletions test/mocks/MockCalldataDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ contract MockCalldataDecoder {
return params.decodeCurrencyPair();
}

function decodeCurrencyPairAndAddress(bytes calldata params)
external
pure
returns (Currency currency0, Currency currency1, address _address)
{
return params.decodeCurrencyPairAndAddress();
}

function decodeCurrencyAndUint256(bytes calldata params) external pure returns (Currency currency, uint256 _uint) {
return params.decodeCurrencyAndUint256();
}
Expand Down
50 changes: 46 additions & 4 deletions test/position-managers/NativeToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
planner.add(
Actions.BURN_POSITION, abi.encode(tokenId, config, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));
lpm.modifyLiquidities(calls, _deadline);
// No decrease/modifyLiq call will actually happen on the call to burn so the deltas array will be the same length.
assertEq(numDeltas, hook.numberDeltasReturned());
Expand Down Expand Up @@ -391,7 +391,7 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
planner.add(
Actions.BURN_POSITION, abi.encode(tokenId, config, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));
lpm.modifyLiquidities(calls, _deadline);
BalanceDelta deltaBurn = getLastDelta();

Expand Down Expand Up @@ -634,7 +634,7 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
tokenId, config, decreaseLiquidityDelta, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES
)
);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));
lpm.modifyLiquidities(calls, _deadline);
BalanceDelta delta = getLastDelta();

Expand Down Expand Up @@ -698,7 +698,7 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
Actions.DECREASE_LIQUIDITY,
abi.encode(tokenId, config, 0, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));
lpm.modifyLiquidities(calls, _deadline);
BalanceDelta delta = getLastDelta();

Expand All @@ -707,6 +707,48 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
assertEq(currency1.balanceOfSelf() - balance1Before, uint128(delta.amount1()));
}

function test_fuzz_collect_native_withTakePair_recipient(IPoolManager.ModifyLiquidityParams memory params) public {
params = createFuzzyLiquidityParams(nativeKey, params, SQRT_PRICE_1_1);
vm.assume(params.tickLower < 0 && 0 < params.tickUpper); // two-sided liquidity

PositionConfig memory config =
PositionConfig({poolKey: nativeKey, tickLower: params.tickLower, tickUpper: params.tickUpper});

// mint the position with native token liquidity
uint256 tokenId = lpm.nextTokenId();
mintWithNative(SQRT_PRICE_1_1, config, uint256(params.liquidityDelta), Constants.MSG_SENDER, ZERO_BYTES);

// donate to generate fee revenue
uint256 feeRevenue0 = 1e18;
uint256 feeRevenue1 = 0.1e18;
donateRouter.donate{value: 1e18}(nativeKey, feeRevenue0, feeRevenue1, ZERO_BYTES);

uint256 balance0Before = address(this).balance;
uint256 balance1Before = currency1.balanceOfSelf();

Plan memory planner = Planner.init();
planner.add(
Actions.DECREASE_LIQUIDITY,
abi.encode(tokenId, config, 0, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);

address alice = address(0xABCD);

uint256 aliceBalance0Before = currency0.balanceOf(alice);
uint256 aliceBalance1Before = currency1.balanceOf(alice);

bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, alice);
lpm.modifyLiquidities(calls, _deadline);
BalanceDelta delta = getLastDelta();

assertEq(currency0.balanceOfSelf() - balance0Before, 0);
assertEq(currency1.balanceOfSelf() - balance1Before, 0);

assertApproxEqAbs(currency0.balanceOf(alice) - aliceBalance0Before, feeRevenue0, 1 wei); // TODO: fuzzer off by 1 wei
assertEq(currency0.balanceOf(alice) - aliceBalance0Before, uint128(delta.amount0()));
assertEq(currency1.balanceOf(alice) - aliceBalance1Before, uint128(delta.amount1()));
}

// this test fails unless subscribe is payable
function test_multicall_mint_subscribe_native() public {
uint256 tokenId = lpm.nextTokenId();
Expand Down
8 changes: 4 additions & 4 deletions test/position-managers/PositionManager.gas.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot {
abi.encode(tokenId, config, 10_000 ether, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);

bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));
lpm.modifyLiquidities(calls, _deadline);
snapLastCall("PositionManager_decreaseLiquidity_withTakePair");
}
Expand Down Expand Up @@ -403,7 +403,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot {
abi.encode(tokenId, config, 0, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);

bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));
lpm.modifyLiquidities(calls, _deadline);
snapLastCall("PositionManager_collect_withTakePair");
}
Expand Down Expand Up @@ -485,7 +485,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot {
Plan memory planner = Planner.init().add(
Actions.BURN_POSITION, abi.encode(tokenId, config, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(config.poolKey, address(this));

lpm.modifyLiquidities(calls, _deadline);
snapLastCall("PositionManager_burn_nonEmpty_withTakePair");
Expand Down Expand Up @@ -661,7 +661,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot {
Actions.BURN_POSITION,
abi.encode(tokenId, configNative, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES)
);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(configNative.poolKey);
bytes memory calls = planner.finalizeModifyLiquidityWithTakePair(configNative.poolKey, address(this));

lpm.modifyLiquidities(calls, _deadline);
snapLastCall("PositionManager_burn_nonEmpty_native_withTakePair");
Expand Down
4 changes: 2 additions & 2 deletions test/shared/Planner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ library Planner {
return plan.encode();
}

function finalizeModifyLiquidityWithTakePair(Plan memory plan, PoolKey memory poolKey)
function finalizeModifyLiquidityWithTakePair(Plan memory plan, PoolKey memory poolKey, address takeRecipient)
internal
pure
returns (bytes memory)
{
plan.add(Actions.TAKE_PAIR, abi.encode(poolKey.currency0, poolKey.currency1));
plan.add(Actions.TAKE_PAIR, abi.encode(poolKey.currency0, poolKey.currency1, takeRecipient));
return plan.encode();
}

Expand Down

0 comments on commit e682040

Please sign in to comment.