#37425 [SC-Insight] redeem collateral does not redeem collateral from riskiest trove but wrongly red
#37425 [SC-Insight] redeem_collateral does not redeem collateral from riskiest trove but wrongly redeem lowest healthy troves with lowest collateral Ratio
Submitted on Dec 4th 2024 at 14:14:53 UTC by @perseverance for IOP | Fluid Protocol
Report ID: #37425
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/Hydrogen-Labs/fluid-protocol/tree/main/contracts/protocol-manager-contract/src/main.sw
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Description
Brief/Intro
The redeem_collateral() in protocol_manager can redeem collateral at any time to receive collateral.
https://github.com/Hydrogen-Labs/fluid-protocol/blob/main/contracts/protocol-manager-contract/src/main.sw#L134-L139
#[storage(read, write), payable]
fn redeem_collateral(
max_iterations: u64,
partial_redemption_hint: u64,
upper_partial_hint: Identity,
lower_partial_hint: Identity,
)
According to the documentation of Fluid Protocol,
So according to the design of the protocol, the redeem_collateral should redeem from the riskiest trove means that the trove with lowest collateral ratio.
The vulnerability
Vulnerability Details
The vulnerability in redeem_collateral() in internal function get_all_assets_info() from line 328-328.
Line 318: Find the last node in sorted_troves for the asset. This is the riskiest trove for the current asset.
Line 326-328: Loop until it finds the current_borrower that is not zero and have current_cr >= MCR = 135%. Then push that current_borrower to the current_borrowers vector at Line 330.
So it means that current_borrowers vector contains that borrower that have collateral ratio is healthy means >= 135%
So notice that in the case, there are troves with Collateral Ratio < 135% that is unhealthy, the system still look for the healhthy troves to redeem.
https://github.com/Hydrogen-Labs/fluid-protocol/blob/main/contracts/protocol-manager-contract/src/main.sw#L313-L333
After that, at line 161, the contract find the borrower with the lowest CR in the current_borrowers vector to redeem the collateral. At line 177, the contract call trove_manager_contract.redeem_collateral_from_trove to redeem the collateral.
https://github.com/Hydrogen-Labs/fluid-protocol/blob/main/contracts/protocol-manager-contract/src/main.sw#L159-L184
In summary, the documentation states that when redeem the collateral, the protocol should redeem from the riskiest troves in the system. But in the code, it does not redeem from the riskiest. In the scenario that there are troves that are not healthy, the system still redeem from the healthy troves.
I give an example as the POC:
Note that this bug can affect the live contract of Fluid Protocol.
So since the system does not take collateral from the riskiest trove, it cause other users to loose his collateral. So if he think that his position is not the lowest CR in the system, he is surprised to see that his collateral was redeemed and lost money.
Impacts
About the severity assessment
Bug Severity: Critical
Impact category:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Link to Proof of Concept
https://gist.github.com/Perseverancesuccess2021/a0a584cc51049b585872b1b87028b1a5#file-success_redemptions_many-rs
Proof of Concept
Proof of concept
Steps to execute the attack:
Step 1: Setup the precondition for this bug as described above
Step 2: Call redeem_collateral
Test Code
Test code to demonstrate this bug: https://gist.github.com/Perseverancesuccess2021/a0a584cc51049b585872b1b87028b1a5#file-success_redemptions_many-rs
Replace the test code function proper_multi_collateral_redemption_from_partially_closed below with the Protocol proper_multi_collateral_redemption_from_partially_closed in fluid-protocol\contracts\protocol-manager-contract\tests\success_redemptions_many.rs
Explanation:
In the POC, scenario is explained above.
The test log showed that the redemptionEvent for wallet_1 and wallet_2 and wallet_3 for asset_0. The collateral of wallet_1 and wallet_2 and wallet_3 was redeemed.
The trove of wallet_2 with asset_1 is unhealthy and is riskiest in the system, but stay untouched.
Test log: https://gist.github.com/Perseverancesuccess2021/a0a584cc51049b585872b1b87028b1a5#file-proper_multi_collateral_redemption_from_partially_closed_241204_1730-log
Full POC:
Download Patch files: https://drive.google.com/file/d/1kYg8_INyCcEZPCxM4FhK8vU6ZlfZpM5c/view?usp=sharing
In folder fluid-protocol , apply all patches file based on commit: 78ab7bdd243b414b424fca6e1eb144218f36a18a
Last updated
Was this helpful?