Volt Protocol contest - saian's results

Inflation Protected Stablecoin.

General Information

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

Volt Protocol

Findings Distribution

Researcher Performance

Rank: 38/42

Findings: 1

Award: $91.25

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

91.2509 USDC - $91.25

Labels

bug
G (Gas Optimization)

External Links

Gas Optimizations

1. Revert string greater than 32 bytes

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

Proof of concept

Some examples in code

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/oracle/ScalingPriceOracle.sol#L141

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/oracle/ScalingPriceOracle.sol#L177

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/refs/CoreRef.sol#L48

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/refs/CoreRef.sol#L56

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/refs/CoreRef.sol#L72

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/refs/CoreRef.sol#L82

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/utils/RateLimited.sol#L103

Mitigation

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/

2. Storage variable can be cached to save gas

Repeated storage calls of same variable in a code block can be cached and re-used instead of reading from storage to save gas

Proof of concept

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/oracle/ScalingPriceOracle.sol#L123-L124

int256 delta = int128(currentMonth) - int128(previousMonth); percentageChange = (delta * Constants.BP_INT) / int128(previousMonth);

decimalsNormalizer in

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/refs/OracleRef.sol#L111

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

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/peg/NonCustodialPSM.sol#L286

uint256 amountFeiToTransfer = Math.min( volt().balanceOf(address(this)), amountVoltOut ); uint256 amountFeiToMint = amountVoltOut - amountFeiToTransfer; if (amountFeiToTransfer != 0) { IERC20(volt()).safeTransfer(to, amountFeiToTransfer); }

3. Re-order statements to save gas on revert

Statements can be re-ordered to reduce gas consumption on revert

Proof of concept

Input validation can be done before storage write and function calls in

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/utils/RateLimited.sol#L41

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

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/utils/RateLimited.sol#L95-L106

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

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/utils/MultiRateLimited.sol#L143

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

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/utils/MultiRateLimited.sol#L266-L273

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" );

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/utils/MultiRateLimited.sol#L297-L308

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" );

4. constant variables can be changed to immutable

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

Proof of concept

https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/core/Permissions.sol#L10

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");

Mitigation

constant variable can be changed to immutable

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter