Platform: Code4rena
Start Date: 21/06/2022
Pot Size: $30,000 USDC
Total HM: 12
Participants: 96
Period: 3 days
Judge: HardlyDifficult
Total Solo HM: 5
Id: 140
League: ETH
Rank: 52/96
Findings: 2
Award: $45.54
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0x52, 0xNazgul, 0xNineDec, 0xc0ffEE, 0xf15ers, 0xkatana, BowTiedWardens, Chom, ElKu, Funen, GalloDaSballo, JC, JMukesh, JohnSmith, Lambda, Limbooo, MadWookie, MiloTruck, Nethermind, Noah3o6, Nyamcil, Picodes, PwnedNoMore, Randyyy, RoiEvenHaim, SmartSek, StErMi, Tadashi, TerrierLover, TomJ, Tomio, Treasure-Seeker, UnusualTurtle, Varun_Verma, Wayne, Waze, _Adam, apostle0x01, asutorufos, berndartmueller, c3phas, catchup, cccz, cloudjunky, codexploder, cryptphi, defsec, delfin454000, dipp, ellahi, exd0tpy, fatherOfBlocks, hansfriese, hyh, joestakey, kebabsec, kenta, masterchief, minhquanym, naps62, oyc_109, pashov, peritoflores, reassor, rfa, robee, sach1r0, saian, sashik_eth, shenwilly, simon135, slywaters, sorrynotsorry, sseefried, unforgiven, xiaoming90, ych18, zuhaibmohd, zzzitron
28.282 USDC - $28.28
As solidity document mentions here, it should be named with all capital letters with underscores separating words. However, following state variable does not follow this pattern.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L28
uint256
instead of uint
for the consistencyThroughout the codebase, uint256
is used. However, the following variables in NibblVault.sol
do not follow this pattern.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L195
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L289
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L336
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L348
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L455
NibblVault.sol
uses ERC20Upgradeable
, but the interfaces used in this contract does not use OpenZeppelin's upgradeable files.
Throughout the codebase, there are 4 spaces in one indentation. However, following 3 codes do not follow this pattern.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L238
function _chargeFeeSecondaryCurve(uint256 _amount) private returns(uint256) { address payable _factory = factory; uint256 _adminFeeAmt = NibblVaultFactory(_factory).feeAdmin();
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L253
function getMaxSecondaryCurveBalance() private view returns(uint256){ return ((secondaryReserveRatio * initialTokenSupply * initialTokenPrice) / (1e18 * SCALE)); }
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L266
function getCurrentValuation() private view returns(uint256) { return totalSupply() < initialTokenSupply ? (secondaryReserveBalance * SCALE /secondaryReserveRatio) : ((primaryReserveBalance) * SCALE / primaryReserveRatio); }
initialize
instead of initialise
Basket.sol
has initialise
function while NibblVault.sol
has initialize
function.
OZ's example uses initialize
so Basket.sol
also should use initialize
.
https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializers
require
Throughout the codebase, require
check sets error messages. However, findPositionInMaxExpArray
function does not follow this pattern, and it simply has require(false)
. It is worth adding why this part should always fail.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L356
buy
fuction and sell
functionComments used at buy
fuction and sell
function in NibblVault.sol
seem to be wrong.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L297
/// @dev if current totalSupply < initialTokenSupply AND _amount to buy tokens for is greater than (maxSecondaryCurveBalance - currentSecondaryCurveBalance) then buy happens on secondary curve and primary curve both
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L358
/// @dev if totalSupply > initialTokenSupply AND _amount to sell is greater than (_amtIn > totalSupply - initialTokenSupply) then sell happens on primary curve and secondary curve both
They say buy happens on secondary curve and primary curve both
and sell happens on secondary curve and primary curve both
, but buy and sell only happen at primary curve only.
initiateBuyout
functionhttps://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L395
/// @dev bidder needs to send funds equal to current valuation - ((primaryReserveBalance - fictitiousPrimaryReserveBalance) + secondaryReserveBalance) to initiate buyout
It seems that current valuation - ((primaryReserveBalance - fictitiousPrimaryReserveBalance) + secondaryReserveBalance)
is no longer used at initiateBuyout
function, and this comment seems to be wrong.
#0 - HardlyDifficult
2022-07-04T19:20:02Z
Mostly NC but worthwhile improvements
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 8olidity, ACai, BowTiedWardens, Chandr, Chom, ElKu, Fitraldys, Funen, IgnacioB, JC, Lambda, Limbooo, MiloTruck, Noah3o6, Nyamcil, Picodes, Randyyy, SmartSek, StErMi, TerrierLover, TomJ, Tomio, UnusualTurtle, Waze, _Adam, ajtra, c3phas, cRat1st0s, catchup, codexploder, cryptphi, defsec, delfin454000, ellahi, exd0tpy, fatherOfBlocks, hansfriese, joestakey, kebabsec, kenta, m_Rassska, minhquanym, oyc_109, pashov, reassor, rfa, robee, sach1r0, saian, sashik_eth, simon135, slywaters, ych18, ynnad, zuhaibmohd
17.2596 USDC - $17.26
!= 0
instead of > 0
on uint variablesuint variables will never be lower than 0. Therefore, > 0
and != 0
have same meanings. Using != 0
can reduce the gas deployment cost, so it is worth using != 0
wherever possible.
Here are list of the gas improvements by using != 0
.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L227
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L243
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L188
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L296
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L323
The default value of uint varibles are 0. Therefore, there is no need to set 0 on uint variables. Not setting 0 on uint variables can reduce the deployment gas cost.
Here are list of the gas improvements.
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L506
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L285
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L312
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L369
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L419
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L460
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L506
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L525
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L547
Following variables or operations can be wrapped by unchecked to reduce the gas cost.
[1] --i
used in the for loop when the end condition is uint or constant
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L296
for (uint8 i = MAX_PRECISION; i > 0;) { x = (x * x) / FIXED_1; // now 1 < x < 4 if (x >= FIXED_2) { x >>= 1; // now 1 < x < 2 res += ONE << (i - 1); } unchecked { --i; } }
[2] if(_totalSupply > _initialTokenSupply)
assures that _totalSupply - _initialTokenSupply
will not underflow
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L378
uint256 _tokensPrimaryCurve; unchecked { _tokensPrimaryCurve = _totalSupply - _initialTokenSupply; }
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L319
unchecked { _purchaseReturn = _initialTokenSupply - _totalSupply; }
[3] primaryReserveBalance - _saleReturn
will not underflow
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L380
primaryReserveBalance -= _saleReturn
is equivalent with primaryReserveBalance = primaryReserveBalance - _saleReturn
which is same with primaryReserveBalance = primaryReserveBalance - (primaryReserveBalance - fictitiousPrimaryReserveBalance) = fictitiousPrimaryReserveBalance
. Therefore primaryReserveBalance -= _saleReturn
can be written like this:
unchecked { primaryReserveBalance -= _saleReturn; }
[4] if (_buyoutBid > _currentValuation)
assures that _buyoutBid - _currentValuation
will not underflow
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/NibblVault.sol#L415
if (_buyoutBid > _currentValuation) { unchecked { safeTransferETH(payable(msg.sender), (_buyoutBid - _currentValuation)); } }
[5] require(... && _sellAmount <= _supply)
assures that _supply - _sellAmount
will not underflow
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L235
uint256 baseD; unchecked { baseD = _supply - _sellAmount; }
Using custom errors can reduce the gas cost.
There are more than 40 callsites which use require
with inline string.
mul
and add
function of SafeMath
library at BancorFormula.sol
increases the gas costIn OpenZeppelin's SafeMath
library, mul
function simply multiply and add
function do addition. mul
function is only used in BancorFormula.sol
, so not using mul
or add
function and removing the usage of SafeMath
library can decrease the gas cost.
Here are OZ's definitions.
function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; }
function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; }
add
functionhttps://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L200
mul
functionhttps://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L196
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L202
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L231
https://github.com/code-423n4/2022-06-nibbl/blob/main/contracts/Bancor/BancorFormula.sol#L237
#0 - mundhrakeshav
2022-06-26T09:36:22Z
https://github.com/code-423n4/2022-06-nibbl-findings/issues/2, https://github.com/code-423n4/2022-06-nibbl-findings/issues/3, https://github.com/code-423n4/2022-06-nibbl-findings/issues/6, https://github.com/code-423n4/2022-06-nibbl-findings/issues/8, https://github.com/code-423n4/2022-06-nibbl-findings/issues/9,
BancorFormula.sol not in scope