Skip to content
This repository was archived by the owner on Oct 21, 2025. It is now read-only.

Commit f8825f8

Browse files
Fix condition of unsetting asset as collateral if its fully liquidated (with non-zero liquidationProtocolFee) (#747)
* fix: collateral should be flagged false when got liquidated totally (#740) * fix: collateral should be flagged false when got liquidated totally * fix: typo Signed-off-by: GopherJ <[email protected]> * test: Fix test case for unsetting asset as collateral after liquidation Signed-off-by: GopherJ <[email protected]> Co-authored-by: Cheng JIANG <[email protected]>
1 parent ee931c4 commit f8825f8

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

contracts/protocol/libraries/logic/LiquidationLogic.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,13 @@ library LiquidationLogic {
214214
);
215215
}
216216

217+
// If the collateral being liquidated is equal to the user balance,
218+
// we set the currency as not being used as collateral anymore
219+
if (vars.actualCollateralToLiquidate + vars.liquidationProtocolFeeAmount == vars.userCollateralBalance) {
220+
userConfig.setUsingAsCollateral(collateralReserve.id, false);
221+
emit ReserveUsedAsCollateralDisabled(params.collateralAsset, params.user);
222+
}
223+
217224
// Transfers the debt asset being repaid to the aToken, where the liquidity is kept
218225
IERC20(params.debtAsset).safeTransferFrom(
219226
msg.sender,

test-suites/liquidation-edge.spec.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
evmSnapshot,
1111
evmRevert,
1212
waitForTx,
13+
AToken__factory,
1314
StableDebtToken__factory,
1415
VariableDebtToken__factory,
1516
} from '@aave/deploy-v3';
@@ -214,4 +215,124 @@ makeSuite('Pool Liquidation: Edge cases', (testEnv: TestEnv) => {
214215
expect(isBorrowing(userConfigBefore, daiData.id)).to.be.true;
215216
expect(isBorrowing(userConfigAfter, daiData.id)).to.be.false;
216217
});
218+
219+
it('Liquidate the whole WETH collateral with 10% liquidation fee, asset should not be set as collateralized anymore', async () => {
220+
const { pool, users, dai, usdc, weth, aWETH, oracle, configurator } = testEnv;
221+
222+
await configurator.setLiquidationProtocolFee(weth.address, '1000'); // 10%
223+
224+
const depositor = users[0];
225+
const borrower = users[1];
226+
227+
// Deposit dai
228+
await dai
229+
.connect(depositor.signer)
230+
['mint(uint256)'](await convertToCurrencyDecimals(dai.address, '1000000'));
231+
await dai.connect(depositor.signer).approve(pool.address, MAX_UINT_AMOUNT);
232+
await pool
233+
.connect(depositor.signer)
234+
.deposit(
235+
dai.address,
236+
await convertToCurrencyDecimals(dai.address, '10000'),
237+
depositor.address,
238+
0
239+
);
240+
241+
// Deposit usdc
242+
await usdc
243+
.connect(depositor.signer)
244+
['mint(uint256)'](await convertToCurrencyDecimals(usdc.address, '1000000'));
245+
await usdc.connect(depositor.signer).approve(pool.address, MAX_UINT_AMOUNT);
246+
await pool
247+
.connect(depositor.signer)
248+
.deposit(
249+
usdc.address,
250+
await convertToCurrencyDecimals(usdc.address, '1000'),
251+
depositor.address,
252+
0
253+
);
254+
255+
// Deposit eth, borrow dai
256+
await weth.connect(borrower.signer)['mint(uint256)'](utils.parseEther('0.9'));
257+
await weth.connect(borrower.signer).approve(pool.address, MAX_UINT_AMOUNT);
258+
await pool
259+
.connect(borrower.signer)
260+
.deposit(weth.address, utils.parseEther('0.9'), borrower.address, 0);
261+
262+
// Borrow usdc
263+
await pool
264+
.connect(borrower.signer)
265+
.borrow(
266+
usdc.address,
267+
await convertToCurrencyDecimals(usdc.address, '1000'),
268+
RateMode.Variable,
269+
0,
270+
borrower.address
271+
);
272+
273+
// Borrow dai stable
274+
await pool
275+
.connect(borrower.signer)
276+
.borrow(
277+
dai.address,
278+
await convertToCurrencyDecimals(dai.address, '100'),
279+
RateMode.Stable,
280+
0,
281+
borrower.address
282+
);
283+
284+
// Borrow dai variable
285+
await pool
286+
.connect(borrower.signer)
287+
.borrow(
288+
dai.address,
289+
await convertToCurrencyDecimals(dai.address, '100'),
290+
RateMode.Variable,
291+
0,
292+
borrower.address
293+
);
294+
295+
// HF = (0.9 * 0.85) / (1000 * 0.0005 + 100 * 0.0005 + 100 * 0.0005) = 1.275
296+
297+
// Increase usdc price to allow liquidation
298+
const usdcPrice = await oracle.getAssetPrice(usdc.address);
299+
await oracle.setAssetPrice(usdc.address, usdcPrice.mul(10));
300+
301+
// HF = (0.9 * 0.85) / (1000 * 0.005 + 100 * 0.0005 + 100 * 0.0005) = 0.15
302+
//
303+
// close factor = 1
304+
// $WETH_collateral = 0.9
305+
// $USDC_debt = 1000 * 0.005 = 5
306+
307+
const wethData = await pool.getReserveData(weth.address);
308+
const aWETHToken = AToken__factory.connect(wethData.aTokenAddress, depositor.signer);
309+
310+
expect(await aWETHToken.balanceOf(borrower.address)).to.be.gt(0);
311+
312+
const userConfigBefore = BigNumber.from(
313+
(await pool.getUserConfiguration(borrower.address)).data
314+
);
315+
316+
expect(await usdc.connect(depositor.signer).approve(pool.address, MAX_UINT_AMOUNT));
317+
expect(
318+
await pool
319+
.connect(depositor.signer)
320+
.liquidationCall(weth.address, usdc.address, borrower.address, MAX_UINT_AMOUNT, false)
321+
);
322+
323+
const userConfigAfter = BigNumber.from(
324+
(await pool.getUserConfiguration(borrower.address)).data
325+
);
326+
327+
const isUsingAsCollateral = (conf, id) =>
328+
conf
329+
.div(BigNumber.from(2).pow(BigNumber.from(id).mul(2).add(1)))
330+
.and(1)
331+
.gt(0);
332+
333+
expect(await aWETHToken.balanceOf(borrower.address)).to.be.eq(0);
334+
335+
expect(isUsingAsCollateral(userConfigBefore, wethData.id)).to.be.true;
336+
expect(isUsingAsCollateral(userConfigAfter, wethData.id)).to.be.false;
337+
});
217338
});

0 commit comments

Comments
 (0)