Platform: Code4rena
Start Date: 31/03/2022
Pot Size: $75,000 USDC
Total HM: 7
Participants: 42
Period: 7 days
Judge: Jack the Pug
Total Solo HM: 5
Id: 102
League: ETH
Rank: 38/42
Findings: 1
Award: $91.25
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0xNazgul, 0xkatana, 0xkowloon, CertoraInc, Dravee, Funen, Hawkeye, Jujic, Kenshin, Meta0xNull, Sleepy, TerrierLover, catchup, csanuragjain, defsec, georgypetrov, kenta, okkothejawa, rayn, rfa, robee, saian, samruna
91.2509 USDC - $91.25
Some revert strings in code are larger than 32 bytes, reducing the strings to 32 bytes reduces code size and save gas on deployment and when require condition is met
Some examples in code
Size of the strings can be reduced or use custom errors introduced in 0.8.4 refer : https://blog.soliditylang.org/2021/04/21/custom-errors/
Repeated storage calls of same variable in a code block can be cached and re-used instead of reading from storage to save gas
int256 delta = int128(currentMonth) - int128(previousMonth); percentageChange = (delta * Constants.BP_INT) / int128(previousMonth);
decimalsNormalizer
in
if (decimalsNormalizer < 0) { scalingFactor = 10**(-1 * decimalsNormalizer).toUint256(); _peg = _peg.div(scalingFactor); } else { scalingFactor = 10**decimalsNormalizer.toUint256(); _peg = _peg.mul(scalingFactor); }
volt()
function call can be cached and re-used in
uint256 amountFeiToTransfer = Math.min( volt().balanceOf(address(this)), amountVoltOut ); uint256 amountFeiToMint = amountVoltOut - amountFeiToTransfer; if (amountFeiToTransfer != 0) { IERC20(volt()).safeTransfer(to, amountFeiToTransfer); }
Statements can be re-ordered to reduce gas consumption on revert
Input validation can be done before storage write and function calls in
lastBufferUsedTime = block.timestamp; _setBufferCap(_bufferCap); bufferStored = _bufferCap; require( _rateLimitPerSecond <= _maxRateLimitPerSecond, "RateLimited: rateLimitPerSecond too high" ); _setRateLimitPerSecond(_rateLimitPerSecond); MAX_RATE_LIMIT_PER_SECOND = _maxRateLimitPerSecond; doPartialAction = _doPartialAction;
newBuffer
can be validation before if condidition
function _depleteBuffer(uint256 amount) internal virtual returns (uint256) { uint256 newBuffer = buffer(); uint256 usedAmount = amount; if (doPartialAction && usedAmount > newBuffer) { usedAmount = newBuffer; } require(newBuffer != 0, "RateLimited: no rate limit buffer"); require(usedAmount <= newBuffer, "RateLimited: rate limit hit"); bufferStored = newBuffer - usedAmount;
Input validation _bufferCap
in require statement can be done before if statement in
if (core().hasRole(TribeRoles.ADD_MINTER_ROLE, msg.sender)) { require( _rateLimitPerSecond <= individualMaxRateLimitPerSecond, "MultiRateLimited: rate limit per second exceeds non governor allowable amount" ); require( _bufferCap <= individualMaxBufferCap, "MultiRateLimited: max buffer cap exceeds non governor allowable amount" ); } require( _bufferCap <= bufferCap, "MultiRateLimited: buffercap too high" );
input validation _rateLimitPerSecond
can be done before storage read in rate limit address validation in
RateLimitData storage rateLimitData = rateLimitPerAddress[ rateLimitedAddress ]; require( rateLimitData.lastBufferUsedTime != 0, "MultiRateLimited: rate limit address does not exist" ); require( _rateLimitPerSecond <= MAX_RATE_LIMIT_PER_SECOND, "MultiRateLimited: rateLimitPerSecond too high" );
require( _bufferCap <= bufferCap, "MultiRateLimited: new buffercap too high" ); require( rateLimitPerAddress[rateLimitedAddress].lastBufferUsedTime == 0, "MultiRateLimited: address already added" ); require( _rateLimitPerSecond <= MAX_RATE_LIMIT_PER_SECOND, "MultiRateLimited: rateLimitPerSecond too high" );
expression assigned to constant variables are evaluated everytime it is called, changing the variable to immutable evaluated the expression once during deployment and avoids repeated evaluation refer: https://github.com/ethereum/solidity/issues/9232
bytes32 public constant override BURNER_ROLE = keccak256("BURNER_ROLE"); bytes32 public constant override MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant override PCV_CONTROLLER_ROLE = keccak256("PCV_CONTROLLER_ROLE"); bytes32 public constant override GOVERN_ROLE = keccak256("GOVERN_ROLE"); bytes32 public constant override GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
constant variable can be changed to immutable