Platform: Code4rena
Start Date: 12/08/2021
Pot Size: $30,000 USDC
Total HM: 9
Participants: 8
Period: 3 days
Judge: ghoulsol
Total Solo HM: 7
Id: 25
League: ETH
Rank: 5/8
Findings: 4
Award: $1,785.79
🌟 Selected for report: 3
🚀 Solo Findings: 0
316.5364 USDC - $316.54
hickuphh3
As it is used in other contracts, rewardsToken
shouldn't be an exception.
#0 - alcueca
2021-08-16T06:51:36Z
#1 - ghoul-sol
2021-09-06T22:24:30Z
duplicate of #31
🌟 Selected for report: moose-code
Also found by: hickuphh3
527.5607 USDC - $527.56
hickuphh3
While it might seem like a good feature to have, being able to switch reward tokens will only be useful for tokens which are equivalent in value (probably stablecoins, pegged tokens) since it carries over unclaimed rewards from the previous reward program. It would be safer to keep the reward token immutable as a safeguard against violations of this condition.
#0 - alcueca
2021-08-16T07:01:31Z
#1 - ghoul-sol
2021-09-06T22:22:46Z
duplicate of #64
🌟 Selected for report: hickuphh3
390.7857 USDC - $390.79
hickuphh3
Given a configuration of target, contacts and permissions, calling terminate()
will permanently prevent this configuration from being used again because the state becomes State.TERMINATED
. All other functions require the configuration to be in the other states (UNKNOWN, PLANNED, or EXECUTED).
In other words, the removal of the restoring option for the configuration through EmergencyBrake
is permanent.
Since EmergencyBrake
cannot reinstate permissions after termination, it would be better to have terminate change its state to UNKNOWN. The TERMINATED state can therefore be removed.
#0 - alcueca
2021-08-14T06:35:25Z
That's right.
#1 - alcueca
2021-08-16T10:24:42Z
🌟 Selected for report: hickuphh3
390.7857 USDC - $390.79
hickuphh3
This would be equivalent to Unipool's rewardPerToken()
function. Note that rewardsPerToken.accumulated
only reflects the latest stored accumulated value, but does not account for pending accumulation like Unipool, and is therefore not the same. It possibly might be mistaken to be so, hence the low risk classification.
A possible implementation is given below.
function latestRewardPerToken() external view returns (uint256) { RewardsPerToken memory rewardsPerToken_ = rewardsPerToken; if (_totalSupply == 0) return rewardsPerToken_.accumulated; uint32 end = earliest(block.timestamp.u32(), rewardsPeriod.end); uint256 timeSinceLastUpdated = end - rewardsPerToken_.lastUpdated; return rewardsPerToken_.accumulated + 1e18 * timeSinceLastUpdated * rewardsPerToken_.rate / _totalSupply; }
#0 - alcueca
2021-08-15T15:31:09Z
Thanks for the suggestion. Even if there is no risk, it will be nice to have this on frontends.
37.9213 USDC - $37.92
hickuphh3
As brought up in a previous audit issue, "the suggestion of changing all public auth functions to external auth will be applied". The same should therefore be done for the new contracts Strategy.sol
and ERC20Rewards.sol
, since all public methods in it aren't called internally.
#0 - alcueca
2021-08-16T06:48:57Z
#1 - alcueca
2021-08-16T11:27:46Z
#2 - ghoul-sol
2021-09-06T22:26:32Z
#42
37.9213 USDC - $37.92
hickuphh3
The uint128
output by _updateRewardsPerToken()
isn't used by any function. Furthermore, L107 returns a wrong value.
if (_totalSupply == 0 || block.timestamp.u32() < rewardsPeriod.start) return 0;
It should return rewardsPerToken_.accumulated
instead, because in the case of a new rewards schedule being set, rewardsPeriod.start
is updated to a new timestamp. Hence, the current accumulated value of all previous reward schedules thus far should be returned.
Since the return value isn't used anywhere, remove it.
#0 - alcueca
2021-08-16T06:47:27Z
#1 - ghoul-sol
2021-09-06T22:25:24Z
duplicate of #34
🌟 Selected for report: hickuphh3
84.2697 USDC - $84.27
hickuphh3
The latest()
function is unused and can be removed.
Remove L68-L71
#0 - alcueca
2021-08-16T07:00:20Z