Platform: Code4rena
Start Date: 04/01/2022
Pot Size: $75,000 USDC
Total HM: 17
Participants: 33
Period: 7 days
Judge: 0xean
Total Solo HM: 14
Id: 74
League: ETH
Rank: 18/33
Findings: 2
Award: $455.21
🌟 Selected for report: 2
🚀 Solo Findings: 0
9.1606 USDC - $9.16
defsec
Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack.
Caching the array length in the stack saves around 3 gas per iteration.
https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L359
None
Consider to cache array length.
#0 - Mathepreneur
2022-01-18T16:32:39Z
Stack too deep error.
#1 - 0xean
2022-01-26T00:22:52Z
dupe of #151
defsec
++i is more gas efficient than i++ in loops forwarding.
https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L359
Code Review
It is recommend to use unchecked{++i} and change i declaration to uint256.
#0 - amateur-dev
2022-01-15T03:23:26Z
Similar issue reported over here #170; hence closing this
41.8864 USDC - $41.89
defsec
Shortening revert strings to fit in 32 bytes will decrease deploy time gas and will decrease runtime gas when the revert condition has been met.
Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.
Revert strings > 32 bytes are here:
Manual Review
Shorten the revert strings to fit in 32 bytes. That will affect gas optimization.
#0 - amateur-dev
2022-01-14T11:17:06Z
Similar issue reported over here #171; hence closing this.
defsec
!= 0
is a cheaper operation compared to > 0
, when dealing with uint.
https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L374 https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L369 https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L314 https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L292 https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L239
Code Review
Use "!=0" instead of ">0" for the gas optimization.
#0 - amateur-dev
2022-01-14T11:09:52Z
Similar issue reported over here #172; hence closing this.
41.8864 USDC - $41.89
defsec
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.
Examples:
https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L341
None
Change memory definition with calldata.
#0 - Mathepreneur
2022-01-18T09:43:22Z
We are having stack too deep errors.
🌟 Selected for report: defsec
93.0809 USDC - $93.08
defsec
Lower than uint256 size storage instance variables are actually less gas efficient. E.g. using uint16 does not give any efficiency, actually, it is the opposite as EVM operates on default of 256-bit values so uint16 is more expensive in this case as it needs a conversion. It only gives improvements in cases where you can pack variables together, e.g. structs.
https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapFactory.sol#L23 https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Core/contracts/TimeswapFactory.sol#L21
None
Consider to review all uint types. Change them with uint256 If the integer is not necessary to present with uint16.
#0 - Mathepreneur
2022-01-18T12:23:24Z
We want to utilize the type as a boundary for the fee and protocolFee.
defsec
Native fund transfers into the TimeswapConvenience contract is only expected from the wrapped token contract. Hence, it would be good to restrict incoming fund transfers to prevent accidental native fund transfers from other sources.
https://github.com/code-423n4/2022-01-timeswap/blob/main/Timeswap/Timeswap-V1-Convenience/contracts/TimeswapConvenience.sol#L69
None
receive() external payable { require(msg.sender == address(WETH) | msg.sender == address(WAVAX), 'only wrapped eth'); }
#0 - Mathepreneur
2022-01-18T16:35:18Z
Duplicate from #35