Platform: Code4rena
Start Date: 14/04/2022
Pot Size: $75,000 USDC
Total HM: 8
Participants: 72
Period: 7 days
Judge: Jack the Pug
Total Solo HM: 2
Id: 110
League: ETH
Rank: 68/72
Findings: 1
Award: $52.67
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Dravee
Also found by: 0v3rf10w, 0x1f8b, 0xAsm0d3us, 0xBug, 0xDjango, 0xNazgul, 0xkatana, CertoraInc, Cityscape, Funen, Hawkeye, IllIllI, MaratCerby, SolidityScan, TerrierLover, TomFrenchBlockchain, Tomio, TrungOre, bae11, berndartmueller, csanuragjain, defsec, delfin454000, ellahi, fatherOfBlocks, gs8nrv, gzeon, horsefacts, ilan, jah, joestakey, joshie, kebabsec, kenta, nahnah, oyc_109, rayn, rfa, robee, saian, securerodd, simon135, slywaters, sorrynotsorry, tchkvsky, teryanarmen, z3s
52.6692 USDC - $52.67
Uninitialized variables by default contain a value equivalent to 0: uint
s are initialized to 0; bool
s to false; address
es to address(0)
.
Explicitly assigning these values to variables when they are declared increases gas costs while providing no funciton.
e.g. change this code:
uint256 var = 0;
to
uint256 var;
For more information, please consult the following resources:
Tips and Tricks to Save Gas and Reduce Bytecode Size
The following lines of code are affected:
src/CitadelMinter.sol:152: for (uint256 i = 0; i < numPools; i++) { src/CitadelMinter.sol:180: uint256 lockingAmount = 0; src/CitadelMinter.sol:181: uint256 stakingAmount = 0; src/CitadelMinter.sol:182: uint256 fundingAmount = 0; src/SupplySchedule.sol:103: uint256 mintable = 0; src/SupplySchedule.sol:192: uint256 mintable = 0;
Newer versions of the Solidity compiler will check for integer overflows and underflows automatically. This provides safety but increases gas costs.
When an unsigned integer is guaranteed to never overflow, the unchecked
feature of Solidity can be used to save gas costs.
A common case for this is for-loops using a strictly-less-than comparision in their conditional statement, e.g.:
uint256 length = someArray.length; for (uint256 i; i < length; ++i) { }
In cases like this, the maximum value for length
is 2**256 - 1
. Therefore, the maximum value of i
is 2**256 - 2
as it will always be strictly less than length
.
This example can be replaced with the following construction to reduce gas costs:
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; } }
An example of this pattern exists already in the Badger Citadel repository in the file src/SupplySchedule.sol
, lines 111-123.
For more information, consult the following resources:
Solidity docs: underflows, overflows, and unchecked
The following lines of code are affected:
src/CitadelMinter.sol:152: for (uint256 i = 0; i < numPools; i++) { src/CitadelMinter.sol:344: for (uint256 i; i < length; ++i) {
Using ++i
costs less gas than using i++
. In the context of a for-loop, gas is saved on each iteration.
The following line of code is affected:
src/CitadelMinter.sol:152: for (uint256 i = 0; i < numPools; i++) {
When checking whether a value is equal to zero, using the construction var != 0
is costs less gas than using var > 0
. Note that this is true only when the comparison occurs in a conditional context and the Solidity compiler is using the Optimizer.
For more information, please consult the following resources:
Twitter discussion detailing the gas costs of != 0 vs > 0 in require() calls
Solidity Compiler: Optimizer options
The following lines of code are affected:
src/CitadelMinter.sol:343: require(length > 0, "CitadelMinter: no funding pools"); src/Funding.sol:170: require(_assetAmountIn > 0, "_assetAmountIn must not be 0"); src/Funding.sol:322: require(amount > 0, "nothing to sweep"); src/Funding.sol:340: require(amount > 0, "nothing to claim"); src/Funding.sol:424: require(_citadelPriceInAsset > 0, "citadel price must not be zero"); src/Funding.sol:452: require(_citadelPriceInAsset > 0, "citadel price must not be zero"); src/KnightingRound.sol:172: require(_tokenInAmount > 0, "_tokenInAmount should be > 0"); src/KnightingRound.sol:215: require(tokenOutAmount_ > 0, "nothing to claim"); src/KnightingRound.sol:411: require(amount > 0, "nothing to sweep"); src/interfaces/convex/BoringMath.sol:122: require(b > 0, "BoringMath: division by zero"); src/interfaces/convex/BoringMath.sol:142: require(b > 0, "BoringMath: division by zero"); src/interfaces/convex/BoringMath.sol:20: require(b > 0, "BoringMath: division by zero");