Files
v4-periphery/test/shared/HookModifyLiquidities.sol

84 lines
3.4 KiB
Solidity

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {Currency} from "@luxamm/v4-core/src/types/Currency.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "@luxamm/v4-core/src/types/BeforeSwapDelta.sol";
import {PoolKey} from "@luxamm/v4-core/src/types/PoolKey.sol";
import {BalanceDelta, BalanceDeltaLibrary} from "@luxamm/v4-core/src/types/BalanceDelta.sol";
import {HookSavesDelta} from "./HookSavesDelta.sol";
import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {IPositionManager} from "../../src/interfaces/IPositionManager.sol";
import {ModifyLiquidityParams, SwapParams} from "@luxamm/v4-core/src/types/PoolOperation.sol";
/// @notice This contract is NOT a production use contract. It is meant to be used in testing to verify that external contracts can modify liquidity without a lock (IPositionManager.modifyLiquiditiesWithoutUnlock)
/// @dev a hook that can modify liquidity in beforeSwap
contract HookModifyLiquidities is HookSavesDelta {
IPositionManager posm;
IAllowanceTransfer permit2;
function setAddresses(IPositionManager _posm, IAllowanceTransfer _permit2) external {
posm = _posm;
permit2 = _permit2;
}
function beforeSwap(
address, /* sender **/
PoolKey calldata key, /* key **/
SwapParams calldata, /* params **/
bytes calldata hookData
)
external
override
returns (bytes4, BeforeSwapDelta, uint24)
{
approvePosmCurrency(key.currency0);
approvePosmCurrency(key.currency1);
(bytes memory actions, bytes[] memory params) = abi.decode(hookData, (bytes, bytes[]));
posm.modifyLiquiditiesWithoutUnlock(actions, params);
return (this.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
}
function beforeAddLiquidity(
address, /* sender **/
PoolKey calldata, /* key **/
ModifyLiquidityParams calldata, /* params **/
bytes calldata hookData
)
external
override
returns (bytes4)
{
if (hookData.length > 0) {
(bytes memory actions, bytes[] memory params) = abi.decode(hookData, (bytes, bytes[]));
posm.modifyLiquiditiesWithoutUnlock(actions, params);
}
return this.beforeAddLiquidity.selector;
}
function beforeRemoveLiquidity(
address, /* sender **/
PoolKey calldata, /* key **/
ModifyLiquidityParams calldata, /* params **/
bytes calldata hookData
) external override returns (bytes4) {
if (hookData.length > 0) {
(bytes memory actions, bytes[] memory params) = abi.decode(hookData, (bytes, bytes[]));
posm.modifyLiquiditiesWithoutUnlock(actions, params);
}
return this.beforeRemoveLiquidity.selector;
}
function approvePosmCurrency(Currency currency) internal {
// Because POSM uses permit2, we must execute 2 permits/approvals.
// 1. First, the caller must approve permit2 on the token.
IERC20(Currency.unwrap(currency)).approve(address(permit2), type(uint256).max);
// 2. Then, the caller must approve POSM as a spender of permit2. TODO: This could also be a signature.
permit2.approve(Currency.unwrap(currency), address(posm), type(uint160).max, type(uint48).max);
}
}