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
Rank: 100/154
Findings: 1
Award: $61.26
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: GalloDaSballo
Also found by: 0x3b, 0xAgro, 0xSmartContract, 0xTheC0der, 0xackermann, 0xnev, 0xsomeone, ABA, BRONZEDISC, Bjorn_bug, Bnke0x0, Breeje, Co0nan, CodeFoxInc, CodingNameKiki, DadeKuma, DeFiHackLabs, IceBear, Josiah, Kaysoft, Lavishq, MohammedRizwan, PaludoX0, PawelK, Phantasmagoria, Raiders, RaymondFam, Rickard, Rolezn, Sathish9098, SleepingBugs, SuperRayss, UdarTeam, Udsen, Viktor_Cortess, arialblack14, ast3ros, bin2chen, brgltd, btk, catellatech, ch0bu, chaduke, chrisdior4, codeislight, cryptonue, delfin454000, descharre, dontonka, emmac002, fs0c, hacker-dom, hansfriese, imare, lukris02, luxartvinsec, martin, matrix_0wl, peanuts, rbserver, shark, tnevler, trustindistrust, tsvetanovv, vagrant, yongskiws, zzzitron
61.2601 USDC - $61.26
Hello,
Thanks in advance for your work.
Here is my QA Report:
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.
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.
Recommended solution: Format everything with a linter.
Recommended solution: Add events for crucial actions like withdrawal, and deposit, so interested parties can subscribe to them
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
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
.
Recommended solution: Emit state-changing events in the Trove manager, so parties can subscribe to those.
Example: https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Vault/contracts/ReaperVaultV2.sol#L41
Recommended solution:
Use 10_000
.
Examples:
Recommended solution: Use error messages with require to improve error handling.
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.
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:
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