Skip to content
Closed
Show file tree
Hide file tree
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
13 changes: 9 additions & 4 deletions contracts/interfaces/INTokenUniswapV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ interface 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
*/
function decreaseUniswapV3Liquidity(
address user,
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min,
bool receiveEthAsWeth
) external;
uint256 amount1Min
)
external
returns (
address token0,
address token1,
uint256 amount0,
uint256 amount1
);
}
4 changes: 1 addition & 3 deletions contracts/interfaces/IPoolCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,13 @@ interface IPoolCore {
* @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
*/
function decreaseUniswapV3Liquidity(
address asset,
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min,
bool receiveEthAsWeth
uint256 amount1Min
) external;

/**
Expand Down
87 changes: 66 additions & 21 deletions contracts/protocol/libraries/logic/SupplyLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {XTokenType} from "../../../interfaces/IXTokenType.sol";
import {INTokenUniswapV3} from "../../../interfaces/INTokenUniswapV3.sol";
import {INTokenStakefish} from "../../../interfaces/INTokenStakefish.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {IPriceOracleGetter} from "../../../interfaces/IPriceOracleGetter.sol";
import {IStakefishNFTManager} from "../../../interfaces/IStakefishNFTManager.sol";
import {IStakefishValidator} from "../../../interfaces/IStakefishValidator.sol";
import {Helpers} from "../helpers/Helpers.sol";
Expand Down Expand Up @@ -88,7 +89,7 @@ library SupplyLogic {
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ExecuteSupplyParams memory params
) external {
) public {
DataTypes.ReserveData storage reserve = reservesData[params.asset];
DataTypes.ReserveCache memory reserveCache = reserve.cache();

Expand Down Expand Up @@ -445,13 +446,26 @@ library SupplyLogic {
DataTypes.ReserveData storage reserve,
DataTypes.ExecuteWithdrawERC721Params memory params
) internal returns (uint64, uint64) {
uint256 amount = 0;
INToken nToken = INToken(xTokenAddress);
if (nToken.getXTokenType() == XTokenType.NTokenUniswapV3) {
uint256 tokenIdLength = params.tokenIds.length;
for (uint256 index = 0; index < tokenIdLength; index++) {
amount += IPriceOracleGetter(params.oracle).getTokenPrice(
params.asset,
params.tokenIds[index]
);
}
} else {
amount = params.tokenIds.length;
}
DataTypes.TimeLockParams memory timeLockParams = GenericLogic
.calculateTimeLockParams(
reserve,
DataTypes.TimeLockFactorParams({
assetType: DataTypes.AssetType.ERC721,
asset: params.asset,
amount: params.tokenIds.length
amount: amount
})
);
timeLockParams.actionType = DataTypes.TimeLockActionType.WITHDRAW;
Expand All @@ -467,7 +481,6 @@ library SupplyLogic {

function executeDecreaseUniswapV3Liquidity(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ExecuteDecreaseUniswapV3LiquidityParams memory params
) external {
Expand All @@ -491,29 +504,61 @@ library SupplyLogic {
tokenIds
);

INTokenUniswapV3(reserveCache.xTokenAddress).decreaseUniswapV3Liquidity(
params.user,
params.tokenId,
params.liquidityDecrease,
params.amount0Min,
params.amount1Min,
params.receiveEthAsWeth
);

(
address token0,
address token1,
uint256 amount0,
uint256 amount1
) = INTokenUniswapV3(reserveCache.xTokenAddress)
.decreaseUniswapV3Liquidity(
params.user,
params.tokenId,
params.liquidityDecrease,
params.amount0Min,
params.amount1Min
);
bool isUsedAsCollateral = ICollateralizableERC721(
reserveCache.xTokenAddress
).isUsedAsCollateral(params.tokenId);
if (isUsedAsCollateral) {
if (userConfig.isBorrowingAny()) {
ValidationLogic.validateHFAndLtvERC721(
if (amount0 > 0) {
executeSupply(
reservesData,
userConfig,
DataTypes.ExecuteSupplyParams({
asset: token0,
amount: amount0,
onBehalfOf: params.user,
payer: address(this),
referralCode: 0
})
);
if (isUsedAsCollateral) {
Helpers.setAssetUsedAsCollateral(
userConfig,
reservesData,
reservesList,
token0,
params.user
);
}
}
if (amount1 > 0) {
executeSupply(
reservesData,
userConfig,
DataTypes.ExecuteSupplyParams({
asset: token1,
amount: amount1,
onBehalfOf: params.user,
payer: address(this),
referralCode: 0
})
);
if (isUsedAsCollateral) {
Helpers.setAssetUsedAsCollateral(
userConfig,
params.asset,
tokenIds,
params.user,
params.reservesCount,
params.oracle
reservesData,
token1,
params.user
);
}
}
Expand Down
2 changes: 0 additions & 2 deletions contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,6 @@ library DataTypes {
uint128 liquidityDecrease;
uint256 amount0Min;
uint256 amount1Min;
bool receiveEthAsWeth;
address oracle;
}

struct FinalizeTransferParams {
Expand Down
8 changes: 2 additions & 6 deletions contracts/protocol/pool/PoolCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -242,15 +242,13 @@ contract PoolCore is
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min,
bool receiveEthAsWeth
uint256 amount1Min
) external virtual override nonReentrant {
DataTypes.PoolStorage storage ps = poolStorage();

return
SupplyLogic.executeDecreaseUniswapV3Liquidity(
ps._reserves,
ps._reservesList,
ps._usersConfig[msg.sender],
DataTypes.ExecuteDecreaseUniswapV3LiquidityParams({
user: msg.sender,
Expand All @@ -259,9 +257,7 @@ contract PoolCore is
reservesCount: ps._reservesCount,
liquidityDecrease: liquidityDecrease,
amount0Min: amount0Min,
amount1Min: amount1Min,
receiveEthAsWeth: receiveEthAsWeth,
oracle: ADDRESSES_PROVIDER.getPriceOracle()
amount1Min: amount1Min
})
);
}
Expand Down
88 changes: 35 additions & 53 deletions contracts/protocol/tokenization/NTokenUniswapV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,25 @@ 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 token0 The address of token0
* @return token1 The address of token1
* @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) {
uint256 amount1Min
)
internal
returns (
address token0,
address token1,
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
Expand All @@ -76,52 +83,21 @@ contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
.decreaseLiquidity(params);
}

(
,
,
address token0,
address token1,
,
,
,
,
,
,
,

) = INonfungiblePositionManager(_ERC721Data.underlyingAsset).positions(
tokenId
);

address weth = _addressesProvider.getWETH();
receiveEthAsWeth = (receiveEthAsWeth &&
(token0 == weth || token1 == weth));
(, , token0, token1, , , , , , , , ) = INonfungiblePositionManager(
_ERC721Data.underlyingAsset
).positions(tokenId);

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

(amount0, amount1) = INonfungiblePositionManager(
_ERC721Data.underlyingAsset
).collect(collectParams);

if (receiveEthAsWeth) {
uint256 balanceWeth = IERC20(weth).balanceOf(address(this));
if (balanceWeth > 0) {
IWETH(weth).withdraw(balanceWeth);
Helpers.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
Expand All @@ -130,20 +106,28 @@ contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
uint256 tokenId,
uint128 liquidityDecrease,
uint256 amount0Min,
uint256 amount1Min,
bool receiveEthAsWeth
) external onlyPool nonReentrant {
uint256 amount1Min
)
external
onlyPool
nonReentrant
returns (
address token0,
address token1,
uint256 amount0,
uint256 amount1
)
{
require(user == ownerOf(tokenId), Errors.NOT_THE_OWNER);

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

function setTraitsMultipliers(uint256[] calldata, uint256[] calldata)
Expand All @@ -154,6 +138,4 @@ contract NTokenUniswapV3 is NToken, INTokenUniswapV3 {
{
revert();
}

receive() external payable {}
}
2 changes: 1 addition & 1 deletion helpers/hardhat-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export const MULTI_SEND_CHUNK_SIZE = parseInt(

export const VERSION = version;
export const COMMIT = git.short();
export const COMPILER_OPTIMIZER_RUNS = 800;
export const COMPILER_OPTIMIZER_RUNS = 200;
export const COMPILER_VERSION = "0.8.10";
export const PKG_DATA = {
version: VERSION,
Expand Down
2 changes: 1 addition & 1 deletion lib/ds-test
Loading