Platform: Code4rena
Start Date: 09/11/2021
Pot Size: $75,000 USDC
Total HM: 57
Participants: 27
Period: 7 days
Judge: alcueca
Total Solo HM: 49
Id: 52
League: ETH
Rank: 9/27
Findings: 5
Award: $2,771.66
🌟 Selected for report: 11
🚀 Solo Findings: 0
728.5837 USDC - $728.58
pauliax
Anyone can call function vestFor and block any user with a tiny amount of Vader. This function has no auth checks so a malicious actor can front-run legit vestFor calls with insignificant amounts. This function locks the user for 365 days and does not allow updating the value, thus forbids legit conversions.
Consider introducing a whitelist of callers that can vest on behalf of others (e.g. Converter).
🌟 Selected for report: pauliax
Also found by: TomFrenchBlockchain
728.5837 USDC - $728.58
pauliax
Unused slippage params. function addLiquidity in VaderRouter (both V1 and V2) do not use slippage parameters:
uint256, // amountAMin = unused uint256, // amountBMin = unused
making it susceptible to sandwich attacks / MEV. For a more detailed explanation, see: https://github.com/code-423n4/2021-09-bvecvx-findings/issues/57
Consider paying some attention to the slippage to reduce possible manipulation attacks from mempool snipers.
#0 - SamSteinGG
2021-11-25T12:49:25Z
Slippage checks are impossible in the Thorchain CLP model.
#1 - alcueca
2021-12-11T05:47:02Z
Taking as main over #1 as it is a more general issue, but refer to #1 for a more detailed description and justification for the severity rating.
🌟 Selected for report: TomFrenchBlockchain
Also found by: pauliax
218.5751 USDC - $218.58
pauliax
There are several loops in the contract which can eventually grow so large as to make future operations of the contract cost too much gas to fit in a block. Specifically, in contract TwapOracle there is no upper boundary on how many pairs can be registered (function registerPair). Functions update and consult iterate over all the pairs. These functions may become unusable if the pairCount grows so large that the execution exceeds the block gas limit, consumes all the gas provided, and fails.
Consider either introducing a reasonable limit or adding a removal function that can be used in an emergency case like this.
#0 - SamSteinGG
2021-11-20T06:51:07Z
Duplicate of #8
🌟 Selected for report: TomFrenchBlockchain
43.715 USDC - $43.72
pauliax
Reliance that Chainlink Oracle decimals is 8:
sumUSD += uint256(price) * (10**10);
Hardcoded values make the code harder to maintain, you can easily miss this when later deciding to deploy the same contracts on other chains, etc.
It would make the code more robust if you do not hardcode such values but fetch them directly. The downside is increased gas costs so at least you can extract this 10**10 as a constant to improve the readability and eliminate the evaluation of not changing value over and over again.
You can check that Chainlink interface contains decimals function: https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol
To be honest, I think in practice It is very unlikely that these decimals will change but nevertheless wanted you to be informed about such a possibility.
#0 - SamSteinGG
2021-11-25T12:46:04Z
Duplicate #49
#1 - alcueca
2021-12-10T14:24:50Z
Duplicate of #18
🌟 Selected for report: ye0lde
Also found by: Meta0xNull, defsec, pants, pauliax
21.2455 USDC - $21.25
pauliax
Open TODOs in Codebase
There are TODOs left in the code. While this does not cause any direct issue, it indicates a bad smell and uncertainty, especially seeing such todo messages:
// TODO: Uncomment prior to launch // TBD
In previous reports, similar submissions were assigned a score of 'low' so I think it's a fair game to submit this as an issue here also. Reference: https://github.com/code-423n4/2021-09-swivel-findings/issues/67 and https://github.com/code-423n4/2021-10-tempus-findings/issues/39
TODOs: https://github.com/code-423n4/2021-11-vader/blob/main/contracts/tokens/USDV.sol#L38 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L157 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L209 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L265 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex-v2/pool/VaderPoolV2.sol#L400 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex/pool/BasePool.sol#L163 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex/pool/VaderPool.sol#L85 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex/pool/VaderPool.sol#L93 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex/router/VaderRouter.sol#L303 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex/utils/GasThrottle.sol#L11 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/dex/math/VaderMath.sol#L80 https://github.com/code-423n4/2021-11-vader/blob/main/contracts/twap/TwapOracle.sol#L125 https://github.com/code-423n4/2021-11-vader/blob/main/repo/vader-bond/contracts/VaderBond.sol#L299 https://github.com/code-423n4/2021-11-vader/blob/main/repo/vader-bond/contracts/VaderBond.sol#L336
Consider fixing TODOs or removing them to ease the work of reviewers.
#0 - SamSteinGG
2021-11-25T12:42:02Z
Duplicate of #102
🌟 Selected for report: pauliax
161.9075 USDC - $161.91
pauliax
Due to the asynchronous nature of blockchains, it is not advised to use toggle functions. In your case, you have function toggleQueue in contracts VaderPool and VaderPoolV2. A similar issue was reported in another contest and assigned a severity of low, you can read more details here: https://github.com/code-423n4/2021-06-realitycards-findings/issues/157
Replace with a function where you can specify the exact value that you want to set.
🌟 Selected for report: pauliax
161.9075 USDC - $161.91
pauliax
These functions do not check if the contract is already initialized or not, only if the new values are not empty. It transfers the ownership to the new gov but does not forbid calling this function again later. I am not entirely sure about the intentions here, maybe this is intentional but usually "init" keyword indicates that it is expected to be called only once. It does not cause any serious risk to the protocol itself but increases the reliance on the fairness of the governance and decreases trust from users because an ability to override the 'nativeAsset' or 'router' doesn't sound fair unless this is clearly mentioned somewhere.
Depends on the intentions but my suggestion is to either forbid initializing it again or rename the function to avoid confusion.
#0 - SamSteinGG
2021-11-25T12:42:32Z
As the finding indicates, the DAO would need to maliciously vote to reset these variables and as such this finding is not of medium risk.
#1 - alcueca
2021-12-11T07:21:59Z
Agree with sponsor.
🌟 Selected for report: pauliax
161.9075 USDC - $161.91
pauliax
function setBondTerms relies on block times to be roughly 13.75s:
// roughly 36 hours (262 blocks / hour) require(_input >= 10000, "vesting < 10000");
However, block times are likely to be reduced to 12s soon: https://twitter.com/TimBeiko/status/1456644168986419200
Just wanted you to be informed about this. It is up to you to decide if this difference is significant enough to make code changes.
#0 - 0xstormtrooper
2021-11-16T01:01:58Z
vesting term can easily be adjusted by contract owner
🌟 Selected for report: pauliax
161.9075 USDC - $161.91
pauliax
the constructor of LinearVesting should validate that vesters are all unique addresses, otherwise, it will overwrite the existing vesting amount for that address.
🌟 Selected for report: TomFrenchBlockchain
18.5358 USDC - $18.54
pauliax
'immutable' greatly reduces gas costs. There are variables that do not change so they can be marked as immutable to greatly improve the gas costs. Examples of such variables are _name in BasePool _name, _vaderPool and _updatePeriod in TwapOracle, vader in XVader.
#0 - 0xstormtrooper
2021-11-16T00:44:12Z
🌟 Selected for report: Reigada
Also found by: Meta0xNull, pants, pauliax
12.5116 USDC - $12.51
pauliax
Avoiding the initialization of loop index to 0 can save some gas. See for more details: https://github.com/code-423n4/2021-09-swivel-findings/issues/115
#0 - SamSteinGG
2021-11-20T06:49:23Z
Duplicate of #82
pauliax
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition has been met. There are some pretty long revert msgs, e.g.: "VaderPoolFactory::initialize: Incorrect Arguments". Consider shortening them.
#0 - SamSteinGG
2021-11-20T06:47:55Z
Duplicate of #104
🌟 Selected for report: pauliax
68.651 USDC - $68.65
pauliax
payout token exponent in function valueOfToken can be precalculated as this value is constant and does not change:
value = _amount.mul(10**PAYOUT_TOKEN_DECIMALS).div(10**IERC20Metadata(_principalToken).decimals());
Extract 10**PAYOUT_TOKEN_DECIMALS as a constant.
Same situation here with 232 and 1010:
uint32 blockTimestamp = uint32(block.timestamp % 2**32); sumUSD += uint256(price) * (10**10);
🌟 Selected for report: pauliax
68.651 USDC - $68.65
pauliax
queueActive in contract VaderPoolFactory is always false and there is no way to update this value so to save some gas consider getting rid of this state variable and just use a value of "false" when creating a new Pool.
🌟 Selected for report: pauliax
68.651 USDC - $68.65
pauliax
There are contracts that declare solidity compiler version >= 0.8 but still use SafeMath, e.g. UniswapV2Library, StakingRewards:
using SafeMath for uint256;
Starting from 0.8 you no longer need to use an external SafeMath library as it is already baked in and used under the hood unless explicitly stated by using the 'unchecked' directive.
#0 - 0xstormtrooper
2021-11-16T01:19:56Z
StakingRewards - duplicate, confirmed https://github.com/code-423n4/2021-11-vader-findings/issues/70
🌟 Selected for report: pauliax
68.651 USDC - $68.65
pauliax
There are some variables that are never used. Remove them to save some gas or use where they were intended. Examples are:
uint256 internal constant _MIN_SWAPS_EXECUTED = 10; uint256 internal constant _DEFAULT_SWAPS_EXECUTED = 50_00; uint256 internal constant _QUEUE_SIZE = 100;
🌟 Selected for report: pauliax
68.651 USDC - $68.65
pauliax
The unchecked keyword can be applied in the following lines of code since there are statements before to ensure the arithmetic operations would not cause an integer underflow or overflow:
return a > b ? a - b : b - a;
By the way, here because Solidity 0.8.9 is used, this desired overflow will fail:
// subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
#0 - SamSteinGG
2021-12-22T07:37:20Z
The TWAP oracle module has been completely removed and redesigned from scratch as LBTwap that is subject of the new audit.