Platform: Code4rena
Start Date: 28/06/2022
Pot Size: $25,000 USDC
Total HM: 14
Participants: 50
Period: 4 days
Judge: GalloDaSballo
Total Solo HM: 7
Id: 141
League: ETH
Rank: 45/50
Findings: 1
Award: $21.80
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0x1f8b
Also found by: 0x29A, 0xArshia, 0xKitsune, Bnke0x0, Chom, Fitraldys, Funen, JC, Lambda, Meera, Noah3o6, Picodes, RedOneN, Rohan16, Sm4rty, TerrierLover, TomJ, Tomio, Waze, ajtra, c3phas, cRat1st0s, defsec, durianSausage, fatherOfBlocks, grGred, hake, ladboy233, m_Rassska, mrpathfindr, oyc_109, rfa, ynnad
21.8032 USDC - $21.80
File Name | SHA-1 Hash |
---|---|
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol | 307e3d50b6b6a8af9dc2708049078ce78af6f83d |
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol | 1a4c315f37e8ec7b1d274e6fba2e69dbda742d4e |
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol | f232643764224059e5d24ab1334fa4a32191e7ef |
While the DIV opcode uses 5 gas, the SHR opcode only uses 3 gas (https://www.evm.codes/). Furthermore, Solidity’s division operation also includes a division-by-0 prevention which is bypassed using shifting.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::23 => uint x = y / 2 + 1;
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::26 => x = (y / x + x) / 2;
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::48 => uint x = y / 2 + 1;
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::51 => x = (y / x + x) / 2;
Replace / 2
with >> 1
.
VS Code
If a variable is not set/initialized, it is assumed to have the default value (0
, false
, 0x0
etc depending on the data type). If you explicitly initialize it with its default value, you are just wasting gas.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::226 => uint nextIndex = 0;
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::227 => uint index = 0;
Do not initialize variables with default values.
VS Code
Pre-increments cost less gas compared to post-increments.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::210 => for (uint i = 0; i < _prices.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::340 => for (uint i = 0; i < 255; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::154 => for (uint i = 0; i < routes.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::380 => for (uint i = 0; i < routes.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::131 => for (uint i = 0; i < len; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::211 => for (uint i = 0; i < len; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::742 => for (uint i = 0; i < assets.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1010 => for(uint i = 0; i < numMarkets; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1352 => for (uint i = 0; i < cTokens.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::66 => for (uint i = 0; i < newProposal.targets.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::88 => for (uint i = 0; i < proposal.targets.length; i++) {
Change i++
to ++i
.
VS Code
In Solidity 0.8+, there’s a default overflow check on unsigned integers.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::210 => for (uint i = 0; i < _prices.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::340 => for (uint i = 0; i < 255; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::154 => for (uint i = 0; i < routes.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::380 => for (uint i = 0; i < routes.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::131 => for (uint i = 0; i < len; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::211 => for (uint i = 0; i < len; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::742 => for (uint i = 0; i < assets.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1010 => for(uint i = 0; i < numMarkets; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1352 => for (uint i = 0; i < cTokens.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::66 => for (uint i = 0; i < newProposal.targets.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::88 => for (uint i = 0; i < proposal.targets.length; i++) {
One example is the code would go from:
for (uint i = 0; i < _prices.length; i++) { priceAverageCumulative += _prices[i]; }
to:
for (uint i = 0; i < _prices.length;) { priceAverageCumulative += _prices[i]; unchecked { i++; } }
VS Code
If a variable is not set/initialized, it is assumed to have the default value (0
, false
, 0x0
etc depending on the data type). If you explicitly initialize it with its default value, you are just wasting gas.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::210 => for (uint i = 0; i < _prices.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::340 => for (uint i = 0; i < 255; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::154 => for (uint i = 0; i < routes.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::380 => for (uint i = 0; i < routes.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::131 => for (uint i = 0; i < len; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::211 => for (uint i = 0; i < len; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::742 => for (uint i = 0; i < assets.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1010 => for(uint i = 0; i < numMarkets; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1352 => for (uint i = 0; i < cTokens.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::66 => for (uint i = 0; i < newProposal.targets.length; i++) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::88 => for (uint i = 0; i < proposal.targets.length; i++) {
Do not initialize variables with default values.
VS Code
!= 0
rather than > 0
for unsigned integers in require()
statementsWhen the optimizer is enabled, gas is wasted by doing a greater-than operation, rather than a not-equals operation inside require()
statements. When using !=,
the optimizer is able to avoid the EQ
, ISZERO
, and associated operations, by relying on the JUMPI
that comes afterwards, which itself checks for zero.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::256 => require(liquidity > 0, 'ILM'); // BaseV1: INSUFFICIENT_LIQUIDITY_MINTED
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::275 => require(amount0 > 0 && amount1 > 0, 'ILB'); // BaseV1: INSUFFICIENT_LIQUIDITY_BURNED
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::289 => require(amount0Out > 0 || amount1Out > 0, 'IOA'); // BaseV1: INSUFFICIENT_OUTPUT_AMOUNT
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::306 => require(amount0In > 0 || amount1In > 0, 'IIA'); // BaseV1: INSUFFICIENT_INPUT_AMOUNT
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::122 => require(amountA > 0, "BaseV1Router: INSUFFICIENT_AMOUNT");
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::123 => require(reserveA > 0 && reserveB > 0, "BaseV1Router: INSUFFICIENT_LIQUIDITY");
Use != 0
rather than > 0
for unsigned integers in require()
statements.
VS Code
Comparing to a constant (true
or false
) is a bit more expensive than directly checking the returned boolean value.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::154 => if (marketToJoin.accountMembership[borrower] == true) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1355 => if (borrowers == true) {
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1362 => if (suppliers == true) {
Remove the == true
.
VS Code
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment. It is recommended to avoid open TODOs as they may indicate programming errors that still need to be fixed.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1237 => // TODO: Don't distribute supplier COMP if the user is not in the supplier market.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1276 => // TODO: Don't distribute supplier COMP if the user is not in the borrower market.
VS Code
Require statements including conditions with the &&
operator can be broken down in multiple require statements to save gas.
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::275 => require(amount0 > 0 && amount1 > 0, 'ILB'); // BaseV1: INSUFFICIENT_LIQUIDITY_BURNED
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::291 => require(amount0Out < _reserve0 && amount1Out < _reserve1, 'IL'); // BaseV1: INSUFFICIENT_LIQUIDITY
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::297 => require(to != _token0 && to != _token1, 'IT'); // BaseV1: INVALID_TO
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::434 => require(recoveredAddress != address(0) && recoveredAddress == owner, 'BaseV1: INVALID_SIGNATURE');
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-core.sol::471 => require(success && (data.length == 0 || abi.decode(data, (bool))));
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::123 => require(reserveA > 0 && reserveB > 0, "BaseV1Router: INSUFFICIENT_LIQUIDITY");
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Stableswap/BaseV1-periphery.sol::477 => require(success && (data.length == 0 || abi.decode(data, (bool))));
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1008 => require(numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input");
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Comptroller.sol::1416 => require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, "Comptroller::_setCompSpeeds invalid input");
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::42 => require(unigovProposal.targets.length == unigovProposal.values.length &&
2022-06-NewBlockchain-v2/lending-market-v2/contracts/Governance/GovernorBravoDelegate.sol::43 => unigovProposal.targets.length == unigovProposal.signatures.length &&
Breakdown each condition in a separate require statement.
VS Code
#0 - GalloDaSballo
2022-08-14T20:43:29Z
No immutables so all the findings will save less than 200 gas