Open code423n4 opened 2 years ago
Only marginal gas improvements.
I'm not convinced that storing the storage pointer will actually save gas
I believe this would save 6 gas per iteraton
Will save 100 gas per instance -> 5 = 500
6 gas
This is a pretty meaningful gas saving in that the current one will cost 20k to set and refund 15k (gas refunds being capped at 1/5 call cost), while the proposed version will cost 5k to set and 5k to unset, with a refund because the original value is set back, this should bring the cost down meaningfully, saving 15k gas
15 gas
Total gas saved: 15527
Gas Optimizations
Save the return value of a function instead of calling it multiple times
Let's take a look at the
getContractRegisteredRange
function in theMessageProxy
contract:In this function, the expression
_getRegistryContracts()[schainHash]
is used and calculated multiple times, and it can be calculated once. The code will look something like this:This can be done also in the
registerExtraContractForAll
function of theMessageProxy
contract:We can save the return value of _getRegistryContracts()[bytes32(0)] instead of calling it twice. The code will be:
loop in
getContractRegisteredRange
(also saving a variable instead ofi - from
)Loops can be optimized in several ways. Let's look for example at the loop in the
getContractRegisteredRange
function of theMessageProxy
contract:We can do several things here:
i - from
in every iteration by saving another index. The code will look something like this:calculating an expression once
Another thing that can be done in this specific function (
getContractRegisteredRange
function of theMessageProxy
contract) is that the expressionto - from
can be calculated once instead of twice, and can be calculated using unchecked becuase of the check above. The code will look like this:no need to call
contains
in most casesIn a lot of places in the contracts you call the contains function to check if an element in the set, and only then removing or adding it. But you can just check the return value of the add or remove function - add returns true if the element was added successfully, which means that he wasn't in the set before. The remove function returns true if the element was removed successfully, which means that he wasn in the set before. So instead of writing something like this:
You can simply use:
This will save the gas spent on the call to the contains function.
This repeats all over the contracts, the places I saw this happening
registerExtraContractForAll
,removeExtraContractForAll
,_registerExtraContract
,_removeExtraContract
functionsloops in
MessageProxyForMainnet
contractIn the
MessageProxyForMainnet
contrcat, there are some loops that can be optimize. Let's take a look at the loop in theinitializeAllRegisteredContracts
function:We can do several things here:
contracts
array length in a local variable instead of accessing it in every iteration.contracts[i]
in a local variable instead of accessing it 4 times in every iteration. This will save accssing the array's ith element 4 times in every iteration ,which requires an address calculation.Another loop that can be optimized is in the
postIncomingMessages
of this contract:The things we can do here:
messages
array length in a local variable instead of accessing it in every iteration.messages[i]
in a local variable instead of accessing it multiple times in every iteration.startingCounter
instead of calculatingstartingCounter + i
in every iteration.Optimizing the reentrency gaurd
The reenterncy guard in the
MessageProxyForMainnet
contract can be optimized. In solidity, changing a variable value from its default value to another value costs more gas then changing it from a non-default value to a non-default value (really weird, I know). So in the current implementation the operation of changing the lock from false to true can be optimized. In order to optimize it, you can use uint8 instead of bool, and use values 1 and 2 for the lock (1 for locked, 2 for unlocked). This will look like this:Loops in the DepositBox contracts
There are lots of loops in these contrcats, and the tricks I explained before will work here too. Every optimization will save gas - even changing the
i++
to++i
.save the element and hash calculation instead of calculating it in every iteration in
getSchainToAllERC721
In the mentioned function, the hash is calculated in order to access a mapping element. But instead of calculating it once and save the hash value, it's being calculated in every iteration, and that will cost extra gas for nothing. More than that, we can save all set instead of accessing the mapping in every interation.
Code before:
Code after: