Ethos Reserve contest - PawelK'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: 100/154

Findings: 1

Award: $61.26

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Hello,

Thanks in advance for your work.

Here is my QA Report:

  1. Interfaces are not used in all necessary places instead of the address argument.

For type safety, interfaces should be used. When a function takes a contract address as an argument, it is better to pass an interface or contract type rather than a raw address. If the function is called elsewhere within the source code, the compiler will provide additional type safety guarantees.

List of places where the interface should be used:

Recommended solution: Use interfaces instead of addresses as function parameters.

  1. Improvement of import usage

The Point struct, which was previously imported globally in Solidity code, may have cluttered the source code with an unused object. This violates the principles of modularity and modular programming, which suggest that we should only import what we need. To address this issue, we can use specific imports with curly braces to better adhere to this principle.

All the files in the scope are affected by this.

Recommended solution: To implement specific imports, we can use the following syntax:

import {IActivePool} from './Interfaces/IActivePool.sol';

This allows us to import only the necessary contracts and avoid cluttering the code with unnecessary objects like the Point struct.

  1. Inconsistent formatting In some places, additional space is added. Examples:

Recommended solution: Format everything with a linter.

  1. No events for ReaperBaseStrategyv4.sol, and ReaperVaultV2.sol

Recommended solution: Add events for crucial actions like withdrawal, and deposit, so interested parties can subscribe to them

  1. Use underscore for all functions arguments for consistency.

In general, across the code underscore is used for argument, but there are places where this pattern is not followed. Examples:

Recommended solution: Use underscores for all functions arguments for consistency

  1. Use a consistent pattern for using setAddresses, across different smart contracts.

In different setAddresses functions implementation inside ActivePool.sol, StabilityPool.sol, TroveManager.sol, BorrowerOperations.sol, CollateralConfig.sol etc. different ways of blocking this function to be called twice are used. It is done through: Ownable contract + _renounceOwnership(), setting owner directly to address(0), setting flag initialized, setting flag addressesSet.

Recommended solution: Choose a consistent pattern for blocking calling twice setAddresses.

  1. No emitted events on Trove manager close trove event

Recommended solution: Emit state-changing events in the Trove manager, so parties can subscribe to those.

  1. Enhance readability, it is suggested to use underscores for number literals.

Example: https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L41

Recommended solution: Use 10_000.

  1. Use a message with require In some places require doesn't contain an error message

Examples:

Recommended solution: Use error messages with require to improve error handling.

  1. Use require instead of the assert

Examples:

Using the assert() function in Solidity code, except for testing purposes, can lead to consuming all available gas instead of returning it. Prior to Solidity 0.8.0, this behavior was different from request()/revert().

Assert() and require(): There is a significant difference between the two functions. When false, assert() uses up all remaining gas and reverts all changes made, whereas require() also reverts changes but refunds remaining gas fees offered to pay. The require() function is the most commonly used for debugging and error handling.

Even after Solidity version 0.8.0, it is recommended to avoid using assert() due to its documentation stating that "The Assert function generates an error of type Panic(uint256). Code that works properly should never Panic, even on invalid external input. If this happens, you need to fix it in your contract. There's a mistake.

Recommendation:

To avoid consuming all available gas and handle errors more efficiently, use require() instead of assert() except for testing purposes.

  1. Use a timelock to critical functions

When implementing critical changes in a project, it is advisable to allow users sufficient time to respond and adapt. One way to accomplish this is by using a timelock mechanism, which enhances security and reduces the level of trust needed from users. Therefore, it is recommended to consider adding a timelock to:

  1. Use Solidity Style Guide for function writing

Functions don't follow https://docs.soliditylang.org/en/v0.8.17/style-guide.html

They should be ordered as follow: constructor, receive function (if exists), fallback function (if exists), external, public, internal, private (within a grouping, place the view and pure functions last)

That is all. Thanks again for checking my work.

Kind regards, Paweł

#0 - c4-judge

2023-03-08T15:18:47Z

trust1995 marked the issue as grade-b

#1 - c4-sponsor

2023-03-17T03:56:16Z

0xBebis marked the issue as sponsor confirmed

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