Lodestar-Finance / lodestar-protocol

Houses the code for the Lodestar Finance DeFi protocol.
BSD 3-Clause "New" or "Revised" License
10 stars 7 forks source link

Gas Optimisation #25

Open pavankv241 opened 1 year ago

pavankv241 commented 1 year ago

1.Functions guaranteed to revert when called by normal users can be marked payable*

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2).

Saves 21 gas per call total gas saves :- 105

Code snippet:- https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L181 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L191 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L201 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L211 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L217

2 .Use named returns for local variables where it is possible :-

Saves deployment cost :- 7200

code snippet:- https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L80 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L103 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L113 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L166 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Oracle/SushiOracle.sol#L39

3 . Short require strings save gas Strings in solidity are handled in 32 byte chunks. A require string longer than 32 bytes uses more gas. Shortening these strings will save gas. More than 32 chunks can consumes more memory slots and gas .

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20.sol#L154 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20.sol#L155 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20.sol#L260 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20Delegate.sol#L30 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20Delegate.sol#L42 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20Delegator.sol#L73 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L35 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L36 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L40 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L498 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L811 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L531 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L930 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1077 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1096 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1117 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1171 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1172 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1173 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1181 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1182 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1183 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1191 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1200 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Oracle/PriceOracleProxyETH.sol#L236

Recommedation :- use custom errors

Reference :- https://blog.soliditylang.org/2021/04/21/custom-errors/

  1. Use != instead of > for checking zero in require statement :- Saves :- 3 code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L40

  2. redundant check :- msg.sender == address(0) is not required and OR operator consumes 3 gas .

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CToken.sol#L927

change to if (msg.sender != pendingAdmin) Gas saves :- 3

  1. Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key’s keccak256 hash (Gkeccak256 - 30 gas) and that calculation’s associated stack operations.

saves 42 per access there are 2 access each means 168 gas saves

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/ComptrollerStorage.sol#L114 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/ComptrollerStorage.sol#L117

  1. Don’t compare boolean expressions to boolean literals :- saves deployment gas saves :- 1002 Total deployment gas saves :- 7014

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L165 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1428 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1435 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1173 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1183 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1192 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1201

  1. Rearrange the struct to save storage slot gas :-

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Lens/CompoundLens.sol#L68

To:- struct CTokenMetadata { address cToken; uint exchangeRateCurrent; uint128 supplyRatePerBlock; uint128 borrowRatePerBlock; uint reserveFactorMantissa; uint totalBorrows; uint totalReserves; uint totalSupply; uint totalCash; bool isListed; uint collateralFactorMantissa; address underlyingAssetAddress; uint cTokenDecimals; uint underlyingDecimals; uint compSupplySpeed; uint compBorrowSpeed; uint borrowCap; //uint supplyCap; }

  1. split the require statement which saves gas :- && Opcode consumes 3 gas

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L1489 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Governance/GovernorAlpha.sol#L228

10 . Use a more recent version of solidity Solidity 0.8.10 has a useful change that reduced gas costs of external calls which expect a return value.

In 0.8.15 the conditions necessary for inlining are relaxed. Benchmarks show that the change significantly decreases the bytecode size (which impacts the deployment cost) while the effect on the runtime gas usage is smaller.

In 0.8.17 prevent the incorrect removal of storage writes before calls to Yul functions that conditionally terminate the external EVM call; Simplify the starting offset of zero-length operations to zero. More efficient overflow checks for multiplication.

All scoped contract can be update to latest version .

  1. Constructor can declare as payable :- If constructor declare as payable it prevents Opcode which were used to check "msg.value == 0" and saves 130 gas.

Total saves gas :- 650

code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Timelock.sol#L27 https://github.com/LodestarFinance/plvglp-oracle/blob/audit-candidate/contracts/plvGLPOracle.sol#L42 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/BaseJumpRateModelV2.sol#L54 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Unitroller.sol#L33 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Comptroller.sol#L106

  1. Instead of calling storage varibles cache them to save gas :- Sload cost 200 - 800 gas total 600 gas saved In one function state varibles called 3 times instead of cache them local varibles which saves gas . code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/BaseJumpRateModelV2.sol#L99 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/BaseJumpRateModelV2.sol#L102 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/BaseJumpRateModelV2.sol#L103

13 . Avoid using state variable in emit Saves 390 gas. code snippet:- https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/BaseJumpRateModelV2.sol#L136 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/Unitroller.sol#L49 https://github.com/LodestarFinance/lodestar-protocol/blob/relaunch-candidate/contracts/CErc20Delegator.sol#L84

By this report total gas saves :- 1900. Deployment gas :- 14214 .

LodestarFinance commented 1 year ago

Hi there, thanks for this detailed submission. Can you please provide references for the changes you've suggested to verify gas savings figures? Thanks.

pavankv241 commented 1 year ago

Sure

pavankv241 commented 1 year ago

Hai @LodestarFinance Due some error in package.json file [yarn test ] command is not working i had tried to resolve but i can't ,so deployed scoped file through remix IDE to estimate gas value . I'm requesting to resolve that in package.json after that i'll try to test in yarn and submit remaining files gas value . So below files are deployed through remix and estimated gas value please verify this .

optimised files :- https://github.com/pavankv241/Lodster-Gas-Opti/blob/main/CErc20.sol https://github.com/pavankv241/Lodster-Gas-Opti/blob/main/CErc20Delegator.sol https://github.com/pavankv241/Lodster-Gas-Opti/blob/main/Comptroller.sol

You can replace above files with your files . Once error resolved in package.json i'll run remaining file test . Thanks

File no 1 :- Comptroller.sol

Before optimization gas 10168545 gas, transaction cost 8842213 gas , execution cost 8173809 gas

After Optimization gas 10084920 gas, transaction cost 8769495 gas , execution cost 8107075 gas


File No 2 :- CErc20.sol

Before :- gas 6882621 gas, transaction cost 5984887 gas , execution cost 5526283 gas ,

After :- gas 6854081 gas, transaction cost 5960070 gas , execution cost 5503446 gas ,


File No :- 3 CToken.sol Can't because of abtract but you can change and see gas difference inhertied file.


File No :- 4 CErc20Delegate.sol

Before gas 7139455 gas, transaction cost 6208221 gas , execution cost 5734585 gas ,

After gas 7093957 gas, transaction cost 6168658 gas , execution cost 5697738 gas


File No :- 5 CErc20Delegator.sol

Before gas 3854322 gas, transaction cost 3351584 gas , execution cost 3024516 gas

After gas 3834579 gas, transaction cost 3334416 gas , execution cost 3009964 gas


File No :- 6 BaseJumpRateModelV2.sol can't because abtract contract