Platform: Code4rena
Start Date: 20/01/2022
Pot Size: $50,000 USDC
Total HM: 3
Participants: 35
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 2
Id: 77
League: ETH
Rank: 3/35
Findings: 2
Award: $1,673.77
π Selected for report: 2
π Solo Findings: 0
π Selected for report: byterocket
19.4163 USDC - $19.42
0x0x0x
It costs less gas to shift than division. So rather than dividing by a power of 2, right shift can be used to save gas.
./libraries/MathLib.sol:43: return ((a * WAD) + (b / 2)) / b; ./libraries/MathLib.sol:55: return ((a + (n / 2)) / n) * n; ./libraries/MathLib.sol:67: return ((a * b) + (WAD / 2)) / WAD; ./libraries/MathLib.sol:85: uint256 x = y / 2 + 1; ./libraries/MathLib.sol:88: x = (y / x + x) / 2;
#0 - 0xean
2022-01-31T14:48:19Z
dupe of #100
π Selected for report: 0x0x0x
106.5364 USDC - $106.54
0x0x0x
removeLiquidity.sol#baseTokenQtyToRemoveFromInternalAccounting
is used only once and caching it does cost extra gas.
So
uint256 baseTokenQtyToRemoveFromInternalAccounting = (_liquidityTokenQty * internalBalances.baseTokenReserveQty) / totalSupplyOfLiquidityTokens; internalBalances .baseTokenReserveQty -= baseTokenQtyToRemoveFromInternalAccounting;
can be replaced with
internalBalances.baseTokenReserveQty -= (_liquidityTokenQty * internalBalances.baseTokenReserveQty) / totalSupplyOfLiquidityTokens;
#0 - GalloDaSballo
2022-02-07T01:47:05Z
Agree with the finding, that should save 6 GAS (MSTORE, MLOAD)
π Selected for report: 0x0x0x
1545.4995 USDC - $1,545.50
0x0x0x
In Exchange.sol
, all functions start with calling isNotExpired
to check whether the function call expired or not. Which is implemented as follows:
function isNotExpired(uint256 _expirationTimeStamp) internal view { require(_expirationTimeStamp >= block.timestamp, "Exchange: EXPIRED"); }
But comments of all functions describe _expirationTimeStamp
as
* @param _expirationTimestamp timestamp that this transaction must occur before (or transaction will revert)
This description is slightly wrong, since when _expirationTimeStamp == block.timestamp
transaction can still be executed. So a better description would be:
* @param _expirationTimestamp timestamp that this transaction will revert after
#0 - 0xean
2022-01-31T14:50:27Z
would be non-critical as the timestamps of the block float and are imprecise to begin with.
#1 - GalloDaSballo
2022-02-05T23:48:02Z
Agree with both sides, but since we gave low severity to #175 and because this is arguably a similar situation, we'll mark the finding as valid with low severity
0x0x0x
!= 0
is a cheaper operation compared to > 0
, when dealing with uint
.
./contracts/Exchange.sol:113: if (tokenQtys.liquidityTokenFeeQty > 0) { ./contracts/Exchange.sol:176: require(this.totalSupply() > 0, "Exchange: INSUFFICIENT_LIQUIDITY"); ./contracts/Exchange.sol:178: _baseTokenQtyMin > 0 && _quoteTokenQtyMin > 0, ./contracts/Exchange.sol:235: if (liquidityTokenFeeQty > 0) { ./contracts/Exchange.sol:267: _baseTokenQty > 0 && _minQuoteTokenQty > 0, ./contracts/Exchange.sol:304: _quoteTokenQty > 0 && _minBaseTokenQty > 0, ./libraries/MathLib.sol:125: require(_tokenAQty > 0, "MathLib: INSUFFICIENT_QTY"); ./libraries/MathLib.sol:127: _tokenAReserveQty > 0 && _tokenBReserveQty > 0, ./libraries/MathLib.sol:266: baseTokenQtyDecayChange > 0, ./libraries/MathLib.sol:336: quoteTokenQtyDecayChange > 0, ./libraries/MathLib.sol:347: require(quoteTokenDecay > 0, "MathLib: NO_QUOTE_DECAY"); ./libraries/MathLib.sol:388: if (_totalSupplyOfLiquidityTokens > 0) { ./libraries/MathLib.sol:496: _baseTokenQtyDesired > 0, ./libraries/MathLib.sol:500: _quoteTokenQtyDesired > 0, ./libraries/MathLib.sol:606: _baseTokenReserveQty > 0 && ./libraries/MathLib.sol:607: _internalBalances.baseTokenReserveQty > 0, ./libraries/MathLib.sol:664: _baseTokenQty > 0 && _quoteTokenQtyMin > 0,
#0 - 0xean
2022-01-31T14:03:17Z
dupe of #161