Platform: Code4rena
Start Date: 14/07/2022
Pot Size: $25,000 USDC
Total HM: 2
Participants: 63
Period: 3 days
Judge: PierrickGT
Total Solo HM: 1
Id: 147
League: ETH
Rank: 51/63
Findings: 1
Award: $17.03
π Selected for report: 0
π Solo Findings: 0
π Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, Aymen0909, Chom, Deivitto, ElKu, JC, JohnSmith, Kaiziron, Limbooo, MadWookie, Meera, ReyAdmirado, Rohan16, Sm4rty, SooYa, TomJ, Trumpero, Waze, __141345__, ajtra, ak1, antonttc, bulej93, c3phas, cRat1st0s, csanuragjain, defsec, durianSausage, fatherOfBlocks, gogo, hake, hickuphh3, ignacio, joestakey, karanctf, kyteg, m_Rassska, pashov, rajatbeladiya, rbserver, robee, rokinot, samruna, sashik_eth, simon135, tofunmi
17.0318 USDC - $17.03
Anytime you are reading from storage more than once, it is cheaper in gas cost to cache the variable in memory: a SLOAD
cost from 100 to 2100 gas, while MLOAD
and MSTORE
cost 3 gas.
Instances include:
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L231-L236
line.proportion
is read two times
Assign storage value to memory variable and use this variable instead of loading from storage multipple times.
> 0
is less efficient than != 0
for unsigned integers.
!= 0
costs less gas compared to > 0
for unsigned integers in require statements with the optimizer enabled (6 gas)
While it may seem that > 0
is cheaper than !=
, this is only true without the optimizer enabled and outside a require statement. If you enable the optimizer at 10k AND youβre in a require statement, this will save gas.
Instances include:
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L255
require(auction_.start > 0, "Vault not under auction");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L300
require(auction_.start > 0, "Vault not under auction");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L358
require(auction_.start > 0, "Vault not under auction");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L393
if (liquidatorCut > 0) {
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L398
if (auctioneerCut > 0) {
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L416
require(auction_.start > 0, "Vault not under auction");
Replace > 0
with != 0
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) while providing the same amount of information, as explained here https://blog.soliditylang.org/2021/04/21/custom-errors/
Custom errors are defined using the error statement
Instances include: https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L84 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L102-L108 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L189 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L200 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L255-L256 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L300 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L313 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L328 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L358 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L365 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L395 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L416 https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L437
Replace require
statements with custom errors.
In the EVM, there is no opcode for >=
or <=
. When using greater than or equal, two operations are performed: >
and ==
.
Using strict comparison operators hence saves gas
Instances include:
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L105
initialOffer == 0 || initialOffer >= 0.01e18,
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L108
require(proportion >= 0.01e18, "Proportion below 1%");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L256
require(cauldron.level(vaultId) >= 0, "Undercollateralized");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L313
require(liquidatorCut >= minInkOut, "Not enough bought");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L108
require(liquidatorCut >= minInkOut, "Not enough bought");
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L108
auction_.art - artIn >= debt.min * (10**debt.dec),
Replace <=
and >=
with <
and >
.
For example change require(liquidatorCut >= minInkOut, "Not enough bought");
to require(minInkOut < liquidatorCut, "Not enough bought");
x = x + y
is cheaper than x += y
x += y
costs more than x = x + y
same as x -= y
Instances include:
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L204
limits_.sum += auction_.ink;
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L259
limits[auction_.ilkId][auction_.baseId].sum -= auction_.ink;
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L430
limits_.sum -= auction_.ink;
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L443-L444
auction_.ink -= inkOut.u128();
auction_.art -= artIn.u128();
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L450
limits_.sum -= inkOut.u128();
https://github.com/code-423n4/2022-07-yield/blob/main/contracts/Witch.sol#L598
liquidatorCut -= auctioneerCut;
Replace x += y
and x -= y
with x = x + y
and x = x - y
.