Platform: Code4rena
Start Date: 03/02/2022
Pot Size: $75,000 USDC
Total HM: 42
Participants: 52
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 21
Id: 83
League: ETH
Rank: 8/52
Findings: 4
Award: $2,594.12
🌟 Selected for report: 2
🚀 Solo Findings: 2
🌟 Selected for report: mtz
Also found by: 0x1f8b, Czar102, GalloDaSballo, GeekyLumberjack, Randyyy, Rhynorater, Ruhum, ShadowyNoobDev, bitbopper, cccz, cmichel, csanuragjain, danb, gzeon, hickuphh3, hyh, leastwood
31.0722 USDC - $31.07
hyh
Shelter.withdraw allows msg.sender
to withdraw to arbitrary to
address and the only state update is claimed[_token][_to] = true
, while claimed
isn't checked on the entrance.
This way msg.sender can withdraw again and again, emptying contract token holdings.
Shelter.withdraw doesn't check or update a state for msg.sender
on a withdrawal:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/Shelter.sol#L53-55
Even if withdraw() would require claimed[_token][_to] == false
it will not work as to
address is arbitrary, so the withdrawals can be repeated with another to
addresses.
This way, the simplest recommended solution is to mark the flag for msg.sender
and check it for the msg.sender
as well.
Now:
require(activated[_token] != 0 && activated[_token] + GRACE_PERIOD < block.timestamp, "shelter not activated"); ... claimed[_token][_to] = true;
To be:
require(activated[_token] != 0 && activated[_token] + GRACE_PERIOD < block.timestamp, "shelter not activated"); require(!claimed[_token][msg.sender], "already claimed"); ... claimed[_token][msg.sender] = true;
Another solution is to use a client for the record keeping, but this requires state translation as well: now only read-only client.shareOf(_token, msg.sender)
and client.totalShare(_token)
are being called and no msg.sender
flags set, i.e. the state isn't updated, the client can't know that msg.sender
withdrew already.
#0 - GalloDaSballo
2022-04-12T22:57:34Z
Duplicate of #246
🌟 Selected for report: hyh
1179.9976 USDC - $1,180.00
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/StakingRewards.sol#L178-185
notifyRewardAmount will be inoperable if rewardsDuration bet set to zero. If will cease to produce meaningful results if rewardsDuration be too small or too big
The setter do not control the value, allowing zero/near zero/enormous duration:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/StakingRewards.sol#L178-185
Division by the duration is used in notifyRewardAmount:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/StakingRewards.sol#L143-156
Check for min and max range in the rewardsDuration setter, as too small or too big rewardsDuration breaks the logic
#0 - GalloDaSballo
2022-04-19T15:15:42Z
Finding is valid, ultimately contingent on admin privilege so I believe Medium Severity to be appropriate
🌟 Selected for report: hyh
1179.9976 USDC - $1,180.00
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L182
If deposits and withdraws are done frequently enough, the reward update operation they invoke will deal mostly with the case when there is nothing to add yet, i.e. reward.remaining
match the reward token balance.
If reward token doesn't allow for zero value transfers, the reward update function will fail on an empty incremental reward transfer, which is now done unconditionally, reverting the caller deposit/withdrawal functionality
When ConvexStakingWrapper isn't paused, every deposit and withdraw update current rewards via _checkpoint
function before proceeding:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L233
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L260
_checkpoint
calls _calcRewardIntegral
for each of the reward tokens of the pid:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L220
_calcRewardIntegral
updates the incremental reward for the token, running the logic even if reward is zero, which is frequently the case:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L182
If the reward token doesn't allow zero value transfers, this transfer will fail, reverting the corresponding deposit or withdraw
Consider checking the reward before doing transfer (and the related computations as an efficiency measure):
Now:
IERC20(reward.token).transfer(address(claimContract), d_reward);
To be:
if (d_reward > 0) IERC20(reward.token).transfer(address(claimContract), d_reward);
#0 - GalloDaSballo
2022-04-19T20:12:36Z
The warden has shown how, due to a pattern that always transfer the reward token to the claim contract, in the case of a 0 transfer, certain transfers could fail, causing reverts.
While there can be an argument that this finding may not happen in reality, I believe that ultimately the system has been shown to be flawed in it's conception, perhaps adding a storage variable for the amount to claim would be more appropriate instead of dripping the rewards each time.
For that reason, and because the finding is contingent on a reward token that does revert on 0 transfer, I believe Medium Severity to be appropriate
🌟 Selected for report: hickuphh3
Also found by: 0x1f8b, 0xw4rd3n, BouSalman, CertoraInc, Czar102, Dravee, IllIllI, Randyyy, Rhynorater, Ruhum, ShadowyNoobDev, Sleepy, SolidityScan, WatchPug, bitbopper, cccz, cryptphi, csanuragjain, defsec, gzeon, harleythedog, hubble, hyh, kenta, kirk-baird, leastwood, mtz, pauliax, peritoflores, rfa, robee, samruna, throttle, wuwe1, ye0lde
203.0461 USDC - $203.05
A range of malfunctions is possible if core configuration parameters are set by mistake to any values that make little sense. It is also not always right away evident that such a mistake took place
Setters don't check the core configuration values:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L69-72
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L82-88
Consider adding zero address, zero and range parameter checks
As different compiler versions have critical behavior specifics if the contract gets accidentally deployed using another compiler version compared to one they tested with, various types of undesired behavior can be introduced
Contracts use pragma solidity ^0.8.11
:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/StakingRewards.sol#L3
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConcurRewardPool.sol#L3
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L3
Fix the compiler version across the system
System then will fail with low level error message on liquidity addition attempt
pool3 balance isn't checked before liquidity provision, looks like it's assumed to always match usdm balance:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/USDMPegRecovery.sol#L80
Check both balances before calling add_liquidity
Code is less clear, gas is overspent on requires
solidity 0.8.11 allows for custom errors:
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/StakingRewards.sol#L3
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConcurRewardPool.sol#L3
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConvexStakingWrapper.sol#L3
Consider introducing and using custom errors instead of the revert strings to save gas:
#0 - GalloDaSballo
2022-04-26T20:39:59Z
ConvexStakingWrapper constructor and core configuration setters don't check the values (low) Finding is valid
Unlocked pragma (low) Ultimately disagree as settings will define the pragma used for compilation
Pool3 balance isn't checked before liquidity provision (non-critical) I genuinely would have preferred for the warden to spend the extra time to further explain this finding as it's probably a medium, that said I'lll mark as valid but won't escalate due to lack of further details
Use custom errors to save gas (low) Disagree that this is a low severity when you literally tell it's to save gas in the title
All in all this looks like a very rushed report which lacks formatting and details, would recommend the warden to spend a few more minutes to add detail to their submissions
Equivalent of 2 findings -- (bad formatting)
#1 - GalloDaSballo
2022-04-26T20:41:12Z
Adding #90 and #88 makes me raise to 3 valid findings