code-423n4 / 2022-05-backd-findings

0 stars 0 forks source link

Gas Optimizations #151

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

if just reading the constant it still costs gas .to make it less gas make it a smaller bytes10 then bytes32 because 1 char =1 byte each byte less saves gas. bytes32 internal constant _START_BOOST = "startBoost"; bytes32 internal constant _MAX_BOOST = "maxBoost"; bytes32 internal constant _INCREASE_PERIOD = "increasePeriod"; bytes32 internal constant _WITHDRAW_DELAY = "withdrawDelay"; https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/BkdLocker.sol#L21-L24 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/Controller.sol#L25

https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/InflationManager.sol#L25-L28

Use Custom Errors instead of Revert Strings to save Gas Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met) Source Custom Errors in Solidity: Starting from Solidity v0.8.4, there is a convenient and gas-efficient way to explain to users why an operation failed through the use of custom errors. Until now, you could already use strings to give more information about failures (e.g., revert("Insufficient funds.");), but they are rather expensive, especially when it comes to deploy cost, and it is difficult to use dynamic information in them. Custom errors are defined using the error statement, which can be used inside and outside of contracts (including interfaces and libraries). ROLEmanager.sol 28: require(hasRole(Roles.GOVERNANCE, msg.sender), Error.UNAUTHORIZED_ACCESS); 46: require(getRoleMemberCount(Roles.GOVERNANCE) > 1, Error.CANNOT_REVOKE_ROLE); 112: require(role != Roles.GOVERNANCE, Error.CANNOT_REVOKE_ROLE); 113: require(hasRole(role, account), Error.INVALID_ARGUMENT); https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/AmmGauge.sol#L104 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/AmmGauge.sol#L125 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/KeeperGauge.sol#L140 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/Minter.sol#L152

—---------------------------------------------- In a require statement it saves gas to make !=0 .Uint variable is anything greater or equal to zero it saves gas to make != 0
https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/BkdLocker.sol#L91-L94 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/AmmGauge.sol#L104 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/KeeperGauge.sol#L140

++i costs less gas compared to i++ or i += 1 ++i costs less gas compared to i++ or i += 1 for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled. i++ increments i and returns the initial value of i. Which means: uint i = 1; i++; // == 1 but i == 2 But ++i returns the actual incremented value: uint i = 1; ++i; // == 2 and i == 2 too, so no need for a temporary variable In the first case, the compiler has to create a temporary variable (when used) for returning 1 instead of 2 epoch++ Change to ++epoch https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/KeeperGauge.sol#L59

Same thing with minus - - Use – i instead of putting multiple assignment to i i = i - 1; https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/BkdLocker.sol#L140

Uint48 after a bool and bool fills the slot of zeros so uint 48 is waste of gas and it will be cheaper to use uint and uint48 like a mix to make it one slot or after the address because address is 160 bits. If you want the bool then make uint48 into uint256 to save gas. https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/AmmGauge.sol#L32 Order: Address -one slot Bool -one slot Uint48-one slot New Order: Address -160 Uint48-48 1 slot with 48 remaining Bool -1slot Saving:20_000 gas —------------------------------------------ Make variable uninitialized to save gas for sstore 20_000 and memory 3 gas Because by default its already zero https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/AmmGauge.sol#L64 —------------------------------------ Reduce the size of error messages (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 is met. Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.
1 byte for each character

https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/Minter.sol#L152 In the EVM, there is no opcode for >= or <=. When using greater than or equal, two operations are performed: > and =. Using strict comparison operators hence saves gas require(delay >= _MIN_DELAY, Error.DELAY_TOO_SHORT); Instead use Delay != _MIN_DELAY https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/utils/Preparable.sol#L29 —------------------------------- Events with 3 fields make indexed to save gas https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/interfaces/vendor/ICvxLocker.sol#L51-L53

Dead code it wastes gas in the code storing type It will never call the approve function https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/RewardHandler.sol#L63

GalloDaSballo commented 2 years ago

if just reading the constant it still costs gas .to make it less gas make it a smaller bytes10 then bytes32 because 1 char =1 byte each byte less saves gas.

Disagree as below 32 bytes sized variables incur checks for zero-bytes

Use Custom Errors instead of Revert Strings to save Gas

Valid but without POC can't give it points

In a require statement it saves gas to make !=0 .Uint variable is anything greater or equal to zero it saves gas to make != 0

Saves 3 gas per instance

3 * 3 = 9

 ++i costs less gas compared to i++ or i += 1

5 gas per instance

Same thing with minus - -

This should save more, about 10 gas

 https://github.com/code-423n4/2022-05-backd/blob/8121e5244ca29f87b0763d05a69e7fc654d14f45/protocol/contracts/tokenomics/AmmGauge.sol#L32

Packing will save gas but in lack of runtime math I can't quantify impact

Make variable uninitialized to save gas for sstore 20_000 and memory 3 gas

Don't believe this is valid

Reduce the size of error messages (Long revert Strings)

Agree, saves 6 gas at runtime

Total Gas Saved 30