Platform: Code4rena
Start Date: 24/06/2021
Pot Size: $80,000 USDC
Total HM: 18
Participants: 12
Period: 7 days
Judge: cemozer
Total Solo HM: 11
Id: 16
League: ETH
Rank: 10/12
Findings: 1
Award: $999.99
π Selected for report: 3
π Solo Findings: 0
π Selected for report: hrkrshnn
333.3333 USDC - $333.33
hrkrshnn
Several variables can be converted into immutables. Doing so can save 2100 gas for storage reads when the slot is warm and 100 otherwise.
Notice: Variable declaration can be converted into an immutable. --> @openzeppelin/contracts/token/ERC20/ERC20.sol:38:5: | 38 | uint256 private _totalSupply; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Insurance.sol:18:5: | 18 | ITracerPerpetualsFactory public perpsFactory; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Insurance.sol:20:5: | 20 | address public collateralAsset; // Address of collateral asset | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Insurance.sol:23:5: | 23 | address public token; // token representation of a users holding in the pool | ^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Insurance.sol:25:5: | 25 | ITracerPerpetualSwaps public tracer; // Tracer associated with Insurance Pool | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Liquidation.sol:28:5: | 28 | IPricing public pricing; | ^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Liquidation.sol:29:5: | 29 | ITracerPerpetualSwaps public tracer; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Liquidation.sol:30:5: | 30 | address public insuranceContract; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Liquidation.sol:31:5: | 31 | address public fastGasOracle; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Pricing.sol:17:5: | 17 | address public tracer; | ^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Pricing.sol:18:5: | 18 | IInsurance public insurance; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Notice: Variable declaration can be converted into an immutable. --> contracts/Pricing.sol:19:5: | 19 | IOracle public oracle; | ^^^^^^^^^^^^^^^^^^^^^
References to source file and line numbers can be seen above.
A custom solidity compiler.
As explained above, these variables can be converted into immutables.
π Selected for report: hrkrshnn
333.3333 USDC - $333.33
hrkrshnn
Gas optimization.
It has an important optimization improvement: a low level inliner. Especially since you have several small functions.
The current hardhat config indicates that version 0.8.0
is being used.
π Selected for report: hrkrshnn
333.3333 USDC - $333.33
hrkrshnn
Gas optimization.
memory
to calldata
There are several places where this is applicable, however, will point out one such occasion:
modified src/contracts/Trader.sol @@ -64,7 +64,7 @@ contract Trader is ITrader { * @param makers An array of signed make orders * @param takers An array of signed take orders */ - function executeTrade(Types.SignedLimitOrder[] memory makers, Types.SignedLimitOrder[] memory takers) + function executeTrade(Types.SignedLimitOrder[] calldata makers, Types.SignedLimitOrder[] calldata takers) external override { @@ -144,7 +144,7 @@ contract Trader is ITrader { * @dev Should only be called with a verified signedOrder and with index * < signedOrders.length */ - function grabOrder(Types.SignedLimitOrder[] memory signedOrders, uint256 index) + function grabOrder(Types.SignedLimitOrder[] calldata signedOrders, uint256 index) internal returns (Perpetuals.Order memory) {
Reason: when you specify memory
for a (non value type)
function-parameter for an external function, the following happens: the
compiler would copy elements from calldata
to memory
(using the
opcode calldatacopy
.) Then later on, the internal call (here
grabOrder
) would pass a memory reference. However, this is a great
example of where copying to memory is unnecessary. Note that there is
also the opcode calldataload
to read an offset from calldata
. By
changing the location from memory
to calldata
, you avoid this
expensive copy from calldata
to memory
, while managing to do exactly
what's needed.
You would only have to use memory
if the function has to modify the
parameter, in which case a copy is really needed as calldata
cannot be
modified.