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

Add wrap, unwrap functionality #369

Merged
merged 17 commits into from
Oct 24, 2024
4 changes: 3 additions & 1 deletion script/DeployPosm.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {PositionManager} from "../src/PositionManager.sol";
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {IPositionDescriptor} from "../src/interfaces/IPositionDescriptor.sol";
import {PositionDescriptor} from "../src/PositionDescriptor.sol";
import {IWETH9} from "../src/interfaces/external/IWETH9.sol";

contract DeployPosmTest is Script {
function setUp() public {}
Expand All @@ -30,7 +31,8 @@ contract DeployPosmTest is Script {
IPoolManager(poolManager),
IAllowanceTransfer(permit2),
unsubscribeGasLimit,
IPositionDescriptor(address(positionDescriptor))
IPositionDescriptor(address(positionDescriptor)),
IWETH9(wrappedNative)
);
console2.log("PositionManager", address(posm));

Expand Down
9 changes: 7 additions & 2 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {CalldataDecoder} from "./libraries/CalldataDecoder.sol";
import {Permit2Forwarder} from "./base/Permit2Forwarder.sol";
import {SlippageCheck} from "./libraries/SlippageCheck.sol";
import {PositionInfo, PositionInfoLibrary} from "./libraries/PositionInfoLibrary.sol";
import {NativeWrapper} from "./base/NativeWrapper.sol";
import {IWETH9} from "./interfaces/external/IWETH9.sol";

// 444444444
// 444444444444 444444
Expand Down Expand Up @@ -102,7 +104,8 @@ contract PositionManager is
ReentrancyLock,
BaseActionsRouter,
Notifier,
Permit2Forwarder
Permit2Forwarder,
NativeWrapper
{
using PoolIdLibrary for PoolKey;
using StateLibrary for IPoolManager;
Expand All @@ -126,12 +129,14 @@ contract PositionManager is
IPoolManager _poolManager,
IAllowanceTransfer _permit2,
uint256 _unsubscribeGasLimit,
IPositionDescriptor _tokenDescriptor
IPositionDescriptor _tokenDescriptor,
IWETH9 _weth9
)
BaseActionsRouter(_poolManager)
Permit2Forwarder(_permit2)
ERC721Permit_v4("Uniswap v4 Positions NFT", "UNI-V4-POSM")
Notifier(_unsubscribeGasLimit)
NativeWrapper(_weth9)
{
tokenDescriptor = _tokenDescriptor;
}
Expand Down
26 changes: 26 additions & 0 deletions src/base/NativeWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IWETH9} from "../interfaces/external/IWETH9.sol";
import {ActionConstants} from "../libraries/ActionConstants.sol";

/// @title Native Wrapper
/// @notice Allows wrapping and unwrapping of native tokens before or after adding/removing liquidity
contract NativeWrapper {
IWETH9 public immutable WETH9;
snreynolds marked this conversation as resolved.
Show resolved Hide resolved

constructor(IWETH9 _weth9) {
WETH9 = _weth9;
}

function wrap(uint256 _amount) external payable {
uint256 amount = _amount == ActionConstants.CONTRACT_BALANCE ? address(this).balance : _amount;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be worth added 2 extra checks to each of these functions

  1. if amount > balance revert - so that theres a nice custom error?
  2. only deposit (or withdraw) if amount != 0. As someone might pass in CONTRACT_BALANCE and the current balance is 0 so then deposit/withdraw shouldnt be called

So maybe like

        if (amount == ActionConstants.CONTRACT_BALANCE) {
            amount = address(this).balance;
        } else if (amount > address(this).balance) {
            revert InsufficientETH();
        }
        if (amount > 0) WETH9.deposit{value: amount}();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call out!

WETH9.deposit{value: amount}();
}

/// @dev payable so it can be multicalled
function unwrap(uint256 _amount) external payable {
uint256 amount = _amount == ActionConstants.CONTRACT_BALANCE ? WETH9.balanceOf(address(this)) : _amount;
WETH9.withdraw(amount);
}
}
13 changes: 13 additions & 0 deletions src/interfaces/external/IWETH9.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

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

/// @title Interface for WETH9
interface IWETH9 is IERC20 {
/// @notice Deposit ether to get wrapped ether
function deposit() external payable;

/// @notice Withdraw wrapped ether to get ether
function withdraw(uint256) external;
}
5 changes: 4 additions & 1 deletion test/shared/PosmTestSetup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {HookSavesDelta} from "./HookSavesDelta.sol";
import {HookModifyLiquidities} from "./HookModifyLiquidities.sol";
import {PositionDescriptor} from "../../src/PositionDescriptor.sol";
import {ERC721PermitHash} from "../../src/libraries/ERC721PermitHash.sol";
import {IWETH9} from "../../src/interfaces/external/IWETH9.sol";
import {WETH} from "solmate/src/tokens/WETH.sol";

/// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic liquidity operations on posm.
contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations {
Expand All @@ -26,6 +28,7 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations {
PositionDescriptor public positionDescriptor;
HookSavesDelta hook;
address hookAddr = address(uint160(Hooks.AFTER_ADD_LIQUIDITY_FLAG | Hooks.AFTER_REMOVE_LIQUIDITY_FLAG));
IWETH9 public _WETH9 = IWETH9(address(new WETH()));

HookModifyLiquidities hookModifyLiquidities;
address hookModifyLiquiditiesAddr = address(
Expand Down Expand Up @@ -60,7 +63,7 @@ contract PosmTestSetup is Test, Deployers, DeployPermit2, LiquidityOperations {
// We use deployPermit2() to prevent having to use via-ir in this repository.
permit2 = IAllowanceTransfer(deployPermit2());
positionDescriptor = new PositionDescriptor(poolManager, 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, "ETH");
lpm = new PositionManager(poolManager, permit2, 100_000, positionDescriptor);
lpm = new PositionManager(poolManager, permit2, 100_000, positionDescriptor, _WETH9);
}

function seedBalance(address to) internal {
Expand Down
Loading