Ethos Reserve contest - MiloTruck's results

A CDP-backed stablecoin platform designed to generate yield on underlying assets to establish a sustainable DeFi stable interest rate.

General Information

Platform: Code4rena

Start Date: 16/02/2023

Pot Size: $144,750 USDC

Total HM: 17

Participants: 154

Period: 19 days

Judge: Trust

Total Solo HM: 5

Id: 216

League: ETH

Ethos Reserve

Findings Distribution

Researcher Performance

Rank: 49/154

Findings: 1

Award: $142.85

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Labels

bug
2 (Med Risk)
satisfactory
edited-by-warden
duplicate-632

Awards

142.8544 USDC - $142.85

External Links

Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L248-L251

Vulnerability details

In the ActivePool contract, the _rebalance() function subtracts the amount of collateral currently in the vault (vars.sharesToAssets) from the amount originally allocated (vars.currentAllocated) to calculate its profit. This can be seen in ActivePool.sol#L248-L251:

vars.sharesToAssets = vars.yieldGenerator.convertToAssets(vars.ownedShares);

// if we have profit that's more than the threshold, record it for withdrawal and redistribution
vars.profit = vars.sharesToAssets.sub(vars.currentAllocated);

As seen from above, the sub() function from SafeMath is used to do the calculation. Hence, whenever the vault is at a loss, _rebalance() will always revert as vars.currentAllocated is less than vars.sharesToAssets, leading to an arithmetic underflow.

This affects the following functions as they call the _rebalance() function:

  • BorrowOperations.sol
    • openTrove
    • closeTrove
    • addColl
    • withdrawColl
    • withdrawLUSD
    • repayLUSD
    • adjustTrove
  • TroveManager.sol
    • redeemCollateral
    • liquidate
    • batchLiquidateTroves
    • liquidateTroves

Impact

Whenever a vault containing one type of collateral is at a loss, all the functions listed above will revert when called with the same type of collateral, massively affecting the protocol's functionality.

Moreover, since all the functions used to withdraw/transfer collateral are affected, all the borrowers who opened troves with the same type of collateral will have their collateral stuck in the protocol until the vault has a non-negative profit.

Proof of Concept

The test in this gist demonstrates how a vault at a loss causes all the functions listed above to revert.

To run the test:

Consider declaring vars.profit as a int256, and changing ActivePool.sol#L250-L254 to the following:

// if we have profit that's more than the threshold, record it for withdrawal and redistribution
if (vars.sharesToAssets < vars.currentAllocated && vars.currentAllocated - vars.sharesToAssets >= yieldClaimThreshold[_collateral]) {
    vars.profit = -int256(vars.currentAllocated - vars.sharesToAssets);
} else if (vars.sharesToAssets > vars.currentAllocated && vars.sharesToAssets - vars.currentAllocated >= yieldClaimThreshold[_collateral]) {
    vars.profit = int256(vars.sharesToAssets - vars.currentAllocated);
}

#0 - c4-judge

2023-03-08T15:14:06Z

trust1995 marked the issue as unsatisfactory: Invalid

#1 - c4-judge

2023-03-22T10:23:24Z

trust1995 marked the issue as satisfactory

#2 - c4-judge

2023-03-22T10:23:35Z

trust1995 marked the issue as duplicate of #632

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter