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

Fix/use balance diff mode while decreasing liquidity #315

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all 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
106 changes: 46 additions & 60 deletions contracts/protocol/tokenization/NTokenUniswapV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
* @param pool The address of the Pool contract
*/
constructor(IPool pool) NToken(pool, true) {
_ERC721Data.balanceLimit = 30;
_ERC721Data.balanceLimit = 5;
}

function getXTokenType() external pure override returns (XTokenType) {
Expand All @@ -44,35 +44,17 @@ contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
* @param liquidityDecrease The amount of liquidity to remove of LP
* @param amount0Min The minimum amount to remove of token0
* @param amount1Min The minimum amount to remove of token1
* @param receiveEthAsWeth If convert weth to ETH
* @return amount0 The amount received back in token0
* @return amount1 The amount returned back in token1
* @param receiveETH If convert weth to ETH
*/
function _decreaseLiquidity(
function decreaseUniswapV3Liquidity(
address user,
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min,
bool receiveEthAsWeth
) internal returns (uint256 amount0, uint256 amount1) {
if (liquidityDecrease > 0) {
// amount0Min and amount1Min are price slippage checks
// if the amount received after burning is not greater than these minimums, transaction will fail
INonfungiblePositionManager.DecreaseLiquidityParams
memory params = INonfungiblePositionManager
.DecreaseLiquidityParams({
tokenId: tokenId,
liquidity: liquidityDecrease,
amount0Min: amount0Min,
amount1Min: amount1Min,
deadline: block.timestamp
});

INonfungiblePositionManager(_underlyingAsset).decreaseLiquidity(
params
);
}
bool receiveETH
) external onlyPool nonReentrant {
require(user == ownerOf(tokenId), Errors.NOT_THE_OWNER);

(
,
Expand All @@ -90,57 +72,61 @@ contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
) = INonfungiblePositionManager(_underlyingAsset).positions(tokenId);

address weth = _addressesProvider.getWETH();
receiveEthAsWeth = (receiveEthAsWeth &&
(token0 == weth || token1 == weth));
(token0, token1) = receiveETH && token1 == weth
? (token1, token0)
: (token0, token1);
receiveETH = receiveETH && token0 == weth;
(uint256 balance0Before, uint256 balance1Before) = receiveETH
? (
IERC20(token0).balanceOf(address(this)),
IERC20(token1).balanceOf(address(this))
)
: (0, 0);

if (liquidityDecrease > 0) {
// amount0Min and amount1Min are price slippage checks
// if the amount received after burning is not greater than these minimums, transaction will fail
INonfungiblePositionManager.DecreaseLiquidityParams
memory params = INonfungiblePositionManager
.DecreaseLiquidityParams({
tokenId: tokenId,
liquidity: liquidityDecrease,
amount0Min: amount0Min,
amount1Min: amount1Min,
deadline: block.timestamp
});

INonfungiblePositionManager(_underlyingAsset).decreaseLiquidity(
params
);
}

INonfungiblePositionManager.CollectParams
memory collectParams = INonfungiblePositionManager.CollectParams({
tokenId: tokenId,
recipient: receiveEthAsWeth ? address(this) : user,
recipient: receiveETH ? address(this) : user,
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
});

(amount0, amount1) = INonfungiblePositionManager(_underlyingAsset)
.collect(collectParams);
INonfungiblePositionManager(_underlyingAsset).collect(collectParams);

if (receiveEthAsWeth) {
uint256 balanceWeth = IERC20(weth).balanceOf(address(this));
if (balanceWeth > 0) {
IWETH(weth).withdraw(balanceWeth);
_safeTransferETH(user, balanceWeth);
if (receiveETH) {
uint256 balance0Diff = IERC20(token0).balanceOf(address(this)) -
balance0Before;
if (balance0Diff > 0) {
IWETH(token0).withdraw(balance0Diff);
_safeTransferETH(user, balance0Diff);
}

address pairToken = (token0 == weth) ? token1 : token0;
uint256 balanceToken = IERC20(pairToken).balanceOf(address(this));
if (balanceToken > 0) {
IERC20(pairToken).safeTransfer(user, balanceToken);
uint256 balance1Diff = IERC20(token1).balanceOf(address(this)) -
balance1Before;
if (balance1Diff > 0) {
IERC20(token1).safeTransfer(user, balance1Diff);
}
}
}

/// @inheritdoc INTokenUniswapV3
function decreaseUniswapV3Liquidity(
address user,
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min,
bool receiveEthAsWeth
) external onlyPool nonReentrant {
require(user == ownerOf(tokenId), Errors.NOT_THE_OWNER);

// interact with Uniswap V3
_decreaseLiquidity(
user,
tokenId,
liquidityDecrease,
amount0Min,
amount1Min,
receiveEthAsWeth
);
}

function _safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "ETH_TRANSFER_FAILED");
Expand Down