Canto contest - 0xNazgul's results

Execution layer for original work.

General Information

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

Canto

Findings Distribution

Researcher Performance

Rank: 32/59

Findings: 2

Award: $513.69

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Awards

687.9945 CANTO - $111.11

142.9793 USDC - $142.98

Labels

bug
QA (Quality Assurance)

External Links

Missing Equivalence Checks in Setters

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.

Max/Infinite Approvals are Dangerous

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.

Value Range Validity for Setters

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 Event

Severity: 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.

Initialize Can Be Called More Than Once

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.

Lack of Event Emission For Critical Functions

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.

State Variable Shadowing

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.

Unintuitive Modifier Name

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.

Use Underscores for Number Literals

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.

Variable Naming Convention

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.

Commented Out Code

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.

TODOs Left In The 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.

Spelling Errors

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.

Use of 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;.

Floating Pragma

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.

Be Aware of the Elastic Supply Tokens

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.

Missing or Incomplete NatSpec

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

Missing Equivalence Checks in Setters

Valid NC

Max/Infinite Approvals are Dangerous

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

Value Range Validity for Setters

Valid Low and may increase

receive() Function Should Emit An Event

Disagree in lack of any explanation, adding an event costs more gas

Initialize Can Be Called More Than Once

Disagree as note can only be set once to non-zero

Lack of Event Emission For Critical Functions

Disagree as these are initializers

##Β State Variable Shadowing Valid Low

Unintuitive Modifier Name

Disagree lock is fairly used

Use Underscores for Number Literals

Valid Refactoring

Variable Naming Convention

Valid Refactoring

Commented Out Code

NC

TODOs Left In The Code

NC

Spelling

NC

Use of ABIEncoderV2 With 0.8+

NC

Floating Pragma

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

Awards

396.9199 CANTO - $64.10

195.4964 USDC - $195.50

Labels

bug
G (Gas Optimization)

External Links

Use ++index instead of 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#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.

The Increment In For Loop Post Condition Can Be Made Unchecked

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.

Catching The Array Length Prior To Loop

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.

In require(), Use != 0 Instead of > 0 With Uint Values

Context: 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.

Use Solmate's 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.

Setting The Constructor To Payable

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.

Function Ordering via Method ID

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

Use Solmate's ReentrancyGuard

-> 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 immutables as well next time to offer extremely effective gas savings without needing to produce a long report

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