Skip to content

Commit

Permalink
save
Browse files Browse the repository at this point in the history
  • Loading branch information
pysel committed Nov 24, 2024
1 parent 4c908b2 commit c5df211
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/v4-periphery
Submodule v4-periphery updated 95 files
+1 −1 .forge-snapshots/Payments_swap_settleFromCaller_takeAllToMsgSender.snap
+1 −1 .forge-snapshots/Payments_swap_settleFromCaller_takeAllToSpecifiedAddress.snap
+1 −1 .forge-snapshots/Payments_swap_settleWithBalance_takeAllToMsgSender.snap
+1 −1 .forge-snapshots/Payments_swap_settleWithBalance_takeAllToSpecifiedAddress.snap
+1 −1 .forge-snapshots/PositionManager_burn_empty.snap
+1 −1 .forge-snapshots/PositionManager_burn_empty_native.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_native_withClose.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_native_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_withClose.snap
+1 −1 .forge-snapshots/PositionManager_burn_nonEmpty_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_collect_native.snap
+1 −1 .forge-snapshots/PositionManager_collect_sameRange.snap
+1 −1 .forge-snapshots/PositionManager_collect_withClose.snap
+1 −1 .forge-snapshots/PositionManager_collect_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_decreaseLiquidity_native.snap
+1 −1 .forge-snapshots/PositionManager_decreaseLiquidity_withClose.snap
+1 −1 .forge-snapshots/PositionManager_decreaseLiquidity_withTakePair.snap
+1 −1 .forge-snapshots/PositionManager_decrease_burnEmpty.snap
+1 −1 .forge-snapshots/PositionManager_decrease_burnEmpty_native.snap
+1 −1 .forge-snapshots/PositionManager_decrease_sameRange_allLiquidity.snap
+1 −1 .forge-snapshots/PositionManager_decrease_take_take.snap
+1 −1 .forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap
+1 −1 .forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap
+1 −1 .forge-snapshots/PositionManager_increaseLiquidity_native.snap
+1 −1 .forge-snapshots/PositionManager_increase_autocompoundExactUnclaimedFees.snap
+1 −1 .forge-snapshots/PositionManager_increase_autocompoundExcessFeesCredit.snap
+1 −1 .forge-snapshots/PositionManager_increase_autocompound_clearExcess.snap
+1 −1 .forge-snapshots/PositionManager_mint_native.snap
+1 −1 .forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap
+1 −1 .forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap
+1 −1 .forge-snapshots/PositionManager_mint_onSameTickLower.snap
+1 −1 .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
+1 −1 .forge-snapshots/PositionManager_mint_sameRange.snap
+1 −1 .forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap
+1 −1 .forge-snapshots/PositionManager_mint_warmedPool_differentRange.snap
+1 −1 .forge-snapshots/PositionManager_mint_withClose.snap
+1 −1 .forge-snapshots/PositionManager_mint_withSettlePair.snap
+1 −1 .forge-snapshots/PositionManager_multicall_initialize_mint.snap
+1 −1 .forge-snapshots/PositionManager_subscribe.snap
+1 −1 .forge-snapshots/PositionManager_unsubscribe.snap
+1 −1 .forge-snapshots/V4Router_Bytecode.snap
+1 −1 .forge-snapshots/V4Router_ExactIn1Hop_nativeIn.snap
+1 −1 .forge-snapshots/V4Router_ExactIn1Hop_nativeOut.snap
+1 −1 .forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap
+1 −1 .forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap
+1 −1 .forge-snapshots/V4Router_ExactIn2Hops.snap
+1 −1 .forge-snapshots/V4Router_ExactIn2Hops_nativeIn.snap
+1 −1 .forge-snapshots/V4Router_ExactIn3Hops.snap
+1 −1 .forge-snapshots/V4Router_ExactIn3Hops_nativeIn.snap
+1 −1 .forge-snapshots/V4Router_ExactInputSingle.snap
+1 −1 .forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap
+1 −1 .forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap
+1 −1 .forge-snapshots/V4Router_ExactOut1Hop_nativeIn_sweepETH.snap
+1 −1 .forge-snapshots/V4Router_ExactOut1Hop_nativeOut.snap
+1 −1 .forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap
+1 −1 .forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap
+1 −1 .forge-snapshots/V4Router_ExactOut2Hops.snap
+1 −1 .forge-snapshots/V4Router_ExactOut2Hops_nativeIn.snap
+1 −1 .forge-snapshots/V4Router_ExactOut3Hops.snap
+1 −1 .forge-snapshots/V4Router_ExactOut3Hops_nativeIn.snap
+1 −1 .forge-snapshots/V4Router_ExactOut3Hops_nativeOut.snap
+1 −1 .forge-snapshots/V4Router_ExactOutputSingle.snap
+1 −1 .forge-snapshots/V4Router_ExactOutputSingle_nativeIn_sweepETH.snap
+1 −1 .forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap
+1 −1 .forge-snapshots/positionDescriptor bytecode size.snap
+0 −1 foundry.toml
+1 −1 lib/v4-core
+6 −6 script/DeployQuoter.s.sol
+2 −71 src/PositionManager.sol
+0 −85 src/UniswapV4DeployerCompetition.sol
+6 −1 src/V4Router.sol
+1 −2 src/base/DeltaResolver.sol
+13 −0 src/base/Notifier.sol
+2 −2 src/interfaces/IQuoter.sol
+4 −0 src/interfaces/ISubscriber.sol
+0 −25 src/interfaces/IUniswapV4DeployerCompetition.sol
+6 −6 src/lens/Quoter.sol
+20 −23 src/libraries/Actions.sol
+0 −101 src/libraries/CalldataDecoder.sol
+0 −75 src/libraries/LiquidityAmounts.sol
+0 −97 src/libraries/VanityAddressLib.sol
+31 −31 test/Quoter.t.sol
+0 −178 test/UniswapV4DeployerCompetition.t.sol
+6 −154 test/libraries/CalldataDecoder.t.sol
+0 −101 test/libraries/VanityAddressLib.t.sol
+9 −0 test/mocks/MockBadSubscribers.sol
+0 −47 test/mocks/MockCalldataDecoder.sol
+0 −43 test/mocks/MockFeeOnTransfer.sol
+5 −0 test/mocks/MockSubscriber.sol
+3 −271 test/position-managers/PositionManager.modifyLiquidities.t.sol
+79 −22 test/position-managers/PositionManager.notifier.t.sol
+1 −2 test/router/Payments.gas.t.sol
+31 −4 test/router/Payments.t.sol
+1 −3 test/shared/Planner.sol
+3 −10 test/shared/PosmTestSetup.sol
2 changes: 1 addition & 1 deletion src/ClvrHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {BeforeSwapDelta, BeforeSwapDeltaLibrary, toBeforeSwapDelta } from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
import {StateLibrary} from "v4-core/libraries/StateLibrary.sol";
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

