Platform: Code4rena
Start Date: 23/05/2022
Pot Size: $50,000 USDC
Total HM: 44
Participants: 99
Period: 5 days
Judge: hickuphh3
Total Solo HM: 11
Id: 129
League: ETH
Rank: 62/99
Findings: 2
Award: $84.15
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1337, 0x1f8b, 0x4non, 0xDjango, 0xKitsune, 0xNazgul, 0xf15ers, ACai, AlleyCat, Bahurum, BouSalman, CertoraInc, Chom, Dravee, ElKu, FSchmoede, Funen, GimelSec, Hawkeye, JC, JMukesh, Kaiziron, MaratCerby, Metatron, PP1004, Picodes, Ruhum, SmartSek, StErMi, TerrierLover, UVvirus, UnusualTurtle, WatchPug, Waze, _Adam, asutorufos, berndartmueller, blackscale, blockdev, broccolirob, c3phas, catchup, cryptphi, csanuragjain, defsec, delfin454000, dipp, eccentricexit, ellahi, fatherOfBlocks, gzeon, hansfriese, horsefacts, hubble, ilan, joestakey, kebabsec, minhquanym, oyc_109, parashar, pauliax, rotcivegaf, sach1r0, sashik_eth, shenwilly, simon135, sorrynotsorry, sseefried, throttle, unforgiven, xiaoming90
52.0353 USDC - $52.04
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathHouse.sol#L327 https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L265
In the setFeeTo function in BathToken, admin can change the address to which the withdrawal fees are sent. There is no timelock or multisig involved in the process. Which makes it easy for a sneaky admin to steal the funds behind everyone's back.
#0 - bghughes
2022-06-03T22:15:47Z
#43 #133 #344
#1 - HickupHH3
2022-06-21T09:34:25Z
I don't see what the adverse impact of changing the fee recipient to is. Downgrading due to insufficient justification. Part of warden's QA report: #178
#2 - HickupHH3
2022-06-25T04:15:14Z
this is the warden's primary report since #178 is invalidated
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xf15ers, 0xkatana, Chom, DavidGialdi, Dravee, ElKu, FSchmoede, Fitraldys, Funen, GimelSec, JC, Kaiziron, MaratCerby, Metatron, MiloTruck, Picodes, Randyyy, RoiEvenHaim, SmartSek, Tomio, UnusualTurtle, WatchPug, Waze, _Adam, antonttc, asutorufos, berndartmueller, blackscale, blockdev, c3phas, catchup, csanuragjain, defsec, delfin454000, ellahi, fatherOfBlocks, gzeon, hansfriese, ilan, joestakey, minhquanym, oyc_109, pauliax, pedroais, reassor, rfa, rotcivegaf, sach1r0, samruna, sashik_eth, simon135, z3s
32.1089 USDC - $32.11
GAS OPTIMIZATION:
can be rewritten as:
return ++last_stratTrade_id;
a. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathPair.sol#L206 b. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L436 2. There are lot of places where we could avoid reading multiple times from storage by just using a temporary variable in memory to hold the storage value. For example: (totalSupply == 0) ? shares = assets : shares = ( assets.mul(totalSupply) ).div(totalAssets());
Can be written as: uint256 ts = totalSupply; (ts == 0) ? shares = assets : shares = ( assets.mul(ts) ).div(totalAssets()); This particular example saves one extra storage read. Storage read is 100 gas while memory read is only 3 gas!
See the below reference links and the storage location we are reading multiple times. a. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathPair.sol#L177 for IBathHouse(bathHouse).reserveRatio() b. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L399 for totalSupply. c. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L457 for totalSupply. d. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L569 for totalSupply. e. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathToken.sol#L703 for allowance[from][msg.sender]. f. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L829 for offers[offerId].buy_amt, offers[offerId].pay_amt g. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L868 for offers[offerId].buy_amt, offers[offerId].pay_amt h. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L909 for offers[offerId].buy_amt, offers[offerId].pay_amt i. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L933 for offers[offerId].buy_amt, offers[offerId].pay_amt j. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L1170 for _rank[id]. k. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/peripheral_contracts/BathBuddy.sol#L149 for "start".
Emit the function input instead of the storage variable. See references below: a. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L749 b. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconMarket.sol#L766
The if block can be outside the for loop. And the for loop can start with an "index" value of 1. This reduces the gas for checking "index == 0" in every iteration. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/RubiconRouter.sol#L86
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathPair.sol#L236 to Line 241 can be changed like this(see Line 226 for the equation):
if (offer1.pay_amt != 0) { //changed here IBathToken(bathAssetAddress).cancel( info.askId, offer1.pay_amt //changed here ); } Same logic can be applied line 256 line 261. Modified if statement will look like this(see Line 227 for the equation):
if (offer2.pay_amt != 0) { IBathToken(bathQuoteAddress).cancel( info.bidId, offer2.pay_amt ); }
https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathHouse.sol#L52 right under line 38 of the same file, to save one slot of storage.
c. https://github.com/code-423n4/2022-05-rubicon/blob/8c312a63a91193c6a192a9aab44ff980fbfd7741/contracts/rubiconPools/BathHouse.sol#L43 reserveRatio(as its max value is 100) can be declared as uint64 or even uint8, and combine with the declarations mentioned in the above point(b) to save one slot of storage.
#0 - itsmetechjay
2022-05-31T18:15:27Z
Warden wanted to submit an updated gas optimization report removing some items per help desk request. Updated the report.