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

Rip Out Vanilla #138

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .forge-snapshots/autocompound_exactUnclaimedFees.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
300126
299380
Original file line number Diff line number Diff line change
@@ -1 +1 @@
239588
238844
2 changes: 1 addition & 1 deletion .forge-snapshots/autocompound_excessFeesCredit.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
320665
319919
2 changes: 1 addition & 1 deletion .forge-snapshots/decreaseLiquidity_erc20.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
215187
214439
2 changes: 1 addition & 1 deletion .forge-snapshots/decreaseLiquidity_erc6909.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
215199
214451
2 changes: 1 addition & 1 deletion .forge-snapshots/increaseLiquidity_erc20.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
195029
194596
2 changes: 1 addition & 1 deletion .forge-snapshots/increaseLiquidity_erc6909.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
195041
194608
2 changes: 1 addition & 1 deletion .forge-snapshots/mintWithLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
512049
513548
102 changes: 29 additions & 73 deletions contracts/NonfungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,35 +51,33 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
ERC721Permit("Uniswap V4 Positions NFT-V1", "UNI-V4-POS", "1")
{}

function unlockAndExecute(bytes[] memory data, Currency[] memory currencies) public returns (bytes memory) {
function unlockAndExecute(bytes[] memory data, Currency[] memory currencies) public returns (int128[] memory) {
msgSender = msg.sender;
return manager.unlock(abi.encode(data, currencies));
return abi.decode(manager.unlock(abi.encode(data, currencies)), (int128[]));
}

function _unlockCallback(bytes calldata payload) internal override returns (bytes memory) {
(bytes[] memory data, Currency[] memory currencies) = abi.decode(payload, (bytes[], Currency[]));

bool success;
bytes memory returnData;

for (uint256 i; i < data.length; i++) {
// TODO: bubble up the return
(success, returnData) = address(this).call(data[i]);
(success,) = address(this).call(data[i]);
Copy link
Member

Choose a reason for hiding this comment

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

I rlly wish we could just parse selector and internally call.. now that I wanna add this modifer :(

if (!success) revert("EXECUTE_FAILED");
}

// close the deltas
int128[] memory returnData = new int128[](currencies.length);
for (uint256 i; i < currencies.length; i++) {
currencies[i].close(manager, msgSender);
returnData[i] = currencies[i].close(manager, msgSender);
currencies[i].close(manager, address(this));
}

// Should just be returning the netted amount that was settled on behalf of the caller (msgSender)
// And any recipient deltas settled earlier.

// TODO: @sara handle the return
// vanilla: return int128[2]
// batch: return int128[data.length]
return returnData;
// TODO: any recipient deltas settled earlier.
// @comment sauce: i dont think we can return recipient deltas since we cant parse the payload
return abi.encode(returnData);
}

// NOTE: more gas efficient as LiquidityAmounts is used offchain
Expand All @@ -90,26 +88,14 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
uint256 deadline,
address owner,
bytes calldata hookData
) public payable returns (BalanceDelta delta) {
// TODO: optimization, read/write manager.isUnlocked to avoid repeated external calls for batched execution
if (manager.isUnlocked()) {
saucepoint marked this conversation as resolved.
Show resolved Hide resolved
_increaseLiquidity(owner, range, liquidity, hookData);

// mint receipt token
uint256 tokenId;
_mint(owner, (tokenId = nextTokenId++));
tokenPositions[tokenId] = TokenPosition({owner: owner, range: range});
} else {
msgSender = msg.sender;
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.mint.selector, range, liquidity, deadline, owner, hookData);

Currency[] memory currencies = new Currency[](2);
currencies[0] = range.poolKey.currency0;
currencies[1] = range.poolKey.currency1;
bytes memory result = unlockAndExecute(data, currencies);
delta = abi.decode(result, (BalanceDelta));
}
) external payable {
// TODO: security -- what happens if PoolManager is already unlocked by UR???
_increaseLiquidity(owner, range, liquidity, hookData);

// mint receipt token
uint256 tokenId;
_mint(owner, (tokenId = nextTokenId++));
tokenPositions[tokenId] = TokenPosition({owner: owner, range: range});
}

// NOTE: more expensive since LiquidityAmounts is used onchain
Expand All @@ -135,43 +121,21 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
function increaseLiquidity(uint256 tokenId, uint256 liquidity, bytes calldata hookData, bool claims)
external
isAuthorizedForToken(tokenId)
returns (BalanceDelta delta)
{
TokenPosition memory tokenPos = tokenPositions[tokenId];

if (manager.isUnlocked()) {
_increaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData);
} else {
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.increaseLiquidity.selector, tokenId, liquidity, hookData, claims);

Currency[] memory currencies = new Currency[](2);
currencies[0] = tokenPos.range.poolKey.currency0;
currencies[1] = tokenPos.range.poolKey.currency1;
bytes memory result = unlockAndExecute(data, currencies);
delta = abi.decode(result, (BalanceDelta));
}
// TODO: security -- what happens if PoolManager is already unlocked by UR???
_increaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData);
}

function decreaseLiquidity(uint256 tokenId, uint256 liquidity, bytes calldata hookData, bool claims)
public
external
isAuthorizedForToken(tokenId)
returns (BalanceDelta delta)
{
TokenPosition memory tokenPos = tokenPositions[tokenId];

if (manager.isUnlocked()) {
_decreaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData);
} else {
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.decreaseLiquidity.selector, tokenId, liquidity, hookData, claims);

