Skip to content
Open
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
5 changes: 4 additions & 1 deletion contracts/interfaces/IPoolCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ interface IPoolCore {
* @param liquidationAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param borrower The address of the borrower getting liquidated
* @param liquidationAmount The debt amount of borrowed `asset` the liquidator wants to cover
* @param creditAmount The credit amount of liquidation `asset` the liquidator wants to use
* @param liquidatedCollateralTokenId The token id of ERC721 asset received by the liquidator
* @param liquidator The address of the liquidator
* @param receiveNToken True if the liquidators wants to receive the collateral NTokens, `false` if he wants
Expand All @@ -154,6 +155,7 @@ interface IPoolCore {
address indexed liquidationAsset,
address indexed borrower,
uint256 liquidationAmount,
uint256 creditAmount,
uint256 liquidatedCollateralTokenId,
address liquidator,
bool receiveNToken
Expand Down Expand Up @@ -439,7 +441,8 @@ interface IPoolCore {
address collateralAsset,
address user,
uint256 collateralTokenId,
uint256 liquidationAmount,
uint256 maxLiquidationAmount,
uint256 creditAmount,
bool receiveNToken
) external payable;

Expand Down
1 change: 1 addition & 0 deletions contracts/mocks/upgradeability/MockPoolCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ contract PoolCoreV2 is
address,
uint256,
uint256,
uint256,
bool
) external payable virtual override nonReentrant {
revert(EMEGENCY_DISABLE_CALL);
Expand Down
135 changes: 105 additions & 30 deletions contracts/protocol/libraries/logic/LiquidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Helpers} from "../../libraries/helpers/Helpers.sol";
import {DataTypes} from "../../libraries/types/DataTypes.sol";
import {ReserveLogic} from "./ReserveLogic.sol";
import {SupplyLogic} from "./SupplyLogic.sol";
import {BorrowLogic} from "./BorrowLogic.sol";
import {ValidationLogic} from "./ValidationLogic.sol";
import {GenericLogic} from "./GenericLogic.sol";
import {UserConfiguration} from "../../libraries/configuration/UserConfiguration.sol";
Expand Down Expand Up @@ -86,6 +87,7 @@ library LiquidationLogic {
address indexed liquidationAsset,
address indexed borrower,
uint256 liquidationAmount,
uint256 creditAmount,
uint256 liquidatedCollateralTokenId,
address liquidator,
bool receiveNToken
Expand Down Expand Up @@ -297,10 +299,12 @@ library LiquidationLogic {
DataTypes.ReserveData storage liquidationAssetReserve = reservesData[
params.liquidationAsset
];
DataTypes.UserConfigurationMap storage userConfig = usersConfig[
DataTypes.UserConfigurationMap storage borrowerConfig = usersConfig[
params.borrower
];

DataTypes.UserConfigurationMap storage liquidatorConfig = usersConfig[
params.liquidator
];
vars.liquidationAssetReserveId = liquidationAssetReserve.id;
vars.liquidationAssetReserveCache = liquidationAssetReserve.cache();
// liquidationAssetReserve.updateState(vars.liquidationAssetReserveCache);
Expand All @@ -323,7 +327,7 @@ library LiquidationLogic {
reservesData,
reservesList,
DataTypes.CalculateUserAccountDataParams({
userConfig: userConfig,
userConfig: borrowerConfig,
reservesCount: params.reservesCount,
user: params.borrower,
oracle: params.priceOracle
Expand All @@ -350,7 +354,7 @@ library LiquidationLogic {

ValidationLogic.validateLiquidateERC721(
reservesData,
userConfig,
borrowerConfig,
collateralReserve,
DataTypes.ValidateLiquidateERC721Params({
liquidationAssetReserveCache: vars.liquidationAssetReserveCache,
Expand All @@ -359,6 +363,7 @@ library LiquidationLogic {
borrower: params.borrower,
globalDebt: vars.userGlobalDebt,
actualLiquidationAmount: vars.actualLiquidationAmount,
creditAmount: params.creditAmount,
maxLiquidationAmount: params.liquidationAmount,
healthFactor: vars.healthFactor,
weth: params.weth,
Expand All @@ -382,18 +387,35 @@ library LiquidationLogic {
);
}

_supplyNewCollateral(reservesData, userConfig, params, vars);

// If the collateral being liquidated is equal to the user balance,
// we set the currency as not being used as collateral anymore
if (vars.userCollateral == 1) {
userConfig.setUsingAsCollateral(collateralReserve.id, false);
borrowerConfig.setUsingAsCollateral(collateralReserve.id, false);
emit ReserveUsedAsCollateralDisabled(
params.collateralAsset,
params.borrower
);
}

// Transfer collateral assets from borrower to liquiditor
if (params.receiveXToken) {
_liquidateNTokens(reservesData, liquidatorConfig, params, vars);
} else {
_burnCollateralNTokens(params, vars);
}

// Transfer liquidation assets from liquidator to borrower
// and supply on behalf of borrower
_supplyLiquidateTokens(
reservesData,
reservesList,
liquidationAssetReserve,
borrowerConfig,
liquidatorConfig,
params,
vars
);

// Transfer fee to treasury if it is non-zero
if (vars.liquidationProtocolFee != 0) {
IERC20(params.liquidationAsset).safeTransferFrom(
Expand All @@ -404,21 +426,12 @@ library LiquidationLogic {
);
}

if (params.receiveXToken) {
INToken(vars.collateralXToken).transferOnLiquidation(
params.borrower,
params.liquidator,
params.collateralTokenId
);
} else {
_burnCollateralNTokens(params, vars);
}

emit LiquidateERC721(
params.collateralAsset,
params.liquidationAsset,
params.borrower,
vars.actualLiquidationAmount,
params.creditAmount,
params.collateralTokenId,
params.liquidator,
params.receiveXToken
Expand Down Expand Up @@ -515,6 +528,37 @@ library LiquidationLogic {
}
}

/**
* @notice Liquidates the user xTokens by transferring them to the liquidator.
* @dev The function also checks the state of the liquidator and activates the xToken as collateral
* @param liquidatorConfig The liquidator configuration that track the supplied/borrowed assets
* @param params The additional parameters needed to execute the liquidation function
* @param vars The executeLiquidateERC20() function local vars
*/
function _liquidateNTokens(
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage liquidatorConfig,
DataTypes.ExecuteLiquidateParams memory params,
ExecuteLiquidateLocalVars memory vars
) internal {
INToken nToken = INToken(vars.collateralXToken);
nToken.transferOnLiquidation(
params.borrower,
params.liquidator,
params.collateralTokenId
);

uint256[] memory tokenIds = new uint256[](1);
tokenIds[0] = params.collateralTokenId;
SupplyLogic.executeCollateralizeERC721(
reservesData,
liquidatorConfig,
params.collateralAsset,
tokenIds,
params.liquidator
);
}

/**
* @notice Burns the debt tokens of the user up to the amount being repaid by the liquidator.
* @dev The function alters the `liquidationAssetReserveCache` state in `vars` to update the debt related data.
Expand Down Expand Up @@ -557,22 +601,52 @@ library LiquidationLogic {
}

/**
* @notice Supply new collateral for taking out of borrower's another collateral
* @param userConfig The user configuration that track the supplied/borrowed assets
* @notice Supply liquidation tokens for taking out of borrower's another collateral
* @param reservesData The state of all the reserves
* @param reservesList The addresses of all the active reserves
* @param liquidationAssetReserve The data of the liquidation asset reserve
* @param borrowerConfig The borrower configuration that track the supplied/borrowed assets
* @param liquidatorConfig The liquidator configuration that track the supplied/borrowed assets
* @param params The additional parameters needed to execute the liquidation function
* @param vars the executeLiquidateERC20() function local vars
*/
function _supplyNewCollateral(
function _supplyLiquidateTokens(
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap storage userConfig,
mapping(uint256 => address) storage reservesList,
DataTypes.ReserveData storage liquidationAssetReserve,
DataTypes.UserConfigurationMap storage borrowerConfig,
DataTypes.UserConfigurationMap storage liquidatorConfig,
DataTypes.ExecuteLiquidateParams memory params,
ExecuteLiquidateLocalVars memory vars
) internal {
_depositETH(params, vars);

// Borrow creditAmount out using liquidated NToken's credit
if (params.creditAmount != 0) {
ValidationLogic.validateFlashloanSimple(liquidationAssetReserve);
IPToken(vars.liquidationAssetReserveCache.xTokenAddress)
.transferUnderlyingTo(vars.payer, params.creditAmount);
BorrowLogic.executeBorrow(
reservesData,
reservesList,
liquidatorConfig,
DataTypes.ExecuteBorrowParams({
asset: params.liquidationAsset,
user: params.liquidator,
onBehalfOf: params.liquidator,
amount: params.creditAmount,
referralCode: 0,
releaseUnderlying: false,
reservesCount: params.reservesCount,
oracle: params.priceOracle,
priceOracleSentinel: params.priceOracleSentinel
})
);
}

SupplyLogic.executeSupply(
reservesData,
userConfig,
borrowerConfig,
DataTypes.ExecuteSupplyParams({
asset: params.liquidationAsset,
amount: vars.actualLiquidationAmount -
Expand All @@ -583,8 +657,10 @@ library LiquidationLogic {
})
);

if (!userConfig.isUsingAsCollateral(vars.liquidationAssetReserveId)) {
userConfig.setUsingAsCollateral(
if (
!borrowerConfig.isUsingAsCollateral(vars.liquidationAssetReserveId)
) {
borrowerConfig.setUsingAsCollateral(
vars.liquidationAssetReserveId,
true
);
Expand Down Expand Up @@ -871,12 +947,11 @@ library LiquidationLogic {
vars.payer = msg.sender;
} else {
vars.payer = address(this);
IWETH(params.weth).deposit{value: vars.actualLiquidationAmount}();
if (msg.value > vars.actualLiquidationAmount) {
Address.sendValue(
payable(msg.sender),
msg.value - vars.actualLiquidationAmount
);
uint256 downpayment = vars.actualLiquidationAmount -
params.creditAmount;
IWETH(params.weth).deposit{value: downpayment}();
if (msg.value > downpayment) {
Address.sendValue(payable(msg.sender), msg.value - downpayment);
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions contracts/protocol/libraries/logic/ValidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,11 @@ library ValidationLogic {
);

require(
params.maxLiquidationAmount >= params.actualLiquidationAmount &&
(msg.value == 0 || msg.value >= params.maxLiquidationAmount),
params.creditAmount <= params.actualLiquidationAmount &&
params.maxLiquidationAmount >= params.actualLiquidationAmount &&
(msg.value == 0 ||
msg.value >=
params.maxLiquidationAmount - params.creditAmount),
Errors.LIQUIDATION_AMOUNT_NOT_ENOUGH
);

Expand Down
2 changes: 2 additions & 0 deletions contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ library DataTypes {
struct ExecuteLiquidateParams {
uint256 reservesCount;
uint256 liquidationAmount;
uint256 creditAmount;
uint256 collateralTokenId;
uint256 auctionRecoveryHealthFactor;
address weth;
Expand Down Expand Up @@ -251,6 +252,7 @@ library DataTypes {
uint256 tokenId;
address weth;
uint256 actualLiquidationAmount;
uint256 creditAmount;
uint256 maxLiquidationAmount;
uint256 auctionRecoveryHealthFactor;
address priceOracleSentinel;
Expand Down
3 changes: 3 additions & 0 deletions contracts/protocol/pool/PoolCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ contract PoolCore is
DataTypes.ExecuteLiquidateParams({
reservesCount: ps._reservesCount,
liquidationAmount: liquidationAmount,
creditAmount: 0,
auctionRecoveryHealthFactor: ps._auctionRecoveryHealthFactor,
weth: ADDRESSES_PROVIDER.getWETH(),
collateralAsset: collateralAsset,
Expand All @@ -460,6 +461,7 @@ contract PoolCore is
address borrower,
uint256 collateralTokenId,
uint256 maxLiquidationAmount,
uint256 creditAmount,
bool receiveNToken
) external payable virtual override nonReentrant {
DataTypes.PoolStorage storage ps = poolStorage();
Expand All @@ -471,6 +473,7 @@ contract PoolCore is
DataTypes.ExecuteLiquidateParams({
reservesCount: ps._reservesCount,
liquidationAmount: maxLiquidationAmount,
creditAmount: creditAmount,
auctionRecoveryHealthFactor: ps._auctionRecoveryHealthFactor,
weth: ADDRESSES_PROVIDER.getWETH(),
collateralAsset: collateralAsset,
Expand Down
2 changes: 2 additions & 0 deletions helpers/contracts-deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ export const deployPoolCoreLibraries = async (
{
["contracts/protocol/libraries/logic/SupplyLogic.sol:SupplyLogic"]:
supplyLogic.address,
["contracts/protocol/libraries/logic/BorrowLogic.sol:BorrowLogic"]:
borrowLogic.address,
},
verify
);
Expand Down
1 change: 1 addition & 0 deletions test/_pool_ape_staking.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,7 @@ describe("APE Coin Staking Test", () => {
user1.address,
0,
await convertToCurrencyDecimals(weth.address, "13"),
0,
false,
{gasLimit: 5000000}
)
Expand Down
Loading