Expand Down
60 changes: 60 additions & 0 deletions test/ClvrHook.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@uniswap/v4-core/src/libraries/StateLibrary.sol";
import {IPositionManager} from "@uniswap/v4-periphery/src/interfaces/IPositionManager.sol";
import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";



import {Test} from "forge-std/Test.sol";
import {console} from "forge-std/console.sol";

import {ClvrHook} from "../src/ClvrHook.sol";
import {EasyPosm} from "./utils/EasyPosm.sol";


import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
import {CurrencyLibrary, Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {PoolSwapTest} from "@uniswap/v4-core/src/test/PoolSwapTest.sol";
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";

import {LiquidityAmounts} from "@uniswap/v4-core/test/utils/LiquidityAmounts.sol";
import {IPositionManager} from "@uniswap/v4-periphery/src/interfaces/IPositionManager.sol";

contract ClvrHookTest is Test, Deployers {
using StateLibrary for IPoolManager;

PoolId poolId;
ClvrHook hook;

function setUp() public {
deployFreshManagerAndRouters();
deployMintAndApprove2Currencies();

address flags = address(
uint160(
Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_DONATE_FLAG
) ^ (0x4444 << 144) // Namespace the hook to avoid collisions
);

bytes memory constructorArgs = abi.encode(manager);
deployCodeTo("ClvrHook.sol:ClvrHook", constructorArgs, flags);
hook = ClvrHook(flags);

key = PoolKey(currency0, currency1, 3000, 60, IHooks(hook));
poolId = key.toId();
manager.initialize(key, SQRT_PRICE_1_1);
}

function testHook() public {
console.log("Hello, World!");
}
}
197 changes: 197 additions & 0 deletions test/utils/EasyPosm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.21;

import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {BalanceDelta, toBalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {IPositionManager} from "v4-periphery/src/interfaces/IPositionManager.sol";
import {Actions} from "v4-periphery/src/libraries/Actions.sol";
import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol";
import {PositionInfo, PositionInfoLibrary} from "v4-periphery/src/libraries/PositionInfoLibrary.sol";

/// @title Easy Position Manager
/// @notice A library for abstracting Position Manager calldata
/// @dev Useable onchain, but expensive because of encoding
library EasyPosm {
using CurrencyLibrary for Currency;
using SafeCast for uint256;
using SafeCast for int256;
using PositionInfoLibrary for PositionInfo;

/// @dev packing data to avoid stack too deep error
struct MintData {
uint256 balance0Before;
uint256 balance1Before;
bytes[] params;
}

/// @dev This function supports sending native tokens (ETH), the amount-to-pay is determined by amount0Max.
/// Any excess amount is NOT refunded since it is not encoding the SWEEP action
function mint(
IPositionManager posm,
PoolKey memory poolKey,
int24 tickLower,
int24 tickUpper,
uint256 liquidity,
uint256 amount0Max,
uint256 amount1Max,
address recipient,
uint256 deadline,
bytes memory hookData
) internal returns (uint256 tokenId, BalanceDelta delta) {
(Currency currency0, Currency currency1) = (poolKey.currency0, poolKey.currency1);

MintData memory mintData = MintData({
balance0Before: currency0.balanceOf(address(this)),
balance1Before: currency1.balanceOf(address(this)),
params: new bytes[](2)
});
mintData.params[0] =
abi.encode(poolKey, tickLower, tickUpper, liquidity, amount0Max, amount1Max, recipient, hookData);
mintData.params[1] = abi.encode(currency0, currency1);

// Mint Liquidity
tokenId = posm.nextTokenId();
uint256 valueToPass = currency0.isAddressZero() ? amount0Max : 0;
posm.modifyLiquidities{value: valueToPass}(
abi.encode(abi.encodePacked(uint8(Actions.MINT_POSITION), uint8(Actions.SETTLE_PAIR)), mintData.params),
deadline
);

delta = toBalanceDelta(
-(mintData.balance0Before - currency0.balanceOf(address(this))).toInt128(),
-(mintData.balance1Before - currency1.balanceOf(address(this))).toInt128()
);
}

function increaseLiquidity(
IPositionManager posm,
uint256 tokenId,
uint256 liquidityToAdd,
uint256 amount0Max,
uint256 amount1Max,
uint256 deadline,
bytes memory hookData
) internal returns (BalanceDelta delta) {
(Currency currency0, Currency currency1) = getCurrencies(posm, tokenId);

bytes[] memory params = new bytes[](3);
params[0] = abi.encode(tokenId, liquidityToAdd, amount0Max, amount1Max, hookData);
params[1] = abi.encode(currency0);
params[2] = abi.encode(currency1);

uint256 balance0Before = currency0.balanceOf(address(this));
uint256 balance1Before = currency1.balanceOf(address(this));

uint256 valueToPass = currency0.isAddressZero() ? amount0Max : 0;
posm.modifyLiquidities{value: valueToPass}(
abi.encode(
abi.encodePacked(
uint8(Actions.INCREASE_LIQUIDITY), uint8(Actions.CLOSE_CURRENCY), uint8(Actions.CLOSE_CURRENCY)
),
params
),
deadline
);

delta = toBalanceDelta(
(currency0.balanceOf(address(this)).toInt256() - balance0Before.toInt256()).toInt128(),
(currency1.balanceOf(address(this)).toInt256() - balance1Before.toInt256()).toInt128()
);
}

function decreaseLiquidity(
IPositionManager posm,
uint256 tokenId,
uint256 liquidityToRemove,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline,
bytes memory hookData
) internal returns (BalanceDelta delta) {
(Currency currency0, Currency currency1) = getCurrencies(posm, tokenId);

bytes[] memory params = new bytes[](2);
params[0] = abi.encode(tokenId, liquidityToRemove, amount0Min, amount1Min, hookData);
params[1] = abi.encode(currency0, currency1, recipient);

uint256 balance0Before = currency0.balanceOf(address(this));
uint256 balance1Before = currency1.balanceOf(address(this));

posm.modifyLiquidities(
abi.encode(abi.encodePacked(uint8(Actions.DECREASE_LIQUIDITY), uint8(Actions.TAKE_PAIR)), params), deadline
);

delta = toBalanceDelta(
(currency0.balanceOf(address(this)) - balance0Before).toInt128(),
(currency1.balanceOf(address(this)) - balance1Before).toInt128()
);
}

function collect(
IPositionManager posm,
uint256 tokenId,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline,
bytes memory hookData
) internal returns (BalanceDelta delta) {
(Currency currency0, Currency currency1) = getCurrencies(posm, tokenId);

bytes[] memory params = new bytes[](2);
// collecting fees is achieved by decreasing liquidity with 0 liquidity removed
params[0] = abi.encode(tokenId, 0, amount0Min, amount1Min, hookData);
params[1] = abi.encode(currency0, currency1, recipient);

uint256 balance0Before = currency0.balanceOf(recipient);
uint256 balance1Before = currency1.balanceOf(recipient);

posm.modifyLiquidities(
abi.encode(abi.encodePacked(uint8(Actions.DECREASE_LIQUIDITY), uint8(Actions.TAKE_PAIR)), params), deadline
);

delta = toBalanceDelta(
(currency0.balanceOf(recipient) - balance0Before).toInt128(),
(currency1.balanceOf(recipient) - balance1Before).toInt128()
);
}

function burn(
IPositionManager posm,
uint256 tokenId,
uint256 amount0Min,
uint256 amount1Min,
address recipient,
uint256 deadline,
bytes memory hookData
) internal returns (BalanceDelta delta) {
(Currency currency0, Currency currency1) = getCurrencies(posm, tokenId);

bytes[] memory params = new bytes[](2);
params[0] = abi.encode(tokenId, 0, amount0Min, amount1Min, hookData);
params[1] = abi.encode(currency0, currency1, recipient);

uint256 balance0Before = currency0.balanceOf(recipient);
uint256 balance1Before = currency1.balanceOf(recipient);

posm.modifyLiquidities(
abi.encode(abi.encodePacked(uint8(Actions.BURN_POSITION), uint8(Actions.TAKE_PAIR)), params), deadline
);

delta = toBalanceDelta(
(currency0.balanceOf(recipient) - balance0Before).toInt128(),
(currency1.balanceOf(recipient) - balance1Before).toInt128()
);
}

function getCurrencies(IPositionManager posm, uint256 tokenId)
internal
view
returns (Currency currency0, Currency currency1)
{
(PoolKey memory key,) = posm.getPoolAndPositionInfo(tokenId);
return (key.currency0, key.currency1);
}
}
88 changes: 88 additions & 0 deletions test/utils/Fixtures.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// // SPDX-License-Identifier: MIT
// pragma solidity ^0.8.24;

// import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
// import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
// import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
// import {PositionManager} from "v4-periphery/src/PositionManager.sol";
// import {IPositionManager} from "v4-periphery/src/interfaces/IPositionManager.sol";
// import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
// import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
// import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol";
// import {IERC20} from "forge-std/interfaces/IERC20.sol";
// import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
// import {DeployPermit2} from "./forks/DeployPermit2.sol";
// import {IERC721Permit_v4} from "v4-periphery/src/interfaces/IERC721Permit_v4.sol";
// import {IEIP712_v4} from "v4-periphery/src/interfaces/IEIP712_v4.sol";
// import {ERC721PermitHash} from "v4-periphery/src/libraries/ERC721PermitHash.sol";
// import {IPositionDescriptor} from "v4-periphery/src/interfaces/IPositionDescriptor.sol";
// import {IWETH9} from "v4-periphery/src/interfaces/external/IWETH9.sol";

// /// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic liquidity operations on posm.
// contract Fixtures is Deployers, DeployPermit2 {
// uint256 constant STARTING_USER_BALANCE = 10_000_000 ether;
// uint256 constant MAX_SLIPPAGE_ADD_LIQUIDITY = type(uint256).max;
// uint256 constant MAX_SLIPPAGE_REMOVE_LIQUIDITY = 0;

// IPositionManager posm;

// function deployAndApprovePosm(IPoolManager poolManager) public {
// deployPosm(poolManager);
// approvePosm();
// }

// function deployPosm(IPoolManager poolManager) internal {
// // We use vm.etch to prevent having to use via-ir in this repository.
// etchPermit2();
// posm = IPositionManager(new PositionManager(poolManager, permit2, 300_000, IPositionDescriptor(address(0)), IWETH9(address(0))));
// }

// function seedBalance(address to) internal {
// IERC20(Currency.unwrap(currency0)).transfer(to, STARTING_USER_BALANCE);
// IERC20(Currency.unwrap(currency1)).transfer(to, STARTING_USER_BALANCE);
// }

// function approvePosm() internal {
// approvePosmCurrency(currency0);
// approvePosmCurrency(currency1);
// }

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

// // Does the same approvals as approvePosm, but for a specific address.
// function approvePosmFor(address addr) internal {
// vm.startPrank(addr);
// approvePosm();
// vm.stopPrank();
// }

// function permit(uint256 privateKey, uint256 tokenId, address operator, uint256 nonce) internal {
// bytes32 digest = getDigest(operator, tokenId, 1, block.timestamp + 1);

// (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
// bytes memory signature = abi.encodePacked(r, s, v);

// vm.prank(operator);
// IERC721Permit_v4(address(posm)).permit(operator, tokenId, block.timestamp + 1, nonce, signature);
// }

// function getDigest(address spender, uint256 tokenId, uint256 nonce, uint256 deadline)
// internal
// view
// returns (bytes32 digest)
// {
// digest = keccak256(
// abi.encodePacked(
// "\x19\x01",
// IEIP712_v4(address(posm)).DOMAIN_SEPARATOR(),
// keccak256(abi.encode(ERC721PermitHash.PERMIT_TYPEHASH, spender, tokenId, nonce, deadline))
// )
// );
// }
// }

0 comments on commit c5df211

Please sign in to comment.