Loops can be optimized in several ways. Let's take for example the loop in the _liquidateMaker function in ClearingHouse.
for (uint i = 0; i < amms.length; i++) {
(,, uint dToken,,,,) = amms[i].makers(maker);
// @todo put checks on slippage
(int256 _realizedPnl, uint _quote) = amms[i].removeLiquidity(maker, dToken, 0, 0);
realizedPnl += _realizedPnl;
quoteAsset += _quote;
}
We can do multiple things here:
Variables in solidity are already initialized to their default value, and initializing them to the same value actually costs more gas. So for example in the loop above, the code can be optimized using uint i; instead of uint i = 0;.
Use ++i instead of i++ to save some gas spent in every iteration.
Save the array length in a local variable before the loop instead of accessing it in every iteration.
Save amms[i] in a local variable instead of accessing the i element of the array twice in every iteration.
So after all these changes, the code will look something like this:
There are more loops in the code that can be optimized the same way, for example in the ClearingHouse, MarginAccount and the HubbleViewer contracts.
save return value of a function instead of calling it multiple times
in the _calcTwap function in the AMM contract there are multiple calls to the _blockTimestamp(), and it can be called once to save gas.
avoid accessing a mapping multiple times
in the _calcTwap function in the AMM contract, instead of accessing the reserveSnapshots[snapshotIndex] twice in the loop it can be accessed only once.
old code:
this can be done in some other places in the code, like the _increasePosition function for example, when the positions mapping is accessed twice.
old code:
positions[trader].size += baseAssetQuantity; // -ve baseAssetQuantity will increase short position
positions[trader].openNotional += quoteAsset;
new code:
Position storage pos = positions[trader];
pos.size += baseAssetQuantity; // -ve baseAssetQuantity will increase short position
pos.openNotional += quoteAsset;
another place it can be done is in removeMargin in the MarginAccount when accessing margin[idx][trader] twice.
Gas Optimizations
Loop optimizations
Loops can be optimized in several ways. Let's take for example the loop in the
_liquidateMaker
function inClearingHouse
.We can do multiple things here:
uint i;
instead ofuint i = 0;
.amms[i]
in a local variable instead of accessing the i element of the array twice in every iteration. So after all these changes, the code will look something like this:There are more loops in the code that can be optimized the same way, for example in the
ClearingHouse
,MarginAccount
and theHubbleViewer
contracts.save return value of a function instead of calling it multiple times
in the
_calcTwap
function in theAMM
contract there are multiple calls to the_blockTimestamp()
, and it can be called once to save gas.avoid accessing a mapping multiple times
in the
_calcTwap
function in theAMM
contract, instead of accessing thereserveSnapshots[snapshotIndex]
twice in the loop it can be accessed only once. old code:new code:
this can be done in some other places in the code, like the
_increasePosition
function for example, when the positions mapping is accessed twice. old code:new code:
another place it can be done is in
removeMargin
in theMarginAccount
when accessingmargin[idx][trader]
twice.