28864 - [SC - Insight] Unfair Liquidation when ICR equals TCR in redee...
Submitted on Feb 29th 2024 at 06:08:41 UTC by @Saediek for Boost | eBTC
Report ID: #28864
Report type: Smart Contract
Report severity: Insight
Target: https://github.com/ebtc-protocol/ebtc/blob/release-0.7/packages/contracts/contracts/LiquidationLibrary.sol
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
According to the docs in recovery Mode liquidation can only occur when the ICR<TCR but the implementation allows liquidation to occur on an ICR which is same as the TCR.
Vulnerability Details
According to the docs i quote "Any CDP whose ICR is below the TCR can be liquidated after the conclusion of the Grace Period. In a way, during Recovery Mode, the TCR becomes the liquidation threshold. This incentivizes rapid repayment or adjustment of CDPs with low ICR." But according to the liquidation it's possible for an ICR which equals TCR to be liquidated.This issue is caused due to the use of the wrong operator in the EBTCBase contract{https://github.com/ebtc-protocol/ebtc/blob/a96bd000c23425f04c3223a441a625bfb21f6686/packages/contracts/contracts/Dependencies/EbtcBase.sol#L126} which is used in the LiquidationLibrary {https://github.com/ebtc-protocol/ebtc/blob/a96bd000c23425f04c3223a441a625bfb21f6686/packages/contracts/contracts/LiquidationLibrary.sol#L83} ,the _checkICRAgainstLiqThreshold() in the EBTCBase makes an internal call _checkICRAgainstTCR() where the operator <= is used instead of the < //Snippet function _checkICRAgainstTCR(uint256 _icr, uint _tcr) internal view returns (bool) { return _icr <= _tcr; }
Impact Details
This issue could give space for unfair liquidation, less trust in the eBTC protocol due to discrepancies between the docs and codebase. The codebase is supposed to adhere strictly to the documentation of a protocol.
References
https://github.com/ebtc-protocol/ebtc/blob/a96bd000c23425f04c3223a441a625bfb21f6686/packages/contracts/contracts/LiquidationLibrary.sol#L83 https://github.com/ebtc-protocol/ebtc/blob/a96bd000c23425f04c3223a441a625bfb21f6686/packages/contracts/contracts/Dependencies/EbtcBase.sol#L126 https://github.com/ebtc-protocol/ebtc/blob/a96bd000c23425f04c3223a441a625bfb21f6686/packages/contracts/contracts/Dependencies/EbtcBase.sol#L142
Proof of Concept
--Check Code for how to run /**
SPDX-License-Identifier:UNLICENSED
@author [email protected] */ import "@ebtc-contracts/BorrowerOperations.sol"; import "@ebtc-contracts/ActivePool.sol"; import "@ebtc-contracts/CollSurplusPool.sol"; import "@ebtc-contracts/SortedCdps.sol"; import "@ebtc-contracts/EBTCToken.sol"; import "@ebtc-contracts/PriceFeed.sol"; import "forge-std/Test.sol"; import "@ebtc-contracts/CdpManager.sol"; import "@ebtc-contracts/FeeRecipient.sol"; import "@ebtc-contracts/Dependencies/Auth.sol"; //sub-dependencies import "@ebtc-contracts/LiquidationLibrary.sol";
pragma solidity ^0.8; /**
To run the test create a new folder in foundry_test and then name it anything of your choice
in your remappings.txt set "@ebtc-contracts/=contracts/"
run forge test --test-match test_liquidation_at_tcr -vvv */
contract BorrowersOperationTest is Test { BorrowerOperations private borrowerOperations; //--done FeeRecipient private feeReceipient; //-done ActivePool private activepool; //--done EBTCToken private cdpToken; //-done PriceFeed private priceFeed; //--done SortedCdps private sortedcdps; //--done CdpManager private cdpManager; //--done MockAuthority private auth; // --done LiquidationLibrary private liquidationLib; //--done CollSurplusPool surplusPool; //--done address eth_btc = 0xAc559F25B1619171CbC396a50854A3240b6A4e99; address steth_eth = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;
}
contract MockAuthority { function canCall(address user, address target, bytes4 functionSig) external view returns (bool) { return true; } }
Last updated
Was this helpful?