Platform: Code4rena
Start Date: 25/10/2022
Pot Size: $50,000 USDC
Total HM: 18
Participants: 127
Period: 5 days
Judge: 0xean
Total Solo HM: 9
Id: 175
League: ETH
Rank: 45/127
Findings: 3
Award: $58.23
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: trustindistrust
Also found by: 0xbepresent, Jujic, Lambda, RaoulSchaffranek, c7e7eff, catchup, codexploder, cryptonue, d3e4, eierina, jwood, pashov, peanuts, pedroais, simon135
33.634 USDC - $33.63
The contract’s admin has control to set values in setCollateralFactorBps()
, setLiquidationFactorBps()
, setReplenismentIncentiveBps()
, setLiquidationIncentiveBps()
, setLiquidationFeeBps()
. All of them have upper bounds, most of them have lower bounds, but they are mostly serving a sanity check role, they aren’t really upper/lower bounds.
For example admin can set the liquidationIncentive
to 99.99% which will result in almost all of the user liquidated collateral going to the liquidator. This is not expected by protocol users and can be seen as an unexpected loss of value for them.
Another issue is admin can set collateralFactorBps
to zero, which will DoS withdrawals for users, because of this check in getWithdrawalLimit()
if(collateralFactorBps == 0) return 0;
and since on withdraw you have the following check
uint limit = getWithdrawalLimitInternal(from); require(limit >= amount, "Insufficient withdrawal limit");
then all withdraws will result in a revert (DoS)
The admin has too much control over setting protocol params and a malicious or a compromised owner can make it so that users can’t withdraw any of their assets or that they get almost all of their liquidated collateral lost, resulting in a value loss for them.
Add sensible upper & lower bounds for all bps
field setters, don’t let collateralFactorBps
be set to zero.
#0 - c4-judge
2022-11-05T23:01:16Z
0xean marked the issue as duplicate
#1 - Simon-Busch
2022-12-05T15:37:03Z
Issue marked as satisfactory as requested by 0xean
#2 - c4-judge
2022-12-07T08:22:05Z
Simon-Busch marked the issue as duplicate of #301
🌟 Selected for report: adriro
Also found by: 8olidity, BClabs, CertoraInc, Chom, Franfran, Lambda, RaoulSchaffranek, Ruhum, codexploder, cryptphi, eierina, joestakey, kaden, neumo, pashov, rvierdiiev, sorrynotsorry
24.2165 USDC - $24.22
https://github.com/code-423n4/2022-10-inverse/blob/cc281e5800d5860c816138980f08b84225e430fe/src/Oracle.sol#L87 https://github.com/code-423n4/2022-10-inverse/blob/cc281e5800d5860c816138980f08b84225e430fe/src/Oracle.sol#L121
Chainlink price feeds usually have 18 decimals, but this is not guaranteed. Also tokens usually have 18 decimals or less but this is also not the case for 100% of widely used tokens (YAM-v2
has 24).
So the normal use case is when both the feed an the token have 18 decimals or less. There are three options when the following code will revert
uint8 decimals = 36 - feedDecimals - tokenDecimals;
feedDecimals
to be 18, but tokenDecimals
to be >18tokenDecimals
to be 18, but feedDecimals
to be >18tokenDecimals + feedDecimals > 36
If some of the examples are the case, then the viewPrice()
and getPrice()
functions in Oracle.sol
will always revert because of the uint underflow, resulting in all of the protocol functions being in a DoS state.
The impact is 100% malfunctioning of the protocol, but it will happen only under some Market
collateral circumstances, hence the Medium severity.
When adding a new token and price feed in Oracle.sol
add a require
statement that makes sure tokenDecimals + feedDecimals <= 36
#0 - c4-judge
2022-11-05T23:00:54Z
0xean marked the issue as duplicate
#1 - c4-judge
2022-11-28T16:02:19Z
0xean marked the issue as not a duplicate
#2 - c4-judge
2022-11-28T16:02:30Z
0xean marked the issue as duplicate of #526
#3 - c4-judge
2022-11-28T16:02:40Z
0xean marked the issue as not a duplicate
#4 - c4-judge
2022-11-28T16:02:47Z
0xean marked the issue as duplicate of #540
#5 - Simon-Busch
2022-12-05T15:34:07Z
Issue marked as satisfactory as requested by 0xean
#6 - c4-judge
2022-12-07T08:18:20Z
Simon-Busch marked the issue as duplicate of #533
🌟 Selected for report: rbserver
Also found by: 0x1f8b, 0xNazgul, 0xc0ffEE, 8olidity, Aymen0909, Chom, Franfran, Jeiwan, Jujic, Lambda, M4TZ1P, Olivierdem, Rolezn, Ruhum, TomJ, Wawrdog, __141345__, bin2chen, c7e7eff, carlitox477, catchup, cccz, codexploder, cuteboiz, d3e4, dipp, djxploit, eierina, elprofesor, hansfriese, horsefacts, idkwhatimdoing, imare, immeas, joestakey, ladboy233, leosathya, martin, minhtrng, pashov, peanuts, pedroais, rokinot, rvierdiiev, saneryee, sorrynotsorry, tonisives
0.385 USDC - $0.38
https://github.com/code-423n4/2022-10-inverse/blob/cc281e5800d5860c816138980f08b84225e430fe/src/Oracle.sol#L82 https://github.com/code-423n4/2022-10-inverse/blob/cc281e5800d5860c816138980f08b84225e430fe/src/Oracle.sol#L116
Chainlink has market the latestAnswer()
method as deprecated for his price feeds, but the code is using it.
The latestAnswer()
method just returns the price and has no way to check if it is stale. If the project is using a stale price it can result in miscalculations of collateral price and in value stolen from the protocol.
Use the latestRoundData
 function to get the price instead. Add checks on the return data with proper revert messages if the price is stale or the round is uncomplete, for example:
(uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound) = feed.latestRoundData(); require(answeredInRound >= roundID, "..."); require(timeStamp != 0, "...");
#0 - neumoxx
2022-10-31T08:36:23Z
Duplicate of #601
#1 - c4-judge
2022-11-05T17:48:33Z
0xean marked the issue as duplicate
#2 - Simon-Busch
2022-12-05T15:30:33Z
Issue marked as satisfactory as requested by 0xean
#3 - c4-judge
2022-12-07T08:14:14Z
Simon-Busch marked the issue as duplicate of #584