Currency[] memory currencies = new Currency[](2);
currencies[0] = tokenPos.range.poolKey.currency0;
currencies[1] = tokenPos.range.poolKey.currency1;
bytes memory result = unlockAndExecute(data, currencies);
delta = abi.decode(result, (BalanceDelta));
}
// TODO: security -- what happens if PoolManager is already unlocked by UR???
_decreaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData);
}

// TODO return type?
Expand All @@ -187,22 +151,14 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
}

// TODO: in v3, we can partially collect fees, but what was the usecase here?
function collect(uint256 tokenId, address recipient, bytes calldata hookData, bool claims)
public
returns (BalanceDelta delta)
{
function collect(uint256 tokenId, address recipient, bytes calldata hookData, bool claims) external {
TokenPosition memory tokenPos = tokenPositions[tokenId];
if (manager.isUnlocked()) {
_collect(recipient, tokenPos.range, hookData);
} else {
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.collect.selector, tokenId, recipient, hookData, claims);

Currency[] memory currencies = new Currency[](2);
currencies[0] = tokenPos.range.poolKey.currency0;
currencies[1] = tokenPos.range.poolKey.currency1;
bytes memory result = unlockAndExecute(data, currencies);
delta = abi.decode(result, (BalanceDelta));

// TODO: security -- what happens if PoolManager is already unlocked by UR???
_collect(recipient, tokenPos.range, hookData);
if (recipient != _msgSenderInternal()) {
saucepoint marked this conversation as resolved.
Show resolved Hide resolved
tokenPos.range.poolKey.currency0.close(manager, recipient);
tokenPos.range.poolKey.currency1.close(manager, recipient);
}
}

Expand Down
19 changes: 5 additions & 14 deletions contracts/interfaces/INonfungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface INonfungiblePositionManager {
uint256 deadline,
address recipient,
bytes calldata hookData
) external payable returns (BalanceDelta delta);
) external payable;

// NOTE: more expensive since LiquidityAmounts is used onchain
// function mint(MintParams calldata params) external payable returns (uint256 tokenId, BalanceDelta delta);
Expand All @@ -28,20 +28,14 @@ interface INonfungiblePositionManager {
/// @param liquidity The amount of liquidity to add
/// @param hookData Arbitrary data passed to the hook
/// @param claims Whether the liquidity increase uses ERC-6909 claim tokens
/// @return delta Corresponding balance changes as a result of increasing liquidity
function increaseLiquidity(uint256 tokenId, uint256 liquidity, bytes calldata hookData, bool claims)
external
returns (BalanceDelta delta);
function increaseLiquidity(uint256 tokenId, uint256 liquidity, bytes calldata hookData, bool claims) external;

/// @notice Decrease liquidity for an existing position
/// @param tokenId The ID of the position
/// @param liquidity The amount of liquidity to remove
/// @param hookData Arbitrary data passed to the hook
/// @param claims Whether the removed liquidity is sent as ERC-6909 claim tokens
/// @return delta Corresponding balance changes as a result of decreasing liquidity applied to user (number of tokens credited to tokensOwed)
function decreaseLiquidity(uint256 tokenId, uint256 liquidity, bytes calldata hookData, bool claims)
external
returns (BalanceDelta delta);
function decreaseLiquidity(uint256 tokenId, uint256 liquidity, bytes calldata hookData, bool claims) external;

// TODO Can decide if we want burn to auto encode a decrease/collect.
/// @notice Burn a position and delete the tokenId
Expand All @@ -56,15 +50,12 @@ interface INonfungiblePositionManager {
/// @param recipient The address to send the collected tokens to
/// @param hookData Arbitrary data passed to the hook
/// @param claims Whether the collected fees are sent as ERC-6909 claim tokens
/// @return delta Corresponding balance changes as a result of collecting fees
function collect(uint256 tokenId, address recipient, bytes calldata hookData, bool claims)
external
returns (BalanceDelta delta);
function collect(uint256 tokenId, address recipient, bytes calldata hookData, bool claims) external;

/// @notice Execute a batch of external calls by unlocking the PoolManager
/// @param data an array of abi.encodeWithSelector(<selector>, <args>) for each call
/// @return delta The final delta changes of the caller
function unlockAndExecute(bytes[] memory data, Currency[] memory currencies) external returns (bytes memory);
function unlockAndExecute(bytes[] memory data, Currency[] memory currencies) external returns (int128[] memory);

/// @notice Returns the fees owed for a position. Includes unclaimed fees + custodied fees + claimable fees
/// @param tokenId The ID of the position
Expand Down
7 changes: 3 additions & 4 deletions contracts/libraries/TransientLiquidityDelta.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,18 @@ library TransientLiquidityDelta {
}
}

function close(Currency currency, IPoolManager manager, address holder) internal {
function close(Currency currency, IPoolManager manager, address holder) internal returns (int128 delta) {
// getDelta(currency, holder);
bytes32 hashSlot = _computeSlot(holder, currency);
int256 delta;
assembly {
delta := tload(hashSlot)
}

// TODO support claims field
if (delta < 0) {
currency.settle(manager, holder, uint256(-delta), false);
currency.settle(manager, holder, uint256(-int256(delta)), false);
} else {
currency.take(manager, holder, uint256(delta), false);
currency.take(manager, holder, uint256(int256(delta)), false);
}

// setDelta(0);
Expand Down
Loading
Loading