20,000 USDC
View results
Submission Details
Severity: gas
Valid

QAG Report

Contents:


Non Critical Issues

No. Issue
1 NatSpec comments should be increased in contracts
2 Tokens accidentally sent to the contract cannot be recovered
3 Use a more recent version of Solidity
4 Use underscores for number literals
5 Omissions in Events
6 Showing the actual values of numbers in NatSpec comments makes checking and reading code easier

[NC-01] NatSpec comments should be increased in contracts


Description:

It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI). It is clearly stated in the Solidity official documentation. In complex projects such as Defi, the interpretation of all functions and their arguments and returns is important for code readability and auditability. https://docs.soliditylang.org/en/v0.8.21/natspec-format.html

Lines of Code:


[NC-02] Tokens accidentally sent to the contract cannot be recovered


Description:

It can't be recovered if the tokens accidentally arrive at the contract address, which has happened to many popular projects, so I recommend adding a recovery code to your critical contracts.

Recommendation:

Add this code:

/**
* @notice Sends ERC20 tokens trapped in contract to external address
* @dev Onlyowner is allowed to make this function call
* @param account is the receiving address
* @param externalToken is the token being sent
* @param amount is the quantity being sent
* @return boolean value indicating whether the operation succeeded.
*
*/
function rescueERC20(address account, address externalToken, uint256 amount) public onlyOwner returns (bool) {
IERC20(externalToken).transfer(account, amount);
return true;
}
}

[NC-03] Use a more recent version of Solidity


Description:

For security, it is best practice to use the latest Solidity version. For the security fix list in the versions: https://github.com/ethereum/solidity/blob/develop/Changelog.md

Recommendation:

Old version of Solidity is used , newer version can be used (0.8.21)

Lines of Code:


[NC-04] Use underscores for number literals


Description:

For example, 1000 should be written as 1_000

Lines of Code:


[NC-05] Omissions in Events


Description:

Throughout the codebase, events are generally emitted when sensitive changes are made to the contracts. However, some events are missing important parameters

Lines of Code:


[NC-06] Showing the actual values of numbers in NatSpec comments makes checking and reading code easier


Description:

For example, 365 days should be written as 365 days; // 31_536_000 (365*24*60*60)

Lines of Code:


Gas Optimizations Report

No. Issue
1 Use Custom Errors rather than revert() / require() strings to save deployment gas [68 gas per instance]
2 Usage of uint/int smaller than 32 bytes (256 bits) incurs overhead
3 ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for-loop and while-loops
4 Optimize names to save gas [22 gas per instance]
5 Setting the constructor to payable [~13 gas per instance]
6 Use a more recent version of solidity
7 <array>.length should not be looked up in every loop of a for-loop
8 x += y costs more gas than x = x + y for state variables
9 Structs can be packed into fewer storage slots (20k gas)
10 Use computed variables to save gas

[G-01] Use Custom Errors rather than revert() / require() strings to save deployment gas [68 gas per instance]


Description:

Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they’re hitby avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas.

https://blog.soliditylang.org/2021/04/21/custom-errors/

Recommendation:

Use the Custom Errors feature.

Lines of Code:


[G-02] Usage of uint/int smaller than 32 bytes (256 bits) incurs overhead


Description:

When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size. Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so.

Recommendation:

Use a larger size then downcast where needed

Lines of Code:


[G-03] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for-loop and while-loops


Description:

In Solidity 0.8+, there’s a default overflow check on unsigned integers. It’s possible to uncheck this in for-loops and save some gas at each iteration, but at the cost of some code readability, as this uncheck cannot be made inline.

Recommendation:

Using Solidity's unchecked block saves the overflow checks.

Proof Of Concept:

https://github.com/byterocket/c4-common-issues/blob/main/0-Gas-Optimizations.md#g011---unnecessary-checked-arithmetic-in-for-loop

Lines of Code:


[G-04] Optimize names to save gas [22 gas per instance]


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.

Recommendation:

Find a lower method ID name for the most called functions for example Call() vs. Call1() is cheaper by 22 gas. For example, the function IDs in the L1GraphTokenGateway.sol contract will be the most used; A lower method ID may be given.

Proof Of Concept:

https://medium.com/joyso/solidity-how-does-function-name-affect-gas-consumption-in-smart-contract-47d270d8ac92

Lines of Code:


[G-05] Setting the constructor to payable [~13 gas per instance]


Lines of Code:


[G-06] Use a more recent version of solidity


Description:

Solidity 0.8.10 has a useful change that reduced gas costs of external calls which expect a return value.

In 0.8.15 the conditions necessary for inlining are relaxed. Benchmarks show that the change significantly decreases the bytecode size (which impacts the deployment cost) while the effect on the runtime gas usage is smaller.

In 0.8.17 prevent the incorrect removal of storage writes before calls to Yul functions that conditionally terminate the external EVM call; Simplify the starting offset of zero-length operations to zero. More efficient overflow checks for multiplication.

Lines of Code:


[G-07] <array>.length should not be looked up in every loop of a for-loop


Description:

The overheads outlined below are PER LOOP, excluding the first loop

  • storage arrays incur a Gwarmaccess (100 gas)

  • memory arrays use MLOAD (3 gas)

  • calldata arrays use CALLDATALOAD (3 gas)

Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP needed to store the stack offset

Lines of Code:


[G-08] x += y costs more gas than x = x + y for state variables


Lines of Code:


[G-10] Use computed variables to save gas


Description:
Since the variables are computed, there is no need to repeat the computation. This saves gas.

Lines of Code:

// Lender.sol#L405-L413
emit Repaid(
loan.borrower,
loan.lender,
loanId,
+ totalDebt,
- loan.debt + lenderInterest + protocolInterest,
loan.collateral,
loan.interestRate,
loan.startTimestamp
);

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!