Platform: Code4rena
Start Date: 04/11/2022
Pot Size: $42,500 USDC
Total HM: 9
Participants: 88
Period: 4 days
Judge: 0xean
Total Solo HM: 2
Id: 180
League: ETH
Rank: 62/88
Findings: 1
Award: $21.13
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0x1f8b
Also found by: 0xSmartContract, 0xdeadbeef, Aymen0909, B2, Bnke0x0, Deivitto, Diana, Dinesh11G, JC, RaymondFam, ReyAdmirado, Rolezn, Sathish9098, TomJ, ajtra, aviggiano, chaduke, cryptostellar5, djxploit, gianganhnguyen, gogo, halden, karanctf, leosathya, lukris02, mcwildy, oyc_109, ret2basic, skyle, slowmoses
21.132 USDC - $21.13
Issue | Contexts | Estimated Gas Saved | |
---|---|---|---|
GAS‑1 | ++i /i++ Should Be unchecked{++i} /unchecked{i++} When It Is Not Possible For Them To Overflow, As Is The Case When Used In For- And While-loops | 2 | - |
GAS‑2 | abi.encode() is less efficient than abi.encodepacked() | 3 | - |
GAS‑3 | Use calldata instead of memory for function parameters | 1 | 300 |
GAS‑4 | Public Functions To External | 1 | - |
GAS‑5 | Optimize names to save gas | 1 | 22 |
GAS‑6 | Use local variable instead of storage variable for event emit | 3 | 300 |
GAS‑7 | Cache/precompute repeated calculations | 2 | 200 |
Total: 11 contexts over 6 issues
++i
/i++
Should Be unchecked{++i}
/unchecked{i++}
When It Is Not Possible For Them To Overflow, As Is The Case When Used In For- And While-loopsThe unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP
244: for (uint256 i; i < bidIndices.length; i++) {
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L244
302: for (uint256 i; i < seenBidMap.length - 1; i++) {
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L302
abi.encode()
is less efficient than abi.encodepacked()
See for more information: https://github.com/ConnorBlockchain/Solidity-Encode-Gas-Comparison
467: return keccak256(abi.encode(message));
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L467
26: bytes memory data = abi.encode(point, scalar);
https://github.com/code-423n4/2022-11-size/blob/main/src/util/ECCMath.sol#L26
61: return keccak256(abi.encode(point));
https://github.com/code-423n4/2022-11-size/blob/main/src/util/ECCMath.sol#L61
In some cases, having function arguments in calldata instead of memory is more optimal.
Consider the following generic example:
contract C { function add(uint[] memory arr) external returns (uint sum) { uint length = arr.length; for (uint i = 0; i < arr.length; i++) { sum += arr[i]; } } }
In the above example, the dynamic array arr has the storage location memory. When the function gets called externally, the array values are kept in calldata and copied to memory during ABI decoding (using the opcode calldataload and mstore). And during the for loop, arr[i] accesses the value in memory using a mload. However, for the above example this is inefficient. Consider the following snippet instead:
contract C { function add(uint[] calldata arr) external returns (uint sum) { uint length = arr.length; for (uint i = 0; i < arr.length; i++) { sum += arr[i]; } } }
In the above snippet, instead of going via memory, the value is directly read from calldata using calldataload. That is, there are no intermediate memory operations that carries this value.
Gas savings: In the former example, the ABI decoding begins with copying value from calldata to memory in a for loop. Each iteration would cost at least 60 gas. In the latter example, this can be completely avoided. This will also reduce the number of instructions and therefore reduces the deploy time cost of the contract.
In short, use calldata instead of memory if the function argument is only read.
Note that in older Solidity versions, changing some function arguments from memory to calldata may cause "unimplemented feature error". This can be avoided by using a newer (0.8.*) Solidity compiler.
Examples Note: The following pattern is prevalent in the codebase:
function f(bytes memory data) external { (...) = abi.decode(data, (..., types, ...)); }
Here, changing to bytes calldata will decrease the gas. The total savings for this change across all such uses would be quite significant.
function finalize(uint256 auctionId, uint256[] memory bidIndices, uint128 clearingBase, uint128 clearingQuote) public atState(idToAuction[auctionId], States.RevealPeriod) {
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L217
The following functions could be set external to save gas and improve code quality. External call cost is less expensive than of public functions.
function computeCommitment(bytes32 message) public pure returns (bytes32) {
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L466
public
/external
function names and public
member variable names can be optimized to save gas. See this link for an example of how it works. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted
File: \2022-11-size\src\SizeSealed.sol
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol
emit
[-] emit AuctionCreated(auctionId, msg.sender, auctionParams, timings, encryptedSellerPrivKey); [+] emit AuctionCreated(auctionId, msg.sender, a.params, a.timings, encryptedSellerPrivKey);
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L107
[-] msg.sender, auctionId, bidIndex, quoteAmount, commitment, pubKey, encryptedMessage, encryptedPrivateKey [+] msg.sender, auctionId, bidIndex, ebid.quoteAmount, ebid.commitment, ebid.pubKey, ebid.encryptedMessage, encryptedPrivateKey
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L166
[-] emit RevealedKey(auctionId, privateKey); [+] emit RevealedKey(auctionId, a.data.privKey);
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L193
290: baseAmount = data.totalBaseAmount - data.filledBase; 319: uint128 unsoldBase = data.totalBaseAmount - data.filledBase;
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L290 https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L319
302: seenBidMap.length - 1 309: seenBidMap.length - 1
https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L302 https://github.com/code-423n4/2022-11-size/blob/main/src/SizeSealed.sol#L309
#0 - c4-judge
2022-11-10T02:19:29Z
0xean marked the issue as grade-b