Platform: Code4rena
Start Date: 21/12/2021
Pot Size: $30,000 USDC
Total HM: 20
Participants: 20
Period: 5 days
Judge: Jack the Pug
Total Solo HM: 13
Id: 70
League: ETH
Rank: 9/20
Findings: 2
Award: $412.39
🌟 Selected for report: 6
🚀 Solo Findings: 0
15.5017 USDC - $15.50
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/2021-12-vader/blob/main/contracts/tokens/USDV.sol#L152
None
Consider to cache array length.
#0 - jack-the-pug
2022-03-12T14:36:05Z
Dup #122
🌟 Selected for report: defsec
143.7924 USDC - $143.79
defsec
In the dexV2 contract, onlyRouter modifier have been used in the multiple function. However in the Basepool contract there is no setter function has been defined.
"""
None
Initiliaze the router contract in the constructor or define setter function in the contracts.
15.5017 USDC - $15.50
defsec
There is a function declared as public that are never called internally within the contract. It is best practice to mark such functions as external instead, as this saves gas (especially in the case where the function takes arguments, as external functions can read arguments directly from calldata instead of having to allocate memory).
Code Review
All of the public functions in the contract are not called internally, so access can be changed to external to reduce gas.
15.5017 USDC - $15.50
defsec
++i is more gas efficient than i++ in loops forwarding.
https://github.com/code-423n4/2021-12-vader/blob/main/contracts/tokens/USDV.sol#L152
Code Review
It is recommend to use unchecked{++i} and change i declaration to uint256.
#0 - jack-the-pug
2022-03-12T14:51:20Z
Dup #123
🌟 Selected for report: defsec
57.4139 USDC - $57.41
defsec
!= 0
is a cheaper operation compared to > 0
, when dealing with uint.
https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L227 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L300 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L331 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L394 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L412 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L419 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L430 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L506 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/BasePoolV2.sol#L561 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/lbt/LiquidityBasedTWAP.sol#L93
None
Consider to replace > 0
with != 0
for gas optimization.
🌟 Selected for report: robee
Also found by: TomFrenchBlockchain, defsec
15.5017 USDC - $15.50
defsec
'immutable' greatly reduces gas costs. There is a variable that does not change so it can be marked as immutable to improve the gas costs:
None
Consider to use 'immutable' variable.
#0 - jack-the-pug
2022-03-13T11:35:32Z
Dup #19
15.5017 USDC - $15.50
defsec
For the arithmetic operations that will never over/underflow, using the unchecked directive (Solidity v0.8 has default overflow/underflow checks) can save some gas from the unnecessary internal over/underflow checks.
https://github.com/code-423n4/2021-12-vader/blob/fd2787013608438beae361ce1bb6d9ffba466c45/contracts/dex-v2/pool/VaderPoolV2.sol#L79 https://github.com/code-423n4/2021-12-vader/blob/fd2787013608438beae361ce1bb6d9ffba466c45/contracts/dex-v2/pool/VaderPoolV2.sol#L79
None
Consider applying unchecked arithmetic where overflow/underflow is not possible.
#0 - jack-the-pug
2022-03-13T12:27:03Z
Dup #130
🌟 Selected for report: defsec
Also found by: Jujic, TomFrenchBlockchain, danb, hyh
18.8684 USDC - $18.87
defsec
The getChainlinkPrice function in the contract LiquidityBasedTWAP.sol fetches the asset price from a Chainlink aggregator using the latestRoundData function. However, there are no checks on timestamp, resulting in stale prices. The oracle wrapper calls out to a chainlink oracle receiving the latestRoundData(). It then checks freshness by verifying that the answer is indeed for the last known round.
Stale prices could put funds at risk. According to Chainlink's documentation, This function does not error if no answer has been reached but returns 0, causing an incorrect price fed to the PriceOracle. The external Chainlink oracle, which provides index price information to the system, introduces risk inherent to any dependency on third-party data sources. For example, the oracle could fall behind or otherwise fail to be maintained, resulting in outdated data being fed to the index price calculations of the AMM. Oracle reliance has historically resulted in crippled on-chain systems, and complications that lead to these outcomes can arise from things as simple as network congestion.
"https://github.com/code-423n4/2021-12-vader/blob/main/contracts/lbt/LiquidityBasedTWAP.sol#L85"
Consider to add checks on the return data (Timestamp) with proper revert messages if the price is stale in the timestamp, for example:
(uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound) = ETH_CHAINLINK.latestRoundData(); require(price > 0, "Chainlink price <= 0"); require(answeredInRound >= roundID, "..."); require(timeStamp != 0, "...");
🌟 Selected for report: defsec
57.4139 USDC - $57.41
defsec
In the wrapper contract, protocol constants are not used. This contract is used in the pool contracts. Therefore, It is submitted.
None
Delete redundant inherited contracts.
🌟 Selected for report: defsec
57.4139 USDC - $57.41
defsec
Lower than uint256 size storage instance variables are actually less gas efficient. E.g. using uint112 does not give any efficiency, actually, it is the opposite as EVM operates on default of 256-bit values so uint8 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/2021-12-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L325 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L395 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L174 https://github.com/code-423n4/2021-12-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L226
None
Consider to review all uint types. Change them with uint256 If the integer is not necessary to present with 112.