Platform: Code4rena
Start Date: 30/06/2023
Pot Size: $100,000 USDC
Total HM: 8
Participants: 22
Period: 14 days
Judge: Trust
Total Solo HM: 6
Id: 253
League: ETH
Rank: 18/22
Findings: 1
Award: $33.48
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Raihan
Also found by: DavidGiladi, LeoS, Rageur, ReyAdmirado, Rolezn, SAAJ, SAQ, SM3_SS, Sathish9098, hunter_w3b, matrix_0wl, naman1778, petrichor
33.4768 USDC - $33.48
unchecked {}
for subtractions where the operands cannot underflow because of a previous require()
or if
statementrequire(a <= b); x = b - a => require(a <= b); unchecked { x = b - a } if(a <= b); x = b - a => if(a <= b); unchecked { x = b - a } this will stop the check for overflow and underflow so it will save gas
make the variable outside the loop and only give the value to variable inside
This change saves 6 gas per instance. The optimization works until solidity version 0.8.13 where there is a regression in gas costs.
calldata
instead of memory
for read-only arguments in external functions saves gasWhen a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution.
LSP0ERC725AccountCore.sol#L280 4 instances here saves lots of gas
LSP7DigitalAssetCore.sol#L160 5 instances in this function. saves lots of gas
Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size. Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so. Use a larger size then downcast where needed https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
operations are being done on a smaller uint
saves 6 gas per instance
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
if instead of -= we use simple subtraction instead we will have a cheaper version if we use the cached version of _tokenOwnerBalances[from]
before line 347
same thing with _operatorAuthorizedAmount[from][operator]
used in line 354 and 365
same here _tokenOwnerBalances[from]
in lines 410 419
The compiler uses opcodes GT
and ISZERO
for solidity code that uses >
, but only requires LT
for >=
saves 3 gas. - Reference
Instead of using address(this)
, it is more gas-efficient to pre-calculate and use the hardcoded address. Foundry's script.sol
and solmate's LibRlp.sol
contracts can help achieve this. - Reference
Using a double if statement instead of logical AND (&&) can provide similar short-circuiting behavior whereas double if is slightly more efficient.
12 instances here
In Solidity, manipulating contract storage comes with significant gas costs. One can optimize gas usage by preventing unnecessary storage updates when the new value is the same as the existing one. If an existing value is the same as the new one, not reassigning it to the storage could potentially save substantial amounts of gas, notably 2900 gas for a 'Gsreset'. This saving may come at the expense of a cold storage load operation ('Gcoldsload'), which costs 2100 gas, or a warm storage access operation ('Gwarmaccess'), which costs 100 gas. Therefore, the gas efficiency of your contract can be significantly improved by adding a check that compares the new value with the current one before any storage update operation. If the values are the same, you can bypass the storage operation, thereby saving gas.
#0 - c4-judge
2023-08-02T09:48:47Z
trust1995 marked the issue as grade-b