Platform: Code4rena
Start Date: 05/05/2022
Pot Size: $125,000 DAI
Total HM: 17
Participants: 62
Period: 14 days
Judge: leastwood
Total Solo HM: 15
Id: 120
League: ETH
Rank: 54/62
Findings: 1
Award: $91.84
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xf15ers, 0xkatana, 0xsomeone, AlleyCat, BowTiedWardens, Cityscape, Fitraldys, Funen, GimelSec, Hawkeye, JC, MaratCerby, MiloTruck, Randyyy, TerrierLover, Tomio, UnusualTurtle, WatchPug, Waze, _Adam, augustg, bobirichman, catchup, csanuragjain, ellahi, fatherOfBlocks, hake, hansfriese, horsefacts, ignacio, joestakey, kenta, mics, oyc_109, robee, samruna, sashik_eth, sikorico, simon135, throttle
91.8428 DAI - $91.84
When initizalising a variable to the default value it can be left blank to save some gas.
FuseTokenAdapterV1.sol#L36 to: uint256 private constant NO_ERROR;
AlchemistV2.sol#L1458 to: uint256 totalValue;
EthAssetManager.sol#L566 to uint256 total;
TransmuterV2.sol#L96 to address public constant ZERO_ADDRESS;
For loops can be optimised a few ways: - i can be left blank as 0 is the default value and doesnโt need to be assigned - The length can be cached to the stack rather than be called every loop (saves roughly 3 gas per iteration or 97 in the instances where a storage variables length is being looped over.) - ++i can be used instead of i++ as it saves a temp variable being created every iteration (will save roughly 5 gas per iteration.)
As an example the for loop on line 141 in CrossChainCanonicalBase.sol would go from: 141 for (uint i = 0; i < bridgeTokensArray.length; i++) {
to: 141 uint256 bridgeTokensArrayLength = bridgeTokensArray.length; 142 for(uint i; i < bridgeTokensArrayLength; ++i) {
Multicall.sol#L14 AlchemistV2.sol#L990 AlchemistV2.sol#L1282 AlchemistV2.sol#L1355 AlchemistV2.sol#L1461 AlchemistV2.sol#L1524 CrossChainCanonicalBase.sol#L57 CrossChainCanonicalBase.sol#L141 EthAssetManager.sol#L567 StakingPools.sol#L188 ThreePoolAssetManager.sol#L250 ThreePoolAssetManager.sol#L254 ThreePoolAssetManager.sol#L353 ThreePoolAssetManager.sol#L773 ThreePoolAssetManager.sol#L902 TransmuterBuffer.sol#L172 TransmuterBuffer.sol#L186 TransmuterBuffer.sol#L235 TransmuterBuffer.sol#L242 TransmuterBuffer.sol#L272 TransmuterBuffer.sol#L382 TransmuterBuffer.sol#L387 TransmuterBuffer.sol#L479
Here, you can emit the memory values as opposed to reading from storage. (save roughly 97 gas every time the event is emitted.)
AlchemicTokenV2Base.sol#L100 to: emit SetFlashMintFee(newFee);
AlchemicTokenV2.sol#L94 to: emit SetFlashMintFee(newFee);
AlchemistV2.sol#L272-L276 to: emit AdminUpdated(params.admin); emit TransmuterUpdated(params.transmuter); emit MinimumCollateralizationUpdated(params.minimumCollateralization); emit ProtocolFeeUpdated(params.protocolFee); emit ProtocolFeeReceiverUpdated(params.protocolFeeReceiver);
TransmuterBuffer.sol#L247 to: emit SetAlchemist(_alchemist);
TransmuterV2.sol#L203 to: emit Paused(pauseState);
Whenever reading a storage variable more than once in a given scope it is cheaper to store in memory (100 gas per SLOAD vs 100 gas SSTORE and 3 gas MSTORE/3 gas for each MLOAD)
pendingAdmin is read 3 times in the following places. AlchemistV2.sol#L289-L295 EthAssetManager.sol#L304-L312 ThreePoolAssetManager.sol#L456-L464
transmuter is read twice in the following places. AlchemistV2.sol#L792-L795 AlchemistV2.sol#L876-L879 AlchemistV2.sol#L942-L945
rewardReceiver is read twice in the following places. EthAssetManager.sol#L698-L699 ThreePoolAssetManager.sol#L632-L633
poolId & exchangeRate are read twice. gALCX.sol#L71-L79
If line 133 is moved to above 131, _pendingGovernance can be used in the require statement saving an SLOAD. Would cost an extra 6 gas whenever the require statement fails, but would save 93 gas everytime the function is called successfully. StakingPools.sol#L131-L133
transmuterBuffer is read twice. ThreePoolAssetManager.sol#L719-L721
alchemist is read 3 times in the following places. TransmuterBuffer.sol#L443-L446
TransmuterBuffer.sol#L513-L522
flowAvailable[underlyingToken] can be read up to 5 times. TransmuterBuffer.sol#L536-L551
amos[underlyingToken] is read twice. TransmuterBuffer.sol#L567-L568
sinkTransmuter and token are both read twice TransmuterConduit.sol#L35-L36