G01 - More gas efficient for loop with ++i increment and unchecked block
Loop index increments can be written as unchecked { ++i } instead of simply i++ to save gas.
contracts/Basket.sol:43 for (uint256 i = 0; i < _tokens.length; i++) {
contracts/Basket.sol:70 for (uint256 i = 0; i < _tokens.length; i++) {
contracts/NibblVault.sol:506 for (uint256 i = 0; i < _assetAddresses.length; i++) {
contracts/NibblVault.sol:525 for (uint256 i = 0; i < _assets.length; i++) {
contracts/NibblVault.sol:547 for (uint256 i = 0; i < _assets.length; i++) {
G02 - unchecked block can be used for gas efficiency of the expression that can't overflow/underflow
L322 could be unchecked due to check on L315
And _totalSupply + _purchaseReturn on L315 could be substituted with _initialTokenSupply since _purchaseReturn = _initialTokenSupply - _totalSupply; (L319)
L351 could be unchecked since it's would not underflow, on L350 would check it.
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition has been met.
Next revert strings are longer than 32 bytes:
contracts/NibblVaultFactory.sol:48 require(msg.value >= MIN_INITIAL_RESERVE_BALANCE, "NibblVaultFactory: Initial reserve balance too low");
contracts/NibblVaultFactory.sol:49 require(IERC721(_assetAddress).ownerOf(_assetTokenID) == msg.sender, "NibblVaultFactory: Invalid sender");
contracts/NibblVaultFactory.sol:107 require(basketUpdateTime != 0 && block.timestamp >= basketUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
contracts/NibblVaultFactory.sol:131 require(feeToUpdateTime != 0 && block.timestamp >= feeToUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
contracts/NibblVaultFactory.sol:141 require(_newFee <= MAX_ADMIN_FEE, "NibblVaultFactory: Fee value greater than MAX_ADMIN_FEE");
contracts/NibblVaultFactory.sol:149 require(feeAdminUpdateTime != 0 && block.timestamp >= feeAdminUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
contracts/NibblVaultFactory.sol:166 require(vaultUpdateTime != 0 && block.timestamp >= vaultUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
G04 - Admin role setup
No need to setup role admin with DEFAULT_ADMIN_ROLE since due to openzeppelin docs:
By default, the admin role for all roles is DEFAULT_ADMIN_ROLE
constructor (address _admin) {
bytes32 _defaultAdminRole = DEFAULT_ADMIN_ROLE;
_grantRole(_defaultAdminRole, _admin);
_setRoleAdmin(_defaultAdminRole, _defaultAdminRole); // @audit gas needed? here and below
_setRoleAdmin(FEE_ROLE, _defaultAdminRole);
_setRoleAdmin(PAUSER_ROLE, _defaultAdminRole);
_setRoleAdmin(IMPLEMENTER_ROLE, _defaultAdminRole);
}
G05 - Use previous index in _getTwav()
Since in _getTwav() on L39 index for previous observation will always be the same as current twavObservationsIndex there is no need to count it.
twavObservationsIndex value could be cached and user on L37 and L39, like next:
G01 - More gas efficient
for
loop with++i
increment andunchecked
blockLoop index increments can be written as unchecked { ++i } instead of simply i++ to save gas.
G02 -
unchecked
block can be used for gas efficiency of the expression that can't overflow/underflowL415 could be
unchecked
due to check on L414L319 could be
unchecked
due to check on L311L322 could be
unchecked
due to check on L315 And_totalSupply + _purchaseReturn
on L315 could be substituted with_initialTokenSupply
since_purchaseReturn = _initialTokenSupply - _totalSupply;
(L319)L351 could be
unchecked
since it's would not underflow, on L350 would check it.L378 could be
unchecked
due to check on L373L428 could be
unchecked
since would be check for overflow on L429 and any userunsettledBids
could not be bigger thantotalUnsettledBids
Lines with adding
block.timestamp
value to constant value could beunchecked
since their overflow would appear only in the extremely far future:L457 could be
unchecked
sincetotalUnsettledBids
always >= than any userunsettledBids
.G03 - Avoid long revert strings
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition has been met. Next revert strings are longer than 32 bytes:
G04 - Admin role setup
No need to setup role admin with
DEFAULT_ADMIN_ROLE
since due to openzeppelin docs: By default, the admin role for all roles is DEFAULT_ADMIN_ROLEG05 - Use previous index in
_getTwav()
Since in
_getTwav()
on L39 index for previous observation will always be the same as currenttwavObservationsIndex
there is no need to count it.twavObservationsIndex
value could be cached and user on L37 and L39, like next:G06 - No needed operations
Next lines:
Equivalent to: