Platform: Code4rena
Start Date: 24/03/2022
Pot Size: $75,000 USDC
Total HM: 15
Participants: 59
Period: 7 days
Judge: gzeon
Id: 103
League: ETH
Rank: 30/59
Findings: 2
Award: $413.19
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: hake
Also found by: 0v3rf10w, 0xDjango, 0xkatana, BouSalman, CertoraInc, Dravee, Hawkeye, IllIllI, JMukesh, Jujic, Kenshin, PPrieditis, Picodes, PranavG, Ruhum, SolidityScan, VAD37, WatchPug, aga7hokakological, catchup, csanuragjain, cthulhu_cult, defsec, dimitri, hickuphh3, hubble, hyh, kenta, kirk-baird, obront, peritoflores, rayn, robee, saian, samruna, shenwilly, shw, sorrynotsorry, tchkvsky, teryanarmen, ych18
268.1375 USDC - $268.14
DexManagerFacet:batchRemoveDex
removes only first matched dexIn batchRemoveDex
second for-loop the first matched dex is removed using _removeDex
and return statement returns from function, the other dexes in the array are not removed from whitelist
return can be replaced with break
statement
anyswap.token == 0
checkIn AnyswapFacet:startBridgeTokensViaAnyswap
function , if _anyswapData.token equals to 0 and _anyswap.amount equals to 0, functions does not fail, if conditions are not executed, but event LifiTransferStarted is emitted.
library LibDiamond
is imported twice
second import statement can be removed
In WithdrawFacet:withdraw
assert statements are used to validate user inputs.
Assert statements should be used to check internal errors and invariants, and require should be used for validating user inputs
Assert statement can be replaced with require
In LogWithdraw
event declaration assetaddress is the first argument, but in the withdraw
function event emmission a variable assetAddress is sent in the second position and address sendTo is sent in first position
Order of arguments can be changed, comments can be added
In LibAsset
constant MAX_INT is defined with an expression, it can be replaced with type(uint256).max
expression can be replaced with type(uint256).max
In LifiDiamond:constructor
and OwnershipFacet:transferOwnership
sddress validation checks can be added to prevent setting wrong owner address
In LibAsset:approveERC20
spender is approved MAX_INT instead of amount tokens
In LibDiamond
events can be placed above functions
https://docs.soliditylang.org/en/v0.8.4/style-guide.html#order-of-layout
#0 - H3xept
2022-04-05T10:52:02Z
Fixed in lifinance/lifi-contracts@0a078bbbdf8ec92bd72efc4257900af416d537d4
#1 - H3xept
2022-04-05T11:09:25Z
Fixed in lifinance/lifi-contracts@5a6fe3914d8f0eead632994332cc8c158dd57b29
#2 - H3xept
2022-04-08T14:57:17Z
Duplicate of #165
#3 - H3xept
2022-04-11T10:40:01Z
Duplicate of #34
#4 - H3xept
2022-04-11T11:20:38Z
Duplicate of #165
🌟 Selected for report: Dravee
Also found by: 0v3rf10w, 0xDjango, 0xNazgul, 0xkatana, ACai, CertoraInc, FSchmoede, Funen, Hawkeye, IllIllI, Jujic, Kenshin, PPrieditis, Picodes, SolidityScan, TerrierLover, Tomio, WatchPug, catchup, csanuragjain, defsec, dimitri, hake, hickuphh3, kenta, minhquanym, obront, peritoflores, rayn, rfa, robee, saian, samruna, tchkvsky, teryanarmen, ych18
145.0463 USDC - $145.05
expression assigned to constants are recomputed every time it is called, so keccak operation is done every time the variable is used This can be prevented by using value directly or using immutable so that value is computed once
Use immutable instead of constant
unchecked
can save gasarithmetic operations that cant overflow/underflow can placed inside a unchecked block to avoid underflow/overflow check and save gas
statement can be placed inside a unchecked block
Storing storage variable re-using it can save ~100 gas on repeated reads
In DexManagerFacet:removeDex
s.dex.length is read in every iteration, this value can be cached in a variable and save ~100 gas in repeated storage reads
In HopFacet:_startBridge
s.hopChainId can be cached
>
with !=
can save gasusing !=
can save gas than >
with uint and optimizer enabled
In AnyswapFacet:swapAndStartBridgeTokensViaAnyswap
, require and update statements can be placed outside if-else statements
require(_postSwapBalance > 0, "ERR_INVALID_AMOUNT"); _anyswapData.amount = _postSwapBalance;
the two statements can be placed outide the if-else block
reducing revert string to under 32 bytes can save deployment costs as well as when require condition fails
prefix increment uses less gas when compared to postfix increment unchecked can be added to save more gas as the variable wont overflow
https://github.com/ethereum/solidity/issues/10695
In all for loop in the project
_executeSwaps()
LifiData can be replaced with bytes32In function _executeSwaps()
input LifiData only transaction ID is used from the structure lifiData , so it can be replaced with a bytes32 lifiData.transactionID
In LibDiamond:removeFunctions
second require statement can be placed above storage read to save gas on revert
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
Place require statement above storage read
In LibSwap:swap
if statement can be combined to reduce one call
if (!LibAsset.isNativeAsset(fromAssetId) && LibAsset.getOwnBalance(fromAssetId) < fromAmount) { LibAsset.transferFromERC20(fromAssetId, msg.sender, address(this), fromAmount); } if (!LibAsset.isNativeAsset(fromAssetId)) { LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount); }
if blocks can be nested
if (!LibAsset.isNativeAsset(fromAssetId)) { if(LibAsset.getOwnBalance(fromAssetId) < fromAmount) { LibAsset.transferFromERC20(fromAssetId, msg.sender, address(this), fromAmount); } LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount); }
#0 - H3xept
2022-04-04T07:44:35Z
We internally decided to avoid unchecked statements and prefix increments for now.
#1 - H3xept
2022-04-04T07:48:22Z
#2 - H3xept
2022-04-08T15:21:12Z
Duplicate of #39
#3 - H3xept
2022-04-11T10:27:43Z
Duplicate of #100
#4 - H3xept
2022-04-11T10:54:19Z
Duplicate of #196
#5 - H3xept
2022-04-11T11:09:37Z
Duplicate of #100
#6 - H3xept
2022-04-11T12:06:19Z
We internally decided to avoid previx increments for now.
#7 - H3xept
2022-04-11T12:53:14Z
Duplicate of #182