The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: low
Invalid

Liquidation won't work for collateral assets with more than 18 decimal places

Summary

Liquidation won't work for collateral assets with more than 18 decimal places.

Vulnerability Details

There are ERC-20 tokens with more than 18 decimal places, for example is YAMv2 with 24 decimal places.
When we use this as collateral asset, it can cause problem in computation of costInEuros (see below), because it will result to underflow error (18 decimal - 24 decimal) in line 245.

File: LiquidationPool.sol
245: uint256 costInEuros = _portion * 10 ** (18 - asset.token.dec) * uint256(assetPriceUsd) / uint256(priceEurUsd)
246: * _hundredPC / _collateralRate; // calculation of euro equivalent of the portion collateral asset

If this part of the code fails, this can revert the function of distributeAssets which can cause to revert the runLiquidation, failing to proceed with liquidation process.

Proof of Concept

Let us run the coded POC to prove the case.
Before we run this test, please replace 8 into 19 like the following code in common.js file in line 52. We are testing 19 decimal places in mock WBTC token.

File: common.js
52: WBTC = await MockERC20Factory.deploy('Wrapped Bitcoin', 'WBTC', 19);

Here is the coded POC, please copy and insert at line 288 of liquidationPool.js, then run npx hardhat test test/liquidationPool.js

File: liquidationPool.js
288: describe.only ('19decimalsTest', async () => {
289: it('should revert when collateral asset has more than 18 decimal places', async () => {
290:
291: const wbtcCollateral = BigNumber.from(1_000_000); // WBTC is 19 decimal token
292:
293: // create some funds to be "liquidated"
294: await WBTC.mint(MockSmartVaultManager.address, wbtcCollateral);
295:
296:
297: let stakeValue = ethers.utils.parseEther('10000');
298: await TST.mint(user1.address, stakeValue); // mint 10k tst to user1
299: await EUROs.mint(user1.address, stakeValue); // mint 10k euros to user1
300: await TST.connect(user1).approve(LiquidationPool.address, stakeValue); //user1 approve liquidation pool to spend 10k tst
301: await EUROs.connect(user1).approve(LiquidationPool.address, stakeValue); //user1 approve liquidation pool to spend 10k euros
302: await LiquidationPool.connect(user1).increasePosition(stakeValue, stakeValue); // user1 increasePosition by 10k tst and 10k euros
303:
304: await fastForward(DAY);
305:
306: await expect(LiquidationPoolManager.runLiquidation(TOKEN_ID))
307: .to.be.reverted;
308:
309: });
310: });

Impact

Liquidation won't be executed and this will result to bad debt of the protocol.

Tools Used

Manual review, Foundry

Recommendations

Revise the formula in costInEuros by replacing 18 in line 245 here by a number matched with number of decimal places of a certain collateral asset. For example, in the list of accepted tokens, 24 is highest number of decimal places, replace the formula with 24

File: LiquidationPool.sol
245: uint256 costInEuros = _portion * 10 ** (18 - asset.token.dec) * uint256(assetPriceUsd) / uint256(priceEurUsd)
246: * _hundredPC / _collateralRate; // calculation of euro equivalent of the portion collateral asset
Updates

Lead Judging Commences

hrishibhat Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

informational/invalid

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!