-
Notifications
You must be signed in to change notification settings - Fork 19
/
NTokenUniswapV3.sol
150 lines (133 loc) · 5.35 KB
/
NTokenUniswapV3.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.10;
import {IERC20} from "../../dependencies/openzeppelin/contracts/IERC20.sol";
import {IERC721} from "../../dependencies/openzeppelin/contracts/IERC721.sol";
import {IERC1155} from "../../dependencies/openzeppelin/contracts/IERC1155.sol";
import {IERC721Metadata} from "../../dependencies/openzeppelin/contracts/IERC721Metadata.sol";
import {Address} from "../../dependencies/openzeppelin/contracts/Address.sol";
import {SafeERC20} from "../../dependencies/openzeppelin/contracts/SafeERC20.sol";
import {SafeCast} from "../../dependencies/openzeppelin/contracts/SafeCast.sol";
import {Errors} from "../libraries/helpers/Errors.sol";
import {WadRayMath} from "../libraries/math/WadRayMath.sol";
import {IPool} from "../../interfaces/IPool.sol";
import {NToken} from "./NToken.sol";
import {DataTypes} from "../libraries/types/DataTypes.sol";
import {INonfungiblePositionManager} from "../../dependencies/uniswap/INonfungiblePositionManager.sol";
import {IWETH} from "../../misc/interfaces/IWETH.sol";
import {XTokenType} from "../../interfaces/IXTokenType.sol";
import {INTokenUniswapV3} from "../../interfaces/INTokenUniswapV3.sol";
/**
* @title UniswapV3 NToken
*
* @notice Implementation of the interest bearing token for the ParaSpace protocol
*/
contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
using SafeERC20 for IERC20;
/**
* @dev Constructor.
* @param pool The address of the Pool contract
*/
constructor(IPool pool) NToken(pool, true) {
_ERC721Data.balanceLimit = 30;
}
function getXTokenType() external pure override returns (XTokenType) {
return XTokenType.NTokenUniswapV3;
}
/**
* @notice A function that decreases the current liquidity.
* @param tokenId The id of the erc721 token
* @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
*/
function _decreaseLiquidity(
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
);
}
(
,
,
address token0,
address token1,
,
,
,
,
,
,
,
) = INonfungiblePositionManager(_underlyingAsset).positions(tokenId);
address weth = _addressesProvider.getWETH();
receiveEthAsWeth = (receiveEthAsWeth &&
(token0 == weth || token1 == weth));
INonfungiblePositionManager.CollectParams
memory collectParams = INonfungiblePositionManager.CollectParams({
tokenId: tokenId,
recipient: receiveEthAsWeth ? address(this) : user,
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
});
(amount0, amount1) = INonfungiblePositionManager(_underlyingAsset)
.collect(collectParams);
if (receiveEthAsWeth) {
uint256 balanceWeth = IERC20(weth).balanceOf(address(this));
if (balanceWeth > 0) {
IWETH(weth).withdraw(balanceWeth);
_safeTransferETH(user, balanceWeth);
}
address pairToken = (token0 == weth) ? token1 : token0;
uint256 balanceToken = IERC20(pairToken).balanceOf(address(this));
if (balanceToken > 0) {
IERC20(pairToken).safeTransfer(user, balanceToken);
}
}
}
/// @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");
}
receive() external payable {}
}