Platform: Code4rena
Start Date: 14/06/2022
Pot Size: $100,000 USDC
Total HM: 26
Participants: 59
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 9
Id: 133
League: ETH
Rank: 32/59
Findings: 2
Award: $513.69
π Selected for report: 0
π Solo Findings: 0
π Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xf15ers, 0xmint, Bronicle, Dravee, Funen, JMukesh, Limbooo, MadWookie, Picodes, Ruhum, TerrierLover, TomJ, Tutturu, WatchPug, Waze, _Adam, asutorufos, c3phas, catchup, cccz, codexploder, cryptphi, csanuragjain, defsec, fatherOfBlocks, gzeon, hake, hansfriese, hyh, ignacio, k, nxrblsrpr, oyc_109, robee, sach1r0, saian, simon135, technicallyty, zzzitron
687.9945 CANTO - $111.11
142.9793 USDC - $142.98
Severity: Low
Context: NoteInterest.sol#L139-L171
Description: Setter functions are missing checks to validate if the new value being set is the same as the current value already set in the contract. Such checks will showcase mismatches between on-chain and off-chain states.
Recommendation: This may hinder detecting discrepancies between on-chain and off-chain states leading to flawed assumptions of on-chain state and protocol behavior.
Severity: Low
Context: AccountantDelegate.sol#L15-L40
, BaseV1Router.sol#L323-L341
, BaseV1Router.sol#L343-L357
Description: Giving max/infinite approvals to contracts are dangerous because if those contracts are exploited then they can remove all the funds from the approving addresses.
Recommendation: Check allowance and approve as much as required.
Severity Low
Context: NoteInterest.sol#L139-L171
Description: These functions doesn't have any checks to ensure that the variables being set is within some kind of value range.
Recommendation: Each variable input parameter updated should have it's own value range checks to ensure their validity.
receive()
Function Should Emit An EventSeverity: Low
Context: BaseV1Router.sol#L81-L83
, AccountantDelegator.sol#L137
, AccountantDelegate.sol#L94
, TreasuryDelegator.sol#L130
Description:
Consider emitting an event inside this function with msg.sender
and msg.value
as the parameters. This would make it easier to track incoming ether transfers.
Recommendation:
Add events to the receive()
functions.
Severity: Low
Context: TreasuryDelegate.sol#L15-L19
Description: The initialize function has initialize in its name which indicates that it should only be called once to initialize the storage. But it can be repeatedly called to overwrite and update the storage.
Recommendation: Consider an initializer modifier or reverting if storage is already initialized.
Severity: Low
Context: TreasuryDelegate.sol#L15-L19
, AccountantDelegate.sol#L15-L40
, Comptroller.sol#L965-L988
, GovernorBravoDelegate.sol#L24-L31
Description: Several functions update critical parameters that are missing event emission. These should be performed to ensure tracking of changes of such critical parameters.
Recommendation: Add events to functions that change critical parameters.
Severity: Low
Context: NoteInterest.sol#L73-L77
Description:
baseRatePerYear
constructor parameter is shadowing the state variable by the same name. This is bad for readability and can confuse future auditors and developers.
Recommendation:
Change the baseRatePerYear
parameter to _baseRatePerYear
.
Severity: Informational
Context: BaseV1Pair#L123-L129 (lock => nonReentrant)
Description: The modifier name is either not as it describes or can be more descriptive.
Recommendation: Change all occurrences of these variables to be more intuitive.
Severity: Informational
Context: BaseV1Pair#L70
, NoteInterest.sol#L27
Description: There are multiple occasions where certain numbers have been hardcoded, either in variables or in the code itself. Large numbers can become hard to read.
Recommendation: Consider using underscores for number literals to improve its readability.
Severity Informational
Context: BaseV1Pair.sol#L41
, BaseV1Pair.sol#L70
, GovernorBravoDelegate.sol#L9
, GovernorBravoDelegate.sol#L12
, Comptroller.sol#L79
, Comptroller.sol#L82
, Comptroller.sol#L85
, Comptroller.sol#L88
, NoteInterest.sol#L27
Description:
The linked variables do not conform to the standard naming convention of Solidity whereby functions and variable names utilize the camelCase
format unless variables are declared as constant
in which case they utilize the UPPER_CASE
format.
Recommendation: Naming conventions utilized by the linked statements are adjusted to reflect the correct type of declaration according to the Solidity style guide.
Severity: Informational
Context: BaseV1Pair.sol#L362
, WETH.sol#L24
, WETH.sol#L32
, WETH.sol#L106-L107
Description: There is commented code that makes the code messy and unneeded.
Recommendation: Remove the commented out code.
Severity: Informational
Context: Comptroller.sol#L1232
, Comptroller.sol#L1271
Description: There should never be any TODOs in the code when deploying.
Recommendation: Finish the TODOs before deploying.
Severity: Informational
Context: BaseV1Pair.sol#L62 (obervations => observations)
, BaseV1Router.sol#L463 (faialure => failure)
, GovernorBravoDelegate.sol#L463 (arity => ???)
, Comptroller.sol#L493 (liquidatable => liquidable)
, AccountantDelegate.sol#L10 (contructor => constructor)
, CNote.sol#L93 (undelrying => underlying)
, NoteInterest.sol#L89 (irrelevent => irrelevant)
, NoteInterest.sol#L106 (irrelevent => irrelevant)
Description: Spelling errors in comments can cause confusion to both users and developers.
Recommendation: Check all misspellings to ensure they are corrected.
ABIEncoderV2
With 0.8+
Severity: Informational
Context: AccountantDelegator.sol
Description:
ABIEncoderV2
is being stated in a solidity version 0.8+
which is not needed since ABIEncoderV2
is activated by default 0.8+
.
Recommendation:
remove pragma experimental ABIEncoderV2;
.
Severity: Informational
Context: All Contracts
Description: Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
Recommendation: Lock the pragma version.
Severity: Informational
Context: All Contracts
Description: Elastic supply tokens could dynamically adjust their price, supply, user's balance, etc. Such a mechanism makes a DeFi system complex, while many security accidents are caused by the elastic tokens. For example, a DEX using deflationary token must double check the token transfer amount when taking swap action because of the difference of actual transfer amount and parameter.
Recommendation: In terms of confidentiality, integrity and availability, it is highly recommend that one should not use elastic supply tokens.
Severity: Informational
Context: All Contracts
Description: Some functions are missing @notice/@dev NatSpec comments for the function, @param for all/some of their parameters and @return for return values. Given that NatSpec is an important part of code documentation, this affects code comprehension, auditability and usability.
Recommendation: Add in full NatSpec comments for all functions to have complete code documentation for future use.
#0 - GalloDaSballo
2022-08-01T23:25:30Z
Valid NC
One is for a lending market, the other 2 are to enable permit to work. In lack of any nuance am marking invalid
#1 - GalloDaSballo
2022-08-02T01:00:19Z
Valid Low and may increase
Disagree in lack of any explanation, adding an event costs more gas
Disagree as note
can only be set once to non-zero
Disagree as these are initializers
##Β State Variable Shadowing Valid Low
Disagree lock
is fairly used
Valid Refactoring
Valid Refactoring
NC
NC
NC
NC
NC
Am going to ignore the last 2 findings as they seem to be copy pasted
It feels like a bot wrote this report
2L 2R 6NC
π Selected for report: _Adam
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xmint, Chom, Dravee, Fitraldys, Funen, JC, Limbooo, MadWookie, Picodes, Ruhum, TerrierLover, TomJ, Tomio, Waze, ak1, c3phas, catchup, defsec, fatherOfBlocks, gzeon, hake, hansfriese, joestakey, k, oyc_109, rfa, robee, sach1r0, saian, simon135, ynnad
396.9199 CANTO - $64.10
195.4964 USDC - $195.50
++index
instead of index++
to increment a loop counterContext: BaseV1Pair.sol#L204-L211
, BaseV1Pair.sol#L336-L358
, BaseV1Router.sol#L132-L142
, BaseV1Router.sol#361-L371
, GovernorBravoDelegate.sol#L37-L75
, GovernorBravoDelegate.sol#L86-L94
, Comptroller.sol#L122-L133
, Comptroller.sol#L174-L224
, Comptroller.sol#L724-L780
, Comptroller.sol#L958-L963
, Comptroller.sol#L1346-L1367 (For all 4)
Description:
Due to reduced stack operations, using ++index
saves 5 gas per iteration.
Recommendation:
Use ++index
to increment a loop counter.
Context: BaseV1Pair.sol#L204-L211
, BaseV1Pair.sol#L336-L358
, BaseV1Router.sol#L132-L142
, BaseV1Router.sol#361-L371
, GovernorBravoDelegate.sol#L37-L75
, GovernorBravoDelegate.sol#L86-L94
, Comptroller.sol#L122-L133
, Comptroller.sol#L174-L224
, Comptroller.sol#L724-L780
, Comptroller.sol#L958-L963
, Comptroller.sol#L1094-L1139
, Comptroller.sol#L1346-L1367 (For all 4)
, Comptroller.sol#L1407-L1416
Description:
(This is only relevant if you are using the default solidity checked arithmetic). i++
involves checked arithmetic, which is not required. This is because the value of i
is always strictly less than length <= 2**256 - 1. Therefore, the theoretical maximum value of i
to enter the for-loop body is 2**256 - 2
. This means that the i++
in the for loop can never overflow. Regardless, the overflow checks are performed by the compiler.
Unfortunately, the Solidity optimizer is not smart enough to detect this and remove the checks. One can manually do this by:
for (uint i = 0; i < length; i = unchecked_inc(i)) { // do something that doesn't change the value of i } function unchecked_inc(uint i) returns (uint) { unchecked { return i + 1; } }
Note that itβs important that the call to unchecked_inc
is inlined. This is only possible for solidity versions starting from 0.8.2
.
Recommendation: The increment in the for loop post condition can be made unchecked.
Context: BaseV1Router.sol#L132-L142
, BaseV1Router.sol#361-L371
, GovernorBravoDelegate.sol#L37-L75
, GovernorBravoDelegate.sol#L86-L94
, Comptroller.sol#L724-L780
, Comptroller.sol#L958-L963
, Comptroller.sol#L1094-L1139
, Comptroller.sol#L1346-L1367 (For all 4)
Description: One can save gas by caching the array length (in stack) and using that set variable in the loop. Replace state variable reads and writes within loops with local variable reads and writes. This is done by assigning state variable values to new local variables, reading and/or writing the local variables in a loop, then after the loop assigning any changed local variables to their equivalent state variables.
Recommendation:
Simply do something like so before the for loop: uint length = variable.length
. Then add length
in place of variable.length
in the for loop.
require()
, Use != 0
Instead of > 0
With Uint ValuesContext: BaseV1Pair.sol#L239-L258 (For L253)
, BaseV1Pair.sol#L262-L281 (For L272)
, BaseV1Pair.sol#L284-L314 (For L286 && L303)
, BaseV1Router.sol#L103-L107 (For L104 && L105)
Description:
In a require, when checking a uint, using != 0
instead of > 0
saves 6 gas. This will jump over or avoid an extra ISZERO
opcode.
Recommendation:
Use != 0
instead of > 0
with uint values but only in require()
statements.
ReentrancyGuard
Context: CNote#L351-L358
Description:
Use of Solmate's version of reentrancyGuard
is a lot cheaper in gas. It employs uint
instead of bool storage variable which saves gas. The initial SSTORE
of true in the unoptimized version costs over 20,000 gas while the second SSTORE
of false costs only 100. But both SSTORE
(for 2 and 1) cost only 100 gas.
Recommendation:
Use Solmate's
ReentrancyGuard
.
Context: All Contracts
Description:
You can cut out 10 opcodes in the creation-time EVM bytecode if you declare a constructor payable. Making the constructor payable eliminates the need for an initial check of msg.value == 0
and saves 21 gas on deployment with no security risks.
Recommendation: Set the constructor to payable.
Context: All Contracts
Description:
Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions. One could use This tool
to help find alternative function names with lower Method IDs while keeping the original name intact.
Recommendation:
Find a lower method ID name for the most called functions for example mostCalled()
vs. mostCalled_41q()
is cheaper by 44 gas.
#0 - GalloDaSballo
2022-08-04T00:13:22Z
-> 15k gas saved
Rest is negligible
#1 - GalloDaSballo
2022-08-15T23:35:12Z
In reviewing other submissions I do believe this is the second best as it saves a lot of gas in a very short amount of space.
I'd recommend looking for immutable
s as well next time to offer extremely effective gas savings without needing to produce a long report